droplet_kit 1.3.3 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
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