tugboat 4.0.0 → 4.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +18 -0
- data/README.md +78 -1
- data/lib/tugboat/cli.rb +98 -1
- data/lib/tugboat/middleware.rb +35 -0
- data/lib/tugboat/middleware/backup_setting.rb +30 -0
- data/lib/tugboat/middleware/base.rb +64 -0
- data/lib/tugboat/middleware/list_droplets.rb +1 -14
- data/lib/tugboat/middleware/list_snapshots.rb +28 -0
- data/lib/tugboat/middleware/scp_droplet.rb +34 -0
- data/lib/tugboat/version.rb +1 -1
- data/spec/cli/backup_setting_spec.rb +69 -0
- data/spec/cli/droplets_cli_spec.rb +148 -0
- data/spec/cli/scp_cli_spec.rb +75 -0
- data/spec/cli/snapshots_cli_spec.rb +46 -0
- data/spec/fixtures/disable_backups_response.json +27 -0
- data/spec/fixtures/enable_backups_response.json +27 -0
- data/spec/fixtures/show_snapshots.json +34 -0
- data/spec/fixtures/show_snapshots_empty.json +7 -0
- metadata +21 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4a56c6cb7473968939a5e1a56012640156bc284a
|
|
4
|
+
data.tar.gz: 6283168b5d267c420c74e57c416ac3be8839b8d4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 507273ace57c2dc9f5a9f948d1da9cdd5cb06adb3476ad945437fcf8311c0bbcf17deed1d7b7fe3141f520163c329cfeaa63174631ba58250dcb05136ecd97bc
|
|
7
|
+
data.tar.gz: cb40271dba29c11d8e3bcec36de00450bb4bf866edfb79b9ca0b0a1809ff52949737e4e4e37b1688a95ad2c22f427b16364f2745a6c81761d71752ca042751ee
|
data/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [v4.1.0](https://github.com/petems/tugboat/tree/v4.1.0) (2018-03-11)
|
|
6
|
+
[Full Changelog](https://github.com/petems/tugboat/compare/v4.0.0...v4.1.0)
|
|
7
|
+
|
|
8
|
+
**Implemented enhancements:**
|
|
9
|
+
|
|
10
|
+
- Commands like "droplets" need formatting switches [\#206](https://github.com/petems/tugboat/issues/206)
|
|
11
|
+
- Add a scp command [\#120](https://github.com/petems/tugboat/issues/120)
|
|
12
|
+
- Turn Backups on/off [\#51](https://github.com/petems/tugboat/issues/51)
|
|
13
|
+
|
|
14
|
+
**Merged pull requests:**
|
|
15
|
+
|
|
16
|
+
- Update README typo. [\#298](https://github.com/petems/tugboat/pull/298) ([simi](https://github.com/simi))
|
|
17
|
+
- Add ability to list snapshots [\#296](https://github.com/petems/tugboat/pull/296) ([petems](https://github.com/petems))
|
|
18
|
+
- Add backup\_config setting [\#295](https://github.com/petems/tugboat/pull/295) ([petems](https://github.com/petems))
|
|
19
|
+
- Adds porcelain option to droplets command [\#294](https://github.com/petems/tugboat/pull/294) ([petems](https://github.com/petems))
|
|
20
|
+
- Adds new SCP feature [\#291](https://github.com/petems/tugboat/pull/291) ([petems](https://github.com/petems))
|
|
21
|
+
|
|
5
22
|
## [v4.0.0](https://github.com/petems/tugboat/tree/v4.0.0) (2017-12-03)
|
|
6
23
|
[Full Changelog](https://github.com/petems/tugboat/compare/v3.1.0...v4.0.0)
|
|
7
24
|
|
|
@@ -13,6 +30,7 @@ All notable changes to this project will be documented in this file.
|
|
|
13
30
|
|
|
14
31
|
**Merged pull requests:**
|
|
15
32
|
|
|
33
|
+
- Bump Version to 4.0.0 [\#293](https://github.com/petems/tugboat/pull/293) ([petems](https://github.com/petems))
|
|
16
34
|
- Removing `Assigned but unused variable` warnings [\#292](https://github.com/petems/tugboat/pull/292) ([petems](https://github.com/petems))
|
|
17
35
|
- Adds helper for showing snapshot parameter [\#290](https://github.com/petems/tugboat/pull/290) ([petems](https://github.com/petems))
|
|
18
36
|
- Updates Faraday middleware gem [\#289](https://github.com/petems/tugboat/pull/289) ([petems](https://github.com/petems))
|
data/README.md
CHANGED
|
@@ -6,7 +6,7 @@ A command line tool for interacting with your [DigitalOcean](https://www.digital
|
|
|
6
6
|
|
|
7
7
|
## History
|
|
8
8
|
|
|
9
|
-
When Tugboat was created, DigitalOcean was an extremely new cloud provider. They'd only released their public beta back in [2012](https://whoapi.com/blog/1497/fast-growing-digitalocean-is-fueled-by-customer-love/), and their new SSD backed machines only
|
|
9
|
+
When Tugboat was created, DigitalOcean was an extremely new cloud provider. They'd only released their public beta back in [2012](https://whoapi.com/blog/1497/fast-growing-digitalocean-is-fueled-by-customer-love/), and their new SSD backed machines only premiered in early [2013](https://techcrunch.com/2013/01/15/techstars-graduate-digitalocean-switches-to-ssd-for-its-5-per-month-vps-to-take-on-linode-and-rackspace/).
|
|
10
10
|
|
|
11
11
|
Tugboat started out life around that time, [back in April 2013](https://github.com/pearkes/tugboat/commit/f0fbc1f438cce81c286f0e60014dc4393ac95cb6). Back then, there were no official libraries for DigitalOcean, and the 1.0 API was a bit unstable and occasionally flakey.
|
|
12
12
|
|
|
@@ -81,6 +81,44 @@ defaults:
|
|
|
81
81
|
pearkes-admin-001 (ip: 30.30.30.3, status: active, region: nyc2, id: 13231512)
|
|
82
82
|
pearkes-api-001 (ip: 30.30.30.5, status: active, region: nyc2, id: 13231513)
|
|
83
83
|
|
|
84
|
+
If you wish to use the droplet listing as part of scripting or munging output, you can use the `--porcelain`:
|
|
85
|
+
|
|
86
|
+
$ tugboat droplets --attribute=ip4
|
|
87
|
+
pearkes-web-001,30.30.30.1
|
|
88
|
+
pearkes-admin-001,30.30.30.3
|
|
89
|
+
pearkes-api-001,30.30.30.5
|
|
90
|
+
|
|
91
|
+
Or `--attribute` parameter:
|
|
92
|
+
|
|
93
|
+
$ tugboat droplets --porcelain
|
|
94
|
+
name pearkes-web-001
|
|
95
|
+
id 13231515
|
|
96
|
+
status active
|
|
97
|
+
ip4 330.30.30.1
|
|
98
|
+
region lon1
|
|
99
|
+
image 6918990
|
|
100
|
+
size 1gb
|
|
101
|
+
backups_active false
|
|
102
|
+
|
|
103
|
+
name pearkes-admin-001
|
|
104
|
+
id 13231513
|
|
105
|
+
status active
|
|
106
|
+
ip4 30.30.30.3
|
|
107
|
+
region lon1
|
|
108
|
+
image 6918990
|
|
109
|
+
size 1gb
|
|
110
|
+
backups_active false
|
|
111
|
+
|
|
112
|
+
name pearkes-web-001
|
|
113
|
+
id 13231514
|
|
114
|
+
status active
|
|
115
|
+
ip4 30.30.30.5
|
|
116
|
+
region lon1
|
|
117
|
+
image 6918990
|
|
118
|
+
size 1gb
|
|
119
|
+
backups_active true
|
|
120
|
+
|
|
121
|
+
|
|
84
122
|
### Fuzzy name matching
|
|
85
123
|
|
|
86
124
|
You can pass a unique fragment of a droplets name for interactions
|
|
@@ -116,6 +154,21 @@ match.
|
|
|
116
154
|
Welcome to Ubuntu 12.10 (GNU/Linux 3.5.0-17-generic x86_64)
|
|
117
155
|
pearkes@pearkes-admin-001:~#
|
|
118
156
|
|
|
157
|
+
### SCP files to droplet
|
|
158
|
+
|
|
159
|
+
*You can configure an SSH username and key path in `tugboat authorize`,
|
|
160
|
+
or by changing your `~/.tugboat`.*
|
|
161
|
+
|
|
162
|
+
This lets you scp a file into a droplet by providing it's name, or a partial
|
|
163
|
+
match.
|
|
164
|
+
|
|
165
|
+
$ tugboat scp test-scp /tmp/foo /tmp/bar
|
|
166
|
+
Droplet fuzzy name provided. Finding droplet ID...done, 72025053 (test-scp)
|
|
167
|
+
Executing SCP on Droplet (test-scp)...
|
|
168
|
+
Attempting SCP with `scp -i /Users/petems/.ssh/digital_ocean /tmp/foo root@132.61.164.113:/tmp/bar`
|
|
169
|
+
foo
|
|
170
|
+
100% 0 0.0KB/s 00:00
|
|
171
|
+
|
|
119
172
|
### Create a droplet
|
|
120
173
|
|
|
121
174
|
$ tugboat create pearkes-www-002 -s 512mb -i ubuntu-12-04-x64 -r nyc2 -k 11251
|
|
@@ -183,6 +236,18 @@ Print a single attribute.
|
|
|
183
236
|
$ tugboat resize admin -s 66
|
|
184
237
|
Queuing resize for 13231512 (pearkes-admin-001)...done
|
|
185
238
|
|
|
239
|
+
### Enabling backups on a droplet
|
|
240
|
+
|
|
241
|
+
$ tugboat backup_config admin --on
|
|
242
|
+
Droplet fuzzy name provided. Finding droplet ID...done\e[0m, 6918990 (example.com)
|
|
243
|
+
Backup action enable backups is complete
|
|
244
|
+
|
|
245
|
+
### Disabling backups on a droplet
|
|
246
|
+
|
|
247
|
+
$ tugboat backup_config admin --off
|
|
248
|
+
Droplet fuzzy name provided. Finding droplet ID...done\e[0m, 6918990 (example.com)
|
|
249
|
+
Backup action disable backups is complete
|
|
250
|
+
|
|
186
251
|
### List Available Images
|
|
187
252
|
|
|
188
253
|
You can list all images
|
|
@@ -206,6 +271,18 @@ Or just list images that you have created.
|
|
|
206
271
|
My application image (id: 6376601, distro: Ubuntu)
|
|
207
272
|
....
|
|
208
273
|
|
|
274
|
+
### List Current Snapshots
|
|
275
|
+
|
|
276
|
+
$ tugboat snapshots
|
|
277
|
+
code-freeze-backup-october (id: 2013184, resource_type: droplet, created_at: 2016-10-06T11:43:06Z)
|
|
278
|
+
test-admin 2017-05-31 (id: 20234485, resource_type: droplet, created_at: 2017-05-31T02:07:07Z)
|
|
279
|
+
test-admin 2017-11-08 (id: 21133567, resource_type: droplet, created_at: 2017-11-08T02:49:09Z)
|
|
280
|
+
test-admin 2017-11-15 (id: 22355454, resource_type: droplet, created_at: 2017-11-15T03:11:08Z)
|
|
281
|
+
test-admin 2017-11-22 (id: 24523423, resource_type: droplet, created_at: 2017-11-22T03:10:09Z)
|
|
282
|
+
test-admin 2017-11-29 (id: 26212345, resource_type: droplet, created_at: 2017-11-29T03:15:25Z)
|
|
283
|
+
....
|
|
284
|
+
|
|
285
|
+
|
|
209
286
|
### List Available Sizes
|
|
210
287
|
|
|
211
288
|
$ tugboat sizes
|
data/lib/tugboat/cli.rb
CHANGED
|
@@ -37,6 +37,33 @@ module Tugboat
|
|
|
37
37
|
'user_quiet' => options[:quiet])
|
|
38
38
|
end
|
|
39
39
|
|
|
40
|
+
desc 'backup_config FUZZY_NAME', 'Manage backups on a droplet.'
|
|
41
|
+
method_option 'id',
|
|
42
|
+
type: :string,
|
|
43
|
+
aliases: '-i',
|
|
44
|
+
desc: 'The ID of the droplet.'
|
|
45
|
+
method_option 'name',
|
|
46
|
+
type: :string,
|
|
47
|
+
aliases: '-n',
|
|
48
|
+
desc: 'The exact name of the droplet'
|
|
49
|
+
method_option 'enable',
|
|
50
|
+
type: :boolean,
|
|
51
|
+
aliases: '--on',
|
|
52
|
+
desc: 'Enable backups on the droplet.'
|
|
53
|
+
method_option 'disable',
|
|
54
|
+
type: :boolean,
|
|
55
|
+
aliases: '--off',
|
|
56
|
+
desc: 'Disable backups on the droplet.'
|
|
57
|
+
def backup_config(name = nil, status = nil)
|
|
58
|
+
Middleware.sequence_backup_config.call('tugboat_action' => __method__,
|
|
59
|
+
'user_droplet_id' => options[:id],
|
|
60
|
+
'user_droplet_name' => options[:name],
|
|
61
|
+
'user_droplet_fuzzy_name' => name,
|
|
62
|
+
'enable' => options[:enable],
|
|
63
|
+
'disable' => options[:disable],
|
|
64
|
+
'user_quiet' => options[:quiet])
|
|
65
|
+
end
|
|
66
|
+
|
|
40
67
|
desc 'config', 'Show your current config information'
|
|
41
68
|
long_desc "This shows the current information in the .tugboat config
|
|
42
69
|
being used by the app
|
|
@@ -71,12 +98,26 @@ module Tugboat
|
|
|
71
98
|
default: 20,
|
|
72
99
|
aliases: '-p',
|
|
73
100
|
desc: 'Chose how many results to fetch from the DigitalOcean API (larger is slower)'
|
|
101
|
+
method_option 'attribute',
|
|
102
|
+
type: :string,
|
|
103
|
+
aliases: '-a',
|
|
104
|
+
desc: 'The name of the attribute to print.'
|
|
105
|
+
method_option 'porcelain',
|
|
106
|
+
type: :boolean,
|
|
107
|
+
desc: 'Give the output in an easy-to-parse format for scripts.'
|
|
108
|
+
method_option 'include_name',
|
|
109
|
+
type: :boolean,
|
|
110
|
+
default: true,
|
|
111
|
+
desc: 'Include the name when listing attributes from droplets.'
|
|
74
112
|
desc 'droplets [OPTIONS]', 'Retrieve a list of your droplets'
|
|
75
113
|
def droplets
|
|
76
114
|
Middleware.sequence_list_droplets.call('tugboat_action' => __method__,
|
|
77
115
|
'user_quiet' => options[:quiet],
|
|
78
116
|
'include_urls' => options['include_urls'],
|
|
79
|
-
'per_page' => options['per_page'],
|
|
117
|
+
'per_page' => options['per_page'],
|
|
118
|
+
'attribute' => options[:attribute],
|
|
119
|
+
'porcelain' => options[:porcelain],
|
|
120
|
+
'include_name' => options[:include_name])
|
|
80
121
|
end
|
|
81
122
|
|
|
82
123
|
desc 'images [OPTIONS]', 'Retrieve a list of images'
|
|
@@ -139,6 +180,48 @@ module Tugboat
|
|
|
139
180
|
'user_quiet' => options[:quiet])
|
|
140
181
|
end
|
|
141
182
|
|
|
183
|
+
desc 'scp FUZZY_NAME FROM_PATH TO_PATH', 'scp files to a droplet'
|
|
184
|
+
method_option 'id',
|
|
185
|
+
type: :string,
|
|
186
|
+
aliases: '-i',
|
|
187
|
+
desc: 'The ID of the droplet.'
|
|
188
|
+
method_option 'from_path',
|
|
189
|
+
type: :string,
|
|
190
|
+
aliases: '-from',
|
|
191
|
+
desc: 'The path of the local file'
|
|
192
|
+
method_option 'to_path',
|
|
193
|
+
type: :string,
|
|
194
|
+
aliases: '-to',
|
|
195
|
+
desc: 'The path to copy to on the remote droplet'
|
|
196
|
+
method_option 'name',
|
|
197
|
+
type: :string,
|
|
198
|
+
aliases: '-n',
|
|
199
|
+
desc: 'The exact name of the droplet'
|
|
200
|
+
method_option 'ssh_user',
|
|
201
|
+
type: :string,
|
|
202
|
+
aliases: '-u',
|
|
203
|
+
desc: 'Specifies which user to log in as'
|
|
204
|
+
method_option 'scp_command',
|
|
205
|
+
type: :string,
|
|
206
|
+
aliases: ['-c'],
|
|
207
|
+
desc: 'Command to run to copy the file, eg scp, rsync (defaults to scp)'
|
|
208
|
+
method_option 'wait',
|
|
209
|
+
type: :boolean,
|
|
210
|
+
aliases: '-w',
|
|
211
|
+
desc: 'Wait for droplet to become active before trying to SSH'
|
|
212
|
+
def scp(name = nil, from_path, to_path)
|
|
213
|
+
Middleware.sequence_scp_droplet.call('tugboat_action' => __method__,
|
|
214
|
+
'user_droplet_id' => options[:id],
|
|
215
|
+
'user_droplet_name' => options[:name],
|
|
216
|
+
'user_droplet_fuzzy_name' => name,
|
|
217
|
+
'user_from_file' => from_path,
|
|
218
|
+
'user_to_file' => to_path,
|
|
219
|
+
'user_droplet_ssh_user' => options[:ssh_user],
|
|
220
|
+
'user_scp_command' => options[:scp_command],
|
|
221
|
+
'user_droplet_ssh_wait' => options[:wait],
|
|
222
|
+
'user_quiet' => options[:quiet])
|
|
223
|
+
end
|
|
224
|
+
|
|
142
225
|
desc 'create NAME', 'Create a droplet.'
|
|
143
226
|
method_option 'size',
|
|
144
227
|
type: :string,
|
|
@@ -456,6 +539,20 @@ module Tugboat
|
|
|
456
539
|
'user_quiet' => options[:quiet])
|
|
457
540
|
end
|
|
458
541
|
|
|
542
|
+
method_option 'per_page',
|
|
543
|
+
type: :boolean,
|
|
544
|
+
default: 20,
|
|
545
|
+
aliases: '-p',
|
|
546
|
+
desc: 'Chose how many results to fetch from the DigitalOcean API (larger is slower)'
|
|
547
|
+
desc 'snapshots [OPTIONS]', 'Retrieve a list of your snapshots'
|
|
548
|
+
def snapshots
|
|
549
|
+
Middleware.sequence_list_snapshots.call(
|
|
550
|
+
'tugboat_action' => __method__,
|
|
551
|
+
'user_quiet' => options[:quiet],
|
|
552
|
+
'per_page' => options['per_page'],
|
|
553
|
+
)
|
|
554
|
+
end
|
|
555
|
+
|
|
459
556
|
desc 'password-reset FUZZY_NAME', 'Reset root password'
|
|
460
557
|
method_option 'id',
|
|
461
558
|
type: :numeric,
|
data/lib/tugboat/middleware.rb
CHANGED
|
@@ -5,6 +5,7 @@ module Tugboat
|
|
|
5
5
|
autoload :AddKey, 'tugboat/middleware/add_key'
|
|
6
6
|
autoload :AskForCredentials, 'tugboat/middleware/ask_for_credentials'
|
|
7
7
|
autoload :Base, 'tugboat/middleware/base'
|
|
8
|
+
autoload :BackupConfig, 'tugboat/middleware/backup_setting'
|
|
8
9
|
autoload :CheckConfiguration, 'tugboat/middleware/check_configuration'
|
|
9
10
|
autoload :CheckCredentials, 'tugboat/middleware/check_credentials'
|
|
10
11
|
autoload :CheckDropletActive, 'tugboat/middleware/check_droplet_active'
|
|
@@ -27,12 +28,14 @@ module Tugboat
|
|
|
27
28
|
autoload :ListImages, 'tugboat/middleware/list_images'
|
|
28
29
|
autoload :ListRegions, 'tugboat/middleware/list_regions'
|
|
29
30
|
autoload :ListSizes, 'tugboat/middleware/list_sizes'
|
|
31
|
+
autoload :ListSnapshots, 'tugboat/middleware/list_snapshots'
|
|
30
32
|
autoload :ListSSHKeys, 'tugboat/middleware/list_ssh_keys'
|
|
31
33
|
autoload :PasswordReset, 'tugboat/middleware/password_reset'
|
|
32
34
|
autoload :ResizeDroplet, 'tugboat/middleware/resize_droplet'
|
|
33
35
|
autoload :RestartDroplet, 'tugboat/middleware/restart_droplet'
|
|
34
36
|
autoload :SnapshotDroplet, 'tugboat/middleware/snapshot_droplet'
|
|
35
37
|
autoload :SSHDroplet, 'tugboat/middleware/ssh_droplet'
|
|
38
|
+
autoload :SCPDroplet, 'tugboat/middleware/scp_droplet'
|
|
36
39
|
autoload :StartDroplet, 'tugboat/middleware/start_droplet'
|
|
37
40
|
autoload :WaitForState, 'tugboat/middleware/wait_for_state'
|
|
38
41
|
|
|
@@ -49,6 +52,16 @@ module Tugboat
|
|
|
49
52
|
end
|
|
50
53
|
end
|
|
51
54
|
|
|
55
|
+
def self.sequence_backup_config
|
|
56
|
+
::Middleware::Builder.new do
|
|
57
|
+
use InjectConfiguration
|
|
58
|
+
use CheckConfiguration
|
|
59
|
+
use InjectClient
|
|
60
|
+
use FindDroplet
|
|
61
|
+
use BackupConfig
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
52
65
|
# This checks that the credentials in ~/.tugboat are valid
|
|
53
66
|
def self.sequence_verify
|
|
54
67
|
::Middleware::Builder.new do
|
|
@@ -148,6 +161,18 @@ module Tugboat
|
|
|
148
161
|
end
|
|
149
162
|
end
|
|
150
163
|
|
|
164
|
+
# SSH into a droplet
|
|
165
|
+
def self.sequence_scp_droplet
|
|
166
|
+
::Middleware::Builder.new do
|
|
167
|
+
use InjectConfiguration
|
|
168
|
+
use CheckConfiguration
|
|
169
|
+
use InjectClient
|
|
170
|
+
use FindDroplet
|
|
171
|
+
use CheckDropletActive
|
|
172
|
+
use SCPDroplet
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
|
|
151
176
|
# Create a droplet
|
|
152
177
|
def self.sequence_create_droplet
|
|
153
178
|
::Middleware::Builder.new do
|
|
@@ -218,6 +243,16 @@ module Tugboat
|
|
|
218
243
|
end
|
|
219
244
|
end
|
|
220
245
|
|
|
246
|
+
# Display a list of available SSH keys
|
|
247
|
+
def self.sequence_list_snapshots
|
|
248
|
+
::Middleware::Builder.new do
|
|
249
|
+
use InjectConfiguration
|
|
250
|
+
use CheckConfiguration
|
|
251
|
+
use InjectClient
|
|
252
|
+
use ListSnapshots
|
|
253
|
+
end
|
|
254
|
+
end
|
|
255
|
+
|
|
221
256
|
# Create a droplet
|
|
222
257
|
def self.sequence_add_key
|
|
223
258
|
::Middleware::Builder.new do
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module Tugboat
|
|
2
|
+
module Middleware
|
|
3
|
+
class BackupConfig < Base
|
|
4
|
+
def call(env)
|
|
5
|
+
ocean = env['droplet_kit']
|
|
6
|
+
|
|
7
|
+
if env['disable'] && env['enable']
|
|
8
|
+
say 'You cannot use both --disable and --enable for backup_config', :red
|
|
9
|
+
exit 1
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
begin
|
|
13
|
+
if env['disable']
|
|
14
|
+
response = ocean.droplet_actions.disable_backups(droplet_id: env['droplet_id'])
|
|
15
|
+
end
|
|
16
|
+
if env['enable']
|
|
17
|
+
response = ocean.droplet_actions.enable_backups(droplet_id: env['droplet_id'])
|
|
18
|
+
end
|
|
19
|
+
rescue DropletKit::Error => e
|
|
20
|
+
say "Failed to configure backups on droplet. Reason given from API: #{e}", :red
|
|
21
|
+
exit 1
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
say "Backup action #{response_stringify(response)} is #{response.status}"
|
|
25
|
+
|
|
26
|
+
@app.call(env)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
@@ -25,6 +25,10 @@ module Tugboat
|
|
|
25
25
|
end
|
|
26
26
|
end
|
|
27
27
|
|
|
28
|
+
def response_stringify(response)
|
|
29
|
+
response.type.gsub(/_/,' ')
|
|
30
|
+
end
|
|
31
|
+
|
|
28
32
|
def call(env)
|
|
29
33
|
@app.call(env)
|
|
30
34
|
end
|
|
@@ -90,6 +94,66 @@ module Tugboat
|
|
|
90
94
|
end
|
|
91
95
|
end
|
|
92
96
|
|
|
97
|
+
def print_droplet_info(droplet, attribute, porcelain, include_urls, include_name)
|
|
98
|
+
droplet_ip4_public = droplet.networks.v4.find { |address| address.type == 'public' }.ip_address unless droplet.networks.v4.empty?
|
|
99
|
+
droplet_ip6_public = droplet.networks.v6.find { |address| address.type == 'public' }.ip_address unless droplet.networks.v6.empty?
|
|
100
|
+
check_private_ip = droplet.networks.v4.find { |address| address.type == 'private' }
|
|
101
|
+
droplet_private_ip = check_private_ip.ip_address if check_private_ip
|
|
102
|
+
|
|
103
|
+
attributes_list = [
|
|
104
|
+
['name', droplet.name],
|
|
105
|
+
['id', droplet.id],
|
|
106
|
+
['status', droplet.status],
|
|
107
|
+
['ip4', droplet_ip4_public],
|
|
108
|
+
['ip6', droplet_ip6_public],
|
|
109
|
+
['private_ip', droplet_private_ip],
|
|
110
|
+
['region', droplet.region.slug],
|
|
111
|
+
['image', droplet.image.id],
|
|
112
|
+
['size', droplet.size_slug],
|
|
113
|
+
['backups_active', !droplet.backup_ids.empty?]
|
|
114
|
+
]
|
|
115
|
+
attributes = Hash[*attributes_list.flatten(1)]
|
|
116
|
+
|
|
117
|
+
if attribute
|
|
118
|
+
if attributes.key? attribute
|
|
119
|
+
if include_name
|
|
120
|
+
say "#{attributes['name']},#{attributes[attribute]}"
|
|
121
|
+
else
|
|
122
|
+
say attributes[attribute]
|
|
123
|
+
end
|
|
124
|
+
else
|
|
125
|
+
say "Invalid attribute \"#{attribute}\"", :red
|
|
126
|
+
say 'Provide one of the following:', :red
|
|
127
|
+
attributes_list.each { |a| say " #{a[0]}", :red }
|
|
128
|
+
exit 1
|
|
129
|
+
end
|
|
130
|
+
else
|
|
131
|
+
if porcelain
|
|
132
|
+
attributes_list.select { |a| !a[1].nil? }.each { |a| say "#{a[0]} #{a[1]}" }
|
|
133
|
+
say ""
|
|
134
|
+
else
|
|
135
|
+
print_droplet_info_full(droplet, include_urls)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def print_droplet_info_full(droplet, include_urls)
|
|
141
|
+
private_addr = droplet.networks.v4.find { |address| address.type == 'private' }
|
|
142
|
+
if private_addr
|
|
143
|
+
private_ip = ", private_ip: #{private_addr.ip_address}"
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
status_color = if droplet.status == 'active'
|
|
147
|
+
GREEN
|
|
148
|
+
else
|
|
149
|
+
RED
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
public_addr = droplet.networks.v4.find { |address| address.type == 'public' }
|
|
153
|
+
|
|
154
|
+
say "#{droplet.name} (ip: #{public_addr.ip_address}#{private_ip}, status: #{status_color}#{droplet.status}#{CLEAR}, region: #{droplet.region.slug}, size: #{droplet.size_slug}, id: #{droplet.id}#{include_urls ? droplet_id_to_url(droplet.id) : ''})"
|
|
155
|
+
end
|
|
156
|
+
|
|
93
157
|
# Get all pages of droplets
|
|
94
158
|
def get_droplet_list(ocean, per_page = 20)
|
|
95
159
|
verify_credentials(ocean)
|
|
@@ -14,20 +14,7 @@ module Tugboat
|
|
|
14
14
|
droplet_list.each do |droplet|
|
|
15
15
|
has_one = true
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
if private_addr
|
|
19
|
-
private_ip = ", private_ip: #{private_addr.ip_address}"
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
status_color = if droplet.status == 'active'
|
|
23
|
-
GREEN
|
|
24
|
-
else
|
|
25
|
-
RED
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
public_addr = droplet.networks.v4.find { |address| address.type == 'public' }
|
|
29
|
-
|
|
30
|
-
say "#{droplet.name} (ip: #{public_addr.ip_address}#{private_ip}, status: #{status_color}#{droplet.status}#{CLEAR}, region: #{droplet.region.slug}, size: #{droplet.size_slug}, id: #{droplet.id}#{env['include_urls'] ? droplet_id_to_url(droplet.id) : ''})"
|
|
17
|
+
print_droplet_info(droplet, env['attribute'], env['porcelain'], env['include_urls'], env['include_name'])
|
|
31
18
|
end
|
|
32
19
|
|
|
33
20
|
unless has_one
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Tugboat
|
|
2
|
+
module Middleware
|
|
3
|
+
# Check if the client has set-up configuration yet.
|
|
4
|
+
class ListSnapshots < Base
|
|
5
|
+
def call(env)
|
|
6
|
+
ocean = env['droplet_kit']
|
|
7
|
+
|
|
8
|
+
verify_credentials(ocean)
|
|
9
|
+
|
|
10
|
+
response = ocean.snapshots.all(per_page: env['per_page'])
|
|
11
|
+
|
|
12
|
+
has_one = false
|
|
13
|
+
|
|
14
|
+
response.each do |snapshot|
|
|
15
|
+
has_one = true
|
|
16
|
+
|
|
17
|
+
say "#{snapshot.name} (id: #{snapshot.id}, resource_type: #{snapshot.resource_type}, created_at: #{snapshot.created_at})"
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
unless has_one
|
|
21
|
+
say "You don't appear to have any snapshots.", :red
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
@app.call(env)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
module Tugboat
|
|
2
|
+
module Middleware
|
|
3
|
+
class SCPDroplet < Base
|
|
4
|
+
def call(env)
|
|
5
|
+
say "Executing SCP on Droplet #{env['droplet_name']}..."
|
|
6
|
+
|
|
7
|
+
identity = File.expand_path(env['config'].ssh_key_path.to_s).strip
|
|
8
|
+
|
|
9
|
+
ssh_user = env['user_droplet_ssh_user'] || env['config'].ssh_user
|
|
10
|
+
|
|
11
|
+
scp_command = env['user_scp_command'] || 'scp'
|
|
12
|
+
|
|
13
|
+
host_ip = env['droplet_ip']
|
|
14
|
+
|
|
15
|
+
host_string = "#{ssh_user}@#{host_ip}"
|
|
16
|
+
|
|
17
|
+
if env['user_droplet_ssh_wait']
|
|
18
|
+
say 'Wait flag given, waiting for droplet to become active'
|
|
19
|
+
wait_for_state(env['droplet_id'], 'active', env['barge'])
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
identity_string = "-i #{identity}"
|
|
23
|
+
|
|
24
|
+
scp_command_string = [scp_command, identity_string, env['user_from_file'], "#{host_string}:#{env['user_to_file']}"].join(' ')
|
|
25
|
+
|
|
26
|
+
say "Attempting SCP with `#{scp_command_string}`"
|
|
27
|
+
|
|
28
|
+
Kernel.exec(scp_command_string)
|
|
29
|
+
|
|
30
|
+
@app.call(env)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
data/lib/tugboat/version.rb
CHANGED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Tugboat::CLI do
|
|
4
|
+
include_context 'spec'
|
|
5
|
+
|
|
6
|
+
describe 'backup_config' do
|
|
7
|
+
it 'enables backups on a droplet with the enable flag' do
|
|
8
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1').
|
|
9
|
+
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' }).
|
|
10
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: {})
|
|
11
|
+
|
|
12
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=200').
|
|
13
|
+
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' }).
|
|
14
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: {})
|
|
15
|
+
|
|
16
|
+
stub_request(:post, 'https://api.digitalocean.com/v2/droplets/6918990/actions').
|
|
17
|
+
with(body: '{"type":"enable_backups"}',
|
|
18
|
+
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' }).
|
|
19
|
+
to_return(status: 200, body: fixture('enable_backups_response'), headers: {})
|
|
20
|
+
|
|
21
|
+
cli.options = cli.options.merge(enable: true)
|
|
22
|
+
|
|
23
|
+
expected_string = <<-eos
|
|
24
|
+
Droplet fuzzy name provided. Finding droplet ID...done\e[0m, 6918990 (example.com)
|
|
25
|
+
Backup action enable backups is in-progress
|
|
26
|
+
eos
|
|
27
|
+
|
|
28
|
+
expect { cli.backup_config('example.com') }.to output(expected_string).to_stdout
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it 'enables backups on a droplet with the disable flag' do
|
|
32
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1').
|
|
33
|
+
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' }).
|
|
34
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: {})
|
|
35
|
+
|
|
36
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=200').
|
|
37
|
+
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' }).
|
|
38
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: {})
|
|
39
|
+
|
|
40
|
+
stub_request(:post, 'https://api.digitalocean.com/v2/droplets/6918990/actions').
|
|
41
|
+
with(body: '{"type":"disable_backups"}',
|
|
42
|
+
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' }).
|
|
43
|
+
to_return(status: 200, body: fixture('disable_backups_response'), headers: {})
|
|
44
|
+
|
|
45
|
+
cli.options = cli.options.merge(disable: true)
|
|
46
|
+
|
|
47
|
+
expected_string = <<-eos
|
|
48
|
+
Droplet fuzzy name provided. Finding droplet ID...done\e[0m, 6918990 (example.com)
|
|
49
|
+
Backup action disable backups is in-progress
|
|
50
|
+
eos
|
|
51
|
+
|
|
52
|
+
expect { cli.backup_config('example.com') }.to output(expected_string).to_stdout
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'shows error if both enable and disable given' do
|
|
56
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1').
|
|
57
|
+
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' }).
|
|
58
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: {})
|
|
59
|
+
|
|
60
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=200').
|
|
61
|
+
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' }).
|
|
62
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: {})
|
|
63
|
+
|
|
64
|
+
cli.options = cli.options.merge(disable: true, enable: true)
|
|
65
|
+
|
|
66
|
+
expect { cli.backup_config('example.com') }.to raise_error(SystemExit).and output(%r{You cannot use both --disable and --enable for backup_config}).to_stdout
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -137,6 +137,154 @@ page2example3.com (ip: 104.236.32.173, status: \e[31moff\e[0m, region: nyc3, siz
|
|
|
137
137
|
expect(a_request(:get, 'https://api.digitalocean.com/v2/droplets?page=2&per_page=3')).to have_been_made
|
|
138
138
|
end
|
|
139
139
|
|
|
140
|
+
it 'gives porcelain output when set' do
|
|
141
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1').
|
|
142
|
+
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' }).
|
|
143
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: {})
|
|
144
|
+
|
|
145
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=20').
|
|
146
|
+
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' }).
|
|
147
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: { 'Content-Type' => 'application/json' })
|
|
148
|
+
|
|
149
|
+
cli.options = cli.options.merge('porcelain' => true)
|
|
150
|
+
|
|
151
|
+
expected_string = <<-eos
|
|
152
|
+
name example.com
|
|
153
|
+
id 6918990
|
|
154
|
+
status active
|
|
155
|
+
ip4 104.236.32.182
|
|
156
|
+
ip6 2604:A880:0800:0010:0000:0000:02DD:4001
|
|
157
|
+
region nyc3
|
|
158
|
+
image 6918990
|
|
159
|
+
size 512mb
|
|
160
|
+
backups_active true
|
|
161
|
+
|
|
162
|
+
name example2.com
|
|
163
|
+
id 3164956
|
|
164
|
+
status active
|
|
165
|
+
ip4 104.236.32.172
|
|
166
|
+
ip6 2604:A880:0800:0010:0000:0000:02DD:4001
|
|
167
|
+
region nyc3
|
|
168
|
+
image 6918990
|
|
169
|
+
size 512mb
|
|
170
|
+
backups_active true
|
|
171
|
+
|
|
172
|
+
name example3.com
|
|
173
|
+
id 3164444
|
|
174
|
+
status off
|
|
175
|
+
ip4 104.236.32.173
|
|
176
|
+
ip6 2604:A880:0800:0010:0000:0000:02DD:4001
|
|
177
|
+
region nyc3
|
|
178
|
+
image 6918990
|
|
179
|
+
size 512mb
|
|
180
|
+
backups_active true
|
|
181
|
+
|
|
182
|
+
eos
|
|
183
|
+
|
|
184
|
+
expect { cli.droplets }.to output(expected_string).to_stdout
|
|
185
|
+
|
|
186
|
+
expect(a_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1')).to have_been_made.twice
|
|
187
|
+
expect(a_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=20')).to have_been_made
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
it 'gives ipv4 attribute output when set' do
|
|
191
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1').
|
|
192
|
+
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' }).
|
|
193
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: {})
|
|
194
|
+
|
|
195
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=20').
|
|
196
|
+
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' }).
|
|
197
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: { 'Content-Type' => 'application/json' })
|
|
198
|
+
|
|
199
|
+
cli.options = cli.options.merge('attribute' => 'ip4', 'include_name' => true)
|
|
200
|
+
|
|
201
|
+
expected_string = <<-eos
|
|
202
|
+
example.com,104.236.32.182
|
|
203
|
+
example2.com,104.236.32.172
|
|
204
|
+
example3.com,104.236.32.173
|
|
205
|
+
eos
|
|
206
|
+
|
|
207
|
+
expect { cli.droplets }.to output(expected_string).to_stdout
|
|
208
|
+
|
|
209
|
+
expect(a_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1')).to have_been_made.twice
|
|
210
|
+
expect(a_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=20')).to have_been_made
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
it 'gives status attribute output when set' do
|
|
214
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1').
|
|
215
|
+
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' }).
|
|
216
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: {})
|
|
217
|
+
|
|
218
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=20').
|
|
219
|
+
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' }).
|
|
220
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: { 'Content-Type' => 'application/json' })
|
|
221
|
+
|
|
222
|
+
cli.options = cli.options.merge('attribute' => 'status', 'include_name' => true)
|
|
223
|
+
|
|
224
|
+
expected_string = <<-eos
|
|
225
|
+
example.com,active
|
|
226
|
+
example2.com,active
|
|
227
|
+
example3.com,off
|
|
228
|
+
eos
|
|
229
|
+
|
|
230
|
+
expect { cli.droplets }.to output(expected_string).to_stdout
|
|
231
|
+
|
|
232
|
+
expect(a_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1')).to have_been_made.twice
|
|
233
|
+
expect(a_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=20')).to have_been_made
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
it 'gives only ip4 attribute output when set and include_name set to false' do
|
|
237
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1').
|
|
238
|
+
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' }).
|
|
239
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: {})
|
|
240
|
+
|
|
241
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=20').
|
|
242
|
+
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' }).
|
|
243
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: { 'Content-Type' => 'application/json' })
|
|
244
|
+
|
|
245
|
+
cli.options = cli.options.merge('attribute' => 'ip4', 'include_name' => false)
|
|
246
|
+
|
|
247
|
+
expected_string = <<-eos
|
|
248
|
+
104.236.32.182
|
|
249
|
+
104.236.32.172
|
|
250
|
+
104.236.32.173
|
|
251
|
+
eos
|
|
252
|
+
|
|
253
|
+
expect { cli.droplets }.to output(expected_string).to_stdout
|
|
254
|
+
|
|
255
|
+
expect(a_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1')).to have_been_made.twice
|
|
256
|
+
expect(a_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=20')).to have_been_made
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
it 'shows error if attribute asked for does not exist' do
|
|
260
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1').
|
|
261
|
+
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' }).
|
|
262
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: {})
|
|
263
|
+
|
|
264
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=20').
|
|
265
|
+
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' }).
|
|
266
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: { 'Content-Type' => 'application/json' })
|
|
267
|
+
|
|
268
|
+
cli.options = cli.options.merge('attribute' => 'foo')
|
|
269
|
+
|
|
270
|
+
expected_string = <<-eos
|
|
271
|
+
Invalid attribute \"foo\"
|
|
272
|
+
Provide one of the following:
|
|
273
|
+
name
|
|
274
|
+
id
|
|
275
|
+
status
|
|
276
|
+
ip4
|
|
277
|
+
ip6
|
|
278
|
+
private_ip
|
|
279
|
+
region
|
|
280
|
+
image
|
|
281
|
+
size
|
|
282
|
+
backups_active
|
|
283
|
+
eos
|
|
284
|
+
|
|
285
|
+
expect { cli.droplets }.to raise_error(SystemExit).and output(expected_string).to_stdout
|
|
286
|
+
end
|
|
287
|
+
|
|
140
288
|
it 'shows error on failure in initial stage' do
|
|
141
289
|
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1').
|
|
142
290
|
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' }).
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Tugboat::CLI do
|
|
4
|
+
include_context 'spec'
|
|
5
|
+
|
|
6
|
+
describe 'scp' do
|
|
7
|
+
it "tries to fetch the droplet's IP from the API" do
|
|
8
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1').
|
|
9
|
+
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' }).
|
|
10
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: {})
|
|
11
|
+
|
|
12
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=200').
|
|
13
|
+
to_return(headers: { 'Content-Type' => 'application/json' }, status: 200, body: fixture('show_droplets'))
|
|
14
|
+
allow(Kernel).to receive(:exec).with("scp -i #{Dir.home}/.ssh/id_rsa2 /tmp/foo baz@104.236.32.182:/tmp/bar")
|
|
15
|
+
|
|
16
|
+
expected_string = <<-eos
|
|
17
|
+
Droplet fuzzy name provided. Finding droplet ID...done\e[0m, 6918990 (example.com)
|
|
18
|
+
Executing SCP on Droplet (example.com)...
|
|
19
|
+
Attempting SCP with `scp -i #{Dir.home}/.ssh/id_rsa2 /tmp/foo baz@104.236.32.182:/tmp/bar`
|
|
20
|
+
eos
|
|
21
|
+
|
|
22
|
+
expect { cli.scp('example.com', '/tmp/foo', '/tmp/bar') }.to output(expected_string).to_stdout
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "runs with rsync if given at the command line" do
|
|
26
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1').
|
|
27
|
+
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' }).
|
|
28
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: {})
|
|
29
|
+
|
|
30
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=200').
|
|
31
|
+
to_return(headers: { 'Content-Type' => 'application/json' }, status: 200, body: fixture('show_droplets'))
|
|
32
|
+
allow(Kernel).to receive(:exec).with("rsync -i #{Dir.home}/.ssh/id_rsa2 /tmp/foo baz@104.236.32.182:/tmp/bar")
|
|
33
|
+
|
|
34
|
+
expected_string = <<-eos
|
|
35
|
+
Droplet fuzzy name provided. Finding droplet ID...done\e[0m, 6918990 (example.com)
|
|
36
|
+
Executing SCP on Droplet (example.com)...
|
|
37
|
+
Attempting SCP with `rsync -i #{Dir.home}/.ssh/id_rsa2 /tmp/foo baz@104.236.32.182:/tmp/bar`
|
|
38
|
+
eos
|
|
39
|
+
|
|
40
|
+
cli.options = cli.options.merge(scp_command: 'rsync')
|
|
41
|
+
|
|
42
|
+
expect { cli.scp('example.com', '/tmp/foo', '/tmp/bar') }.to output(expected_string).to_stdout
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "wait's until droplet active if -w command is given and droplet eventually active" do
|
|
46
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1').
|
|
47
|
+
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
|
+
to_return(status: 200, body: '', headers: {})
|
|
49
|
+
|
|
50
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets/6918990?per_page=200').
|
|
51
|
+
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' }).
|
|
52
|
+
to_return(
|
|
53
|
+
{ status: 200, body: fixture('show_droplet_inactive'), headers: {} },
|
|
54
|
+
status: 200, body: fixture('show_droplet'), headers: {}
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=200').
|
|
58
|
+
to_return(headers: { 'Content-Type' => 'application/json' }, status: 200, body: fixture('show_droplets'))
|
|
59
|
+
allow(Kernel).to receive(:exec).with("scp -i #{Dir.home}/.ssh/id_rsa2 /tmp/foo baz@104.236.32.182:/tmp/bar")
|
|
60
|
+
|
|
61
|
+
cli.options = cli.options.merge(wait: true)
|
|
62
|
+
|
|
63
|
+
expected_string = <<-eos
|
|
64
|
+
Droplet fuzzy name provided. Finding droplet ID...done\e[0m, 6918990 (example.com)
|
|
65
|
+
Executing SCP on Droplet (example.com)...
|
|
66
|
+
Wait flag given, waiting for droplet to become active
|
|
67
|
+
..done\e[0m (2s)
|
|
68
|
+
Attempting SCP with `scp -i #{Dir.home}/.ssh/id_rsa2 /tmp/foo baz@104.236.32.182:/tmp/bar`
|
|
69
|
+
eos
|
|
70
|
+
|
|
71
|
+
expect { cli.scp('example.com', '/tmp/foo', '/tmp/bar') }.to output(expected_string).to_stdout
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
end
|
|
75
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe Tugboat::CLI do
|
|
4
|
+
include_context 'spec'
|
|
5
|
+
|
|
6
|
+
describe 'snapshots' do
|
|
7
|
+
it 'shows a list when snapshots exist' do
|
|
8
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1').
|
|
9
|
+
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' }).
|
|
10
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: {})
|
|
11
|
+
|
|
12
|
+
stub_request(:get, "https://api.digitalocean.com/v2/snapshots?page=1&per_page=20").
|
|
13
|
+
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'}).
|
|
14
|
+
to_return(status: 200, body: fixture('show_snapshots'), headers: {})
|
|
15
|
+
|
|
16
|
+
expected_string = <<-eos
|
|
17
|
+
5.10 x64 (id: 6372321, resource_type: droplet, created_at: 2014-09-26T16:40:18Z)
|
|
18
|
+
eos
|
|
19
|
+
|
|
20
|
+
expect { cli.snapshots }.to output(expected_string).to_stdout
|
|
21
|
+
|
|
22
|
+
expect(a_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1')).to have_been_made.once
|
|
23
|
+
expect(a_request(:get, 'https://api.digitalocean.com/v2/snapshots?page=1&per_page=20')).to have_been_made.once
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
it 'shows a message when no snapshots exist' do
|
|
27
|
+
stub_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1').
|
|
28
|
+
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' }).
|
|
29
|
+
to_return(status: 200, body: fixture('show_droplets'), headers: {})
|
|
30
|
+
|
|
31
|
+
stub_request(:get, "https://api.digitalocean.com/v2/snapshots?page=1&per_page=20").
|
|
32
|
+
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'}).
|
|
33
|
+
to_return(status: 200, body: fixture('show_snapshots_empty'), headers: {})
|
|
34
|
+
|
|
35
|
+
expected_string = <<-eos
|
|
36
|
+
You don't appear to have any snapshots.
|
|
37
|
+
eos
|
|
38
|
+
|
|
39
|
+
expect { cli.snapshots }.to output(expected_string).to_stdout
|
|
40
|
+
|
|
41
|
+
expect(a_request(:get, 'https://api.digitalocean.com/v2/droplets?page=1&per_page=1')).to have_been_made.once
|
|
42
|
+
expect(a_request(:get, 'https://api.digitalocean.com/v2/snapshots?page=1&per_page=20')).to have_been_made.once
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
end
|
|
46
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"action": {
|
|
3
|
+
"id": 2,
|
|
4
|
+
"status": "in-progress",
|
|
5
|
+
"type": "disable_backups",
|
|
6
|
+
"started_at": "2014-07-29T14:35:27Z",
|
|
7
|
+
"completed_at": null,
|
|
8
|
+
"resource_id": 12,
|
|
9
|
+
"resource_type": "droplet",
|
|
10
|
+
"region_slug": "nyc1",
|
|
11
|
+
"region": {
|
|
12
|
+
"name": "New York",
|
|
13
|
+
"slug": "nyc1",
|
|
14
|
+
"available": true,
|
|
15
|
+
"sizes": [
|
|
16
|
+
"512mb"
|
|
17
|
+
],
|
|
18
|
+
"features": [
|
|
19
|
+
"virtio",
|
|
20
|
+
"private_networking",
|
|
21
|
+
"backups",
|
|
22
|
+
"ipv6",
|
|
23
|
+
"metadata"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"action": {
|
|
3
|
+
"id": 2,
|
|
4
|
+
"status": "in-progress",
|
|
5
|
+
"type": "enable_backups",
|
|
6
|
+
"started_at": "2014-07-29T14:35:27Z",
|
|
7
|
+
"completed_at": null,
|
|
8
|
+
"resource_id": 12,
|
|
9
|
+
"resource_type": "droplet",
|
|
10
|
+
"region_slug": "nyc1",
|
|
11
|
+
"region": {
|
|
12
|
+
"name": "New York",
|
|
13
|
+
"slug": "nyc1",
|
|
14
|
+
"available": true,
|
|
15
|
+
"sizes": [
|
|
16
|
+
"512mb"
|
|
17
|
+
],
|
|
18
|
+
"features": [
|
|
19
|
+
"virtio",
|
|
20
|
+
"private_networking",
|
|
21
|
+
"backups",
|
|
22
|
+
"ipv6",
|
|
23
|
+
"metadata"
|
|
24
|
+
]
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"snapshots": [
|
|
3
|
+
{
|
|
4
|
+
"id": 6372321,
|
|
5
|
+
"name": "5.10 x64",
|
|
6
|
+
"regions": [
|
|
7
|
+
"nyc1",
|
|
8
|
+
"ams1",
|
|
9
|
+
"sfo1",
|
|
10
|
+
"nyc2",
|
|
11
|
+
"ams2",
|
|
12
|
+
"sgp1",
|
|
13
|
+
"lon1",
|
|
14
|
+
"nyc3",
|
|
15
|
+
"ams3",
|
|
16
|
+
"fra1",
|
|
17
|
+
"tor1"
|
|
18
|
+
],
|
|
19
|
+
"created_at": "2014-09-26T16:40:18Z",
|
|
20
|
+
"resource_id": 2713828,
|
|
21
|
+
"resource_type": "droplet",
|
|
22
|
+
"min_disk_size": 20,
|
|
23
|
+
"size_gigabytes": 1.42
|
|
24
|
+
}
|
|
25
|
+
],
|
|
26
|
+
"links": {
|
|
27
|
+
"pages": {
|
|
28
|
+
"last": "https://api.digitalocean.com/v2/snapshots?page=1&per_page=1"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"meta": {
|
|
32
|
+
"total": 1
|
|
33
|
+
}
|
|
34
|
+
}
|
metadata
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: tugboat
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.
|
|
4
|
+
version: 4.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jack Pearkes
|
|
8
8
|
- Peter Souter
|
|
9
|
-
- Ørjan Blom
|
|
9
|
+
- "Ørjan Blom"
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date:
|
|
13
|
+
date: 2018-03-11 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: thor
|
|
@@ -396,6 +396,7 @@ files:
|
|
|
396
396
|
- lib/tugboat/middleware.rb
|
|
397
397
|
- lib/tugboat/middleware/add_key.rb
|
|
398
398
|
- lib/tugboat/middleware/ask_for_credentials.rb
|
|
399
|
+
- lib/tugboat/middleware/backup_setting.rb
|
|
399
400
|
- lib/tugboat/middleware/base.rb
|
|
400
401
|
- lib/tugboat/middleware/check_configuration.rb
|
|
401
402
|
- lib/tugboat/middleware/check_credentials.rb
|
|
@@ -419,11 +420,13 @@ files:
|
|
|
419
420
|
- lib/tugboat/middleware/list_images.rb
|
|
420
421
|
- lib/tugboat/middleware/list_regions.rb
|
|
421
422
|
- lib/tugboat/middleware/list_sizes.rb
|
|
423
|
+
- lib/tugboat/middleware/list_snapshots.rb
|
|
422
424
|
- lib/tugboat/middleware/list_ssh_keys.rb
|
|
423
425
|
- lib/tugboat/middleware/password_reset.rb
|
|
424
426
|
- lib/tugboat/middleware/rebuild_droplet.rb
|
|
425
427
|
- lib/tugboat/middleware/resize_droplet.rb
|
|
426
428
|
- lib/tugboat/middleware/restart_droplet.rb
|
|
429
|
+
- lib/tugboat/middleware/scp_droplet.rb
|
|
427
430
|
- lib/tugboat/middleware/snapshot_droplet.rb
|
|
428
431
|
- lib/tugboat/middleware/ssh_droplet.rb
|
|
429
432
|
- lib/tugboat/middleware/start_droplet.rb
|
|
@@ -432,6 +435,7 @@ files:
|
|
|
432
435
|
- license/dependency_decisions.yml
|
|
433
436
|
- spec/cli/add_key_spec.rb
|
|
434
437
|
- spec/cli/authorize_cli_spec.rb
|
|
438
|
+
- spec/cli/backup_setting_spec.rb
|
|
435
439
|
- spec/cli/config_cli_spec.rb
|
|
436
440
|
- spec/cli/create_cli_spec.rb
|
|
437
441
|
- spec/cli/debug_cli_spec.rb
|
|
@@ -450,8 +454,10 @@ files:
|
|
|
450
454
|
- spec/cli/regions_cli_spec.rb
|
|
451
455
|
- spec/cli/resize_cli_spec.rb
|
|
452
456
|
- spec/cli/restart_cli_spec.rb
|
|
457
|
+
- spec/cli/scp_cli_spec.rb
|
|
453
458
|
- spec/cli/sizes_cli_spec.rb
|
|
454
459
|
- spec/cli/snapshot_cli_spec.rb
|
|
460
|
+
- spec/cli/snapshots_cli_spec.rb
|
|
455
461
|
- spec/cli/ssh_cli_spec.rb
|
|
456
462
|
- spec/cli/start_cli_spec.rb
|
|
457
463
|
- spec/cli/verify_cli_spec.rb
|
|
@@ -463,8 +469,10 @@ files:
|
|
|
463
469
|
- spec/fixtures/create_droplet.json
|
|
464
470
|
- spec/fixtures/create_ssh_key.json
|
|
465
471
|
- spec/fixtures/create_ssh_key_from_file.json
|
|
472
|
+
- spec/fixtures/disable_backups_response.json
|
|
466
473
|
- spec/fixtures/droplet_no_network.json
|
|
467
474
|
- spec/fixtures/droplet_start_response.json
|
|
475
|
+
- spec/fixtures/enable_backups_response.json
|
|
468
476
|
- spec/fixtures/not_found.json
|
|
469
477
|
- spec/fixtures/password_reset_response.json
|
|
470
478
|
- spec/fixtures/power_cycle_response.json
|
|
@@ -487,6 +495,8 @@ files:
|
|
|
487
495
|
- spec/fixtures/show_redmine_image.json
|
|
488
496
|
- spec/fixtures/show_regions.json
|
|
489
497
|
- spec/fixtures/show_sizes.json
|
|
498
|
+
- spec/fixtures/show_snapshots.json
|
|
499
|
+
- spec/fixtures/show_snapshots_empty.json
|
|
490
500
|
- spec/fixtures/shutdown_response.json
|
|
491
501
|
- spec/fixtures/snapshot_response.json
|
|
492
502
|
- spec/fixtures/ubuntu_image_9801951.json
|
|
@@ -524,7 +534,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
524
534
|
version: '0'
|
|
525
535
|
requirements: []
|
|
526
536
|
rubyforge_project:
|
|
527
|
-
rubygems_version: 2.5
|
|
537
|
+
rubygems_version: 2.4.5
|
|
528
538
|
signing_key:
|
|
529
539
|
specification_version: 4
|
|
530
540
|
summary: A command line tool for interacting with your DigitalOcean droplets.
|
|
@@ -538,6 +548,7 @@ test_files:
|
|
|
538
548
|
- features/tugboat/config_number_key.feature
|
|
539
549
|
- spec/cli/add_key_spec.rb
|
|
540
550
|
- spec/cli/authorize_cli_spec.rb
|
|
551
|
+
- spec/cli/backup_setting_spec.rb
|
|
541
552
|
- spec/cli/config_cli_spec.rb
|
|
542
553
|
- spec/cli/create_cli_spec.rb
|
|
543
554
|
- spec/cli/debug_cli_spec.rb
|
|
@@ -556,8 +567,10 @@ test_files:
|
|
|
556
567
|
- spec/cli/regions_cli_spec.rb
|
|
557
568
|
- spec/cli/resize_cli_spec.rb
|
|
558
569
|
- spec/cli/restart_cli_spec.rb
|
|
570
|
+
- spec/cli/scp_cli_spec.rb
|
|
559
571
|
- spec/cli/sizes_cli_spec.rb
|
|
560
572
|
- spec/cli/snapshot_cli_spec.rb
|
|
573
|
+
- spec/cli/snapshots_cli_spec.rb
|
|
561
574
|
- spec/cli/ssh_cli_spec.rb
|
|
562
575
|
- spec/cli/start_cli_spec.rb
|
|
563
576
|
- spec/cli/verify_cli_spec.rb
|
|
@@ -569,8 +582,10 @@ test_files:
|
|
|
569
582
|
- spec/fixtures/create_droplet.json
|
|
570
583
|
- spec/fixtures/create_ssh_key.json
|
|
571
584
|
- spec/fixtures/create_ssh_key_from_file.json
|
|
585
|
+
- spec/fixtures/disable_backups_response.json
|
|
572
586
|
- spec/fixtures/droplet_no_network.json
|
|
573
587
|
- spec/fixtures/droplet_start_response.json
|
|
588
|
+
- spec/fixtures/enable_backups_response.json
|
|
574
589
|
- spec/fixtures/not_found.json
|
|
575
590
|
- spec/fixtures/password_reset_response.json
|
|
576
591
|
- spec/fixtures/power_cycle_response.json
|
|
@@ -593,6 +608,8 @@ test_files:
|
|
|
593
608
|
- spec/fixtures/show_redmine_image.json
|
|
594
609
|
- spec/fixtures/show_regions.json
|
|
595
610
|
- spec/fixtures/show_sizes.json
|
|
611
|
+
- spec/fixtures/show_snapshots.json
|
|
612
|
+
- spec/fixtures/show_snapshots_empty.json
|
|
596
613
|
- spec/fixtures/shutdown_response.json
|
|
597
614
|
- spec/fixtures/snapshot_response.json
|
|
598
615
|
- spec/fixtures/ubuntu_image_9801951.json
|