A command line tool for interacting with your DigitalOcean droplets.
When Tugboat was created, DigitalOcean was an extremely new cloud provider. They'd only released their public beta back in 2012, and their new SSD backed machines only premiered in early 2013.
Tugboat started out life around that time, back in April 2013. Back then, there were no official libraries for DigitalOcean, and the 1.0 API was a bit unstable and occasionally flakey.
Since then, DigitalOcean has expanded rapidly and has started offering official libraries.
They now have an offically maintained command-line client called doctl.
Some people have asked, where does that leave Tugboat?
If you want the bleeding edge of new features and official support from DigitalOcean engineers, Doctl is the way to go. However, as long as there is one other user out there who likes Tugboat and it's workflow, I will try my darndest to maintain this project, investigate bugs, implement new features and merge pull-requests.
gem install tugboat Please note that Tugboat version 0.2.0 and up requires Ruby 1.9 or higher.
Run the configuration utility, tugboat authorize. You can grab your keys here.
$ tugboat authorize Enter your client key: foo Enter your API key: bar Enter your SSH key path (optional, defaults to ~/.ssh/id_rsa): Enter your SSH user (optional, defaults to jack): Enter your SSH port number (optional, defaults to 22): To retrieve region, image, size and key ID's, you can use the corresponding tugboat command, such as `tugboat images`. Defaults can be changed at any time in your ~/.tugboat configuration file. Enter your default region ID (optional, defaults to 1 (New York)): Enter your default image ID (optional, defaults to 350076 (Ubuntu 13.04 x64)): Enter your default size ID (optional, defaults to 66 (512MB)): Enter your default ssh key IDs (optional, defaults to '', comma separated string): Authentication with DigitalOcean was successful! This will create a .tugboat file in your home folder (eg. ~/.tugboat).
Tugboat will look for a .tugboat config file first in the current directory you're running it in, then will look for one in the home directory.
An example of a .tugboat file:
--- authentication: access_token: f8sazukxeh729ggxh9gjavvzw5cabdpq95txpzhz6ep6jvtquxztfkf2chyejcsg5 ssh: ssh_user: root ssh_key_path: "~/.ssh/id_rsa" ssh_port: '22' defaults: region: nyc2 image: ubuntu-14-04-x64 size: 512mb ssh_key: ['1234','5678'] private_networking: 'false' backups_enabled: 'false' ip6: 'false'$ tugboat droplets pearkes-web-001 (ip: 30.30.30.1, status: active, region: nyc2, id: 13231511) pearkes-admin-001 (ip: 30.30.30.3, status: active, region: nyc2, id: 13231512) pearkes-api-001 (ip: 30.30.30.5, status: active, region: nyc2, id: 13231513) If you wish to use the droplet listing as part of scripting or munging output, you can use the --porcelain:
$ tugboat droplets --attribute=ip4 pearkes-web-001,30.30.30.1 pearkes-admin-001,30.30.30.3 pearkes-api-001,30.30.30.5 Or --attribute parameter:
$ tugboat droplets --porcelain name pearkes-web-001 id 13231515 status active ip4 330.30.30.1 region lon1 image 6918990 size 1gb backups_active false name pearkes-admin-001 id 13231513 status active ip4 30.30.30.3 region lon1 image 6918990 size 1gb backups_active false name pearkes-web-001 id 13231514 status active ip4 30.30.30.5 region lon1 image 6918990 size 1gb backups_active true You can pass a unique fragment of a droplets name for interactions throughout tugboat.
$ tugboat restart admin Droplet fuzzy name provided. Finding droplet ID...done, 13231512 (pearkes-admin-001) Queuing restart for 13231512 (pearkes-admin-001)...done tugboat handles multiple matches as well:
$ tugboat restart pearkes Droplet fuzzy name provided. Finding droplet ID...Multiple droplets found. 0) pearkes-web-001 (13231511) 1) pearkes-admin-001 (13231512) 2) pearkes-api-001 (13231513) Please choose a droplet: ["0", "1", "2"] 0 Queuing restart for 13231511 (pearkes-web-001)...done You can configure an SSH username and key path in tugboat authorize, or by changing your ~/.tugboat.
This lets you ssh into a droplet by providing it's name, or a partial match.
$ tugboat ssh admin Droplet fuzzy name provided. Finding droplet ID...done, 13231512 (pearkes-admin-001) Executing SSH (pearkes-admin-001)... Welcome to Ubuntu 12.10 (GNU/Linux 3.5.0-17-generic x86_64) pearkes@pearkes-admin-001:~# You can configure an SSH username and key path in tugboat authorize, or by changing your ~/.tugboat.
This lets you scp a file into a droplet by providing it's name, or a partial match.
$ tugboat scp test-scp /tmp/foo /tmp/bar Droplet fuzzy name provided. Finding droplet ID...done, 72025053 (test-scp) Executing SCP on Droplet (test-scp)... Attempting SCP with `scp -i /Users/petems/.ssh/digital_ocean /tmp/foo root@132.61.164.113:/tmp/bar` foo 100% 0 0.0KB/s 00:00 $ tugboat create pearkes-www-002 -s 512mb -i ubuntu-12-04-x64 -r nyc2 -k 11251 Queueing creation of droplet 'pearkes-www-002'...done $ tugboat info admin Droplet fuzzy name provided. Finding droplet ID...done, 13231512 (pearkes-admin-001) Name: pearkes-admin-001 ID: 13231512 Status: active IP: 30.30.30.3 Backups Active: false IP6: 2A03:B0C0:0001:00D0:0000:0000:0308:D001 Region: London 1 - lon1 Image: 6918990 - ubuntu-14-04-x64 Size: 1GB Print info in machine-readable format. The --porcelain flag silences extra output for easy parsing. Fuzzy name matching is not supported with the --porcelain flag.
$ tugboat info -n pearkes-admin-001 --porcelain name pearkes-admin-001 id 13231512 status active ip4 30.30.30.3 region lon1 image 6918990 size 1gb backups_active false Print a single attribute.
$ tugboat info -n pearkes-admin-001 --attribute ip --porcelain 30.30.30.3 $ tugboat destroy pearkes-www-002 Droplet fuzzy name provided. Finding droplet ID...done, 13231515 (pearkes-www-002) Warning! Potentially destructive action. Please confirm [y/n]: y Queuing destroy for 13231515 (pearkes-www-002)...done $ tugboat restart admin Droplet fuzzy name provided. Finding droplet ID...done, 13231512 (pearkes-admin-001) Queuing restart for 13231512 (pearkes-admin-001)...done $ tugboat halt admin Droplet fuzzy name provided. Finding droplet ID...done, 13231512 (pearkes-admin-001) Queuing shutdown for 13231512 (pearkes-admin-001)...done $ tugboat snapshot test-admin-snaphot admin Queuing snapshot 'test-admin-snapshot' for 13231512 (pearkes-admin-001)...done $ tugboat resize admin -s 66 Queuing resize for 13231512 (pearkes-admin-001)...done $ tugboat backup_config admin --on Droplet fuzzy name provided. Finding droplet ID...done\e[0m, 6918990 (example.com) Backup action enable backups is complete $ tugboat backup_config admin --off Droplet fuzzy name provided. Finding droplet ID...done\e[0m, 6918990 (example.com) Backup action disable backups is complete You can list all images
$ tugboat images Showing both private and public images Private Images: My application image (id: 6376601, distro: Ubuntu) Public Images: 745.1.0 (alpha) (slug: coreos-alpha, id: 12789325, distro: CoreOS) 723.3.0 (beta) (slug: coreos-beta, id: 12789350, distro: CoreOS) 717.3.0 (stable) (slug: coreos-stable, id: 12789351, distro: CoreOS) .... Or just list images that you have created.
$ tugboat images --show_just_private_images # or -p Showing just private images Private Images: My application image (id: 6376601, distro: Ubuntu) .... $ tugboat snapshots code-freeze-backup-october (id: 2013184, resource_type: droplet, created_at: 2016-10-06T11:43:06Z) test-admin 2017-05-31 (id: 20234485, resource_type: droplet, created_at: 2017-05-31T02:07:07Z) test-admin 2017-11-08 (id: 21133567, resource_type: droplet, created_at: 2017-11-08T02:49:09Z) test-admin 2017-11-15 (id: 22355454, resource_type: droplet, created_at: 2017-11-15T03:11:08Z) test-admin 2017-11-22 (id: 24523423, resource_type: droplet, created_at: 2017-11-22T03:10:09Z) test-admin 2017-11-29 (id: 26212345, resource_type: droplet, created_at: 2017-11-29T03:15:25Z) .... $ tugboat sizes Sizes: Disk: 20GB, Memory: 512MB (slug: 512mb) Disk: 30GB, Memory: 1024MB (slug: 1gb) Disk: 40GB, Memory: 2048MB (slug: 2gb) Disk: 60GB, Memory: 4096MB (slug: 4gb) Disk: 80GB, Memory: 8192MB (slug: 8gb) Disk: 160GB, Memory: 16384MB (slug: 16gb) Disk: 320GB, Memory: 32768MB (slug: 32gb) Disk: 480GB, Memory: 49152MB (slug: 48gb) Disk: 640GB, Memory: 65536MB (slug: 64gb) ... $ tugboat regions Regions: Amsterdam 1 (slug: ams1) Amsterdam 2 (slug: ams2) Amsterdam 3 (slug: ams3) London 1 (slug: lon1) New York 1 (slug: nyc1) New York 2 (slug: nyc2) New York 3 (slug: nyc3) San Francisco 1 (slug: sfo1) Singapore 1 (slug: sgp1) $ tugboat add-key digitalocean Possible public key paths from /Users/pearkes/.ssh: /Users/pearkes/.ssh/digitalocean.pub /Users/pearkes/.ssh/fog.pub /Users/pearkes/.ssh/github.pub /Users/pearkes/.ssh/id_rsa.pub /Users/pearkes/.ssh/terraform.pub Enter the path to your SSH key: /Users/petersouter/.ssh/digitalocean.pub Queueing upload of SSH key 'digitalocean'...SSH Key uploaded Name: digitalocean ID: 1384812 ... $ tugboat keys Keys: Name: pearkes, (id: 231192), fingerprint: 3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa ... Sometimes you want to wait for a droplet to enter some state, for example "off".
$ tugboat wait admin --state off Droplet fuzzy name provided. Finding droplet ID...done, 13231512 (pearkes-admin-001) Waiting for droplet to become off.... ... This will simply block until the droplet returns a state of "off". A period will be printed after each request.
If you're curious about command flags for a specific command, you can ask tugboat about it.
$ tugboat help restart For a complete overview of all of the available commands, run:
$ tugboat help Depending on your local configuration, you may need to install a CA bundle (OS X only) using homebrew to communicate with DigitalOcean through SSL/TLS:
$ brew install curl-ca-bundle After installation, source the bundle path in your .bash_profile/.bashrc:
export SSL_CERT_FILE=/usr/local/opt/curl-ca-bundle/share/ca-bundle.crt Yes, please!
You can create a new issue here. To help with the investigation of your issue, you can set the environment variable DEBUG to give verbose Faraday logging.
- DEBUG=1 is full unredacted
- DEBUG=2 redacts private keys from the log.
Example:
DEBUG=2 bundle exec tugboat regions I, [2015-12-06T12:04:27.148922 #92772] INFO -- : Started GET request to: https://api.digitalocean.com/v2/regions?per_page=200 D, [2015-12-06T12:04:27.149334 #92772] DEBUG -- : Request Headers: ---------------- Authorization : Bearer [TOKEN REDACTED] Content-Type : application/json User-Agent : Faraday v0.9.2 Request Body: ------------- { "regions": [ { "name": "New York 1", "slug": "nyc1", "sizes": [ "32gb", "16gb", "2gb", "1gb", "4gb", "8gb", "512mb", "64gb", "48gb" ], "features": [ "private_networking", "backups", "ipv6", "metadata" ], "available": true }, { "name": "Amsterdam 1", "slug": "ams1", "sizes": [ "16gb", "2gb", "1gb", "4gb", "8gb", "512mb" ], "features": [ "backups" ], "available": true }, { "name": "San Francisco 1", "slug": "sfo1", "sizes": [ "32gb", "16gb", "2gb", "1gb", "4gb", "8gb", "512mb", "64gb", "48gb" ], "features": [ "private_networking", "backups", "ipv6", "metadata" ], "available": true }, { "name": "New York 2", "slug": "nyc2", "sizes": [ "32gb", "16gb", "2gb", "1gb", "4gb", "8gb", "512mb", "64gb", "48gb" ], "features": [ "private_networking", "backups", "ipv6", "metadata" ], "available": true }, { "name": "Amsterdam 2", "slug": "ams2", "sizes": [ "32gb", "16gb", "2gb", "1gb", "4gb", "8gb", "512mb", "64gb", "48gb" ], "features": [ "private_networking", "backups", "ipv6", "metadata" ], "available": true }, { "name": "Singapore 1", "slug": "sgp1", "sizes": [ "32gb", "16gb", "2gb", "1gb", "4gb", "8gb", "512mb", "64gb", "48gb" ], "features": [ "private_networking", "backups", "ipv6", "metadata" ], "available": true }, { "name": "London 1", "slug": "lon1", "sizes": [ "32gb", "16gb", "2gb", "1gb", "4gb", "8gb", "512mb", "64gb", "48gb" ], "features": [ "private_networking", "backups", "ipv6", "metadata" ], "available": true }, { "name": "New York 3", "slug": "nyc3", "sizes": [ "32gb", "16gb", "2gb", "1gb", "4gb", "8gb", "512mb", "64gb", "48gb" ], "features": [ "private_networking", "backups", "ipv6", "metadata" ], "available": true }, { "name": "Amsterdam 3", "slug": "ams3", "sizes": [ "32gb", "16gb", "2gb", "1gb", "4gb", "8gb", "512mb", "64gb", "48gb" ], "features": [ "private_networking", "backups", "ipv6", "metadata" ], "available": true }, { "name": "Frankfurt 1", "slug": "fra1", "sizes": [ "32gb", "16gb", "2gb", "1gb", "4gb", "8gb", "512mb", "64gb", "48gb" ], "features": [ "private_networking", "backups", "ipv6", "metadata" ], "available": true }, { "name": "Toronto 1", "slug": "tor1", "sizes": [ "32gb", "16gb", "2gb", "1gb", "4gb", "8gb", "512mb", "64gb", "48gb" ], "features": [ "private_networking", "backups", "ipv6", "metadata" ], "available": true } ], "links": { }, "meta": { "total": 11 } }See the contributing guide.