tugboat 2.0.0.RC1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -2
- data/README.md +47 -34
- data/lib/tugboat/cli.rb +53 -13
- data/lib/tugboat/config.rb +15 -1
- data/lib/tugboat/middleware/ask_for_credentials.rb +1 -1
- data/lib/tugboat/middleware/create_droplet.rb +38 -17
- data/lib/tugboat/middleware/find_droplet.rb +13 -3
- data/lib/tugboat/middleware/find_image.rb +3 -1
- data/lib/tugboat/middleware/info_droplet.rb +8 -2
- data/lib/tugboat/middleware/info_image.rb +1 -0
- data/lib/tugboat/middleware/list_droplets.rb +7 -1
- data/lib/tugboat/middleware/ssh_droplet.rb +3 -1
- data/lib/tugboat/version.rb +1 -1
- data/spec/cli/add_key_spec.rb +2 -0
- data/spec/cli/authorize_cli_spec.rb +2 -2
- data/spec/cli/create_cli_spec.rb +44 -4
- data/spec/cli/droplets_cli_spec.rb +18 -0
- data/spec/cli/env_variable_spec.rb +36 -0
- data/spec/cli/info_cli_spec.rb +30 -7
- data/spec/cli/info_image_cli_spec.rb +4 -0
- data/spec/fixtures/show_droplet_user_image.json +82 -0
- data/spec/fixtures/user_data.sh +3 -0
- data/spec/middleware/find_droplet_spec.rb +4 -0
- data/spec/middleware/find_image_spec.rb +4 -0
- data/spec/middleware/ssh_droplet_spec.rb +1 -1
- metadata +10 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d9cd87077814b0c15d54c53ba161fffdf4adcd5
|
4
|
+
data.tar.gz: cea9da9936b38ff7b773643406cbf2ed6ac8b844
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 04e3dd2f82fc781620cdea6ec5966b4e6ac836333d276f541bccfd526cc051d06adcbcfe25975ae5677757d046f52bd8d04e8bd911d33e8fac85e22a9e395ffb
|
7
|
+
data.tar.gz: 59aebcb1e96713bd589e071088a4c35af544b8b2d065ba0ef3e54f696622bb14edfaca431b8b19f3258f3796132182f717a4af3207781da8b028a57d2be9da44
|
data/CHANGELOG.md
CHANGED
@@ -1,8 +1,26 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
## [v2.0.0.RC1](https://github.com/pearkes/tugboat/tree/v2.0.0.RC1) (2015-10-20)
|
4
|
+
|
5
|
+
[Full Changelog](https://github.com/pearkes/tugboat/compare/v1.3.1...v2.0.0.RC1)
|
6
|
+
|
7
|
+
**Closed issues:**
|
8
|
+
|
9
|
+
- Possible to delete an image/snapshot? [\#177](https://github.com/pearkes/tugboat/issues/177)
|
10
|
+
|
11
|
+
**Merged pull requests:**
|
12
|
+
|
13
|
+
- Update gemspec [\#181](https://github.com/pearkes/tugboat/pull/181) ([petems](https://github.com/petems))
|
14
|
+
|
15
|
+
- API 2.0 Release Candidate PR [\#180](https://github.com/pearkes/tugboat/pull/180) ([petems](https://github.com/petems))
|
16
|
+
|
17
|
+
- Add CLI config spec and slight formatting changes [\#179](https://github.com/pearkes/tugboat/pull/179) ([petems](https://github.com/petems))
|
18
|
+
|
19
|
+
- Fix interactive prompt during authorize [\#175](https://github.com/pearkes/tugboat/pull/175) ([conorsch](https://github.com/conorsch))
|
20
|
+
|
3
21
|
## [v1.3.1](https://github.com/pearkes/tugboat/tree/v1.3.1) (2015-08-02)
|
4
22
|
|
5
|
-
[Full Changelog](https://github.com/pearkes/tugboat/compare/
|
23
|
+
[Full Changelog](https://github.com/pearkes/tugboat/compare/v2.1.0.ALPHA...v1.3.1)
|
6
24
|
|
7
25
|
**Closed issues:**
|
8
26
|
|
@@ -12,6 +30,10 @@
|
|
12
30
|
|
13
31
|
- Removes wrong help messages for `images`. [\#173](https://github.com/pearkes/tugboat/pull/173) ([haihappen](https://github.com/haihappen))
|
14
32
|
|
33
|
+
## [v2.1.0.ALPHA](https://github.com/pearkes/tugboat/tree/v2.1.0.ALPHA) (2015-07-20)
|
34
|
+
|
35
|
+
[Full Changelog](https://github.com/pearkes/tugboat/compare/v1.3.0...v2.1.0.ALPHA)
|
36
|
+
|
15
37
|
## [v1.3.0](https://github.com/pearkes/tugboat/tree/v1.3.0) (2015-07-19)
|
16
38
|
|
17
39
|
[Full Changelog](https://github.com/pearkes/tugboat/compare/v1.2.0...v1.3.0)
|
@@ -38,12 +60,14 @@
|
|
38
60
|
|
39
61
|
## [v1.1.0](https://github.com/pearkes/tugboat/tree/v1.1.0) (2015-07-18)
|
40
62
|
|
41
|
-
[Full Changelog](https://github.com/pearkes/tugboat/compare/
|
63
|
+
[Full Changelog](https://github.com/pearkes/tugboat/compare/v1.0.0...v1.1.0)
|
42
64
|
|
43
65
|
**Closed issues:**
|
44
66
|
|
45
67
|
- Unable to bundle to run tugboat from git repo version for testing [\#171](https://github.com/pearkes/tugboat/issues/171)
|
46
68
|
|
69
|
+
- 1.0.0 Release [\#125](https://github.com/pearkes/tugboat/issues/125)
|
70
|
+
|
47
71
|
**Merged pull requests:**
|
48
72
|
|
49
73
|
- Update ssh to private ip [\#172](https://github.com/pearkes/tugboat/pull/172) ([petems](https://github.com/petems))
|
data/README.md
CHANGED
@@ -28,7 +28,7 @@ Run the configuration utility, `tugboat authorize`. You can grab your keys
|
|
28
28
|
Enter your default region ID (optional, defaults to 1 (New York)):
|
29
29
|
Enter your default image ID (optional, defaults to 350076 (Ubuntu 13.04 x64)):
|
30
30
|
Enter your default size ID (optional, defaults to 66 (512MB)):
|
31
|
-
Enter your default ssh key
|
31
|
+
Enter your default ssh key IDs (optional, defaults to '', comma separated string):
|
32
32
|
|
33
33
|
Authentication with DigitalOcean was successful!
|
34
34
|
|
@@ -41,9 +41,9 @@ Tugboat will look for a .tugboat config file first in the current directory you'
|
|
41
41
|
### Retrieve a list of your droplets
|
42
42
|
|
43
43
|
$ tugboat droplets
|
44
|
-
pearkes-web-001 (ip: 30.30.30.1, status: active, region:
|
45
|
-
pearkes-admin-001 (ip: 30.30.30.3, status: active, region:
|
46
|
-
pearkes-api-001 (ip: 30.30.30.5, status: active, region:
|
44
|
+
pearkes-web-001 (ip: 30.30.30.1, status: active, region: nyc2, id: 13231511)
|
45
|
+
pearkes-admin-001 (ip: 30.30.30.3, status: active, region: nyc2, id: 13231512)
|
46
|
+
pearkes-api-001 (ip: 30.30.30.5, status: active, region: nyc2, id: 13231513)
|
47
47
|
|
48
48
|
### Fuzzy name matching
|
49
49
|
|
@@ -82,7 +82,7 @@ match.
|
|
82
82
|
|
83
83
|
### Create a droplet
|
84
84
|
|
85
|
-
$ tugboat create pearkes-www-002 -s
|
85
|
+
$ tugboat create pearkes-www-002 -s 512mb -i ubuntu-12-04-x64 -r nyc2 -k 11251
|
86
86
|
Queueing creation of droplet 'pearkes-www-002'...done
|
87
87
|
|
88
88
|
### Info about a droplet
|
@@ -94,10 +94,11 @@ match.
|
|
94
94
|
ID: 13231512
|
95
95
|
Status: active
|
96
96
|
IP: 30.30.30.3
|
97
|
-
Region ID: 1
|
98
|
-
Image ID: 25489
|
99
|
-
Size ID: 66
|
100
97
|
Backups Active: false
|
98
|
+
IP6: 2A03:B0C0:0001:00D0:0000:0000:0308:D001
|
99
|
+
Region: London 1 - lon1
|
100
|
+
Image: 6918990 - ubuntu-14-04-x64
|
101
|
+
Size: 1GB
|
101
102
|
|
102
103
|
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.
|
103
104
|
|
@@ -105,10 +106,10 @@ Print info in machine-readable format. The ``--porcelain`` flag silences extra o
|
|
105
106
|
name pearkes-admin-001
|
106
107
|
id 13231512
|
107
108
|
status active
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
109
|
+
ip4 30.30.30.3
|
110
|
+
region lon1
|
111
|
+
image 6918990
|
112
|
+
size 1gb
|
112
113
|
backups_active false
|
113
114
|
|
114
115
|
Print a single attribute.
|
@@ -148,44 +149,61 @@ Print a single attribute.
|
|
148
149
|
|
149
150
|
### List Available Images
|
150
151
|
|
151
|
-
You can list images
|
152
|
+
You can list all images
|
152
153
|
|
153
154
|
$ tugboat images
|
154
|
-
|
155
|
-
|
155
|
+
Showing both private and public images
|
156
|
+
Private Images:
|
157
|
+
My application image (id: 6376601, distro: Ubuntu)
|
158
|
+
|
159
|
+
Public Images:
|
160
|
+
745.1.0 (alpha) (slug: coreos-alpha, id: 12789325, distro: CoreOS)
|
161
|
+
723.3.0 (beta) (slug: coreos-beta, id: 12789350, distro: CoreOS)
|
162
|
+
717.3.0 (stable) (slug: coreos-stable, id: 12789351, distro: CoreOS)
|
156
163
|
....
|
157
164
|
|
158
|
-
|
165
|
+
Or just list images that you have created.
|
159
166
|
|
160
|
-
$ tugboat images --
|
161
|
-
|
162
|
-
|
167
|
+
$ tugboat images --show_just_private_images # or -p
|
168
|
+
Showing just private images
|
169
|
+
Private Images:
|
170
|
+
My application image (id: 6376601, distro: Ubuntu)
|
163
171
|
....
|
164
|
-
Global Images:
|
165
|
-
CentOS 5.8 x64 (id: 1601, distro: CentOS)
|
166
|
-
...
|
167
172
|
|
168
173
|
### List Available Sizes
|
169
174
|
|
170
175
|
$ tugboat sizes
|
171
176
|
Sizes:
|
172
|
-
512MB (
|
173
|
-
|
177
|
+
Disk: 20GB, Memory: 512MB (slug: 512mb)
|
178
|
+
Disk: 30GB, Memory: 1024MB (slug: 1gb)
|
179
|
+
Disk: 40GB, Memory: 2048MB (slug: 2gb)
|
180
|
+
Disk: 60GB, Memory: 4096MB (slug: 4gb)
|
181
|
+
Disk: 80GB, Memory: 8192MB (slug: 8gb)
|
182
|
+
Disk: 160GB, Memory: 16384MB (slug: 16gb)
|
183
|
+
Disk: 320GB, Memory: 32768MB (slug: 32gb)
|
184
|
+
Disk: 480GB, Memory: 49152MB (slug: 48gb)
|
185
|
+
Disk: 640GB, Memory: 65536MB (slug: 64gb)
|
174
186
|
...
|
175
187
|
|
176
188
|
### List Available Regions
|
177
189
|
|
178
190
|
$ tugboat regions
|
179
191
|
Regions:
|
180
|
-
|
181
|
-
Amsterdam
|
182
|
-
|
192
|
+
Amsterdam 1 (slug: ams1)
|
193
|
+
Amsterdam 2 (slug: ams2)
|
194
|
+
Amsterdam 3 (slug: ams3)
|
195
|
+
London 1 (slug: lon1)
|
196
|
+
New York 1 (slug: nyc1)
|
197
|
+
New York 2 (slug: nyc2)
|
198
|
+
New York 3 (slug: nyc3)
|
199
|
+
San Francisco 1 (slug: sfo1)
|
200
|
+
Singapore 1 (slug: sgp1)
|
183
201
|
|
184
202
|
### List SSH Keys
|
185
203
|
|
186
204
|
$ tugboat keys
|
187
205
|
Keys:
|
188
|
-
pearkes (id:
|
206
|
+
Name: pearkes, (id: 231192), fingerprint: 3b:16:bf:e4:8b:00:8b:b8:59:8c:a9:d3:f0:19:45:fa
|
189
207
|
...
|
190
208
|
|
191
209
|
### Wait for Droplet State
|
@@ -213,7 +231,6 @@ For a complete overview of all of the available commands, run:
|
|
213
231
|
|
214
232
|
$ tugboat help
|
215
233
|
|
216
|
-
|
217
234
|
Depending on your local configuration, you may need to install a CA bundle (OS X only) using [homebrew](http://brew.sh/) to communicate with DigitalOcean through SSL/TLS:
|
218
235
|
|
219
236
|
$ brew install curl-ca-bundle
|
@@ -226,12 +243,8 @@ After installation, source the bundle path in your `.bash_profile`/`.bashrc`:
|
|
226
243
|
|
227
244
|
Yes, please!
|
228
245
|
|
229
|
-
It's very helpful if you can run `DEBUG=1 tugboat ...` with the command
|
230
|
-
that is causing you issues, and then include that in the issue.
|
231
|
-
|
232
246
|
You can create a new issue [here](https://github.com/pearkes/tugboat/issues/new). Thank you!
|
233
247
|
|
234
248
|
## Contributing
|
235
249
|
|
236
|
-
See the [contributing guide](CONTRIBUTING.md).
|
237
|
-
|
250
|
+
See the [contributing guide](CONTRIBUTING.md).
|
data/lib/tugboat/cli.rb
CHANGED
@@ -36,6 +36,7 @@ module Tugboat
|
|
36
36
|
"
|
37
37
|
def authorize
|
38
38
|
Middleware.sequence_authorize.call({
|
39
|
+
"tugboat_action" => __method__,
|
39
40
|
"user_quiet" => options[:quiet]
|
40
41
|
})
|
41
42
|
end
|
@@ -51,6 +52,7 @@ module Tugboat
|
|
51
52
|
:desc => "Hide your API keys"
|
52
53
|
def config
|
53
54
|
Middleware.sequence_config.call({
|
55
|
+
"tugboat_action" => __method__,
|
54
56
|
"user_hide_keys" => options[:hide],
|
55
57
|
})
|
56
58
|
end
|
@@ -62,14 +64,22 @@ module Tugboat
|
|
62
64
|
"
|
63
65
|
def verify
|
64
66
|
Middleware.sequence_verify.call({
|
67
|
+
"tugboat_action" => __method__,
|
65
68
|
"user_quiet" => options[:quiet]
|
66
69
|
})
|
67
70
|
end
|
68
71
|
|
69
|
-
|
72
|
+
method_option "include_urls",
|
73
|
+
:type => :boolean,
|
74
|
+
:default => false,
|
75
|
+
:aliases => "-i",
|
76
|
+
:desc => "Include URLs for the droplets (can be opened in a browser)"
|
77
|
+
desc "droplets [OPTIONS]", "Retrieve a list of your droplets"
|
70
78
|
def droplets
|
71
79
|
Middleware.sequence_list_droplets.call({
|
72
|
-
"
|
80
|
+
"tugboat_action" => __method__,
|
81
|
+
"user_quiet" => options[:quiet],
|
82
|
+
"include_urls" => options["include_urls"]
|
73
83
|
})
|
74
84
|
end
|
75
85
|
|
@@ -81,6 +91,7 @@ module Tugboat
|
|
81
91
|
:desc => "Show just private images"
|
82
92
|
def images
|
83
93
|
Middleware.sequence_list_images.call({
|
94
|
+
"tugboat_action" => __method__,
|
84
95
|
"user_show_just_private_images" => options[:show_just_private_images],
|
85
96
|
"user_quiet" => options[:quiet]
|
86
97
|
})
|
@@ -114,10 +125,11 @@ module Tugboat
|
|
114
125
|
:desc => "Custom SSH options"
|
115
126
|
method_option "ssh_command",
|
116
127
|
:type => :string,
|
117
|
-
:aliases => "-c",
|
128
|
+
:aliases => [ "-c", "-y" ,],
|
118
129
|
:desc => "Command to run on the droplet"
|
119
130
|
def ssh(name=nil)
|
120
131
|
Middleware.sequence_ssh_droplet.call({
|
132
|
+
"tugboat_action" => __method__,
|
121
133
|
"user_droplet_id" => options[:id],
|
122
134
|
"user_droplet_name" => options[:name],
|
123
135
|
"user_droplet_fuzzy_name" => name,
|
@@ -134,15 +146,15 @@ module Tugboat
|
|
134
146
|
method_option "size",
|
135
147
|
:type => :numeric,
|
136
148
|
:aliases => "-s",
|
137
|
-
:desc => "The
|
149
|
+
:desc => "The size slug of the droplet"
|
138
150
|
method_option "image",
|
139
151
|
:type => :numeric,
|
140
152
|
:aliases => "-i",
|
141
|
-
:desc => "The
|
153
|
+
:desc => "The image slug of the droplet"
|
142
154
|
method_option "region",
|
143
155
|
:type => :numeric,
|
144
156
|
:aliases => "-r",
|
145
|
-
:desc => "The
|
157
|
+
:desc => "The region slug of the droplet"
|
146
158
|
method_option "keys",
|
147
159
|
:type => :string,
|
148
160
|
:aliases => "-k",
|
@@ -151,6 +163,14 @@ module Tugboat
|
|
151
163
|
:type => :boolean,
|
152
164
|
:aliases => "-p",
|
153
165
|
:desc => "Enable private networking on the droplet"
|
166
|
+
method_option "ip6",
|
167
|
+
:type => :boolean,
|
168
|
+
:aliases => "-l",
|
169
|
+
:desc => "Enable IP6 on the droplet"
|
170
|
+
method_option "user_data",
|
171
|
+
:type => :string,
|
172
|
+
:aliases => "-u",
|
173
|
+
:desc => "Location of a file to read and use as user data"
|
154
174
|
method_option "backups_enabled",
|
155
175
|
:type => :boolean,
|
156
176
|
:aliases => "-b",
|
@@ -163,11 +183,14 @@ module Tugboat
|
|
163
183
|
end
|
164
184
|
|
165
185
|
Middleware.sequence_create_droplet.call({
|
166
|
-
"
|
167
|
-
"create_droplet_image_id" => options[:image],
|
168
|
-
"create_droplet_region_id" => options[:region],
|
186
|
+
"tugboat_action" => __method__,
|
169
187
|
"create_droplet_ssh_key_ids" => options[:keys],
|
188
|
+
"create_droplet_size_slug" => options[:size],
|
189
|
+
"create_droplet_image_slug" => options[:image],
|
190
|
+
"create_droplet_region_slug" => options[:region],
|
170
191
|
"create_droplet_private_networking" => options[:private_networking],
|
192
|
+
"create_droplet_ip6" => options[:ip6],
|
193
|
+
"create_droplet_user_data" => options[:user_data],
|
171
194
|
"create_droplet_backups_enabled" => options[:backups_enabled],
|
172
195
|
"create_droplet_name" => name,
|
173
196
|
"user_quiet" => options[:quiet]
|
@@ -185,7 +208,7 @@ module Tugboat
|
|
185
208
|
:desc => "The exact name of the droplet"
|
186
209
|
method_option "confirm",
|
187
210
|
:type => :boolean,
|
188
|
-
:aliases => "-c",
|
211
|
+
:aliases => [ "-c", "-y" ,],
|
189
212
|
:desc => "Skip confirmation of the action"
|
190
213
|
method_option "image_id",
|
191
214
|
:type => :numeric,
|
@@ -197,6 +220,7 @@ module Tugboat
|
|
197
220
|
:desc => "The exact name of the image"
|
198
221
|
def rebuild(name=nil, image_name=nil)
|
199
222
|
Middleware.sequence_rebuild_droplet.call({
|
223
|
+
"tugboat_action" => __method__,
|
200
224
|
"user_droplet_id" => options[:id],
|
201
225
|
"user_droplet_name" => options[:name],
|
202
226
|
"user_droplet_fuzzy_name" => name,
|
@@ -219,10 +243,11 @@ module Tugboat
|
|
219
243
|
:desc => "The exact name of the droplet"
|
220
244
|
method_option "confirm",
|
221
245
|
:type => :boolean,
|
222
|
-
:aliases => "-c",
|
246
|
+
:aliases => [ "-c", "-y" ,],
|
223
247
|
:desc => "Skip confirmation of the action"
|
224
248
|
def destroy(name=nil)
|
225
249
|
Middleware.sequence_destroy_droplet.call({
|
250
|
+
"tugboat_action" => __method__,
|
226
251
|
"user_droplet_id" => options[:id],
|
227
252
|
"user_droplet_name" => options[:name],
|
228
253
|
"user_confirm_action" => options[:confirm],
|
@@ -242,10 +267,11 @@ module Tugboat
|
|
242
267
|
:desc => "The exact name of the image"
|
243
268
|
method_option "confirm",
|
244
269
|
:type => :boolean,
|
245
|
-
:aliases => "-c",
|
270
|
+
:aliases => [ "-c", "-y" ,],
|
246
271
|
:desc => "Skip confirmation of the action"
|
247
272
|
def destroy_image(name=nil)
|
248
273
|
Middleware.sequence_destroy_image.call({
|
274
|
+
"tugboat_action" => __method__,
|
249
275
|
"user_image_id" => options[:id],
|
250
276
|
"user_image_name" => options[:name],
|
251
277
|
"user_image_fuzzy_name" => name,
|
@@ -269,6 +295,7 @@ module Tugboat
|
|
269
295
|
:desc => "Perform a hard restart"
|
270
296
|
def restart(name=nil)
|
271
297
|
Middleware.sequence_restart_droplet.call({
|
298
|
+
"tugboat_action" => __method__,
|
272
299
|
"user_droplet_id" => options[:id],
|
273
300
|
"user_droplet_name" => options[:name],
|
274
301
|
"user_droplet_hard" => options[:hard],
|
@@ -292,6 +319,7 @@ module Tugboat
|
|
292
319
|
:desc => "Perform a hard shutdown"
|
293
320
|
def halt(name=nil)
|
294
321
|
Middleware.sequence_halt_droplet.call({
|
322
|
+
"tugboat_action" => __method__,
|
295
323
|
"user_droplet_id" => options[:id],
|
296
324
|
"user_droplet_name" => options[:name],
|
297
325
|
"user_droplet_hard" => options[:hard],
|
@@ -318,6 +346,7 @@ module Tugboat
|
|
318
346
|
:desc => "Give the output in an easy-to-parse format for scripts."
|
319
347
|
def info(name=nil)
|
320
348
|
Middleware.sequence_info_droplet.call({
|
349
|
+
"tugboat_action" => __method__,
|
321
350
|
"user_droplet_id" => options[:id],
|
322
351
|
"user_droplet_name" => options[:name],
|
323
352
|
"user_droplet_fuzzy_name" => name,
|
@@ -338,6 +367,7 @@ module Tugboat
|
|
338
367
|
:desc => "The exact name of the image"
|
339
368
|
def info_image(name=nil)
|
340
369
|
Middleware.sequence_info_image.call({
|
370
|
+
"tugboat_action" => __method__,
|
341
371
|
"user_image_id" => options[:id],
|
342
372
|
"user_image_name" => options[:name],
|
343
373
|
"user_image_fuzzy_name" => name,
|
@@ -356,6 +386,7 @@ module Tugboat
|
|
356
386
|
:desc => "The exact name of the droplet"
|
357
387
|
def snapshot(snapshot_name, name=nil)
|
358
388
|
Middleware.sequence_snapshot_droplet.call({
|
389
|
+
"tugboat_action" => __method__,
|
359
390
|
"user_droplet_id" => options[:id],
|
360
391
|
"user_droplet_name" => options[:name],
|
361
392
|
"user_droplet_fuzzy_name" => name,
|
@@ -366,7 +397,9 @@ module Tugboat
|
|
366
397
|
|
367
398
|
desc "keys", "Show available SSH keys"
|
368
399
|
def keys
|
369
|
-
Middleware.sequence_ssh_keys.call({
|
400
|
+
Middleware.sequence_ssh_keys.call({
|
401
|
+
"tugboat_action" => __method__,
|
402
|
+
})
|
370
403
|
end
|
371
404
|
|
372
405
|
desc "add-key KEY-NAME", "Upload an ssh public key to DigitalOcean, to be assigned to a droplet later"
|
@@ -383,6 +416,7 @@ module Tugboat
|
|
383
416
|
:desc => "The path to the ssh key"
|
384
417
|
def add_key(name)
|
385
418
|
Middleware.sequence_add_key.call({
|
419
|
+
"tugboat_action" => __method__,
|
386
420
|
"add_key_name" => name,
|
387
421
|
"add_key_pub_key" => options[:key],
|
388
422
|
"add_key_file_path" => options[:path],
|
@@ -393,6 +427,7 @@ module Tugboat
|
|
393
427
|
desc "regions", "Show regions"
|
394
428
|
def regions
|
395
429
|
Middleware.sequence_regions.call({
|
430
|
+
"tugboat_action" => __method__,
|
396
431
|
"user_quiet" => options[:quiet]
|
397
432
|
})
|
398
433
|
end
|
@@ -405,6 +440,7 @@ module Tugboat
|
|
405
440
|
desc "sizes", "Show available droplet sizes"
|
406
441
|
def sizes
|
407
442
|
Middleware.sequence_sizes.call({
|
443
|
+
"tugboat_action" => __method__,
|
408
444
|
"user_quiet" => options[:quiet]
|
409
445
|
})
|
410
446
|
end
|
@@ -420,6 +456,7 @@ module Tugboat
|
|
420
456
|
:desc => "The exact name of the droplet"
|
421
457
|
def start(name=nil)
|
422
458
|
Middleware.sequence_start_droplet.call({
|
459
|
+
"tugboat_action" => __method__,
|
423
460
|
"user_droplet_id" => options[:id],
|
424
461
|
"user_droplet_name" => options[:name],
|
425
462
|
"user_droplet_fuzzy_name" => name,
|
@@ -443,6 +480,7 @@ module Tugboat
|
|
443
480
|
:desc => "The size_id to resize the droplet to"
|
444
481
|
def resize(name=nil)
|
445
482
|
Middleware.sequence_resize_droplet.call({
|
483
|
+
"tugboat_action" => __method__,
|
446
484
|
"user_droplet_id" => options[:id],
|
447
485
|
"user_droplet_name" => options[:name],
|
448
486
|
"user_droplet_size" => options[:size],
|
@@ -463,6 +501,7 @@ module Tugboat
|
|
463
501
|
|
464
502
|
def password_reset(name=nil)
|
465
503
|
Middleware.sequence_password_reset.call({
|
504
|
+
"tugboat_action" => __method__,
|
466
505
|
"user_droplet_id" => options[:id],
|
467
506
|
"user_droplet_name" => options[:name],
|
468
507
|
"user_droplet_fuzzy_name" => name,
|
@@ -487,6 +526,7 @@ module Tugboat
|
|
487
526
|
|
488
527
|
def wait(name=nil)
|
489
528
|
Middleware.sequence_wait.call({
|
529
|
+
"tugboat_action" => __method__,
|
490
530
|
"user_droplet_id" => options[:id],
|
491
531
|
"user_droplet_name" => options[:name],
|
492
532
|
"user_droplet_desired_state" => options[:state],
|
data/lib/tugboat/config.rb
CHANGED
@@ -16,8 +16,10 @@ module Tugboat
|
|
16
16
|
DEFAULT_IMAGE = 'ubuntu-14-04-x64'
|
17
17
|
DEFAULT_SIZE = '512mb'
|
18
18
|
DEFAULT_SSH_KEY = ''
|
19
|
+
DEFAULT_IP6 = 'false'
|
19
20
|
DEFAULT_PRIVATE_NETWORKING = 'false'
|
20
21
|
DEFAULT_BACKUPS_ENABLED = 'false'
|
22
|
+
DEFAULT_USER_DATA = nil
|
21
23
|
|
22
24
|
# Load config file from current directory, if not exit load from user's home directory
|
23
25
|
def initialize
|
@@ -38,7 +40,7 @@ module Tugboat
|
|
38
40
|
end
|
39
41
|
|
40
42
|
def access_token
|
41
|
-
@data['authentication']['access_token']
|
43
|
+
env_access_token || @data['authentication']['access_token']
|
42
44
|
end
|
43
45
|
|
44
46
|
def ssh_key_path
|
@@ -73,6 +75,14 @@ module Tugboat
|
|
73
75
|
@data['defaults'].nil? ? DEFAULT_SSH_KEY : @data['defaults']['ssh_key']
|
74
76
|
end
|
75
77
|
|
78
|
+
def default_ip6
|
79
|
+
@data['defaults'].nil? ? DEFAULT_IP6 : @data['defaults']['ip6']
|
80
|
+
end
|
81
|
+
|
82
|
+
def default_user_data
|
83
|
+
@data['defaults'].nil? ? DEFAULT_USER_DATA : @data['defaults']['user_data']
|
84
|
+
end
|
85
|
+
|
76
86
|
def default_private_networking
|
77
87
|
@data['defaults'].nil? ? DEFAULT_PRIVATE_NETWORKING : @data['defaults']['private_networking']
|
78
88
|
end
|
@@ -81,6 +91,10 @@ module Tugboat
|
|
81
91
|
@data['defaults'].nil? ? DEFAULT_BACKUPS_ENABLED : @data['defaults']['backups_enabled']
|
82
92
|
end
|
83
93
|
|
94
|
+
def env_access_token
|
95
|
+
ENV['DO_API_TOKEN'] unless ENV['DO_API_TOKEN'].to_s.empty?
|
96
|
+
end
|
97
|
+
|
84
98
|
# Re-runs initialize
|
85
99
|
def reset!
|
86
100
|
self.send(:initialize)
|
@@ -17,7 +17,7 @@ module Tugboat
|
|
17
17
|
region = ask "Enter your default region (optional, defaults to nyc1):"
|
18
18
|
image = ask "Enter your default image ID or image slug (optional, defaults to ubuntu-14-04-x64):"
|
19
19
|
size = ask "Enter your default size (optional, defaults to 512mb)):"
|
20
|
-
ssh_key = ask "Enter your default ssh key
|
20
|
+
ssh_key = ask "Enter your default ssh key IDs (optional, defaults to none, comma separated string):"
|
21
21
|
private_networking = ask "Enter your default for private networking (optional, defaults to false):"
|
22
22
|
backups_enabled = ask "Enter your default for enabling backups (optional, defaults to false):"
|
23
23
|
|
@@ -6,41 +6,62 @@ module Tugboat
|
|
6
6
|
|
7
7
|
say "Queueing creation of droplet '#{env["create_droplet_name"]}'...", nil, false
|
8
8
|
|
9
|
-
env["
|
10
|
-
|
11
|
-
|
9
|
+
env["create_droplet_region_slug"] ?
|
10
|
+
droplet_region_slug = env["create_droplet_region_slug"] :
|
11
|
+
droplet_region_slug = env["config"].default_region
|
12
12
|
|
13
|
-
env["
|
14
|
-
|
15
|
-
|
13
|
+
env["create_droplet_image_slug"] ?
|
14
|
+
droplet_image_slug = env["create_droplet_image_slug"] :
|
15
|
+
droplet_image_slug = env["config"].default_image
|
16
16
|
|
17
|
-
env["
|
18
|
-
|
19
|
-
|
17
|
+
env["create_droplet_size_slug"] ?
|
18
|
+
droplet_size_slug = env["create_droplet_size_slug"] :
|
19
|
+
droplet_size_slug = env["config"].default_size
|
20
20
|
|
21
21
|
env["create_droplet_ssh_key_ids"] ?
|
22
|
-
|
23
|
-
|
22
|
+
droplet_ssh_key_ids = env["create_droplet_ssh_key_ids"] :
|
23
|
+
droplet_ssh_key_ids = env["config"].default_ssh_key
|
24
24
|
|
25
25
|
env["create_droplet_private_networking"] ?
|
26
26
|
droplet_private_networking = env["create_droplet_private_networking"] :
|
27
27
|
droplet_private_networking = env["config"].default_private_networking
|
28
28
|
|
29
|
+
env["create_droplet_ip6"] ?
|
30
|
+
droplet_ip6 = env["create_droplet_ip6"] :
|
31
|
+
droplet_ip6 = env["config"].default_ip6
|
32
|
+
|
33
|
+
env["create_droplet_user_data"] ?
|
34
|
+
droplet_user_data = env["create_droplet_user_data"] :
|
35
|
+
droplet_user_data = env["config"].default_user_data
|
36
|
+
|
37
|
+
if droplet_user_data
|
38
|
+
unless File.file?(droplet_user_data)
|
39
|
+
say "Could not find file: #{droplet_user_data}, check your user_data setting"
|
40
|
+
exit 1
|
41
|
+
else
|
42
|
+
user_data_string = File.open(droplet_user_data, 'rb') { |f| f.read }
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
29
46
|
env["create_droplet_backups_enabled"] ?
|
30
47
|
droplet_backups_enabled = env["create_droplet_backups_enabled"] :
|
31
48
|
droplet_backups_enabled = env["config"].default_backups_enabled
|
32
49
|
|
33
|
-
|
50
|
+
droplet_key_array = droplet_ssh_key_ids.split(',')
|
51
|
+
|
52
|
+
droplet_key_array = nil if [droplet_key_array].empty?
|
53
|
+
|
34
54
|
|
35
55
|
create_opts = {
|
36
56
|
:name => env["create_droplet_name"],
|
37
|
-
:size =>
|
38
|
-
:image => "#{
|
39
|
-
:region =>
|
40
|
-
:ssh_keys =>
|
57
|
+
:size => droplet_size_slug,
|
58
|
+
:image => "#{droplet_image_slug}",
|
59
|
+
:region => droplet_region_slug,
|
60
|
+
:ssh_keys => droplet_key_array,
|
41
61
|
:private_networking => droplet_private_networking,
|
42
62
|
:backups_enabled => droplet_backups_enabled,
|
43
|
-
:ipv6 =>
|
63
|
+
:ipv6 => droplet_ip6,
|
64
|
+
:user_data => user_data_string,
|
44
65
|
}
|
45
66
|
|
46
67
|
response = ocean.droplet.create(create_opts)
|
@@ -12,7 +12,10 @@ module Tugboat
|
|
12
12
|
# First, if nothing is provided to us, we should quit and
|
13
13
|
# let the user know.
|
14
14
|
if !user_fuzzy_name && !user_droplet_name && !user_droplet_id
|
15
|
-
|
15
|
+
|
16
|
+
say "Tugboat attempted to find a droplet with no arguments.", :red
|
17
|
+
say "Try running `tugboat #{env['tugboat_action']} dropletname`", :green
|
18
|
+
say "For more help run: `tugboat help #{env['tugboat_action']}`", :blue
|
16
19
|
exit 1
|
17
20
|
end
|
18
21
|
|
@@ -113,10 +116,17 @@ module Tugboat
|
|
113
116
|
end
|
114
117
|
say
|
115
118
|
choice = ask "Please choose a droplet:", :limited_to => choices
|
119
|
+
for ip_list in found_droplets[choice.to_i].networks.v4 do
|
120
|
+
if ip_list.type == "private"
|
121
|
+
private_ip = ip_list.ip_address
|
122
|
+
elsif ip_list.type == "public"
|
123
|
+
public_ip = ip_list.ip_address
|
124
|
+
end
|
125
|
+
end
|
116
126
|
env["droplet_id"] = found_droplets[choice.to_i].id
|
117
127
|
env["droplet_name"] = found_droplets[choice.to_i].name
|
118
|
-
env["droplet_ip"] =
|
119
|
-
env["droplet_ip_private"] =
|
128
|
+
env["droplet_ip"] = public_ip
|
129
|
+
env["droplet_ip_private"] = private_ip
|
120
130
|
env["droplet_status"] = found_droplets[choice.to_i].status
|
121
131
|
end
|
122
132
|
|
@@ -11,7 +11,9 @@ module Tugboat
|
|
11
11
|
# First, if nothing is provided to us, we should quit and
|
12
12
|
# let the user know.
|
13
13
|
if !user_fuzzy_name && !user_image_name && !user_image_id
|
14
|
-
say "Tugboat attempted to find an image with no arguments.
|
14
|
+
say "Tugboat attempted to find an image with no arguments.", :red
|
15
|
+
say "Try running `tugboat #{env['tugboat_action']} imagename`", :green
|
16
|
+
say "For more help run: `tugboat help #{env['tugboat_action']}`", :blue
|
15
17
|
exit 1
|
16
18
|
end
|
17
19
|
|
@@ -39,7 +39,7 @@ module Tugboat
|
|
39
39
|
["ip6", droplet_ip6_public],
|
40
40
|
["private_ip", droplet_private_ip],
|
41
41
|
["region", droplet.region.slug],
|
42
|
-
["
|
42
|
+
["image", droplet.image.id],
|
43
43
|
["size", droplet.size_slug],
|
44
44
|
["backups_active", !droplet.backup_ids.empty?]
|
45
45
|
]
|
@@ -69,8 +69,14 @@ module Tugboat
|
|
69
69
|
say "Private IP: #{droplet_private_ip}"
|
70
70
|
end
|
71
71
|
|
72
|
+
if droplet.image.slug.nil?
|
73
|
+
image_description = droplet.image.name
|
74
|
+
else
|
75
|
+
image_description = droplet.image.slug
|
76
|
+
end
|
77
|
+
|
72
78
|
say "Region: #{droplet.region.name} - #{droplet.region.slug}"
|
73
|
-
say "Image: #{droplet.image.id} - #{
|
79
|
+
say "Image: #{droplet.image.id} - #{image_description}"
|
74
80
|
say "Size: #{droplet.size_slug.upcase}"
|
75
81
|
say "Backups Active: #{!droplet.backup_ids.empty?}"
|
76
82
|
end
|
@@ -25,12 +25,18 @@ module Tugboat
|
|
25
25
|
end
|
26
26
|
|
27
27
|
public_addr = droplet.networks.v4.detect { |address| address.type == 'public' }
|
28
|
-
say "#{droplet.name} (ip: #{public_addr.ip_address}#{private_ip}, status: #{status_color}#{droplet.status}#{CLEAR}, region: #{droplet.region.slug}, id: #{droplet.id})"
|
28
|
+
say "#{droplet.name} (ip: #{public_addr.ip_address}#{private_ip}, status: #{status_color}#{droplet.status}#{CLEAR}, region: #{droplet.region.slug}, id: #{droplet.id}#{env["include_urls"] ? droplet_id_to_url(droplet.id) : '' })"
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
32
|
@app.call(env)
|
33
33
|
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def droplet_id_to_url(id)
|
38
|
+
", url: 'https://cloud.digitalocean.com/droplets/#{id}'"
|
39
|
+
end
|
34
40
|
end
|
35
41
|
end
|
36
42
|
end
|
@@ -2,7 +2,7 @@ module Tugboat
|
|
2
2
|
module Middleware
|
3
3
|
class SSHDroplet < Base
|
4
4
|
def call(env)
|
5
|
-
say "Executing SSH #{env["droplet_name"]}..."
|
5
|
+
say "Executing SSH on Droplet #{env["droplet_name"]}..."
|
6
6
|
|
7
7
|
options = [
|
8
8
|
"-o", "IdentitiesOnly=yes",
|
@@ -44,6 +44,8 @@ module Tugboat
|
|
44
44
|
|
45
45
|
host_string = "#{ssh_user}@#{host_ip}"
|
46
46
|
|
47
|
+
say "Attempting SSH: #{host_string}"
|
48
|
+
|
47
49
|
options << host_string
|
48
50
|
|
49
51
|
if env["user_droplet_ssh_command"]
|
data/lib/tugboat/version.rb
CHANGED
data/spec/cli/add_key_spec.rb
CHANGED
@@ -39,7 +39,9 @@ ID: 3
|
|
39
39
|
before :each do
|
40
40
|
allow(ENV).to receive(:[]).with('HOME').and_return(fake_home)
|
41
41
|
allow(ENV).to receive(:[]).with('DEBUG').and_return(nil)
|
42
|
+
allow(ENV).to receive(:[]).with('DO_API_TOKEN').and_return(nil)
|
42
43
|
allow(ENV).to receive(:[]).with('http_proxy').and_return(nil)
|
44
|
+
|
43
45
|
FileUtils.mkdir_p "#{fake_home}/.ssh"
|
44
46
|
File.open("#{fake_home}/.ssh/id_rsa.pub", 'w') {|f| f.write("ssh-dss A456= user@host") }
|
45
47
|
end
|
@@ -30,7 +30,7 @@ describe Tugboat::CLI do
|
|
30
30
|
expect($stdin).to receive(:gets).and_return(image)
|
31
31
|
expect($stdout).to receive(:print).with("Enter your default size (optional, defaults to 512mb)): ")
|
32
32
|
expect($stdin).to receive(:gets).and_return(size)
|
33
|
-
expect($stdout).to receive(:print).with("Enter your default ssh key
|
33
|
+
expect($stdout).to receive(:print).with("Enter your default ssh key IDs (optional, defaults to none, comma separated string): ")
|
34
34
|
expect($stdin).to receive(:gets).and_return(ssh_key_id)
|
35
35
|
expect($stdout).to receive(:print).with("Enter your default for private networking (optional, defaults to false): ")
|
36
36
|
expect($stdin).to receive(:gets).and_return(private_networking)
|
@@ -76,7 +76,7 @@ describe Tugboat::CLI do
|
|
76
76
|
expect($stdin).to receive(:gets).and_return('')
|
77
77
|
expect($stdout).to receive(:print).with("Enter your default size (optional, defaults to 512mb)): ")
|
78
78
|
expect($stdin).to receive(:gets).and_return('')
|
79
|
-
expect($stdout).to receive(:print).with("Enter your default ssh key
|
79
|
+
expect($stdout).to receive(:print).with("Enter your default ssh key IDs (optional, defaults to none, comma separated string): ")
|
80
80
|
expect($stdin).to receive(:gets).and_return('')
|
81
81
|
expect($stdout).to receive(:print).with("Enter your default for private networking (optional, defaults to false): ")
|
82
82
|
expect($stdin).to receive(:gets).and_return('')
|
data/spec/cli/create_cli_spec.rb
CHANGED
@@ -6,7 +6,7 @@ describe Tugboat::CLI do
|
|
6
6
|
describe "create a droplet" do
|
7
7
|
it "with a name, uses defaults from configuration" do
|
8
8
|
stub_request(:post, "https://api.digitalocean.com/v2/droplets").
|
9
|
-
with(:body => "{\"name\":\"foo\",\"size\":\"512mb\",\"image\":\"ubuntu-14-04-x64\",\"region\":\"nyc2\",\"ssh_keys\":[\"1234\"],\"private_networking\":\"false\",\"backups_enabled\":\"false\",\"ipv6\":null}",
|
9
|
+
with(:body => "{\"name\":\"foo\",\"size\":\"512mb\",\"image\":\"ubuntu-14-04-x64\",\"region\":\"nyc2\",\"ssh_keys\":[\"1234\"],\"private_networking\":\"false\",\"backups_enabled\":\"false\",\"ipv6\":null,\"user_data\":null}",
|
10
10
|
:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization'=>'Bearer foo', 'Content-Type'=>'application/json', 'User-Agent'=>'Faraday v0.9.2'}).
|
11
11
|
to_return(:status => 200, :body => fixture('create_droplet'), :headers => {})
|
12
12
|
|
@@ -19,7 +19,7 @@ Queueing creation of droplet '#{droplet_name}'...Droplet created!
|
|
19
19
|
|
20
20
|
it "with args does not use defaults from configuration" do
|
21
21
|
stub_request(:post, "https://api.digitalocean.com/v2/droplets").
|
22
|
-
with(:body => "{\"name\":\"example.com\",\"size\":\"1gb\",\"image\":\"ubuntu-12-04-x64\",\"region\":\"nyc3\",\"ssh_keys\":[\"foo_bar_key\"],\"private_networking\":\"false\",\"backups_enabled\":\"false\",\"ipv6\":null}",
|
22
|
+
with(:body => "{\"name\":\"example.com\",\"size\":\"1gb\",\"image\":\"ubuntu-12-04-x64\",\"region\":\"nyc3\",\"ssh_keys\":[\"foo_bar_key\"],\"private_networking\":\"false\",\"backups_enabled\":\"false\",\"ipv6\":null,\"user_data\":null}",
|
23
23
|
:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization'=>'Bearer foo', 'Content-Type'=>'application/json', 'User-Agent'=>'Faraday v0.9.2'}).
|
24
24
|
to_return(:status => 200, :body => fixture('create_droplet'), :headers => {})
|
25
25
|
|
@@ -32,8 +32,48 @@ Queueing creation of droplet 'example.com'...Droplet created!
|
|
32
32
|
|
33
33
|
end
|
34
34
|
|
35
|
+
it "with ip6 enable args" do
|
36
|
+
stub_request(:post, "https://api.digitalocean.com/v2/droplets").
|
37
|
+
with(:body => "{\"name\":\"example.com\",\"size\":\"512mb\",\"image\":\"ubuntu-14-04-x64\",\"region\":\"nyc2\",\"ssh_keys\":[\"1234\"],\"private_networking\":\"false\",\"backups_enabled\":\"false\",\"ipv6\":\"true\",\"user_data\":null}",
|
38
|
+
:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization'=>'Bearer foo', 'Content-Type'=>'application/json', 'User-Agent'=>'Faraday v0.9.2'}).
|
39
|
+
to_return(:status => 200, :body => fixture('create_droplet'), :headers => {})
|
40
|
+
|
41
|
+
@cli.options = @cli.options.merge(:ip6 => 'true')
|
42
|
+
@cli.create('example.com')
|
43
|
+
|
44
|
+
expect($stdout.string).to eq <<-eos
|
45
|
+
Queueing creation of droplet 'example.com'...Droplet created!
|
46
|
+
eos
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
it "with user data args" do
|
51
|
+
stub_request(:post, "https://api.digitalocean.com/v2/droplets").
|
52
|
+
with(:body => "{\"name\":\"example.com\",\"size\":\"512mb\",\"image\":\"ubuntu-14-04-x64\",\"region\":\"nyc2\",\"ssh_keys\":[\"1234\"],\"private_networking\":\"false\",\"backups_enabled\":\"false\",\"ipv6\":null,\"user_data\":\"#!/bin/bash\\n\\necho \\\"Hello world\\\"\"}",
|
53
|
+
:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization'=>'Bearer foo', 'Content-Type'=>'application/json', 'User-Agent'=>'Faraday v0.9.2'}).
|
54
|
+
to_return(:status => 200, :body => fixture('create_droplet'), :headers => {})
|
55
|
+
|
56
|
+
@cli.options = @cli.options.merge(:user_data => project_path + "/spec/fixtures/user_data.sh")
|
57
|
+
@cli.create('example.com')
|
58
|
+
|
59
|
+
expect($stdout.string).to eq <<-eos
|
60
|
+
Queueing creation of droplet 'example.com'...Droplet created!
|
61
|
+
eos
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
it "fails when user data file does not exist" do
|
66
|
+
@cli.options = @cli.options.merge(:user_data => "/foo/bar/baz.sh")
|
67
|
+
expect {@cli.create("example.com")}.to raise_error(SystemExit)
|
68
|
+
|
69
|
+
expect($stdout.string).to eq <<-eos
|
70
|
+
Queueing creation of droplet 'example.com'...Could not find file: /foo/bar/baz.sh, check your user_data setting
|
71
|
+
eos
|
72
|
+
|
73
|
+
end
|
74
|
+
|
35
75
|
it "doesn't create a droplet when mistyping help command" do
|
36
|
-
help_text = "Usage:\n rspec create NAME\n\nOptions:\n -s, [--size=N]
|
76
|
+
help_text = "Usage:\n rspec create NAME\n\nOptions:\n -s, [--size=N] # The size slug of the droplet\n -i, [--image=N] # The image slug of the droplet\n -r, [--region=N] # The region slug of the droplet\n -k, [--keys=KEYS] # A comma separated list of SSH key ids to add to the droplet\n -p, [--private-networking] # Enable private networking on the droplet\n -l, [--ip6] # Enable IP6 on the droplet\n -u, [--user-data=USER_DATA] # Location of a file to read and use as user data\n -b, [--backups-enabled] # Enable backups on the droplet\n -q, [--quiet] \n\nCreate a droplet.\n"
|
37
77
|
|
38
78
|
@cli.create('help')
|
39
79
|
expect($stdout.string).to eq help_text
|
@@ -47,7 +87,7 @@ Queueing creation of droplet 'example.com'...Droplet created!
|
|
47
87
|
|
48
88
|
it "does not clobber named droplets that contain the word help" do
|
49
89
|
stub_request(:post, "https://api.digitalocean.com/v2/droplets").
|
50
|
-
with(:body => "{\"name\":\"somethingblahblah--help\",\"size\":\"512mb\",\"image\":\"ubuntu-14-04-x64\",\"region\":\"nyc2\",\"ssh_keys\":[\"1234\"],\"private_networking\":\"false\",\"backups_enabled\":\"false\",\"ipv6\":null}",
|
90
|
+
with(:body => "{\"name\":\"somethingblahblah--help\",\"size\":\"512mb\",\"image\":\"ubuntu-14-04-x64\",\"region\":\"nyc2\",\"ssh_keys\":[\"1234\"],\"private_networking\":\"false\",\"backups_enabled\":\"false\",\"ipv6\":null,\"user_data\":null}",
|
51
91
|
:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization'=>'Bearer foo', 'Content-Type'=>'application/json', 'User-Agent'=>'Faraday v0.9.2'}).
|
52
92
|
to_return(:status => 200, :body => fixture('create_droplet'), :headers => {})
|
53
93
|
|
@@ -34,6 +34,7 @@ Try creating one with \e[32m`tugboat create`\e[0m
|
|
34
34
|
|
35
35
|
expect(a_request(:get, "https://api.digitalocean.com/v2/droplets?per_page=200")).to have_been_made
|
36
36
|
end
|
37
|
+
|
37
38
|
it "shows no output when --quiet is set" do
|
38
39
|
stub_request(:get, "https://api.digitalocean.com/v2/droplets?per_page=200").
|
39
40
|
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization'=>'Bearer foo', 'Content-Type'=>'application/json', 'User-Agent'=>'Faraday v0.9.2'}).
|
@@ -47,6 +48,23 @@ Try creating one with \e[32m`tugboat create`\e[0m
|
|
47
48
|
|
48
49
|
expect(a_request(:get, "https://api.digitalocean.com/v2/droplets?per_page=200")).to have_been_made
|
49
50
|
end
|
51
|
+
|
52
|
+
it "includes urls when --include-urls is set" do
|
53
|
+
stub_request(:get, "https://api.digitalocean.com/v2/droplets?per_page=200").
|
54
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization'=>'Bearer foo', 'Content-Type'=>'application/json', 'User-Agent'=>'Faraday v0.9.2'}).
|
55
|
+
to_return(:status => 200, :body => fixture("show_droplets"), :headers => {'Content-Type' => 'application/json'},)
|
56
|
+
|
57
|
+
@cli.options = @cli.options.merge("include_urls" => true)
|
58
|
+
@cli.droplets
|
59
|
+
|
60
|
+
expect($stdout.string).to eq <<-eos
|
61
|
+
example.com (ip: 104.236.32.182, status: \e[32mactive\e[0m, region: nyc3, id: 6918990, url: 'https://cloud.digitalocean.com/droplets/6918990')
|
62
|
+
example2.com (ip: 104.236.32.172, status: \e[32mactive\e[0m, region: nyc3, id: 3164956, url: 'https://cloud.digitalocean.com/droplets/3164956')
|
63
|
+
example3.com (ip: 104.236.32.173, status: \e[31moff\e[0m, region: nyc3, id: 3164444, url: 'https://cloud.digitalocean.com/droplets/3164444')
|
64
|
+
eos
|
65
|
+
|
66
|
+
expect(a_request(:get, "https://api.digitalocean.com/v2/droplets?per_page=200")).to have_been_made
|
67
|
+
end
|
50
68
|
end
|
51
69
|
|
52
70
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Tugboat::CLI do
|
4
|
+
include_context "spec"
|
5
|
+
|
6
|
+
describe "DO_API_TOKEN=foobar" do
|
7
|
+
it "verifies with the ENV variable DO_API_TOKEN" do
|
8
|
+
stub_request(:get, "https://api.digitalocean.com/v2/droplets?per_page=200").
|
9
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization'=>'Bearer env_variable', 'Content-Type'=>'application/json', 'User-Agent'=>'Faraday v0.9.2'}).
|
10
|
+
to_return(:status => 200, :body => fixture('show_droplets'), :headers => {})
|
11
|
+
|
12
|
+
allow(ENV).to receive(:[]).with('HOME').and_return('/tmp/fake_home')
|
13
|
+
allow(ENV).to receive(:[]).with('DO_API_TOKEN').and_return('env_variable')
|
14
|
+
allow(ENV).to receive(:[]).with('http_proxy').and_return(nil)
|
15
|
+
|
16
|
+
@cli.verify
|
17
|
+
expect($stdout.string).to eq "Authentication with DigitalOcean was successful.\n"
|
18
|
+
expect(a_request(:get, "https://api.digitalocean.com/v2/droplets?per_page=200")).to have_been_made
|
19
|
+
end
|
20
|
+
|
21
|
+
it "does not use ENV variable DO_API_TOKEN if empty" do
|
22
|
+
stub_request(:get, "https://api.digitalocean.com/v2/droplets?per_page=200").
|
23
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization'=>'Bearer foo', 'Content-Type'=>'application/json', 'User-Agent'=>'Faraday v0.9.2'}).
|
24
|
+
to_return(:status => 200, :body => fixture('show_droplets'), :headers => {})
|
25
|
+
|
26
|
+
allow(ENV).to receive(:[]).with('HOME').and_return('/tmp/fake_home')
|
27
|
+
allow(ENV).to receive(:[]).with('DO_API_TOKEN').and_return('')
|
28
|
+
allow(ENV).to receive(:[]).with('http_proxy').and_return(nil)
|
29
|
+
|
30
|
+
@cli.verify
|
31
|
+
expect($stdout.string).to eq "Authentication with DigitalOcean was successful.\n"
|
32
|
+
expect(a_request(:get, "https://api.digitalocean.com/v2/droplets?per_page=200")).to have_been_made
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
data/spec/cli/info_cli_spec.rb
CHANGED
@@ -24,13 +24,36 @@ Status: \e[32mactive\e[0m
|
|
24
24
|
IP4: 104.131.186.241
|
25
25
|
IP6: 2604:A880:0800:0010:0000:0000:031D:2001
|
26
26
|
Region: New York 3 - nyc3
|
27
|
-
Image: 6918990 - 14
|
27
|
+
Image: 6918990 - ubuntu-14-04-x64
|
28
28
|
Size: 512MB
|
29
29
|
Backups Active: false
|
30
30
|
eos
|
31
31
|
|
32
32
|
end
|
33
33
|
|
34
|
+
it "shows a droplet made from a user image" do
|
35
|
+
stub_request(:get, "https://api.digitalocean.com/v2/droplets/6918990?per_page=200").
|
36
|
+
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization'=>'Bearer foo', 'Content-Type'=>'application/json', 'User-Agent'=>'Faraday v0.9.2'}).
|
37
|
+
to_return(:status => 200, :body => fixture('show_droplet_user_image'), :headers => {})
|
38
|
+
|
39
|
+
@cli.options = @cli.options.merge(:id => 6918990)
|
40
|
+
@cli.info
|
41
|
+
|
42
|
+
expect($stdout.string).to eq <<-eos
|
43
|
+
Droplet id provided. Finding Droplet...done\e[0m, 6918990 (example.com)
|
44
|
+
|
45
|
+
Name: example.com
|
46
|
+
ID: 6918990
|
47
|
+
Status: \e[32mactive\e[0m
|
48
|
+
IP4: 104.131.186.241
|
49
|
+
IP6: 2604:A880:0800:0010:0000:0000:031D:2001
|
50
|
+
Region: New York 3 - nyc3
|
51
|
+
Image: 36646276 - Super Cool Custom Image
|
52
|
+
Size: 512MB
|
53
|
+
Backups Active: false
|
54
|
+
eos
|
55
|
+
end
|
56
|
+
|
34
57
|
it "shows a droplet with an id" do
|
35
58
|
stub_request(:get, "https://api.digitalocean.com/v2/droplets/6918990?per_page=200").
|
36
59
|
with(:headers => {'Accept'=>'*/*', 'Accept-Encoding'=>'gzip;q=1.0,deflate;q=0.6,identity;q=0.3', 'Authorization'=>'Bearer foo', 'Content-Type'=>'application/json', 'User-Agent'=>'Faraday v0.9.2'}).
|
@@ -48,7 +71,7 @@ Status: \e[32mactive\e[0m
|
|
48
71
|
IP4: 104.131.186.241
|
49
72
|
IP6: 2604:A880:0800:0010:0000:0000:031D:2001
|
50
73
|
Region: New York 3 - nyc3
|
51
|
-
Image: 6918990 - 14
|
74
|
+
Image: 6918990 - ubuntu-14-04-x64
|
52
75
|
Size: 512MB
|
53
76
|
Backups Active: false
|
54
77
|
eos
|
@@ -75,7 +98,7 @@ Status: \e[32mactive\e[0m
|
|
75
98
|
IP4: 104.131.186.241
|
76
99
|
IP6: 2604:A880:0800:0010:0000:0000:031D:2001
|
77
100
|
Region: New York 3 - nyc3
|
78
|
-
Image: 6918990 - 14
|
101
|
+
Image: 6918990 - ubuntu-14-04-x64
|
79
102
|
Size: 512MB
|
80
103
|
Backups Active: false
|
81
104
|
eos
|
@@ -108,7 +131,7 @@ Status: \e[32mactive\e[0m
|
|
108
131
|
IP4: 104.131.186.241
|
109
132
|
IP6: 2604:A880:0800:0010:0000:0000:031D:2001
|
110
133
|
Region: New York 3 - nyc3
|
111
|
-
Image: 6918990 - 14
|
134
|
+
Image: 6918990 - ubuntu-14-04-x64
|
112
135
|
Size: 512MB
|
113
136
|
Backups Active: false
|
114
137
|
eos
|
@@ -131,7 +154,7 @@ status active
|
|
131
154
|
ip4 104.131.186.241
|
132
155
|
ip6 2604:A880:0800:0010:0000:0000:031D:2001
|
133
156
|
region nyc3
|
134
|
-
|
157
|
+
image 6918990
|
135
158
|
size 512mb
|
136
159
|
backups_active false
|
137
160
|
eos
|
@@ -156,7 +179,7 @@ status active
|
|
156
179
|
ip4 104.131.186.241
|
157
180
|
ip6 2604:A880:0800:0010:0000:0000:031D:2001
|
158
181
|
region nyc3
|
159
|
-
|
182
|
+
image 6918990
|
160
183
|
size 512mb
|
161
184
|
backups_active false
|
162
185
|
eos
|
@@ -212,7 +235,7 @@ Provide one of the following:
|
|
212
235
|
ip6
|
213
236
|
private_ip
|
214
237
|
region
|
215
|
-
|
238
|
+
image
|
216
239
|
size
|
217
240
|
backups_active
|
218
241
|
eos
|
@@ -21,6 +21,7 @@ Image fuzzy name provided. Finding image ID...done\e[0m, 12789325 (745.1.0 (alph
|
|
21
21
|
Name: 745.1.0 (alpha)
|
22
22
|
ID: 12789325
|
23
23
|
Distribution: CoreOS
|
24
|
+
Min Disk Size: 20GB
|
24
25
|
eos
|
25
26
|
end
|
26
27
|
|
@@ -42,6 +43,7 @@ Image id provided. Finding Image...done\e[0m, 12438838 (Redmine on 14.04)
|
|
42
43
|
Name: Redmine on 14.04
|
43
44
|
ID: 12438838
|
44
45
|
Distribution: Ubuntu
|
46
|
+
Min Disk Size: 20GB
|
45
47
|
eos
|
46
48
|
end
|
47
49
|
|
@@ -63,6 +65,7 @@ Image name provided. Finding Image...done\e[0m, 12438838 (Redmine on 14.04)
|
|
63
65
|
Name: Redmine on 14.04
|
64
66
|
ID: 12438838
|
65
67
|
Distribution: Ubuntu
|
68
|
+
Min Disk Size: 20GB
|
66
69
|
eos
|
67
70
|
end
|
68
71
|
|
@@ -139,6 +142,7 @@ Please choose a image: ["0", "1", "2", "3", "4", "5", "6", "7"]\x20
|
|
139
142
|
Name: 14.10 x32
|
140
143
|
ID: 9801951
|
141
144
|
Distribution: Ubuntu
|
145
|
+
Min Disk Size: 20GB
|
142
146
|
eos
|
143
147
|
end
|
144
148
|
|
@@ -0,0 +1,82 @@
|
|
1
|
+
{
|
2
|
+
"droplet": {
|
3
|
+
"id": 6918990,
|
4
|
+
"name": "example.com",
|
5
|
+
"memory": 512,
|
6
|
+
"vcpus": 1,
|
7
|
+
"disk": 20,
|
8
|
+
"locked": false,
|
9
|
+
"status": "active",
|
10
|
+
"kernel": {
|
11
|
+
"id": 2233,
|
12
|
+
"name": "Ubuntu 14.04 x64 vmlinuz-3.13.0-37-generic",
|
13
|
+
"version": "3.13.0-37-generic"
|
14
|
+
},
|
15
|
+
"created_at": "2014-11-14T16:36:31Z",
|
16
|
+
"features": [
|
17
|
+
"ipv6",
|
18
|
+
"virtio"
|
19
|
+
],
|
20
|
+
"backup_ids": [
|
21
|
+
|
22
|
+
],
|
23
|
+
"snapshot_ids": [
|
24
|
+
|
25
|
+
],
|
26
|
+
"image": {
|
27
|
+
"id": 36646276,
|
28
|
+
"name": "Super Cool Custom Image",
|
29
|
+
"distribution": "CentOS",
|
30
|
+
"slug": null,
|
31
|
+
"public": false,
|
32
|
+
"regions": [
|
33
|
+
"lon1"
|
34
|
+
],
|
35
|
+
"created_at": "2015-02-27T14:44:25Z",
|
36
|
+
"min_disk_size": 20,
|
37
|
+
"type": "snapshot"
|
38
|
+
},
|
39
|
+
"size_slug": "512mb",
|
40
|
+
"networks": {
|
41
|
+
"v4": [
|
42
|
+
{
|
43
|
+
"ip_address": "104.131.186.241",
|
44
|
+
"netmask": "255.255.240.0",
|
45
|
+
"gateway": "104.131.176.1",
|
46
|
+
"type": "public"
|
47
|
+
}
|
48
|
+
],
|
49
|
+
"v6": [
|
50
|
+
{
|
51
|
+
"ip_address": "2604:A880:0800:0010:0000:0000:031D:2001",
|
52
|
+
"netmask": 64,
|
53
|
+
"gateway": "2604:A880:0800:0010:0000:0000:0000:0001",
|
54
|
+
"type": "public"
|
55
|
+
}
|
56
|
+
]
|
57
|
+
},
|
58
|
+
"region": {
|
59
|
+
"name": "New York 3",
|
60
|
+
"slug": "nyc3",
|
61
|
+
"sizes": [
|
62
|
+
"32gb",
|
63
|
+
"16gb",
|
64
|
+
"2gb",
|
65
|
+
"1gb",
|
66
|
+
"4gb",
|
67
|
+
"8gb",
|
68
|
+
"512mb",
|
69
|
+
"64gb",
|
70
|
+
"48gb"
|
71
|
+
],
|
72
|
+
"features": [
|
73
|
+
"virtio",
|
74
|
+
"private_networking",
|
75
|
+
"backups",
|
76
|
+
"ipv6",
|
77
|
+
"metadata"
|
78
|
+
],
|
79
|
+
"available": true
|
80
|
+
}
|
81
|
+
}
|
82
|
+
}
|
@@ -6,6 +6,10 @@ describe Tugboat::Middleware::FindDroplet do
|
|
6
6
|
describe ".call" do
|
7
7
|
it "raises SystemExit with no droplet data" do
|
8
8
|
expect {described_class.new(app).call(env) }.to raise_error(SystemExit)
|
9
|
+
|
10
|
+
expect($stdout.string).to include 'Tugboat attempted to find a droplet with no arguments'
|
11
|
+
expect($stdout.string).to include 'For more help run: '
|
12
|
+
expect($stdout.string).to include 'Try running `tugboat '
|
9
13
|
end
|
10
14
|
end
|
11
15
|
|
@@ -6,6 +6,10 @@ describe Tugboat::Middleware::FindImage do
|
|
6
6
|
describe ".call" do
|
7
7
|
it "raises SystemExit with no image data" do
|
8
8
|
expect {described_class.new(app).call(env) }.to raise_error(SystemExit)
|
9
|
+
|
10
|
+
expect($stdout.string).to include 'Tugboat attempted to find an image with no arguments'
|
11
|
+
expect($stdout.string).to include 'For more help run: '
|
12
|
+
expect($stdout.string).to include 'Try running `tugboat '
|
9
13
|
end
|
10
14
|
end
|
11
15
|
|
@@ -83,7 +83,7 @@ describe Tugboat::Middleware::SSHDroplet do
|
|
83
83
|
expect {described_class.new(app).call(env)}.to raise_error(SystemExit)
|
84
84
|
|
85
85
|
expect($stdout.string).to eq <<-eos
|
86
|
-
Executing SSH ...
|
86
|
+
Executing SSH on Droplet ...
|
87
87
|
You asked to ssh to the private IP, but no Private IP found!
|
88
88
|
eos
|
89
89
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tugboat
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jack Pearkes
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2015-
|
13
|
+
date: 2015-11-03 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: thor
|
@@ -234,6 +234,7 @@ files:
|
|
234
234
|
- spec/cli/destroy_cli_spec.rb
|
235
235
|
- spec/cli/destroy_image_cli_spec.rb
|
236
236
|
- spec/cli/droplets_cli_spec.rb
|
237
|
+
- spec/cli/env_variable_spec.rb
|
237
238
|
- spec/cli/halt_cli_spec.rb
|
238
239
|
- spec/cli/help_cli_spec.rb
|
239
240
|
- spec/cli/images_cli_spec.rb
|
@@ -266,6 +267,7 @@ files:
|
|
266
267
|
- spec/fixtures/show_coreos_image.json
|
267
268
|
- spec/fixtures/show_droplet.json
|
268
269
|
- spec/fixtures/show_droplet_inactive.json
|
270
|
+
- spec/fixtures/show_droplet_user_image.json
|
269
271
|
- spec/fixtures/show_droplets.json
|
270
272
|
- spec/fixtures/show_droplets_empty.json
|
271
273
|
- spec/fixtures/show_image.json
|
@@ -279,6 +281,7 @@ files:
|
|
279
281
|
- spec/fixtures/shutdown_response.json
|
280
282
|
- spec/fixtures/snapshot_response.json
|
281
283
|
- spec/fixtures/ubuntu_image_9801951.json
|
284
|
+
- spec/fixtures/user_data.sh
|
282
285
|
- spec/middleware/base_spec.rb
|
283
286
|
- spec/middleware/check_configuration_spec.rb
|
284
287
|
- spec/middleware/check_credentials_spec.rb
|
@@ -307,9 +310,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
307
310
|
version: 1.9.2
|
308
311
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
309
312
|
requirements:
|
310
|
-
- - "
|
313
|
+
- - ">="
|
311
314
|
- !ruby/object:Gem::Version
|
312
|
-
version:
|
315
|
+
version: '0'
|
313
316
|
requirements: []
|
314
317
|
rubyforge_project:
|
315
318
|
rubygems_version: 2.4.8
|
@@ -328,6 +331,7 @@ test_files:
|
|
328
331
|
- spec/cli/destroy_cli_spec.rb
|
329
332
|
- spec/cli/destroy_image_cli_spec.rb
|
330
333
|
- spec/cli/droplets_cli_spec.rb
|
334
|
+
- spec/cli/env_variable_spec.rb
|
331
335
|
- spec/cli/halt_cli_spec.rb
|
332
336
|
- spec/cli/help_cli_spec.rb
|
333
337
|
- spec/cli/images_cli_spec.rb
|
@@ -360,6 +364,7 @@ test_files:
|
|
360
364
|
- spec/fixtures/show_coreos_image.json
|
361
365
|
- spec/fixtures/show_droplet.json
|
362
366
|
- spec/fixtures/show_droplet_inactive.json
|
367
|
+
- spec/fixtures/show_droplet_user_image.json
|
363
368
|
- spec/fixtures/show_droplets.json
|
364
369
|
- spec/fixtures/show_droplets_empty.json
|
365
370
|
- spec/fixtures/show_image.json
|
@@ -373,6 +378,7 @@ test_files:
|
|
373
378
|
- spec/fixtures/shutdown_response.json
|
374
379
|
- spec/fixtures/snapshot_response.json
|
375
380
|
- spec/fixtures/ubuntu_image_9801951.json
|
381
|
+
- spec/fixtures/user_data.sh
|
376
382
|
- spec/middleware/base_spec.rb
|
377
383
|
- spec/middleware/check_configuration_spec.rb
|
378
384
|
- spec/middleware/check_credentials_spec.rb
|