dorb 0.0.1.pre

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +16 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE.txt +22 -0
  7. data/README.md +198 -0
  8. data/Rakefile +4 -0
  9. data/dorb.gemspec +30 -0
  10. data/lib/dorb.rb +18 -0
  11. data/lib/dorb/config.rb +36 -0
  12. data/lib/dorb/core_ext/hash.rb +24 -0
  13. data/lib/dorb/droplet.rb +10 -0
  14. data/lib/dorb/image.rb +10 -0
  15. data/lib/dorb/region.rb +10 -0
  16. data/lib/dorb/resource.rb +126 -0
  17. data/lib/dorb/size.rb +16 -0
  18. data/lib/dorb/ssh_key.rb +10 -0
  19. data/lib/dorb/version.rb +3 -0
  20. data/spec/config_spec.rb +34 -0
  21. data/spec/droplet_spec.rb +7 -0
  22. data/spec/fixtures/cassettes/DORB_Droplet/all.yml +57 -0
  23. data/spec/fixtures/cassettes/DORB_Droplet/find.yml +111 -0
  24. data/spec/fixtures/cassettes/DORB_Droplet/find_missing.yml +57 -0
  25. data/spec/fixtures/cassettes/DORB_Image/all.yml +75 -0
  26. data/spec/fixtures/cassettes/DORB_Image/find.yml +129 -0
  27. data/spec/fixtures/cassettes/DORB_Image/find_missing.yml +57 -0
  28. data/spec/fixtures/cassettes/DORB_Region/all.yml +58 -0
  29. data/spec/fixtures/cassettes/DORB_Region/find.yml +112 -0
  30. data/spec/fixtures/cassettes/DORB_Region/find_missing.yml +57 -0
  31. data/spec/fixtures/cassettes/DORB_SSHKey/all.yml +57 -0
  32. data/spec/fixtures/cassettes/DORB_SSHKey/find.yml +113 -0
  33. data/spec/fixtures/cassettes/DORB_SSHKey/find_missing.yml +57 -0
  34. data/spec/fixtures/cassettes/DORB_Size/all.yml +597 -0
  35. data/spec/fixtures/cassettes/DORB_Size/find.yml +651 -0
  36. data/spec/fixtures/cassettes/DORB_Size/find_missing.yml +57 -0
  37. data/spec/image_spec.rb +7 -0
  38. data/spec/region_spec.rb +7 -0
  39. data/spec/size_spec.rb +19 -0
  40. data/spec/spec_helper.rb +17 -0
  41. data/spec/ssh_key_spec.rb +7 -0
  42. data/spec/support/shared_examples_for_resource.rb +40 -0
  43. data/spec/support/vcr.rb +8 -0
  44. metadata +209 -0
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 60ba017e4aaa0670f9debe6271fd0a4934b88a76
4
+ data.tar.gz: 1032b5218896c4007081a48f0af4ac0a6977c1c7
5
+ SHA512:
6
+ metadata.gz: 06f866a53ccacdba53dcf965c56acc7b32f725be954eb8b0bcd736ef1daa18b9310306c6fcff8efb1284e4b046dd6f5c331c5f03a631e1299dc31342e09fb238
7
+ data.tar.gz: 209117c4efc5527a2f1a1777953b47c456840cad55c7389f5bc4fe7e12f28d3f990dda08712e67f8efc5a474c150df6a2e755f748c36596808a5dfdda48386dc
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --color
2
+ --format documentation
@@ -0,0 +1,16 @@
1
+ language: ruby
2
+ rvm:
3
+ - "1.8.7"
4
+ - "1.9.2"
5
+ - "1.9.3"
6
+ - "2.0.0"
7
+ - jruby-18mode # JRuby in 1.8 mode
8
+ - jruby-19mode # JRuby in 1.9 mode
9
+ - rbx-18mode
10
+ - rbx-19mode
11
+ env:
12
+ - DIGITAL_OCEAN_CLIENT_ID=123456789 DIGITAL_OCEAN_API_KEY=fedcba9876543210
13
+ before_install:
14
+ - gem install bundler
15
+ # uncomment this line if your project needs to run something other than `rake`:
16
+ # script: bundle exec rspec spec
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dorb.gemspec
4
+ gemspec
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2013 Darrin Wortlehock
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
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.
@@ -0,0 +1,198 @@
1
+ [![Build Status](https://travis-ci.org/exempla/dorb.png)](https://travis-ci.org/exempla/dorb)
2
+ [![Code Climate](https://codeclimate.com/github/exempla/dorb.png)](https://codeclimate.com/github/exempla/dorb)
3
+
4
+ # DORB - Digital Ocean Ruby Bindings
5
+
6
+ Interact with the [Digital Ocean](http://www.digitalocean.com) [API](http://www.digitalocean.com/api) in an idiomatic ruby way.
7
+
8
+ DORB exposes the Digital Ocean API as Ruby objects, has a comprehensive test suite and supports the entire API.
9
+
10
+ ## Installation
11
+
12
+ Add this line to your application's Gemfile:
13
+
14
+ gem 'dorb'
15
+
16
+ And then execute:
17
+
18
+ $ bundle
19
+
20
+ Or install it yourself as:
21
+
22
+ $ gem install dorb
23
+
24
+ ## Usage
25
+
26
+ Require the library in your code as
27
+
28
+ require 'dorb'
29
+
30
+ ## Configuration
31
+
32
+ Set your client key and API key
33
+
34
+ # This should be in an initializer or similar
35
+ DORB::Config.setup \
36
+ :client_key => 'YOUR_CLIENT_KEY_HERE',
37
+ :api_key => 'YOUR_API_KEY_HERE'
38
+
39
+ Any method that calls the Digital Ocean API will raise DORB::ConfigurationError if either Client Key or API Key are not configured
40
+
41
+ ## Getting Started
42
+
43
+ ### Droplets
44
+
45
+ ##### Show all active droplets
46
+ This method returns all active droplets that are currently running in your account.
47
+
48
+ DORB::Droplet.all
49
+
50
+ ##### Show droplet
51
+ This method returns a droplet for a specific droplet id.
52
+
53
+ DORB::Droplet.find id
54
+
55
+ DORB::Droplet.find_by_ip ip_address
56
+
57
+ DORB::Droplet.find_all_by_name name
58
+
59
+ ##### New droplet
60
+ This method allows you to create a new droplet.
61
+
62
+ DORB::Droplet.new :name => name, :size => size, :image => image, :region => region, :ssh_keys => [keys]
63
+
64
+ ##### Reboot droplet
65
+ This method allows you to reboot a droplet. This is the preferred method to use if a server is not responding
66
+
67
+ droplet.reboot
68
+
69
+ ##### Power cycle droplet
70
+ This method will turn off the droplet and then turn it back on
71
+
72
+ droplet.power_cycle
73
+
74
+ ##### Shut down droplet
75
+ This method allows you to shutdown a running droplet. The droplet will remain in your account
76
+
77
+ droplet.shutdown
78
+
79
+ ##### Power off droplet
80
+ This method allows you to power off a running droplet. The droplet will remain in your account
81
+
82
+ droplet.power_off
83
+
84
+ ##### Power on droplet
85
+ This method allows you to power on a powered off droplet
86
+
87
+ droplet.power_on
88
+
89
+ ##### Reset root password
90
+ This method will reset the root password for a droplet. Please be aware that this will reboot the droplet to allow resetting the password.
91
+
92
+ droplet.password_reset
93
+
94
+ ##### Resize droplet
95
+ This method allows you to resize a specific droplet to a different size. This will affect the number of processors and memory allocated to the droplet.
96
+
97
+ droplet.resize size
98
+
99
+ ##### Take a snapshot
100
+ This method allows you to take a snapshot of the running droplet, which can later be restored or used to create a new droplet from the same image. Please be aware this may cause a reboot.
101
+
102
+ droplet.snapshot
103
+
104
+ ##### Restore droplet
105
+ This method allows you to restore a droplet with a previous image or snapshot. This will be a mirror copy of the image or snapshot to your droplet. Be sure you have backed up any necessary information prior to restore.
106
+
107
+ droplet.restore image
108
+
109
+ ##### Rebuild droplet
110
+ This method allows you to reinstall a droplet with a default image. This is useful if you want to start again but retain the same IP address for your droplet.
111
+
112
+ droplet.rebuild image
113
+
114
+ ##### Enable automatic backups
115
+ This method enables automatic backups which run in the background daily to backup your droplet's data.
116
+
117
+ droplet.enable_backups
118
+
119
+ ##### Disable automatic backups
120
+ This method disables automatic backups from running to backup your droplet's data.
121
+
122
+ droplet.disable_backups
123
+
124
+ ##### Destroy droplet
125
+ This method destroys one of your droplets - this is irreversible.
126
+
127
+ droplet.destroy
128
+
129
+ ### Images
130
+
131
+ ##### All images
132
+ This method returns all the available images that can be accessed by your client ID. You will have access to all public images by default, and any snapshots or backups that you have created in your own account.
133
+
134
+ DORB::Image.all
135
+
136
+ ##### Find image
137
+ This method returns an image instance
138
+
139
+ DORB::Image.find id
140
+
141
+ DORB::Image.find_all_by_name name
142
+
143
+ ##### Destroy image
144
+ This method allows you to destroy an image. There is no way to restore a deleted image so be careful and ensure your data is properly backed up.
145
+
146
+ image.destroy
147
+
148
+ ### SSH Keys
149
+
150
+ ##### All SSH keys
151
+ This method lists all the available public SSH keys in your account that can be added to a droplet.
152
+
153
+ DORB::SSHKey.all
154
+
155
+ ##### Find SSH key
156
+ This method returns an SSHKey instance
157
+
158
+ DORB::SSHKey.find id
159
+
160
+ DORB::SSHKey.find_all_by_name name
161
+
162
+ ##### Add SSH key
163
+ This method allows you to add a new public SSH key to your account.
164
+
165
+ DORB::SSHKey.add name, ssh_key_pub
166
+
167
+ ##### Edit SSH key
168
+ This method allows you to modify an existing public SSH key in your account.
169
+
170
+ ssh_key.edit ssh_key_pub
171
+
172
+ ##### Destroy SSH Key
173
+ This method will delete the SSH key from your account.
174
+
175
+ ssh_key.destroy
176
+
177
+ ### Sizes
178
+
179
+ ##### All Sizes
180
+ This method returns all the available sizes that can be used to create a droplet.
181
+
182
+ DORB::Size.all
183
+
184
+ ### Regions
185
+
186
+ ##### All Regions
187
+ This method will return all the available regions within the Digital Ocean cloud.
188
+
189
+ DORB::Region.all
190
+
191
+
192
+ ## Contributing
193
+
194
+ 1. Fork it
195
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
196
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
197
+ 4. Push to the branch (`git push origin my-new-feature`)
198
+ 5. Create new Pull Request
@@ -0,0 +1,4 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ RSpec::Core::RakeTask.new('spec')
4
+ task :default => :spec
@@ -0,0 +1,30 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dorb/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "dorb"
8
+ spec.version = DORB::VERSION
9
+ spec.authors = ["Darrin Wortlehock"]
10
+ spec.email = ["darrin@exempla.co.uk"]
11
+ spec.description = %q{Interact with the Digital Ocean API in an idiomatic ruby way.}
12
+ spec.summary = %q{DORB exposes the Digital Ocean API as Ruby objects, has 100% test coverage and supports the entire API.}
13
+ spec.homepage = "https://github.com/exempla/dorb"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files`.split($/)
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_dependency "rest-client"
22
+ spec.add_dependency "json"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.3"
25
+ spec.add_development_dependency "rake"
26
+ spec.add_development_dependency "rspec"
27
+ spec.add_development_dependency "vcr"
28
+ spec.add_development_dependency "webmock"
29
+
30
+ end
@@ -0,0 +1,18 @@
1
+ require 'rest-client'
2
+
3
+ require 'dorb/core_ext/hash'
4
+ require 'dorb/version'
5
+ require 'dorb/config'
6
+ require 'dorb/resource'
7
+ require 'dorb/region'
8
+ require 'dorb/size'
9
+ require 'dorb/image'
10
+ require 'dorb/ssh_key'
11
+ require 'dorb/droplet'
12
+
13
+ module DORB
14
+ API_ENDPOINT = 'https://api.digitalocean.com'
15
+ APIError = Class.new StandardError
16
+ ConfigurationError = Class.new StandardError
17
+ InvalidStateError = Class.new StandardError
18
+ end
@@ -0,0 +1,36 @@
1
+ module DORB
2
+ module Config
3
+ attr_writer :client_id, :api_key
4
+
5
+ def client_id
6
+ if @client_id
7
+ @client_id
8
+ else
9
+ raise DORB::ConfigurationError.new \
10
+ "Cannot complete request. Please set client_id with DORB::Config.setup first!"
11
+ end
12
+ end
13
+
14
+ def api_key
15
+ if @api_key
16
+ @api_key
17
+ else
18
+ raise DORB::ConfigurationError.new \
19
+ "Cannot complete request. Please set api_key with DORB::Config.setup first!"
20
+ end
21
+ end
22
+
23
+ def setup opts={}
24
+ opts.map do |k,v|
25
+ send("#{k}=", v)
26
+ end
27
+ end
28
+
29
+ # def method_missing(meth, *args, &blk)
30
+ # const = meth.to_s.upcase
31
+ # DORB.const_set(const, args.first) unless DORB.const_defined? const
32
+ # end
33
+
34
+ extend self
35
+ end
36
+ end
@@ -0,0 +1,24 @@
1
+ class Hash
2
+
3
+ def stringify_keys
4
+ dup.stringify_keys!
5
+ end
6
+
7
+ def stringify_keys!
8
+ keys.each do |key|
9
+ self[key.to_s] = delete(key)
10
+ end
11
+ end
12
+
13
+ def symbolize_keys
14
+ dup.symbolize_keys!
15
+ end
16
+
17
+ def symbolize_keys!
18
+ keys.each do |key|
19
+ self[(key.to_sym rescue key) || key] = delete(key)
20
+ end
21
+ self
22
+ end
23
+
24
+ end
@@ -0,0 +1,10 @@
1
+ module DORB
2
+ class Droplet
3
+
4
+ include Resource
5
+
6
+ self.collection_resource_name = 'droplets'
7
+ self.singular_resource_name = 'droplet'
8
+
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module DORB
2
+ class Image
3
+
4
+ include Resource
5
+
6
+ self.collection_resource_name = 'images'
7
+ self.singular_resource_name = 'image'
8
+
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module DORB
2
+ class Region
3
+
4
+ include Resource
5
+
6
+ self.singular_resource_name = 'region'
7
+ self.collection_resource_name = 'regions'
8
+
9
+ end
10
+ end
@@ -0,0 +1,126 @@
1
+ require 'json'
2
+ require 'rest_client'
3
+
4
+ module DORB
5
+ module Resource
6
+
7
+ def self.included klass
8
+ klass.extend ClassMethods
9
+ end
10
+
11
+ module ClassMethods
12
+
13
+ attr_accessor :collection_resource_name
14
+ attr_accessor :singular_resource_name
15
+ attr_accessor :attribute_names
16
+ attr_accessor :extended_attributes
17
+ alias :extended_attributes? :extended_attributes
18
+
19
+ def define_attribute names
20
+ [names].flatten.each do |name|
21
+ self.attribute_names = [self.attribute_names].flatten.compact << name
22
+ attr_accessor(name)
23
+ end
24
+ end
25
+
26
+ def all(options={})
27
+ all_attributes = index(options)
28
+ all_attributes.map do |attributes|
29
+ if self.extended_attributes?
30
+ find(attributes['id'])
31
+ else
32
+ new(attributes)
33
+ end
34
+ end
35
+ end
36
+
37
+ def find(id, options={})
38
+ api_response = show(id, options)
39
+ new(api_response)
40
+ end
41
+
42
+ private
43
+
44
+ def index(options={})
45
+ call_api
46
+ end
47
+
48
+ def show(id, options={})
49
+ call_api(id)
50
+ end
51
+
52
+ def create(params={})
53
+ raise NotImplementedError
54
+ end
55
+
56
+ def update(params={})
57
+ raise NotImplementedError
58
+ end
59
+
60
+ def delete(params={})
61
+ raise NotImplementedError
62
+ end
63
+
64
+ def call_api(action=nil, extra_params={})
65
+ url = url_for_action(action)
66
+ params = extra_params.merge(credentials)
67
+ response = RestClient.get url, :params => params do |response, request, result, &block|
68
+ raise APIError.new(api_call_error_message(request,response)) unless response.code < 400
69
+ response.return!(request, result, &block)
70
+ end
71
+ parse_api_response(response)
72
+ end
73
+
74
+ def api_call_error_message(request, response)
75
+ "API Call to #{request.method} #{request.url} failed. Response was #{response.description}"
76
+ end
77
+
78
+ def url_for_action(action=nil)
79
+ uri = URI.parse(DORB::API_ENDPOINT)
80
+ uri.path << "/#{self.collection_resource_name}"
81
+ uri.path << "/#{action}" unless action.nil?
82
+ uri.path.gsub!(/\/\/+/, '/')
83
+ uri.to_s
84
+ end
85
+
86
+ def credentials
87
+ { :client_id => DORB::Config.client_id, :api_key => DORB::Config.api_key }
88
+ end
89
+
90
+ def parse_api_response(response)
91
+ parsed_response = JSON.parse(response.to_str)
92
+ unless parsed_response['status'] == 'OK'
93
+ message = "API call failed."
94
+ parsed_response.each do |key, value|
95
+ message << " #{key.gsub('_',' ').capitalize} was '#{value}'."
96
+ end
97
+ raise APIError.new(message)
98
+ end
99
+ parsed_response[self.collection_resource_name] || parsed_response[self.singular_resource_name]
100
+ end
101
+
102
+ end
103
+
104
+ attr_accessor :id, :name
105
+
106
+ def initialize( attributes={} )
107
+ required, optional = split_required_attributes(attributes, [:id, :name])
108
+ self.id = required[:id]
109
+ self.name = required[:name]
110
+ end
111
+
112
+ private
113
+
114
+ def split_required_attributes(attributes, required)
115
+ optional_attributes = attributes.symbolize_keys
116
+ required_attributes = {}
117
+ required.each do |key|
118
+ required_attributes[key] = optional_attributes.delete(key) do |missing_key|
119
+ raise ArgumentError.new("Attribute #{missing_key.inspect} is required")
120
+ end
121
+ end
122
+ [required_attributes, optional_attributes]
123
+ end
124
+
125
+ end
126
+ end