bbrowning-deltacloud-core 0.0.3.1 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -37,15 +37,22 @@ Rake::TestTask.new("test") { |t|
37
37
  'tests/images_test.rb',
38
38
  'tests/instances_test.rb',
39
39
  'tests/instance_states_test.rb',
40
+ 'tests/url_for_test.rb'
40
41
  ]
41
42
  t.verbose = true
42
43
  t.warning = false
43
44
  }
44
45
 
45
- load 'deltacloud-core.gemspec'
46
46
 
47
- Rake::GemPackageTask.new(@spec) do |pkg|
48
- pkg.need_tar = true
47
+ @specs = ['ruby', 'java'].inject({}) do |hash, spec_platform|
48
+ $platform = spec_platform
49
+ hash.update(spec_platform => Gem::Specification.load('deltacloud-core.gemspec'))
50
+ end
51
+
52
+ @specs.values.each do |spec|
53
+ Rake::GemPackageTask.new(spec) do |pkg|
54
+ pkg.need_tar = true
55
+ end
49
56
  end
50
57
 
51
58
  desc "Install API"
data/bin/deltacloudd CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'rubygems'
4
4
  require 'optparse'
5
- require 'thin'
6
5
 
7
6
  options = {
8
7
  :env => 'development'
@@ -44,45 +43,78 @@ end
44
43
  ENV["API_HOST"] = "localhost" unless ENV["API_HOST"]
45
44
  ENV["API_PORT"] = "3001" unless ENV["API_PORT"]
46
45
 
46
+ puts "Starting Deltacloud API :: #{ENV["API_DRIVER"]} :: http://#{ENV["API_HOST"]}:#{ENV["API_PORT"]}/api"
47
+ puts
48
+
47
49
  dirname="#{File.dirname(__FILE__)}/.."
50
+ platform = RUBY_PLATFORM[/java/] || 'ruby'
48
51
 
49
- argv_opts = ARGV.clone
50
- argv_opts << ['start'] unless Thin::Runner.commands.include?(options[0])
51
- argv_opts << ['--address', ENV["API_HOST"] ]
52
- argv_opts << ['--port', ENV["API_PORT"] ]
53
- argv_opts << ['--rackup', 'config.ru' ]
54
- argv_opts << ['--chdir', dirname ]
55
- argv_opts << ['-e', options[:env] ]
56
- argv_opts << ['--threaded', '-D', '--stats', '/stats']
57
-
58
- argv_opts.flatten!
59
-
60
- if options[:env] == "development"
61
- use_rerun = false
62
- begin
63
- require "rerun"
64
- use_rerun = true
65
- rescue
66
- # Do nothing
67
- end
68
- end
52
+ if platform == 'java'
53
+ require 'rack'
69
54
 
70
- puts "Starting Deltacloud API :: #{ENV["API_DRIVER"]} :: http://#{ENV["API_HOST"]}:#{ENV["API_PORT"]}/api"
71
- puts
55
+ # We can't chdir with webrick so add our root directory
56
+ # onto the load path
57
+ $: << dirname
58
+
59
+ # Read in config.ru and convert it to an instance of Rack::Builder
60
+ cfgfile = File.read(File.join(dirname, 'config.ru'))
61
+ inner_app = eval("Rack::Builder.new {(" + cfgfile + "\n )}.to_app",
62
+ nil, 'config.ru')
72
63
 
73
- if use_rerun
74
- argv_opts.unshift "thin"
75
- command = argv_opts.join(" ")
76
- topdir = File::expand_path(File::join(File::dirname(__FILE__), ".."))
77
- rerun = Rerun::Runner.new(command, :dir => topdir)
78
- rerun.start
79
- rerun.join
64
+ app = Rack::Builder.new {
65
+ use Rack::CommonLogger # apache-like logging
66
+ use Rack::Reloader if options[:env] == "development"
67
+ set :root, dirname # Set Sinatra root since we can't chdir to ../
68
+ run inner_app
69
+ }.to_app
70
+
71
+ # There's a bug with string ports on JRuby so convert to int
72
+ # http://jira.codehaus.org/browse/JRUBY-4868
73
+ port = ENV["API_PORT"].to_i
74
+
75
+ puts "=> Ctrl-C to shutdown server"
76
+ Rack::Handler::WEBrick.run(app,
77
+ :Host => ENV["API_HOST"],
78
+ :Port => port,
79
+ :AccessLog => [])
80
80
  else
81
- thin = Thin::Runner.new(argv_opts)
81
+ require 'thin'
82
+
83
+ argv_opts = ARGV.clone
84
+ argv_opts << ['start'] unless Thin::Runner.commands.include?(options[0])
85
+ argv_opts << ['--address', ENV["API_HOST"] ]
86
+ argv_opts << ['--port', ENV["API_PORT"] ]
87
+ argv_opts << ['--rackup', 'config.ru' ]
88
+ argv_opts << ['--chdir', dirname ]
89
+ argv_opts << ['-e', options[:env] ]
90
+ argv_opts << ['--threaded', '-D', '--stats', '/stats']
91
+
92
+ argv_opts.flatten!
93
+
94
+ if options[:env] == "development"
95
+ use_rerun = false
96
+ begin
97
+ require "rerun"
98
+ use_rerun = true
99
+ rescue
100
+ # Do nothing
101
+ end
102
+ end
103
+
104
+ if use_rerun
105
+ argv_opts.unshift "thin"
106
+ command = argv_opts.join(" ")
107
+ topdir = File::expand_path(File::join(File::dirname(__FILE__), ".."))
108
+ rerun = Rerun::Runner.new(command, :dir => topdir)
109
+ rerun.start
110
+ rerun.join
111
+ else
112
+ thin = Thin::Runner.new(argv_opts)
82
113
 
83
- begin
84
- thin.run!
85
- rescue Exception => e
86
- puts "ERROR: #{e.message}"
114
+ begin
115
+ thin.run!
116
+ rescue Exception => e
117
+ puts "ERROR: #{e.message}"
118
+ end
87
119
  end
88
120
  end
data/config.ru CHANGED
@@ -1,5 +1,5 @@
1
- require 'sinatra'
2
1
  require 'rubygems'
2
+ require 'sinatra'
3
3
 
4
4
  require 'server.rb'
5
5
  run Sinatra::Application
data/deltacloud.rb CHANGED
@@ -9,6 +9,7 @@ require 'deltacloud/models/base_model'
9
9
  require 'deltacloud/models/realm'
10
10
  require 'deltacloud/models/image'
11
11
  require 'deltacloud/models/instance'
12
+ require 'deltacloud/models/key'
12
13
  require 'deltacloud/models/instance_profile'
13
14
  require 'deltacloud/models/storage_snapshot'
14
15
  require 'deltacloud/models/storage_volume'
@@ -31,6 +31,16 @@ module Deltacloud
31
31
  end
32
32
  end
33
33
 
34
+ class BackendFeatureUnsupported < StandardError
35
+ attr_reader :code, :cause, :details
36
+ def initialize(code, cause, message, details)
37
+ super(message)
38
+ @code = code
39
+ @cause = cause
40
+ @details = details
41
+ end
42
+ end
43
+
34
44
  class BaseDriver
35
45
 
36
46
  def self.define_hardware_profile(name,&block)
@@ -195,6 +205,25 @@ module Deltacloud
195
205
  return false
196
206
  end
197
207
 
208
+ def catched_exceptions_list
209
+ { :error => [], :auth => [], :glob => [] }
210
+ end
211
+
212
+ def safely(&block)
213
+ begin
214
+ block.call
215
+ rescue *catched_exceptions_list[:error] => e
216
+ raise Deltacloud::BackendError.new(502, e.class.to_s, e.message, e.backtrace)
217
+ rescue *catched_exceptions_list[:auth] => e
218
+ raise Deltacloud::AuthException.new
219
+ rescue => e
220
+ catched_exceptions_list[:glob].each do |ex|
221
+ raise Deltacloud::BackendError.new(502, e.class.to_s, e.message, e.backtrace) if e.class.name =~ ex
222
+ end
223
+ raise e
224
+ end
225
+ end
226
+
198
227
  end
199
228
 
200
229
  end
@@ -120,6 +120,13 @@ module Deltacloud
120
120
  #
121
121
  # Declaration of optional features
122
122
  #
123
+ declare_feature :images, :owner_id do
124
+ description "Filter images using owner id"
125
+ operation :index do
126
+ param :owner_id, :string, :optional, nil, "Owner ID"
127
+ end
128
+ end
129
+
123
130
  declare_feature :instances, :user_name do
124
131
  description "Accept a user-defined name on instance creation"
125
132
  operation :create do
@@ -11,10 +11,13 @@ module Mock
11
11
  [
12
12
  :describe_images,
13
13
  :describe_availability_zones,
14
+ :describe_keypairs,
15
+ :create_keypair,
14
16
  :run_instances,
15
17
  :describe_instances,
16
18
  :reboot_instances,
17
- :terminate_instances
19
+ :terminate_instances,
20
+ :delete_keypair
18
21
  ]
19
22
  end
20
23
 
@@ -35,8 +35,13 @@ module Deltacloud
35
35
  module EC2
36
36
  class EC2Driver < Deltacloud::BaseDriver
37
37
 
38
+ def supported_collections
39
+ DEFAULT_COLLECTIONS + [ :keys ]
40
+ end
41
+
38
42
  feature :instances, :user_data
39
43
  feature :instances, :authentication_key
44
+ feature :images, :owner_id
40
45
 
41
46
  define_hardware_profile('m1.small') do
42
47
  cpu 1
@@ -170,40 +175,60 @@ class EC2Driver < Deltacloud::BaseDriver
170
175
  def create_instance(credentials, image_id, opts)
171
176
  ec2 = new_client( credentials )
172
177
  realm_id = opts[:realm_id]
173
- image = image(credentials, :id => image_id )
174
- hwp = find_hardware_profile(credentials, opts[:hwp_id], image.id)
175
- ec2_instances = ec2.run_instances(
176
- :image_id => image.id,
177
- :user_data => opts[:user_data],
178
- :key_name => opts[:keyname],
179
- :availability_zone => realm_id,
180
- :monitoring_enabled => true,
181
- :instance_type => hwp.name,
182
- :disable_api_termination => false,
183
- :instance_initiated_shutdown_behavior => 'terminate'
184
- )
185
- convert_instance( ec2_instances.instancesSet.item.first, 'pending' )
178
+ safely do
179
+ image = image(credentials, :id => image_id )
180
+ hwp = find_hardware_profile(credentials, opts[:hwp_id], image.id)
181
+ ec2_instances = ec2.run_instances(
182
+ :image_id => image.id,
183
+ :user_data => opts[:user_data],
184
+ :key_name => opts[:keyname],
185
+ :availability_zone => realm_id,
186
+ :monitoring_enabled => true,
187
+ :instance_type => hwp.name,
188
+ :disable_api_termination => false,
189
+ :instance_initiated_shutdown_behavior => 'terminate'
190
+ )
191
+ return convert_instance( ec2_instances.instancesSet.item.first, 'pending' )
192
+ end
193
+ end
194
+
195
+ def generate_instance(ec2, id, backup)
196
+ begin
197
+ this_instance = ec2.describe_instances( :instance_id => id ).reservationSet.item.first.instancesSet.item.first
198
+ convert_instance(this_instance, this_instance.ownerId)
199
+ rescue Exception => e
200
+ puts "WARNING: ignored error during instance refresh: #{e.message}"
201
+ # at this point, the action has succeeded but our follow-up
202
+ # "describe_instances" failed for some reason. Create a simple Instance
203
+ # object with only the ID and new state in place
204
+ state = backup.instancesSet.item.first.currentState.name
205
+ Instance.new( {
206
+ :id => id,
207
+ :state => state,
208
+ :actions => instance_actions_for( state ),
209
+ } )
210
+ end
186
211
  end
187
212
 
188
213
  def reboot_instance(credentials, id)
189
214
  ec2 = new_client(credentials)
190
- safely do
191
- ec2.reboot_instances( :instance_id => id )
192
- end
215
+ backup = ec2.reboot_instances( :instance_id => id )
216
+
217
+ generate_instance(ec2, id, backup)
193
218
  end
194
219
 
195
220
  def stop_instance(credentials, id)
196
221
  ec2 = new_client(credentials)
197
- safely do
198
- ec2.terminate_instances( :instance_id => id )
199
- end
222
+ backup = ec2.terminate_instances( :instance_id => id )
223
+
224
+ generate_instance(ec2, id, backup)
200
225
  end
201
226
 
202
227
  def destroy_instance(credentials, id)
203
228
  ec2 = new_client(credentials)
204
- safely do
205
- ec2.terminate_instances( :instance_id => id )
206
- end
229
+ backup = ec2.terminate_instances( :instance_id => id )
230
+
231
+ generate_instance(ec2, id, backup)
207
232
  end
208
233
 
209
234
  #
@@ -252,6 +277,39 @@ class EC2Driver < Deltacloud::BaseDriver
252
277
  snapshots
253
278
  end
254
279
 
280
+ def key(credentials, opts=nil)
281
+ keys(credentials, opts).first
282
+ end
283
+
284
+ def keys(credentials, opts=nil)
285
+ ec2 = new_client( credentials )
286
+ opts[:key_name] = opts[:id] if opts and opts[:id]
287
+ keypairs = ec2.describe_keypairs(opts || {})
288
+ result = []
289
+ safely do
290
+ keypairs.keySet.item.each do |keypair|
291
+ result << convert_key(keypair)
292
+ end
293
+ end
294
+ result
295
+ end
296
+
297
+ def create_key(credentials, opts={})
298
+ key = Key.new
299
+ ec2 = new_client( credentials )
300
+ safely do
301
+ key = convert_key(ec2.create_keypair(opts))
302
+ end
303
+ return key
304
+ end
305
+
306
+ def destroy_key(credentials, opts={})
307
+ safely do
308
+ ec2 = new_client( credentials )
309
+ ec2.delete_keypair(opts)
310
+ end
311
+ end
312
+
255
313
  private
256
314
 
257
315
  def new_client(credentials)
@@ -260,7 +318,18 @@ class EC2Driver < Deltacloud::BaseDriver
260
318
  :secret_access_key => credentials.password
261
319
  }
262
320
  opts[:server] = ENV['DCLOUD_EC2_URL'] if ENV['DCLOUD_EC2_URL']
263
- AWS::EC2::Base.new(opts)
321
+ safely do
322
+ AWS::EC2::Base.new(opts)
323
+ end
324
+ end
325
+
326
+ def convert_key(key)
327
+ Key.new({
328
+ :id => key['keyName'],
329
+ :fingerprint => key['keyFingerprint'],
330
+ :credential_type => :key,
331
+ :pem_rsa_key => key['keyMaterial']
332
+ })
264
333
  end
265
334
 
266
335
  def convert_image(ec2_image)
@@ -326,14 +395,12 @@ class EC2Driver < Deltacloud::BaseDriver
326
395
  } )
327
396
  end
328
397
 
329
- def safely(&block)
330
- begin
331
- block.call
332
- rescue AWS::AuthFailure => e
333
- raise Deltacloud::AuthException.new
334
- rescue Exception => e
335
- puts "ERROR: #{e.message}\n#{e.backtrace.join("\n")}"
336
- end
398
+ def catched_exceptions_list
399
+ {
400
+ :auth => [ AWS::AuthFailure ],
401
+ :error => [],
402
+ :glob => [ /AWS::(\w+)/ ]
403
+ }
337
404
  end
338
405
 
339
406
  end
@@ -9,7 +9,7 @@ class GoGridClient
9
9
  apikey='YOUR API KEY',
10
10
  secret='YOUR SHARED SECRET',
11
11
  format='json',
12
- version='1.4')
12
+ version='1.5')
13
13
  @server = server
14
14
  @secret = secret
15
15
  @default_params = {'format'=>format, 'v'=>version,'api_key' => apikey}
@@ -30,7 +30,12 @@ class GoGridClient
30
30
  open(getRequestURL(method,params)).read
31
31
  end
32
32
 
33
- def request(method, params={})
33
+ def request(method, params={}, version=nil)
34
+ if version
35
+ @default_params['v'] = version
36
+ else
37
+ @default_params['v'] = '1.5'
38
+ end
34
39
  begin
35
40
  JSON::parse(sendAPIRequest(method, params))
36
41
  rescue Exception => e
@@ -44,20 +44,8 @@ class GogridDriver < Deltacloud::BaseDriver
44
44
  end
45
45
 
46
46
  def supported_collections
47
- DEFAULT_COLLECTIONS.reject { |c| [ :storage_volumes, :storage_snapshots ].include?(c) }
48
- end
49
-
50
- # The only valid option for flavors is server RAM for now
51
- def flavors(credentials, opts=nil)
52
- flavors = []
53
- safely do
54
- flavors=new_client(credentials).request('common/lookup/list', { 'lookup' => 'server.ram' })['list'].collect do |flavor|
55
- convert_flavor(flavor)
56
- end
57
- end
58
- flavors = filter_on( flavors, :id, opts )
59
- flavors = filter_on( flavors, :architecture, opts )
60
- flavors
47
+ DEFAULT_COLLECTIONS.reject! { |c| [ :storage_volumes, :storage_snapshots ].include?(c) }
48
+ DEFAULT_COLLECTIONS + [ :keys ]
61
49
  end
62
50
 
63
51
  def images(credentials, opts=nil)
@@ -79,7 +67,7 @@ class GogridDriver < Deltacloud::BaseDriver
79
67
 
80
68
  def realms(credentials, opts=nil)
81
69
  safely do
82
- new_client(credentials).request('common/lookup/list', { 'lookup' => 'image.type' })['list'].collect do |realm|
70
+ new_client(credentials).request('common/lookup/list', { 'lookup' => 'ip.datacenter' })['list'].collect do |realm|
83
71
  convert_realm(realm)
84
72
  end
85
73
  end
@@ -100,7 +88,7 @@ class GogridDriver < Deltacloud::BaseDriver
100
88
  'name' => name,
101
89
  'image' => image_id,
102
90
  'server.ram' => server_ram,
103
- 'ip' => get_next_free_ip(credentials)
91
+ 'ip' => get_free_ip_from_realm(credentials, opts[:realm_id] || '1')
104
92
  })['list'].first
105
93
  if instance
106
94
  login_data = get_login_data(client, instance[:id])
@@ -132,6 +120,7 @@ class GogridDriver < Deltacloud::BaseDriver
132
120
  end
133
121
 
134
122
  def instances(credentials, opts=nil)
123
+ require 'ap'
135
124
  instances = []
136
125
  if opts and opts[:id]
137
126
  begin
@@ -166,26 +155,41 @@ class GogridDriver < Deltacloud::BaseDriver
166
155
 
167
156
  def reboot_instance(credentials, id)
168
157
  safely do
169
- new_client(credentials).request('grid/server/power', { 'id' => id, 'power' => 'reboot'})
158
+ new_client(credentials).request('grid/server/power', { 'name' => id, 'power' => 'reboot'})
170
159
  end
171
160
  end
172
161
 
173
162
  def destroy_instance(credentials, id)
174
163
  safely do
175
- new_client(credentials).request('grid/server/delete', { 'id' => id})
164
+ new_client(credentials).request('grid/server/delete', { 'name' => id})
176
165
  end
177
166
  end
178
167
 
179
168
  def stop_instance(credentials, id)
180
169
  safely do
181
- new_client(credentials).request('grid/server/power', { 'id' => id, 'power' => 'off'})
170
+ new_client(credentials).request('grid/server/power', { 'name' => id, 'power' => 'off'})
182
171
  end
183
172
  end
184
173
 
185
174
  def start_instance(credentials, id)
186
175
  safely do
187
- new_client(credentials).request('grid/server/power', { 'id' => id, 'power' => 'on'})
176
+ new_client(credentials).request('grid/server/power', { 'name' => id, 'power' => 'on'})
177
+ end
178
+ end
179
+
180
+ def key(credentials, opts=nil)
181
+ keys(credentials, opts).first
182
+ end
183
+
184
+ def keys(credentials, opts=nil)
185
+ gogrid = new_client( credentials )
186
+ creds = []
187
+ safely do
188
+ gogrid.request('support/password/list')['list'].each do |password|
189
+ creds << convert_key(password)
190
+ end
188
191
  end
192
+ return creds
189
193
  end
190
194
 
191
195
  define_instance_states do
@@ -201,6 +205,7 @@ class GogridDriver < Deltacloud::BaseDriver
201
205
 
202
206
  def new_client(credentials)
203
207
  GoGridClient.new('https://api.gogrid.com/api', credentials.user, credentials.password)
208
+
204
209
  end
205
210
 
206
211
  def get_login_data(client, instance_id)
@@ -219,6 +224,15 @@ class GogridDriver < Deltacloud::BaseDriver
219
224
  return login_data
220
225
  end
221
226
 
227
+ def convert_key(password)
228
+ Key.new({
229
+ :id => password['id'],
230
+ :username => password['username'],
231
+ :password => password['password'],
232
+ :credential_type => :password
233
+ })
234
+ end
235
+
222
236
  def convert_image(gg_image, owner_id=nil)
223
237
  Image.new( {
224
238
  :id=>gg_image['id'],
@@ -237,15 +251,6 @@ class GogridDriver < Deltacloud::BaseDriver
237
251
  end
238
252
  end
239
253
 
240
- def convert_flavor(flavor)
241
- Flavor.new(
242
- :id => flavor['id'],
243
- :architecture => 'x86',
244
- :memory => flavor['name'].tr('G', ''),
245
- :storage => '1'
246
- )
247
- end
248
-
249
254
  def convert_realm(realm)
250
255
  Realm.new(
251
256
  :id => realm['id'],
@@ -279,10 +284,9 @@ class GogridDriver < Deltacloud::BaseDriver
279
284
  :id => instance['name'],
280
285
  :owner_id => owner_id,
281
286
  :image_id => instance['image']['id'],
282
- :flavor_id => instance['ram']['id'],
283
287
  :instance_profile => prof,
284
288
  :name => instance['name'],
285
- :realm_id => instance['type']['id'],
289
+ :realm_id => instance['ip']['datacenter']['id'],
286
290
  :state => convert_server_state(instance['state']['name'], instance['id']),
287
291
  :actions => instance_actions_for(convert_server_state(instance['state']['name'], instance['id'])),
288
292
  :public_addresses => [ instance['ip']['ip'] ],
@@ -301,12 +305,13 @@ class GogridDriver < Deltacloud::BaseDriver
301
305
  state.eql?('Off') ? 'STOPPED' : 'RUNNING'
302
306
  end
303
307
 
304
- def get_next_free_ip(credentials)
308
+ def get_free_ip_from_realm(credentials, realm_id)
305
309
  ip = ""
306
310
  safely do
307
311
  ip = new_client(credentials).request('grid/ip/list', {
308
312
  'ip.type' => '1',
309
- 'ip.state' => '1'
313
+ 'ip.state' => '1',
314
+ 'datacenter' => realm_id
310
315
  })['list'].first['ip']
311
316
  end
312
317
  return ip
@@ -316,7 +321,7 @@ class GogridDriver < Deltacloud::BaseDriver
316
321
  begin
317
322
  block.call
318
323
  rescue Exception => e
319
- puts "ERROR: #{e.message}"
324
+ raise Deltacloud::BackendError.new(500, e.class.to_s, e.message, e.backtrace)
320
325
  end
321
326
  end
322
327