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.
Files changed (35) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/LICENSE.txt +1 -1
  4. data/README.md +46 -0
  5. data/Rakefile +0 -1
  6. data/droplet_kit.gemspec +1 -1
  7. data/lib/droplet_kit.rb +9 -1
  8. data/lib/droplet_kit/client.rb +2 -1
  9. data/lib/droplet_kit/mappings/droplet_mapping.rb +1 -0
  10. data/lib/droplet_kit/mappings/tag_mapping.rb +18 -0
  11. data/lib/droplet_kit/mappings/tagged_droplets_resources_mapping.rb +16 -0
  12. data/lib/droplet_kit/mappings/tagged_resources_mapping.rb +15 -0
  13. data/lib/droplet_kit/models/droplet.rb +1 -1
  14. data/lib/droplet_kit/models/tag.rb +6 -0
  15. data/lib/droplet_kit/models/tagged_droplets_resources.rb +6 -0
  16. data/lib/droplet_kit/models/tagged_resources.rb +5 -0
  17. data/lib/droplet_kit/paginated_resource.rb +5 -1
  18. data/lib/droplet_kit/resources/droplet_action_resource.rb +24 -0
  19. data/lib/droplet_kit/resources/droplet_resource.rb +7 -1
  20. data/lib/droplet_kit/resources/tag_resource.rb +48 -0
  21. data/lib/droplet_kit/version.rb +1 -1
  22. data/spec/fixtures/droplets/all.json +4 -0
  23. data/spec/fixtures/droplets/create.json +3 -0
  24. data/spec/fixtures/droplets/find.json +4 -0
  25. data/spec/fixtures/tags/all.json +26 -0
  26. data/spec/fixtures/tags/all_empty.json +7 -0
  27. data/spec/fixtures/tags/create.json +11 -0
  28. data/spec/fixtures/tags/find.json +92 -0
  29. data/spec/lib/droplet_kit/paginated_resource_spec.rb +11 -2
  30. data/spec/lib/droplet_kit/resources/droplet_action_resource_spec.rb +53 -4
  31. data/spec/lib/droplet_kit/resources/droplet_resource_spec.rb +19 -7
  32. data/spec/lib/droplet_kit/resources/tag_resource_spec.rb +135 -0
  33. data/spec/spec_helper.rb +2 -0
  34. data/spec/support/request_stub_helpers.rb +2 -2
  35. metadata +22 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9a86ff8a04cf0c309cc0664c732326179bb5c645
4
- data.tar.gz: d38e878482a1ebe271bc139dc5a90a3f0b1d094b
3
+ metadata.gz: 3766abf70fbb920d8beb72cfc9b8db1b84c68d93
4
+ data.tar.gz: a39c01eb0af5fbb13da576c578419a1ba4f8765f
5
5
  SHA512:
6
- metadata.gz: ce73f66a82d4a2d08638c4e4af1a8e171fee5d0ae0c50ee10dfc40701c5a6aab5c536a11e68fca4fbc6160cb635d203d4a1c6c89c53ba08b762f0cbcb928ec70
7
- data.tar.gz: af22eec48bfa4e8e159df286252db56da1de69247857933e6c35be9b559d600746920b328f6d87c2ba2510b1518afbb4a2eba9f5a30eaf155b10d21360ed979e
6
+ metadata.gz: d79cc94964d34123b130791442d112cc1ca9926611132dfff1f3d9d174069a1f24e2ebde48463fcc0545ac6a9a543e40b9b45592ff5f4175ee16d97125e62547
7
+ data.tar.gz: 38028b0f20a9219ba2db2794de0bb608f922a05bd24dae3c58e5f671eaf5d7f696cfd6109dbf3a61c81a28716ae3ffac2b68ffde4ed3b944c218223105c38f92
data/Gemfile CHANGED
@@ -11,4 +11,4 @@ version = case (ENV['ACTIVESUPPORT_VERSION'] || '4')
11
11
  '~> 3.1'
12
12
  end
13
13
 
14
- gem 'activesupport', version
14
+ gem 'activesupport', version
@@ -1,4 +1,4 @@
1
- Copyright (c) 2014 Robert Ross
1
+ Copyright (c) 2014-2016 Robert Ross
2
2
 
3
3
  MIT License
4
4
 
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
@@ -1,4 +1,3 @@
1
1
  require "bundler/gem_tasks"
2
2
 
3
3
  load './lib/tasks/resource_doc.rake'
4
-
@@ -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.4'
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'
@@ -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 :limit, :remaining, :reset_at
84
+ attr_accessor :reset_at
85
+ attr_writer :limit, :remaining
78
86
 
79
87
  def limit
80
88
  @limit.to_i if @limit
@@ -31,6 +31,7 @@ module DropletKit
31
31
  account: AccountResource,
32
32
  floating_ips: FloatingIpResource,
33
33
  floating_ip_actions: FloatingIpActionResource,
34
+ tags: TagResource
34
35
  }
35
36
  end
36
37
 
@@ -59,4 +60,4 @@ module DropletKit
59
60
  }
60
61
  end
61
62
  end
62
- end
63
+ end
@@ -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
 
@@ -0,0 +1,6 @@
1
+ module DropletKit
2
+ class Tag < BaseModel
3
+ attribute :name
4
+ attribute :resources
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ module DropletKit
2
+ class TaggedDropletsResources < BaseModel
3
+ attribute :count
4
+ attribute :last_tagged
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module DropletKit
2
+ class TaggedResources < BaseModel
3
+ attribute :droplets
4
+ end
5
+ end
@@ -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
@@ -1,3 +1,3 @@
1
1
  module DropletKit
2
- VERSION = "1.3.3"
2
+ VERSION = "1.4.0"
3
3
  end
@@ -76,6 +76,10 @@
76
76
  ],
77
77
  "action_ids": [
78
78
 
79
+ ],
80
+ "tags": [
81
+ "tag-1",
82
+ "tag-2"
79
83
  ]
80
84
  }
81
85
  ],
@@ -75,6 +75,9 @@
75
75
  ],
76
76
  "action_ids": [
77
77
 
78
+ ],
79
+ "tags": [
80
+
78
81
  ]
79
82
  }
80
83
  }
@@ -75,6 +75,10 @@
75
75
  ],
76
76
  "action_ids": [
77
77
 
78
+ ],
79
+ "tags": [
80
+ "tag-1",
81
+ "tag-2"
78
82
  ]
79
83
  }
80
84
  }
@@ -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,7 @@
1
+ {
2
+ "tags": [
3
+ ],
4
+ "meta": {
5
+ "total": 0
6
+ }
7
+ }
@@ -0,0 +1,11 @@
1
+ {
2
+ "tag": {
3
+ "name": "testing-1",
4
+ "resources": {
5
+ "droplets": {
6
+ "count": 0,
7
+ "last_tagged": null
8
+ }
9
+ }
10
+ }
11
+ }
@@ -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
- ACTIONS_WITHOUT_INPUT = %w(reboot power_cycle shutdown power_off
12
- power_on password_reset enable_ipv6 disable_backups enable_backups
13
- enable_private_networking upgrade)
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
- ACTIONS_WITHOUT_INPUT.each do |action_name|
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
@@ -2,6 +2,8 @@ require 'simplecov'
2
2
 
3
3
  SimpleCov.start
4
4
 
5
+ require 'faraday'
6
+ require 'addressable/uri'
5
7
  require 'droplet_kit'
6
8
  require 'webmock/rspec'
7
9
 
@@ -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.3.3
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: 2015-12-14 00:00:00.000000000 Z
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.4
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.4
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.4.6
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