digitalocean 0.0.3 → 1.0.0.rc.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,4 +1,4 @@
1
- Copyright (c) 2013 Scott Motte
1
+ Copyright (c) 2014 Scott Motte
2
2
 
3
3
  MIT License
4
4
 
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
19
  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
20
  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
21
  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
- WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -6,71 +6,88 @@ This gem is a wrapper for [DigitalOcean.com](https://www.digitalocean.com)'s API
6
6
 
7
7
  Add this line to your application's Gemfile:
8
8
 
9
- gem 'digitalocean'
9
+ ```
10
+ gem 'digitalocean'
11
+ ```
10
12
 
11
13
  And then execute:
12
14
 
13
- $ bundle
15
+ ```
16
+ bundle
17
+ ```
14
18
 
15
19
  Or install it yourself as:
16
20
 
17
- $ gem install digitalocean
21
+ ```
22
+ gem install digitalocean
23
+ ```
18
24
 
19
25
  Then in your application initialize the gem:
20
26
 
21
- $ Digitalocean.client_id = "your_client_id"
22
- $ Digitalocean.api_key = "your_api_key"
27
+ ```ruby
28
+ Digitalocean.client_id = "your_client_id"
29
+ Digitalocean.api_key = "your_api_key"
30
+ ```
23
31
 
24
32
  ## Usage
25
33
 
26
34
  ### List Droplets
27
35
 
28
- $ Digitalocean::Droplet.all
36
+ ```ruby
37
+ Digitalocean::Droplet.all
38
+ ```
29
39
 
30
- ### Retrieve Droplet
40
+ ### Find Droplet
31
41
 
32
- $ Digitalocean::Droplet.retrieve("id_of_droplet")
42
+ ```ruby
43
+ Digitalocean::Droplet.find("id_of_droplet")
44
+ ```
33
45
 
34
46
  ### Create Droplet
35
47
 
36
- $ Digitalocean::Droplet.create({:name => droplet_name, :size_id => size_id, :image_id => image_id, :region_id => region_id)
37
-
48
+ ```ruby
49
+ Digitalocean::Droplet.create({:name => droplet_name, :size_id => size_id, :image_id => image_id, :region_id => region_id)
50
+ ```
38
51
  ## Available Commands
39
52
 
40
- $ Digitalocean::Droplet.all
41
- $ Digitalocean::Droplet.retrieve(id)
42
- $ Digitalocean::Droplet.create({})
43
- $ Digitalocean::Droplet.reboot(id)
44
- $ Digitalocean::Droplet.power_cycle(id)
45
- $ Digitalocean::Droplet.shut_down(id)
46
- $ Digitalocean::Droplet.power_off(id)
47
- $ Digitalocean::Droplet.power_on(id)
48
- $ Digitalocean::Droplet.snapshot(id)
49
- $ Digitalocean::Droplet.destroy(id)
50
-
51
- $ Digitalocean::Image.all
52
- $ Digitalocean::Image.find(id)
53
- $ Digitalocean::Image.destroy(id)
54
- $ Digitalocean::Image.transfer(id, region_id)
55
-
56
- $ Digitalocean::Region.all
57
-
58
- $ Digitalocean::Size.all
59
-
60
- $ Digitalocean::SshKey.all
61
- $ Digitalocean::SshKey.retrieve(id)
62
- $ Digitalocean::SshKey.create({})
63
-
64
- $ Digitalocean::Domain.all
65
- $ Digitalocean::Domain.find(id)
66
- $ Digitalocean::Domain.create(domain_name, ip_address)
67
- $ Digitalocean::Domain.destroy(id)
68
-
69
- $ Digitalocean::Record.all(domain_id)
70
- $ Digitalocean::Record.find(domain_id, record_id)
71
- $ Digitalocean::Record.create(domain_id, record_type, data, [name, priority, port, weight])
72
- $ Digitalocean::Record.edit(domain_id, record_id, {})
73
- $ Digitalocean::Record.destroy(domain_id, record_id)
53
+ ```ruby
54
+ Digitalocean::Domain.all
55
+ Digitalocean::Domain.find(id)
56
+ Digitalocean::Domain.create({name: name, ip_address: ip_address})
57
+ Digitalocean::Domain.destroy(id)
58
+
59
+ Digitalocean::Droplet.all
60
+ Digitalocean::Droplet.find(id)
61
+ Digitalocean::Droplet.rename(id, {name: name})
62
+ Digitalocean::Droplet.reboot(id)
63
+ Digitalocean::Droplet.power_cycle(id)
64
+ Digitalocean::Droplet.shut_down(id)
65
+ Digitalocean::Droplet.power_off(id)
66
+ Digitalocean::Droplet.power_on(id)
67
+ Digitalocean::Droplet.snapshot(id, {name: name})
68
+ Digitalocean::Droplet.create({name: name, size_id: size_id, image_id: image_id, region_id: region_id, ssh_key_ids: ssh_key_ids})
69
+ Digitalocean::Droplet.destroy(id)
70
+
71
+ Digitalocean::Image.all
72
+ Digitalocean::Image.all({filter: "my_images"})
73
+ Digitalocean::Image.find(id)
74
+ Digitalocean::Image.destroy(id)
75
+ Digitalocean::Image.transfer(id, {region_id: region_id})
76
+
77
+ Digitalocean::Record.all(domain_id)
78
+ Digitalocean::Record.find(domain_id, record_id)
79
+ Digitalocean::Record.create(domain_id, {record_type: record_type, data: data})
80
+ Digitalocean::Record.edit(domain_id, record_id, {record_type: record_type, data: data})
81
+ Digitalocean::Record.destroy(domain_id, record_id)
82
+
83
+ Digitalocean::Region.all
84
+
85
+ Digitalocean::Size.all
86
+
87
+ Digitalocean::SshKey.all
88
+ Digitalocean::SshKey.find(id)
89
+ Digitalocean::SshKey.create({name: name, ssh_pub_key: ssh_pub_key})
90
+ ```
74
91
 
75
92
  ## Contributing
76
93
 
@@ -80,8 +97,19 @@ Then in your application initialize the gem:
80
97
  6. Push to the branch (`git push origin my-new-feature`)
81
98
  7. Create new Pull Request
82
99
 
100
+ When adding methods, add to the list of DEFINITIONS in `lib/digitalocean.rb`. Additionally, write a spec and add it to the list in the README.
101
+
83
102
  ## Running Specs
84
103
 
85
- 1. cp .env-example .env
86
- 2. Set your credentials in the .env file
87
- 3. bundle exec foreman run bundle exec rspec spec/digitalocean/*
104
+ ```
105
+ bundle exec rspec spec/*
106
+ ```
107
+
108
+ ## Publish to RubyGems.org
109
+
110
+ You first need to request access from [scottmotte](http://github.com/scottmotte).
111
+
112
+ ```
113
+ gem build digitalocean.gemspec
114
+ gem push digitalocean-1.0.0.rc.1.gem
115
+ ```
@@ -2,18 +2,84 @@ require "faraday"
2
2
  require "faraday_middleware"
3
3
  require "recursive-open-struct"
4
4
  require "digitalocean/version"
5
- require "digitalocean/droplet"
6
- require "digitalocean/image"
7
- require "digitalocean/region"
8
- require "digitalocean/size"
9
- require "digitalocean/ssh_key"
10
- require "digitalocean/domain"
11
- require "digitalocean/record"
12
-
13
5
 
14
6
  module Digitalocean
15
7
  extend self
16
8
 
9
+ DEFINITIONS = {
10
+ "Domain" => {
11
+ "all" => "https://api.digitalocean.com/domains?client_id=[your_client_id]&api_key=[your_api_key]",
12
+ "find" => "https://api.digitalocean.com/domains/[domain_id]?client_id=[your_client_id]&api_key=[your_api_key]",
13
+ "create" => "https://api.digitalocean.com/domains/new?client_id=[your_client_id]&api_key=[your_api_key]&name=[domain]&ip_address=[ip_address]",
14
+ "destroy" => "https://api.digitalocean.com/domains/[domain_id]/destroy?client_id=[your_client_id]&api_key=[your_api_key]"
15
+ },
16
+ "Droplet" => {
17
+ "all" => "https://api.digitalocean.com/droplets/?client_id=[your_client_id]&api_key=[your_api_key]",
18
+ "find" => "https://api.digitalocean.com/droplets/[droplet_id]?client_id=[your_client_id]&api_key=[your_api_key]",
19
+ "rename" => "https://api.digitalocean.com/droplets/[droplet_id]/rename/?client_id=[your_client_id]&api_key=[your_api_key]&name=[name]",
20
+ "reboot" => "https://api.digitalocean.com/droplets/[droplet_id]/reboot/?client_id=[your_client_id]&api_key=[your_api_key]",
21
+ "power_cycle" => "https://api.digitalocean.com/droplets/[droplet_id]/power_cycle/?client_id=[your_client_id]&api_key=[your_api_key]",
22
+ "shut_down" => "https://api.digitalocean.com/droplets/[droplet_id]/shut_down/?client_id=[your_client_id]&api_key=[your_api_key]",
23
+ "power_off" => "https://api.digitalocean.com/droplets/[droplet_id]/power_off/?client_id=[your_client_id]&api_key=[your_api_key]",
24
+ "power_on" => "https://api.digitalocean.com/droplets/[droplet_id]/power_on/?client_id=[your_client_id]&api_key=[your_api_key]",
25
+ "snapshot" => "https://api.digitalocean.com/droplets/[droplet_id]/snapshot/?name=[snapshot_name]&client_id=[your_client_id]&api_key=[your_api_key]",
26
+ "create" => "https://api.digitalocean.com/droplets/new?client_id=[your_client_id]&api_key=[your_api_key]&name=[droplet_name]&size_id=[size_id]&image_id=[image_id]&region_id=[region_id]&ssh_key_ids=[ssh_key_ids]", # unique case that is not copy/paste
27
+ "destroy" => "https://api.digitalocean.com/droplets/[droplet_id]/destroy/?client_id=[your_client_id]&api_key=[your_api_key]"
28
+ },
29
+ "Image" => {
30
+ "all" => "https://api.digitalocean.com/images/?client_id=[your_client_id]&api_key=[your_api_key]",
31
+ "find" => "https://api.digitalocean.com/images/[image_id]/?client_id=[your_client_id]&api_key=[your_api_key]",
32
+ "destroy" => "https://api.digitalocean.com/images/[image_id]/destroy/?client_id=[your_client_id]&api_key=[your_api_key]",
33
+ "transfer" => "https://api.digitalocean.com/images/[image_id]/transfer/?client_id=[your_client_id]&api_key=[your_api_key]&region_id=[region_id]"
34
+ },
35
+ "Record" => {
36
+ "all" => "https://api.digitalocean.com/domains/[domain_id]/records?client_id=[your_client_id]&api_key=[your_api_key]",
37
+ "find" => "https://api.digitalocean.com/domains/[domain_id]/records/[record_id]?client_id=[your_client_id]&api_key=[your_api_key]",
38
+ "create" => "https://api.digitalocean.com/domains/[domain_id]/records/new?client_id=[your_client_id]&api_key=[your_api_key]&record_type=[record_type]&data=[data]",
39
+ "edit" => "https://api.digitalocean.com/domains/[domain_id]/records/[record_id]/edit?client_id=[your_client_id]&api_key=[your_api_key]",
40
+ "destroy" => "https://api.digitalocean.com/domains/[domain_id]/records/[record_id]/destroy?client_id=[your_client_id]&api_key=[your_api_key]"
41
+ },
42
+ "Region" => {
43
+ "all" => "https://api.digitalocean.com/regions/?client_id=[your_client_id]&api_key=[your_api_key]"
44
+ },
45
+ "Size" => {
46
+ "all" => "https://api.digitalocean.com/sizes/?client_id=[your_client_id]&api_key=[your_api_key]"
47
+ },
48
+ "SshKey" => {
49
+ "all" => "https://api.digitalocean.com/ssh_keys/?client_id=[your_client_id]&api_key=[your_api_key]",
50
+ "find" => "https://api.digitalocean.com/ssh_keys/[ssh_key_id]/?client_id=[your_client_id]&api_key=[your_api_key]",
51
+ "create" => "https://api.digitalocean.com/ssh_keys/new/?name=[ssh_key_name]&ssh_pub_key=[ssh_public_key]&client_id=[your_client_id]&api_key=[your_api_key]"
52
+ }
53
+ }
54
+
55
+ DEFINITIONS.each do |resource|
56
+ resource_name = resource[0]
57
+
58
+ resource_class = Class.new(Object) do
59
+ # http://stackoverflow.com/questions/3026943/define-method-for-instance-of-class
60
+ singleton = class << self; self end
61
+
62
+ DEFINITIONS[resource_name].each do |method_name, url|
63
+ parts = url.split("?")
64
+ pre_query = parts[0]
65
+ post_query = parts[1]
66
+
67
+ singleton.send :define_method, "_#{method_name}" do |*args|
68
+ pre_query = Digitalocean.process_standard_args_from_part(pre_query, args)
69
+ post_query = Digitalocean.process_hash_args_from_part(post_query, args)
70
+
71
+ [pre_query, post_query].join("?")
72
+ end
73
+
74
+ singleton.send :define_method, method_name do |*args|
75
+ Digitalocean.request_and_respond send("_#{method_name}", *args)
76
+ end
77
+ end
78
+ end
79
+
80
+ Digitalocean.const_set(resource_name, resource_class)
81
+ end
82
+
17
83
  def request=(request)
18
84
  @request = request
19
85
  end
@@ -31,7 +97,7 @@ module Digitalocean
31
97
 
32
98
  def client_id
33
99
  return @client_id if @client_id
34
- "missing_client_id"
100
+ "client_id_required"
35
101
  end
36
102
 
37
103
  def api_key=(api_key)
@@ -43,15 +109,73 @@ module Digitalocean
43
109
 
44
110
  def api_key
45
111
  return @api_key if @api_key
46
- "missing_api_key"
112
+ "api_key_required"
47
113
  end
48
114
 
49
115
  def api_endpoint
50
116
  "https://api.digitalocean.com"
51
117
  end
52
118
 
53
- def credential_attrs
54
- {:client_id => Digitalocean.client_id, :api_key => Digitalocean.api_key}
119
+ def request_and_respond(url)
120
+ resp = Digitalocean.request.get url
121
+ hash = RecursiveOpenStruct.new(resp.body, :recurse_over_arrays => true)
122
+
123
+ hash
124
+ end
125
+
126
+ def process_standard_args_from_part(part, args)
127
+ parts = part.split(/\[|\]/)
128
+
129
+ if parts.length > 1
130
+ parts.each_with_index do |v, i|
131
+ is_every_other = (i%2 == 1)
132
+ parts[i] = args.shift if is_every_other
133
+ end
134
+ end
135
+
136
+ parts.join("")
137
+ end
138
+
139
+ def process_client_id_and_api_key(parts)
140
+ # Begin by taking care of the client_id and api_key
141
+ client_id_index = parts.index "client_id="
142
+ client_id_index = parts.index "&client_id=" if !client_id_index
143
+ parts[client_id_index+1] = client_id if client_id_index
144
+
145
+ api_key_index = parts.index "api_key="
146
+ api_key_index = parts.index "&api_key=" if !api_key_index
147
+ parts[api_key_index+1] = api_key if api_key_index
148
+
149
+ parts
150
+ end
151
+
152
+ def process_hash_args_from_part(part, args)
153
+ parts = part.split(/\[|\]/)
154
+ parts = process_client_id_and_api_key(parts)
155
+
156
+ hash = args[-1]
157
+ if hash.is_a?(Hash)
158
+ if parts.length > 1
159
+ hash.each do |key, value|
160
+ query_setter = "#{key}="
161
+ query_arg_index = parts.index query_setter
162
+ query_arg_index = parts.index "&#{query_setter}" if !query_arg_index # handle case of ampersand
163
+
164
+ if query_arg_index != nil
165
+ parts[query_arg_index+1] = value
166
+ hash.delete(key) # cleanup
167
+ end
168
+ end
169
+ end
170
+
171
+ # append any additional hash arguments (optional params)
172
+ hash.each do |key, value|
173
+ appendable_param = "&#{key}=#{value}"
174
+ parts.push(appendable_param)
175
+ end
176
+ end
177
+
178
+ parts.join("")
55
179
  end
56
180
 
57
181
  private
@@ -59,9 +183,7 @@ module Digitalocean
59
183
  def setup_request!
60
184
  options = {
61
185
  :headers => {'Accept' => "application/json"},
62
- :ssl => {:verify => false},
63
- :url => Digitalocean.api_endpoint,
64
- :params => Digitalocean.credential_attrs
186
+ :ssl => {:verify => false}
65
187
  }
66
188
 
67
189
  Digitalocean.request = ::Faraday::Connection.new(options) do |builder|
@@ -71,4 +193,4 @@ module Digitalocean
71
193
  builder.adapter ::Faraday.default_adapter
72
194
  end
73
195
  end
74
- end
196
+ end
@@ -1,3 +1,3 @@
1
1
  module Digitalocean
2
- VERSION = "0.0.3"
2
+ VERSION = "1.0.0.rc.2"
3
3
  end
@@ -1,69 +1,53 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Digitalocean::Domain do
4
- let(:ok) { "OK" }
5
4
  let(:subject) { Digitalocean::Domain }
6
5
 
7
- context "correct api key" do
6
+ describe "._all" do
8
7
  before do
9
- set_client_id_and_api_key!
8
+ @url = subject._all
10
9
  end
11
10
 
12
- describe ".all" do
13
- before do
14
- @response = subject.all
15
- end
16
-
17
- context "default" do
18
- it do
19
- @response.status.should eq ok
20
- end
21
- end
11
+ it do
12
+ @url.should eq "https://api.digitalocean.com/domains?client_id=client_id_required&api_key=api_key_required"
13
+ end
14
+ end
22
15
 
23
- describe ".find" do
24
- before do
25
- domain_id = @response.domains.first.id
26
- @response2 = subject.find(domain_id)
27
- end
16
+ describe "._find" do
17
+ let(:domain_id) { "1234" }
28
18
 
29
- context "default" do
30
- it do
31
- @response2.status.should eq ok
32
- end
33
- end
34
- end
19
+ before do
20
+ @url = subject._find(domain_id)
21
+ end
35
22
 
36
- describe ".create" do
37
- let(:domain_name) { ["digitalocean_spec_", SecureRandom.hex(15), ".com"].join }
23
+ it do
24
+ @url.should eq "https://api.digitalocean.com/domains/#{domain_id}?client_id=client_id_required&api_key=api_key_required"
25
+ end
26
+ end
38
27
 
39
- before do
40
- domain = @response.domains.first
41
- @response_create = subject.create(domain_name, domain.ip_address)
42
- end
28
+ describe "._create" do
29
+ let(:name) { "test_domain" }
30
+ let(:ip_address) { "test_ip_address" }
31
+ let(:args) { {name: name, ip_address: ip_address } }
43
32
 
44
- context "default" do
45
- it do
46
- @response_create.status.should eq ok
47
- end
48
- end
49
- end
33
+ before do
34
+ @url = subject._create(args)
35
+ end
50
36
 
51
- describe ".destroy" do
52
- let(:domain_name) { ["digitalocean_spec_", SecureRandom.hex(15), ".com"].join }
37
+ it do
38
+ @url.should eq "https://api.digitalocean.com/domains/new?client_id=client_id_required&api_key=api_key_required&name=test_domain&ip_address=test_ip_address"
39
+ end
40
+ end
53
41
 
54
- before do
55
- droplet = @response.droplets.first
56
- @response_create = subject.create(domain_name, droplet.ip_address)
57
- @response_destroy = subject.destroy(@response_create.id)
58
- end
42
+ describe "._destroy" do
43
+ let(:domain_id) { "test_domain_id" }
59
44
 
60
- context "default" do
61
- it do
62
- @response_destroy.status.should eq ok
63
- end
64
- end
65
- end
45
+ before do
46
+ @url = subject._destroy(domain_id)
47
+ end
66
48
 
49
+ it do
50
+ @url.should eq "https://api.digitalocean.com/domains/test_domain_id/destroy?client_id=client_id_required&api_key=api_key_required"
67
51
  end
68
52
  end
69
- end
53
+ end