droplet_kit 1.3.3 → 1.4.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/Gemfile +1 -1
- data/LICENSE.txt +1 -1
- data/README.md +46 -0
- data/Rakefile +0 -1
- data/droplet_kit.gemspec +1 -1
- data/lib/droplet_kit.rb +9 -1
- data/lib/droplet_kit/client.rb +2 -1
- data/lib/droplet_kit/mappings/droplet_mapping.rb +1 -0
- data/lib/droplet_kit/mappings/tag_mapping.rb +18 -0
- data/lib/droplet_kit/mappings/tagged_droplets_resources_mapping.rb +16 -0
- data/lib/droplet_kit/mappings/tagged_resources_mapping.rb +15 -0
- data/lib/droplet_kit/models/droplet.rb +1 -1
- data/lib/droplet_kit/models/tag.rb +6 -0
- data/lib/droplet_kit/models/tagged_droplets_resources.rb +6 -0
- data/lib/droplet_kit/models/tagged_resources.rb +5 -0
- data/lib/droplet_kit/paginated_resource.rb +5 -1
- data/lib/droplet_kit/resources/droplet_action_resource.rb +24 -0
- data/lib/droplet_kit/resources/droplet_resource.rb +7 -1
- data/lib/droplet_kit/resources/tag_resource.rb +48 -0
- data/lib/droplet_kit/version.rb +1 -1
- data/spec/fixtures/droplets/all.json +4 -0
- data/spec/fixtures/droplets/create.json +3 -0
- data/spec/fixtures/droplets/find.json +4 -0
- data/spec/fixtures/tags/all.json +26 -0
- data/spec/fixtures/tags/all_empty.json +7 -0
- data/spec/fixtures/tags/create.json +11 -0
- data/spec/fixtures/tags/find.json +92 -0
- data/spec/lib/droplet_kit/paginated_resource_spec.rb +11 -2
- data/spec/lib/droplet_kit/resources/droplet_action_resource_spec.rb +53 -4
- data/spec/lib/droplet_kit/resources/droplet_resource_spec.rb +19 -7
- data/spec/lib/droplet_kit/resources/tag_resource_spec.rb +135 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/support/request_stub_helpers.rb +2 -2
- metadata +22 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3766abf70fbb920d8beb72cfc9b8db1b84c68d93
|
4
|
+
data.tar.gz: a39c01eb0af5fbb13da576c578419a1ba4f8765f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d79cc94964d34123b130791442d112cc1ca9926611132dfff1f3d9d174069a1f24e2ebde48463fcc0545ac6a9a543e40b9b45592ff5f4175ee16d97125e62547
|
7
|
+
data.tar.gz: 38028b0f20a9219ba2db2794de0bb608f922a05bd24dae3c58e5f671eaf5d7f696cfd6109dbf3a61c81a28716ae3ffac2b68ffde4ed3b944c218223105c38f92
|
data/Gemfile
CHANGED
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -74,10 +74,12 @@ client.droplets #=> DropletKit::DropletResource
|
|
74
74
|
Actions supported:
|
75
75
|
|
76
76
|
* `client.droplets.all()`
|
77
|
+
* `client.droplets.all(tag_name: 'tag_name')`
|
77
78
|
* `client.droplets.find(id: 'id')`
|
78
79
|
* `client.droplets.create(droplet)`
|
79
80
|
* `client.droplets.create_multiple(droplet)`
|
80
81
|
* `client.droplets.delete(id: 'id')`
|
82
|
+
* `client.droplets.delete_for_tag(tag_name: 'tag_name')`
|
81
83
|
* `client.droplets.kernels(id: 'id')`
|
82
84
|
* `client.droplets.snapshots(id: 'id')`
|
83
85
|
* `client.droplets.backups(id: 'id')`
|
@@ -94,22 +96,33 @@ Actions supported:
|
|
94
96
|
|
95
97
|
* `client.droplet_actions.reboot(droplet_id: droplet.id)`
|
96
98
|
* `client.droplet_actions.power_cycle(droplet_id: droplet.id)`
|
99
|
+
* `client.droplet_actions.power_cycle_for_tag(tag: 'tag_name')`
|
97
100
|
* `client.droplet_actions.shutdown(droplet_id: droplet.id)`
|
101
|
+
* `client.droplet_actions.shutdown_for_tag(tag: 'tag_name')`
|
98
102
|
* `client.droplet_actions.power_off(droplet_id: droplet.id)`
|
103
|
+
* `client.droplet_actions.power_off_for_tag(tag: 'tag_name')`
|
99
104
|
* `client.droplet_actions.power_on(droplet_id: droplet.id)`
|
105
|
+
* `client.droplet_actions.power_on_for_tag(tag: 'tag_name')`
|
100
106
|
* `client.droplet_actions.password_reset(droplet_id: droplet.id)`
|
101
107
|
* `client.droplet_actions.enable_ipv6(droplet_id: droplet.id)`
|
108
|
+
* `client.droplet_actions.enable_ipv6_for_tag(tag: 'tag_name')`
|
102
109
|
* `client.droplet_actions.enable_backups(droplet_id: droplet.id)`
|
110
|
+
* `client.droplet_actions.enable_backups_for_tag(tag: 'tag_name')`
|
103
111
|
* `client.droplet_actions.disable_backups(droplet_id: droplet.id)`
|
112
|
+
* `client.droplet_actions.disable_backups_for_tag(tag: 'tag_name')`
|
104
113
|
* `client.droplet_actions.upgrade(droplet_id: droplet.id)`
|
105
114
|
* `client.droplet_actions.enable_private_networking(droplet_id: droplet.id)`
|
115
|
+
* `client.droplet_actions.enable_private_networking_for_tag(tag: 'tag_name')`
|
106
116
|
* `client.droplet_actions.snapshot(droplet_id: droplet.id, name: 'Snapshot Name')`
|
117
|
+
* `client.droplet_actions.snapshot_for_tag(tag: 'tag_name', name: 'Snapshot Name')`
|
107
118
|
* `client.droplet_actions.change_kernel(droplet_id: droplet.id, kernel: 'kernel_id')`
|
108
119
|
* `client.droplet_actions.rename(droplet_id: droplet.id, name: 'New-Droplet-Name')`
|
109
120
|
* `client.droplet_actions.rebuild(droplet_id: droplet.id, image: 'image_id')`
|
110
121
|
* `client.droplet_actions.restore(droplet_id: droplet.id, image: 'image_id')`
|
111
122
|
* `client.droplet_actions.resize(droplet_id: droplet.id, size: '1gb')`
|
112
123
|
* `client.droplet_actions.find(droplet_id: droplet.id, id: action.id)`
|
124
|
+
* `client.droplet_actions.action_for_id(droplet_id: droplet.id, type: 'event_name', param: 'value')`
|
125
|
+
* `client.droplet_actions.action_for_tag(tag: 'tag_name', type: 'event_name', param: 'value')`
|
113
126
|
|
114
127
|
## Domain resource
|
115
128
|
|
@@ -207,6 +220,16 @@ client = DropletKit::Client.new(access_token: 'TOKEN')
|
|
207
220
|
client.ssh_keys #=> DropletKit::SSHKeyResource
|
208
221
|
```
|
209
222
|
|
223
|
+
When you want to create a droplet using your stored SSH key.
|
224
|
+
|
225
|
+
```ruby
|
226
|
+
client = DropletKit::Client.new(access_token: 'YOUR_TOKEN')
|
227
|
+
my_ssh_keys = client.ssh_keys.all.collect {|key| key.fingerprint}
|
228
|
+
droplet = DropletKit::Droplet.new(name: 'mysite.com', region: 'nyc2', image: 'ubuntu-14-04-x64', size: '512mb', ssh_keys: my_ssh_keys)
|
229
|
+
created = client.droplets.create(droplet)
|
230
|
+
# => DropletKit::Droplet(id: 1231, name: 'something.com', ...)
|
231
|
+
```
|
232
|
+
|
210
233
|
Actions supported:
|
211
234
|
|
212
235
|
* `client.ssh_keys.all()`
|
@@ -227,6 +250,29 @@ Actions supported:
|
|
227
250
|
* `client.account.info()`
|
228
251
|
|
229
252
|
|
253
|
+
## Floating IP resource
|
254
|
+
|
255
|
+
client = DropletKit::Client.new(access_token: 'TOKEN')
|
256
|
+
client.floating_ips #=> DropletKit::FloatingIpResource
|
257
|
+
|
258
|
+
Actions supported:
|
259
|
+
|
260
|
+
* `client.floating_ips.all()`
|
261
|
+
* `client.floating_ips.find(ip: 'ip address')`
|
262
|
+
* `client.floating_ips.create(floating_ip)`
|
263
|
+
* `client.floating_ips.delete(ip: 'ip address')`
|
264
|
+
|
265
|
+
## Floating IP Action resource
|
266
|
+
|
267
|
+
client = DropletKit::Client.new(access_token: 'TOKEN')
|
268
|
+
client.floating_ip_actions #=> DropletKit::FloatingIpActionResource
|
269
|
+
|
270
|
+
Actions supported:
|
271
|
+
|
272
|
+
* `client.floating_ip_actions.assign(ip: floating_ip.ip, droplet_id: droplet.id)`
|
273
|
+
* `client.floating_ip_actions.unassign(ip: floating_ip.ip)`
|
274
|
+
|
275
|
+
|
230
276
|
## Contributing
|
231
277
|
|
232
278
|
1. Fork it ( https://github.com/digitalocean/droplet_kit/fork )
|
data/Rakefile
CHANGED
data/droplet_kit.gemspec
CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.required_ruby_version = '>= 2.0.0'
|
22
22
|
|
23
23
|
spec.add_dependency 'virtus', '~> 1.0.3'
|
24
|
-
spec.add_dependency "resource_kit", '~> 0.1.
|
24
|
+
spec.add_dependency "resource_kit", '~> 0.1.5'
|
25
25
|
spec.add_dependency "kartograph", '~> 0.2.3'
|
26
26
|
spec.add_dependency "activesupport", '> 3.0', '< 5.0.0'
|
27
27
|
spec.add_dependency "faraday", '~> 0.9.1'
|
data/lib/droplet_kit.rb
CHANGED
@@ -26,6 +26,9 @@ module DropletKit
|
|
26
26
|
autoload :Account, 'droplet_kit/models/account'
|
27
27
|
autoload :DropletUpgrade, 'droplet_kit/models/droplet_upgrade'
|
28
28
|
autoload :FloatingIp, 'droplet_kit/models/floating_ip'
|
29
|
+
autoload :Tag, 'droplet_kit/models/tag'
|
30
|
+
autoload :TaggedResources, 'droplet_kit/models/tagged_resources'
|
31
|
+
autoload :TaggedDropletsResources, 'droplet_kit/models/tagged_droplets_resources'
|
29
32
|
|
30
33
|
# Resources
|
31
34
|
autoload :DropletResource, 'droplet_kit/resources/droplet_resource'
|
@@ -42,6 +45,7 @@ module DropletKit
|
|
42
45
|
autoload :DropletUpgradeResource, 'droplet_kit/resources/droplet_upgrade_resource'
|
43
46
|
autoload :FloatingIpResource, 'droplet_kit/resources/floating_ip_resource'
|
44
47
|
autoload :FloatingIpActionResource, 'droplet_kit/resources/floating_ip_action_resource'
|
48
|
+
autoload :TagResource, 'droplet_kit/resources/tag_resource'
|
45
49
|
|
46
50
|
# JSON Maps
|
47
51
|
autoload :DropletMapping, 'droplet_kit/mappings/droplet_mapping'
|
@@ -62,6 +66,9 @@ module DropletKit
|
|
62
66
|
autoload :AccountMapping, 'droplet_kit/mappings/account_mapping'
|
63
67
|
autoload :DropletUpgradeMapping, 'droplet_kit/mappings/droplet_upgrade_mapping'
|
64
68
|
autoload :FloatingIpMapping, 'droplet_kit/mappings/floating_ip_mapping'
|
69
|
+
autoload :TagMapping, 'droplet_kit/mappings/tag_mapping'
|
70
|
+
autoload :TaggedResourcesMapping, 'droplet_kit/mappings/tagged_resources_mapping'
|
71
|
+
autoload :TaggedDropletsResourcesMapping, 'droplet_kit/mappings/tagged_droplets_resources_mapping'
|
65
72
|
|
66
73
|
# Utils
|
67
74
|
autoload :PaginatedResource, 'droplet_kit/paginated_resource'
|
@@ -74,7 +81,8 @@ module DropletKit
|
|
74
81
|
FailedUpdate = Class.new(DropletKit::Error)
|
75
82
|
|
76
83
|
class RateLimitReached < DropletKit::Error
|
77
|
-
attr_accessor :
|
84
|
+
attr_accessor :reset_at
|
85
|
+
attr_writer :limit, :remaining
|
78
86
|
|
79
87
|
def limit
|
80
88
|
@limit.to_i if @limit
|
data/lib/droplet_kit/client.rb
CHANGED
@@ -19,6 +19,7 @@ module DropletKit
|
|
19
19
|
property :action_ids, scopes: [:read]
|
20
20
|
property :features, scopes: [:read]
|
21
21
|
property :size_slug, scopes: [:read]
|
22
|
+
property :tags, scopes: [:read]
|
22
23
|
|
23
24
|
property :region, scopes: [:read], include: RegionMapping
|
24
25
|
property :image, scopes: [:read], include: ImageMapping
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module DropletKit
|
2
|
+
class TagMapping
|
3
|
+
include Kartograph::DSL
|
4
|
+
|
5
|
+
kartograph do
|
6
|
+
mapping Tag
|
7
|
+
root_key plural: 'tags', singular: 'tag', scopes: [:read]
|
8
|
+
|
9
|
+
scoped :read, :create, :update do
|
10
|
+
property :name
|
11
|
+
end
|
12
|
+
|
13
|
+
scoped :read do
|
14
|
+
property :resources, include: TaggedResourcesMapping
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module DropletKit
|
2
|
+
class TaggedDropletsResourcesMapping
|
3
|
+
include Kartograph::DSL
|
4
|
+
|
5
|
+
kartograph do
|
6
|
+
mapping TaggedDropletsResources
|
7
|
+
|
8
|
+
root_key plural: 'droplets', singular: 'tag', scopes: [:read]
|
9
|
+
|
10
|
+
scoped :read do
|
11
|
+
property :count
|
12
|
+
property :last_tagged, include: DropletMapping
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module DropletKit
|
2
|
+
class TaggedResourcesMapping
|
3
|
+
include Kartograph::DSL
|
4
|
+
|
5
|
+
kartograph do
|
6
|
+
mapping TaggedResources
|
7
|
+
|
8
|
+
root_key plural: 'resources', singular: 'resource', scopes: [:read]
|
9
|
+
|
10
|
+
scoped :read do
|
11
|
+
property :droplets, include: TaggedDropletsResourcesMapping
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -2,7 +2,7 @@ module DropletKit
|
|
2
2
|
class Droplet < BaseModel
|
3
3
|
[:id, :name, :memory, :vcpus, :disk, :locked, :created_at,
|
4
4
|
:status, :backup_ids, :snapshot_ids, :action_ids, :features,
|
5
|
-
:region, :image, :networks, :kernel, :size_slug].each do |key|
|
5
|
+
:region, :image, :networks, :kernel, :size_slug, :tags].each do |key|
|
6
6
|
attribute(key)
|
7
7
|
end
|
8
8
|
|
@@ -21,6 +21,10 @@ module DropletKit
|
|
21
21
|
@options[:per_page] || PER_PAGE
|
22
22
|
end
|
23
23
|
|
24
|
+
def [](index)
|
25
|
+
@collection[index]
|
26
|
+
end
|
27
|
+
|
24
28
|
def each(start = 0)
|
25
29
|
# Start off with the first page if we have no idea of anything yet
|
26
30
|
fetch_next_page if total.nil?
|
@@ -73,4 +77,4 @@ module DropletKit
|
|
73
77
|
end
|
74
78
|
end
|
75
79
|
end
|
76
|
-
end
|
80
|
+
end
|
@@ -6,9 +6,25 @@ module DropletKit
|
|
6
6
|
password_reset enable_ipv6 enable_backups disable_backups
|
7
7
|
enable_private_networking)
|
8
8
|
|
9
|
+
TAG_ACTIONS = %w(
|
10
|
+
enable_backups disable_backups power_cycle power_on power_off shutdown
|
11
|
+
enable_private_networking enable_ipv6 snapshot
|
12
|
+
)
|
13
|
+
|
9
14
|
resources do
|
10
15
|
default_handler(422) { |response| ErrorMapping.fail_with(FailedCreate, response.body) }
|
11
16
|
|
17
|
+
action :action_for_id, 'POST /v2/droplets/:droplet_id/actions' do
|
18
|
+
body { |hash| hash.tap { |h| h.delete(:droplet_id) }.to_json }
|
19
|
+
handler(201, 200) { |response| ActionMapping.extract_single(response.body, :read) }
|
20
|
+
end
|
21
|
+
|
22
|
+
action :action_for_tag, 'POST /v2/droplets/actions' do
|
23
|
+
query_keys :tag
|
24
|
+
body { |hash| hash.to_json }
|
25
|
+
handler(201, 200) { |response| ActionMapping.extract_single(response.body, :read) }
|
26
|
+
end
|
27
|
+
|
12
28
|
ACTIONS_WITHOUT_INPUT.each do |action_name|
|
13
29
|
action action_name.to_sym, 'POST /v2/droplets/:droplet_id/actions' do
|
14
30
|
body { |_| { type: action_name }.to_json }
|
@@ -16,6 +32,14 @@ module DropletKit
|
|
16
32
|
end
|
17
33
|
end
|
18
34
|
|
35
|
+
TAG_ACTIONS.each do |action_name|
|
36
|
+
action "#{action_name}_for_tag".to_sym, 'POST /v2/droplets/actions' do
|
37
|
+
query_keys :tag
|
38
|
+
body { |_| { type: action_name }.to_json }
|
39
|
+
handler(201, 200) { |response| ActionMapping.extract_collection(response.body, :read) }
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
19
43
|
action :snapshot, 'POST /v2/droplets/:droplet_id/actions' do
|
20
44
|
body { |hash| { type: 'snapshot', name: hash[:name] }.to_json }
|
21
45
|
handler(201, 200) { |response| ActionMapping.extract_single(response.body, :read) }
|
@@ -4,7 +4,7 @@ module DropletKit
|
|
4
4
|
|
5
5
|
resources do
|
6
6
|
action :all, 'GET /v2/droplets' do
|
7
|
-
query_keys :per_page, :page
|
7
|
+
query_keys :per_page, :page, :tag_name
|
8
8
|
handler(200) { |response| DropletMapping.extract_collection(response.body, :read) }
|
9
9
|
end
|
10
10
|
|
@@ -47,6 +47,12 @@ module DropletKit
|
|
47
47
|
query_keys :per_page, :page
|
48
48
|
handler(200) { |response| ActionMapping.extract_collection(response.body, :read) }
|
49
49
|
end
|
50
|
+
|
51
|
+
action :delete_for_tag, 'DELETE /v2/droplets' do
|
52
|
+
verb :delete
|
53
|
+
query_keys :tag_name
|
54
|
+
handler(204) { |_| true }
|
55
|
+
end
|
50
56
|
end
|
51
57
|
|
52
58
|
def all(*args)
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module DropletKit
|
2
|
+
class TagResource < ResourceKit::Resource
|
3
|
+
include ErrorHandlingResourcable
|
4
|
+
|
5
|
+
resources do
|
6
|
+
action :all, 'GET /v2/tags' do
|
7
|
+
query_keys :per_page, :page
|
8
|
+
handler(200) { |response| TagMapping.extract_collection(response.body, :read) }
|
9
|
+
end
|
10
|
+
|
11
|
+
action :find, 'GET /v2/tags/:name' do
|
12
|
+
handler(200) { |response| TagMapping.extract_single(response.body, :read) }
|
13
|
+
end
|
14
|
+
|
15
|
+
action :create, 'POST /v2/tags' do
|
16
|
+
body { |object| TagMapping.representation_for(:create, object) }
|
17
|
+
handler(201) { |response| TagMapping.extract_single(response.body, :read) }
|
18
|
+
handler(422) { |response| ErrorMapping.fail_with(FailedCreate, response.body) }
|
19
|
+
end
|
20
|
+
|
21
|
+
action :update, 'PUT /v2/tags/:name' do
|
22
|
+
body { |object| TagMapping.representation_for(:update, object) }
|
23
|
+
handler(200) { |response| TagMapping.extract_single(response.body, :read) }
|
24
|
+
end
|
25
|
+
|
26
|
+
action :delete, 'DELETE /v2/tags/:name' do
|
27
|
+
handler(204) { |_| true }
|
28
|
+
handler(422) { |response| ErrorMapping.fail_with(FailedCreate, response.body) }
|
29
|
+
end
|
30
|
+
|
31
|
+
action :tag_resources, 'POST /v2/tags/:name/resources' do
|
32
|
+
verb :post
|
33
|
+
body { |hash| { resources: hash[:resources] }.to_json }
|
34
|
+
handler(204) { |_| true }
|
35
|
+
end
|
36
|
+
|
37
|
+
action :untag_resources, 'DELETE /v2/tags/:name/resources' do
|
38
|
+
verb :delete
|
39
|
+
body { |hash| { resources: hash[:resources] }.to_json }
|
40
|
+
handler(204) { |_| true }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def all(*args)
|
45
|
+
PaginatedResource.new(action(:all), self, *args)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/droplet_kit/version.rb
CHANGED
@@ -0,0 +1,26 @@
|
|
1
|
+
{
|
2
|
+
"tags": [
|
3
|
+
{
|
4
|
+
"name": "testing-1",
|
5
|
+
"resources": {
|
6
|
+
"droplets": {
|
7
|
+
"count": 0,
|
8
|
+
"last_tagged": null
|
9
|
+
}
|
10
|
+
}
|
11
|
+
},
|
12
|
+
{
|
13
|
+
"name": "testing-2",
|
14
|
+
"resources": {
|
15
|
+
"droplets": {
|
16
|
+
"count": 0,
|
17
|
+
"last_tagged": null
|
18
|
+
}
|
19
|
+
}
|
20
|
+
}
|
21
|
+
],
|
22
|
+
"links": {},
|
23
|
+
"meta": {
|
24
|
+
"total": 2
|
25
|
+
}
|
26
|
+
}
|
@@ -0,0 +1,92 @@
|
|
1
|
+
{
|
2
|
+
"tag": {
|
3
|
+
"name": "testing-1",
|
4
|
+
"resources": {
|
5
|
+
"droplets": {
|
6
|
+
"count": 1,
|
7
|
+
"last_tagged": {
|
8
|
+
"id": 1,
|
9
|
+
"name": "test.example.com",
|
10
|
+
"memory": 1024,
|
11
|
+
"vcpus": 2,
|
12
|
+
"disk": 20,
|
13
|
+
"region": {
|
14
|
+
"slug": "nyc1",
|
15
|
+
"name": "New York",
|
16
|
+
"sizes": [
|
17
|
+
"1024mb",
|
18
|
+
"512mb"
|
19
|
+
],
|
20
|
+
"available": true,
|
21
|
+
"features": [
|
22
|
+
"virtio",
|
23
|
+
"private_networking",
|
24
|
+
"backups",
|
25
|
+
"ipv6"
|
26
|
+
]
|
27
|
+
},
|
28
|
+
"image": {
|
29
|
+
"id": 119192817,
|
30
|
+
"name": "Ubuntu 13.04",
|
31
|
+
"distribution": "ubuntu",
|
32
|
+
"slug": "ubuntu1304",
|
33
|
+
"public": true,
|
34
|
+
"regions": [
|
35
|
+
"nyc1"
|
36
|
+
],
|
37
|
+
"created_at": "2014-07-29T14:35:37Z"
|
38
|
+
},
|
39
|
+
"size_slug": "1024mb",
|
40
|
+
"locked": false,
|
41
|
+
"status": "active",
|
42
|
+
"networks": {
|
43
|
+
"v4": [
|
44
|
+
{
|
45
|
+
"ip_address": "10.0.0.19",
|
46
|
+
"netmask": "255.255.0.0",
|
47
|
+
"gateway": "10.0.0.1",
|
48
|
+
"type": "private"
|
49
|
+
},
|
50
|
+
{
|
51
|
+
"ip_address": "127.0.0.19",
|
52
|
+
"netmask": "255.255.255.0",
|
53
|
+
"gateway": "127.0.0.20",
|
54
|
+
"type": "public"
|
55
|
+
}
|
56
|
+
],
|
57
|
+
"v6": [
|
58
|
+
{
|
59
|
+
"ip_address": "2001::13",
|
60
|
+
"cidr": 124,
|
61
|
+
"gateway": "2400:6180:0000:00D0:0000:0000:0009:7000",
|
62
|
+
"type": "public"
|
63
|
+
}
|
64
|
+
]
|
65
|
+
},
|
66
|
+
"kernel": {
|
67
|
+
"id": 485432985,
|
68
|
+
"name": "DO-recovery-static-fsck",
|
69
|
+
"version": "3.8.0-25-generic"
|
70
|
+
},
|
71
|
+
"created_at": "2014-07-29T14:35:37Z",
|
72
|
+
"features": [
|
73
|
+
"ipv6"
|
74
|
+
],
|
75
|
+
"backup_ids": [
|
76
|
+
449676382
|
77
|
+
],
|
78
|
+
"snapshot_ids": [
|
79
|
+
449676383
|
80
|
+
],
|
81
|
+
"action_ids": [
|
82
|
+
|
83
|
+
],
|
84
|
+
"tags": [
|
85
|
+
"tag-1",
|
86
|
+
"tag-2"
|
87
|
+
]
|
88
|
+
}
|
89
|
+
}
|
90
|
+
}
|
91
|
+
}
|
92
|
+
}
|
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'addressable/uri'
|
3
2
|
|
4
3
|
RequestCounter = Struct.new(:count)
|
5
4
|
|
@@ -45,6 +44,16 @@ RSpec.describe DropletKit::PaginatedResource do
|
|
45
44
|
end
|
46
45
|
end
|
47
46
|
|
47
|
+
describe '#[]' do
|
48
|
+
subject(:paginated) { DropletKit::PaginatedResource.new(action, resource) }
|
49
|
+
|
50
|
+
it 'returns the nth element in the collection' do
|
51
|
+
paginated.each_with_index do |elem, i|
|
52
|
+
expect(paginated[i]).to eq(elem)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
48
57
|
describe '#each' do
|
49
58
|
subject(:paginated) { DropletKit::PaginatedResource.new(action, resource) }
|
50
59
|
|
@@ -73,4 +82,4 @@ RSpec.describe DropletKit::PaginatedResource do
|
|
73
82
|
end
|
74
83
|
end
|
75
84
|
end
|
76
|
-
end
|
85
|
+
end
|
@@ -8,11 +8,37 @@ RSpec.describe DropletKit::DropletActionResource do
|
|
8
8
|
|
9
9
|
include_context 'resources'
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
|
11
|
+
describe '#action_for_id' do
|
12
|
+
let(:action) { 'event' }
|
13
|
+
let(:path) { "/v2/droplets/#{droplet_id}/actions" }
|
14
|
+
let(:fixture) { api_fixture('droplet_actions/find') }
|
14
15
|
|
15
|
-
|
16
|
+
it 'performs the action' do
|
17
|
+
request = stub_do_api(path, :post).with(
|
18
|
+
body: { type: action, param_1: 1, param_2: 2 }.to_json
|
19
|
+
).to_return(body: fixture, status: 201)
|
20
|
+
|
21
|
+
resource.action_for_id(droplet_id: droplet_id, type: action, param_1: 1, param_2: 2)
|
22
|
+
expect(request).to have_been_made
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#action_for_tag' do
|
27
|
+
let(:action) { 'event' }
|
28
|
+
let(:path) { '/v2/droplets/actions' }
|
29
|
+
let(:fixture) { api_fixture('droplet_actions/find') }
|
30
|
+
|
31
|
+
it 'performs the action' do
|
32
|
+
request = stub_do_api(path, :post).with(
|
33
|
+
body: { tag: 'test-tag', type: action, param_1: 1, param_2: 2 }.to_json
|
34
|
+
).to_return(body: fixture, status: 201)
|
35
|
+
|
36
|
+
resource.action_for_tag(tag: 'test-tag', type: action, param_1: 1, param_2: 2)
|
37
|
+
expect(request).to have_been_made
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
described_class::ACTIONS_WITHOUT_INPUT.each do |action_name|
|
16
42
|
describe "Action #{action_name}" do
|
17
43
|
let(:action) { action_name }
|
18
44
|
let(:path) { "/v2/droplets/#{droplet_id}/actions" }
|
@@ -35,6 +61,29 @@ RSpec.describe DropletKit::DropletActionResource do
|
|
35
61
|
end
|
36
62
|
end
|
37
63
|
|
64
|
+
described_class::TAG_ACTIONS.each do |action_name|
|
65
|
+
describe "Batch Action #{action_name}" do
|
66
|
+
let(:action) { "#{action_name}_for_tag" }
|
67
|
+
let(:path) { "/v2/droplets/actions?tag=testing-1" }
|
68
|
+
let(:fixture) do
|
69
|
+
single_action = DropletKit::ActionMapping.extract_single(api_fixture("droplet_actions/#{action_name}"), :read)
|
70
|
+
|
71
|
+
DropletKit::ActionMapping.represent_collection_for(:read, [single_action])
|
72
|
+
end
|
73
|
+
|
74
|
+
it 'performs the action' do
|
75
|
+
request = stub_do_api(path, :post).with(
|
76
|
+
body: { type: action_name }.to_json
|
77
|
+
).to_return(body: fixture, status: 201)
|
78
|
+
|
79
|
+
returned_actions = resource.send(action, tag: 'testing-1')
|
80
|
+
|
81
|
+
expect(request).to have_been_made
|
82
|
+
expect(returned_actions.first.type).to eq(action_name)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
38
87
|
describe "Action snapshot" do
|
39
88
|
let(:action) { 'snapshot' }
|
40
89
|
|
@@ -5,7 +5,7 @@ RSpec.describe DropletKit::DropletResource do
|
|
5
5
|
include_context 'resources'
|
6
6
|
|
7
7
|
# There's a lot to check
|
8
|
-
def check_droplet(droplet, overrides = {})
|
8
|
+
def check_droplet(droplet, tags = [], overrides = {})
|
9
9
|
attrs = {
|
10
10
|
id: 19,
|
11
11
|
name: 'test.example.com',
|
@@ -25,6 +25,9 @@ RSpec.describe DropletKit::DropletResource do
|
|
25
25
|
expect(droplet.snapshot_ids).to include(449676383)
|
26
26
|
expect(droplet.action_ids).to be_empty
|
27
27
|
expect(droplet.features).to include('ipv6')
|
28
|
+
tags.each do |tag|
|
29
|
+
expect(droplet.tags).to include(tag)
|
30
|
+
end
|
28
31
|
|
29
32
|
expect(droplet.region).to be_kind_of(DropletKit::Region)
|
30
33
|
expect(droplet.region.slug).to eq('nyc1')
|
@@ -74,7 +77,7 @@ RSpec.describe DropletKit::DropletResource do
|
|
74
77
|
droplets = resource.all
|
75
78
|
expect(droplets).to all(be_kind_of(DropletKit::Droplet))
|
76
79
|
|
77
|
-
check_droplet(droplets.first)
|
80
|
+
check_droplet(droplets.first, ['tag-1', 'tag-2'])
|
78
81
|
end
|
79
82
|
|
80
83
|
it 'returns an empty array of droplets' do
|
@@ -94,7 +97,7 @@ RSpec.describe DropletKit::DropletResource do
|
|
94
97
|
stub_do_api('/v2/droplets/20', :get).to_return(body: api_fixture('droplets/find'))
|
95
98
|
droplet = resource.find(id: 20)
|
96
99
|
expect(droplet).to be_kind_of(DropletKit::Droplet)
|
97
|
-
check_droplet(droplet)
|
100
|
+
check_droplet(droplet, ['tag-1', 'tag-2'])
|
98
101
|
end
|
99
102
|
|
100
103
|
it_behaves_like 'resource that handles common errors' do
|
@@ -192,8 +195,8 @@ RSpec.describe DropletKit::DropletResource do
|
|
192
195
|
stub_do_api(path, :post).with(body: as_string).to_return(body: api_fixture('droplets/create_multiple'), status: 202)
|
193
196
|
|
194
197
|
created_droplets = resource.create_multiple(droplet)
|
195
|
-
check_droplet(created_droplets[0], name: 'test-01.example.com')
|
196
|
-
check_droplet(created_droplets[1], id: 20, name: 'test-02.example.com')
|
198
|
+
check_droplet(created_droplets[0], [], name: 'test-01.example.com')
|
199
|
+
check_droplet(created_droplets[1], [], id: 20, name: 'test-02.example.com')
|
197
200
|
end
|
198
201
|
|
199
202
|
it 'reuses the same object' do
|
@@ -207,8 +210,8 @@ RSpec.describe DropletKit::DropletResource do
|
|
207
210
|
json = DropletKit::DropletMapping.representation_for(:create, droplet)
|
208
211
|
stub_do_api(path, :post).with(body: json).to_return(body: api_fixture('droplets/create_multiple'), status: 202)
|
209
212
|
created_droplets = resource.create_multiple(droplet)
|
210
|
-
check_droplet(created_droplets[0], name: 'test-01.example.com')
|
211
|
-
check_droplet(created_droplets[1], id: 20, name: 'test-02.example.com')
|
213
|
+
check_droplet(created_droplets[0], [], name: 'test-01.example.com')
|
214
|
+
check_droplet(created_droplets[1], [], id: 20, name: 'test-02.example.com')
|
212
215
|
end
|
213
216
|
end
|
214
217
|
|
@@ -321,4 +324,13 @@ RSpec.describe DropletKit::DropletResource do
|
|
321
324
|
expect(request).to have_been_made
|
322
325
|
end
|
323
326
|
end
|
327
|
+
|
328
|
+
describe '#delete_tagged' do
|
329
|
+
it 'sends a delete request for the tagged droplet' do
|
330
|
+
request = stub_do_api('/v2/droplets?tag_name=testing-1', :delete)
|
331
|
+
resource.delete_for_tag(tag_name: 'testing-1')
|
332
|
+
|
333
|
+
expect(request).to have_been_made
|
334
|
+
end
|
335
|
+
end
|
324
336
|
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe DropletKit::TagResource do
|
4
|
+
subject(:resource) { described_class.new(connection: connection) }
|
5
|
+
include_context 'resources'
|
6
|
+
|
7
|
+
RSpec::Matchers.define :match_tag_fixture do |expected|
|
8
|
+
match do |actual|
|
9
|
+
expect(actual).to be_kind_of(DropletKit::Tag)
|
10
|
+
expect(actual.name).to eq('testing-1')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#all' do
|
15
|
+
it 'returns all of the tags' do
|
16
|
+
stub_do_api('/v2/tags', :get)
|
17
|
+
.to_return(body: api_fixture('tags/all'))
|
18
|
+
tags = resource.all
|
19
|
+
|
20
|
+
expect(tags).to all(be_kind_of(DropletKit::Tag))
|
21
|
+
expect(tags[0].name).to eq('testing-1')
|
22
|
+
expect(tags[1].name).to eq('testing-2')
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when empty' do
|
26
|
+
it 'returns an empty array of tags' do
|
27
|
+
stub_do_api('/v2/tags', :get)
|
28
|
+
.to_return(body: api_fixture('tags/all_empty'))
|
29
|
+
tags = resource.all.map(&:id)
|
30
|
+
|
31
|
+
expect(tags).to be_empty
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it_behaves_like 'a paginated index' do
|
36
|
+
let(:fixture_path) { 'tags/all' }
|
37
|
+
let(:api_path) { '/v2/tags' }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#find' do
|
42
|
+
it 'returns a singular tag' do
|
43
|
+
stub_do_api('/v2/tags/testing-1', :get)
|
44
|
+
.to_return(body: api_fixture('tags/find'))
|
45
|
+
|
46
|
+
tag = resource.find(name: 'testing-1')
|
47
|
+
|
48
|
+
expect(tag).to be_kind_of(DropletKit::Tag)
|
49
|
+
expect(tag).to match_tag_fixture
|
50
|
+
expect(tag.resources.droplets.count).to eq(1)
|
51
|
+
expect(tag.resources.droplets.last_tagged).to be_kind_of(DropletKit::Droplet)
|
52
|
+
expect(tag.resources.droplets.last_tagged.id).to eq(1)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
describe '#create' do
|
57
|
+
it 'returns the created tag' do
|
58
|
+
tag = DropletKit::Tag.new(name: 'testing-1')
|
59
|
+
|
60
|
+
as_string = DropletKit::TagMapping.representation_for(:create, tag)
|
61
|
+
|
62
|
+
stub_do_api('/v2/tags', :post).with(body: as_string)
|
63
|
+
.to_return(body: api_fixture('tags/create'), status: 201)
|
64
|
+
created_tag = resource.create(tag)
|
65
|
+
|
66
|
+
expect(created_tag).to match_tag_fixture
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe '#update' do
|
71
|
+
it 'updateds a tag' do
|
72
|
+
tag = DropletKit::Tag.new(name: 'old-testing-1')
|
73
|
+
tag.name = 'testing-1'
|
74
|
+
|
75
|
+
request = stub_do_api('/v2/tags/old-testing-1', :put)
|
76
|
+
.with(body: DropletKit::TagMapping.representation_for(:update, tag))
|
77
|
+
.to_return(body: api_fixture('tags/find'))
|
78
|
+
|
79
|
+
tag = resource.update(tag, name: 'old-testing-1')
|
80
|
+
expect(tag.name).to eq('testing-1')
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe '#delete' do
|
85
|
+
it 'deletes a tag' do
|
86
|
+
request = stub_do_api('/v2/tags/testing-1', :delete)
|
87
|
+
.to_return(body: '', status: 204)
|
88
|
+
|
89
|
+
resource.delete(name: 'testing-1')
|
90
|
+
expect(request).to have_been_made
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
describe '#tag_resources' do
|
95
|
+
it 'adds a tag' do
|
96
|
+
params = {
|
97
|
+
resources: [
|
98
|
+
{
|
99
|
+
resource_id: '1',
|
100
|
+
resource_type: "droplet"
|
101
|
+
}
|
102
|
+
]
|
103
|
+
}
|
104
|
+
|
105
|
+
request = stub_do_api('/v2/tags/testing-1/resources', :post)
|
106
|
+
.with(body: params.to_json)
|
107
|
+
.to_return(body: '', status: 204)
|
108
|
+
|
109
|
+
resource.tag_resources(params.merge(name: 'testing-1'))
|
110
|
+
|
111
|
+
expect(request).to have_been_made
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe '#untag_resources' do
|
116
|
+
it 'removes a tag' do
|
117
|
+
params = {
|
118
|
+
resources: [
|
119
|
+
{
|
120
|
+
resource_id: '1',
|
121
|
+
resource_type: "droplet"
|
122
|
+
}
|
123
|
+
]
|
124
|
+
}
|
125
|
+
|
126
|
+
request = stub_do_api('/v2/tags/testing-1/resources', :delete)
|
127
|
+
.with(body: params.to_json)
|
128
|
+
.to_return(body: '', status: 204)
|
129
|
+
|
130
|
+
resource.untag_resources(params.merge(name: 'testing-1'))
|
131
|
+
|
132
|
+
expect(request).to have_been_made
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module RequestStubHelpers
|
2
2
|
def stub_do_api(path, verb = :any)
|
3
|
-
stub_request(verb, %r[#{DropletKit::Client::DIGITALOCEAN_API}#{path}])
|
3
|
+
stub_request(verb, %r[#{DropletKit::Client::DIGITALOCEAN_API}#{Regexp.escape(path)}])
|
4
4
|
end
|
5
5
|
|
6
6
|
def api_fixture(fixture_name)
|
@@ -25,4 +25,4 @@ module RequestStubHelpers
|
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
28
|
-
end
|
28
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: droplet_kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert Ross
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-03-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: virtus
|
@@ -30,14 +30,14 @@ dependencies:
|
|
30
30
|
requirements:
|
31
31
|
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: 0.1.
|
33
|
+
version: 0.1.5
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: 0.1.
|
40
|
+
version: 0.1.5
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: kartograph
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -207,6 +207,9 @@ files:
|
|
207
207
|
- lib/droplet_kit/mappings/size_mapping.rb
|
208
208
|
- lib/droplet_kit/mappings/snapshot_mapping.rb
|
209
209
|
- lib/droplet_kit/mappings/ssh_key_mapping.rb
|
210
|
+
- lib/droplet_kit/mappings/tag_mapping.rb
|
211
|
+
- lib/droplet_kit/mappings/tagged_droplets_resources_mapping.rb
|
212
|
+
- lib/droplet_kit/mappings/tagged_resources_mapping.rb
|
210
213
|
- lib/droplet_kit/models/account.rb
|
211
214
|
- lib/droplet_kit/models/action.rb
|
212
215
|
- lib/droplet_kit/models/backup.rb
|
@@ -227,6 +230,9 @@ files:
|
|
227
230
|
- lib/droplet_kit/models/size.rb
|
228
231
|
- lib/droplet_kit/models/snapshot.rb
|
229
232
|
- lib/droplet_kit/models/ssh_key.rb
|
233
|
+
- lib/droplet_kit/models/tag.rb
|
234
|
+
- lib/droplet_kit/models/tagged_droplets_resources.rb
|
235
|
+
- lib/droplet_kit/models/tagged_resources.rb
|
230
236
|
- lib/droplet_kit/paginated_resource.rb
|
231
237
|
- lib/droplet_kit/resources/account_resource.rb
|
232
238
|
- lib/droplet_kit/resources/action_resource.rb
|
@@ -242,6 +248,7 @@ files:
|
|
242
248
|
- lib/droplet_kit/resources/region_resource.rb
|
243
249
|
- lib/droplet_kit/resources/size_resource.rb
|
244
250
|
- lib/droplet_kit/resources/ssh_key_resource.rb
|
251
|
+
- lib/droplet_kit/resources/tag_resource.rb
|
245
252
|
- lib/droplet_kit/version.rb
|
246
253
|
- lib/tasks/resource_doc.rake
|
247
254
|
- spec/fixtures/account/info.json
|
@@ -305,6 +312,10 @@ files:
|
|
305
312
|
- spec/fixtures/ssh_keys/create.json
|
306
313
|
- spec/fixtures/ssh_keys/find.json
|
307
314
|
- spec/fixtures/ssh_keys/update.json
|
315
|
+
- spec/fixtures/tags/all.json
|
316
|
+
- spec/fixtures/tags/all_empty.json
|
317
|
+
- spec/fixtures/tags/create.json
|
318
|
+
- spec/fixtures/tags/find.json
|
308
319
|
- spec/lib/droplet_kit/client_spec.rb
|
309
320
|
- spec/lib/droplet_kit/models/base_model_spec.rb
|
310
321
|
- spec/lib/droplet_kit/models/droplet_spec.rb
|
@@ -323,6 +334,7 @@ files:
|
|
323
334
|
- spec/lib/droplet_kit/resources/region_resource_spec.rb
|
324
335
|
- spec/lib/droplet_kit/resources/size_resource_spec.rb
|
325
336
|
- spec/lib/droplet_kit/resources/ssh_key_resource_spec.rb
|
337
|
+
- spec/lib/droplet_kit/resources/tag_resource_spec.rb
|
326
338
|
- spec/spec_helper.rb
|
327
339
|
- spec/support/fake_server.rb
|
328
340
|
- spec/support/request_stub_helpers.rb
|
@@ -350,7 +362,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
350
362
|
version: '0'
|
351
363
|
requirements: []
|
352
364
|
rubyforge_project:
|
353
|
-
rubygems_version: 2.
|
365
|
+
rubygems_version: 2.5.1
|
354
366
|
signing_key:
|
355
367
|
specification_version: 4
|
356
368
|
summary: Droplet Kit is the official Ruby library for DigitalOcean's API
|
@@ -416,6 +428,10 @@ test_files:
|
|
416
428
|
- spec/fixtures/ssh_keys/create.json
|
417
429
|
- spec/fixtures/ssh_keys/find.json
|
418
430
|
- spec/fixtures/ssh_keys/update.json
|
431
|
+
- spec/fixtures/tags/all.json
|
432
|
+
- spec/fixtures/tags/all_empty.json
|
433
|
+
- spec/fixtures/tags/create.json
|
434
|
+
- spec/fixtures/tags/find.json
|
419
435
|
- spec/lib/droplet_kit/client_spec.rb
|
420
436
|
- spec/lib/droplet_kit/models/base_model_spec.rb
|
421
437
|
- spec/lib/droplet_kit/models/droplet_spec.rb
|
@@ -434,6 +450,7 @@ test_files:
|
|
434
450
|
- spec/lib/droplet_kit/resources/region_resource_spec.rb
|
435
451
|
- spec/lib/droplet_kit/resources/size_resource_spec.rb
|
436
452
|
- spec/lib/droplet_kit/resources/ssh_key_resource_spec.rb
|
453
|
+
- spec/lib/droplet_kit/resources/tag_resource_spec.rb
|
437
454
|
- spec/spec_helper.rb
|
438
455
|
- spec/support/fake_server.rb
|
439
456
|
- spec/support/request_stub_helpers.rb
|