deltacloud-core 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (32) hide show
  1. data/Rakefile +1 -24
  2. data/lib/deltacloud/base_driver/features.rb +15 -0
  3. data/lib/deltacloud/base_driver/mock_driver.rb +37 -0
  4. data/lib/deltacloud/drivers/ec2/ec2_driver.rb +70 -48
  5. data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +97 -14
  6. data/lib/deltacloud/drivers/{rimu/rimu_hosting_client.rb → rimuhosting/rimuhosting_client.rb} +5 -8
  7. data/lib/deltacloud/drivers/{rimu/rimu_hosting_driver.rb → rimuhosting/rimuhosting_driver.rb} +6 -5
  8. data/lib/deltacloud/drivers/terremark/terremark_driver.rb +261 -0
  9. data/lib/deltacloud/hardware_profile.rb +22 -0
  10. data/lib/deltacloud/helpers/application_helper.rb +18 -0
  11. data/lib/deltacloud/helpers/conversion_helper.rb +2 -3
  12. data/lib/deltacloud/method_serializer.rb +84 -0
  13. data/lib/drivers.rb +4 -3
  14. data/lib/sinatra/accept_media_types.rb +128 -0
  15. data/lib/sinatra/respond_to.rb +23 -16
  16. data/public/javascripts/application.js +30 -0
  17. data/public/javascripts/jquery-1.4.2.min.js +154 -0
  18. data/server.rb +23 -21
  19. data/support/fedora/deltacloudd +68 -0
  20. data/support/fedora/rubygem-deltacloud-core.spec +91 -0
  21. data/views/instances/index.html.haml +2 -1
  22. data/views/instances/index.xml.haml +3 -3
  23. data/views/instances/new.html.haml +9 -3
  24. data/views/instances/show.html.haml +2 -1
  25. data/views/instances/show.xml.haml +16 -3
  26. data/views/layout.html.haml +2 -0
  27. metadata +19 -37
  28. data/lib/converters/xml_converter.rb +0 -133
  29. data/public/javascripts/controls.js +0 -963
  30. data/public/javascripts/dragdrop.js +0 -973
  31. data/public/javascripts/effects.js +0 -1128
  32. data/public/javascripts/prototype.js +0 -4320
data/Rakefile CHANGED
@@ -22,8 +22,6 @@ require 'rake'
22
22
  require 'rake/testtask'
23
23
  require 'rake/gempackagetask'
24
24
 
25
-
26
-
27
25
  desc "Run basic unit tests"
28
26
  Rake::TestTask.new("test") { |t|
29
27
  t.test_files = FileList[
@@ -37,29 +35,8 @@ Rake::TestTask.new("test") { |t|
37
35
  t.warning = false
38
36
  }
39
37
 
40
- begin
41
- require 'cucumber'
42
- require 'cucumber/rake/task'
43
-
44
- Cucumber::Rake::Task.new(:features) do |t|
45
- t.cucumber_opts = "features --format html --out tmp/cucumber.html"
46
- t.rcov = false
47
- end
48
-
49
- Cucumber::Rake::Task.new(:rcov) do |t|
50
- t.cucumber_opts = "features --format pretty"
51
- t.rcov = true
52
- t.rcov_opts << %[-o "tmp/coverage"]
53
- end
54
- rescue LoadError
55
- desc 'Cucumber rake task not available'
56
- task :features do
57
- abort 'Cucumber rake task is not available. Be sure to install cucumber as a gem'
58
- end
59
- end
60
-
61
-
62
38
  load 'deltacloud-core.gemspec'
39
+
63
40
  Rake::GemPackageTask.new(@spec) do |pkg|
64
41
  pkg.need_tar = true
65
42
  end
@@ -136,6 +136,21 @@ module Deltacloud
136
136
  end
137
137
  end
138
138
 
139
+ declare_feature :instances, :authentication_key do
140
+ operation :create do
141
+ param :keyname, :string, :optional, nil
142
+ "EC2 key authentification method"
143
+ end
144
+ operation :show do
145
+ end
146
+ end
147
+
148
+ declare_feature :instances, :authentication_password do
149
+ operation :create do
150
+ param :password, :string, :optional
151
+ end
152
+ end
153
+
139
154
  declare_feature :instances, :hardware_profiles do
140
155
  description "Size instances according to changes to a hardware profile"
141
156
  # The parameters are filled in from the hardware profiles
@@ -0,0 +1,37 @@
1
+ require 'deltacloud/method_serializer'
2
+
3
+ # Create 'mock' version of original driver client/gem:
4
+
5
+ module Mock
6
+ class EC2 < AWS::EC2::Base
7
+
8
+ include MethodSerializer::Cache
9
+
10
+ def self.cached_methods
11
+ [
12
+ :describe_images,
13
+ :describe_availability_zones,
14
+ :run_instances,
15
+ :describe_instances,
16
+ :reboot_instances,
17
+ :terminate_instances
18
+ ]
19
+ end
20
+
21
+ MethodSerializer::Cache::wrap_methods(self, :cache_dir => File.join(File.dirname(__FILE__), '..', '..', '..', '..', 'tests', 'ec2', 'support'))
22
+ end
23
+ end
24
+
25
+
26
+ # Replace original client with mock client
27
+ Deltacloud::Drivers::EC2::EC2Driver.class_eval do
28
+ alias_method :original_new_client, :new_client
29
+
30
+ def new_client(credentials, opts={})
31
+ Mock::EC2.new(
32
+ :access_key_id => credentials.user,
33
+ :secret_access_key => credentials.password
34
+ )
35
+ end
36
+
37
+ end
@@ -17,11 +17,16 @@
17
17
 
18
18
 
19
19
  require 'deltacloud/base_driver'
20
- begin
21
- require 'AWS'
22
- rescue LoadError
23
- puts "ERROR: Please install Amazon-EC2 gem first. (gem install amazon-ec2)"
24
- exit(1)
20
+ require 'AWS'
21
+
22
+ class Instance
23
+ attr_accessor :keyname
24
+ attr_accessor :authn_error
25
+
26
+ def authn_feature_failed?
27
+ return true unless authn_error.nil?
28
+ end
29
+
25
30
  end
26
31
 
27
32
  module Deltacloud
@@ -30,54 +35,62 @@ module Deltacloud
30
35
  class EC2Driver < Deltacloud::BaseDriver
31
36
 
32
37
  feature :instances, :user_data
38
+ feature :instances, :authentication_key
33
39
 
34
- define_hardware_profile('m1-small') do
35
- cpu 1
36
- memory 1.7 * 1024
37
- storage 160
38
- architecture 'i386'
40
+ define_hardware_profile('m1.small') do
41
+ cpu 1
42
+ memory 1.7 * 1024
43
+ storage 160
44
+ architecture 'i386'
39
45
  end
40
46
 
41
- define_hardware_profile('m1-large') do
47
+ define_hardware_profile('m1.large') do
42
48
  cpu 4
43
- memory 7.5 * 1024
44
- storage 850
45
- architecture 'x86_64'
49
+ memory 7.5 * 1024
50
+ storage 850
51
+ architecture 'x86_64'
46
52
  end
47
53
 
48
- define_hardware_profile('m1-xlarge') do
54
+ define_hardware_profile('m1.xlarge') do
49
55
  cpu 8
50
- memory 15 * 1024
51
- storage 1690
52
- architecture 'x86_64'
56
+ memory 15 * 1024
57
+ storage 1690
58
+ architecture 'x86_64'
53
59
  end
54
60
 
55
- define_hardware_profile('c1-medium') do
61
+ define_hardware_profile('c1.medium') do
56
62
  cpu 5
57
- memory 1.7 * 1024
58
- storage 350
59
- architecture 'i386'
63
+ memory 1.7 * 1024
64
+ storage 350
65
+ architecture 'i386'
60
66
  end
61
67
 
62
- define_hardware_profile('c1-xlarge') do
63
- cpu 20
64
- memory 7 * 1024
65
- storage 1690
66
- architecture 'x86_64'
68
+ define_hardware_profile('c1.xlarge') do
69
+ cpu 20
70
+ memory 7 * 1024
71
+ storage 1690
72
+ architecture 'x86_64'
67
73
  end
68
74
 
69
- define_hardware_profile('m2-xlarge') do
70
- cpu 6.5
71
- memory 17.1 * 1024
72
- storage 420
73
- architecture 'x86_64'
75
+ define_hardware_profile('m2.xlarge') do
76
+ cpu 6.5
77
+ memory 17.1 * 1024
78
+ storage 420
79
+ architecture 'x86_64'
74
80
  end
75
81
 
76
- define_hardware_profile('m2-2xlarge') do
77
- cpu 13
78
- memory 34.2 * 1024
79
- storage 850
80
- architecture 'x86_64'
82
+ define_hardware_profile('m2.2xlarge') do
83
+ cpu 13
84
+ memory 34.2 * 1024
85
+ storage 850
86
+ architecture 'x86_64'
87
+ end
88
+
89
+ define_hardware_profile('m2.4xlarge') do
90
+ cpu 26
91
+ memory 68.4 * 1024
92
+ storage 1690
93
+ architecture 'x86_64'
81
94
  end
82
95
 
83
96
  define_instance_states do
@@ -99,9 +112,14 @@ class EC2Driver < Deltacloud::BaseDriver
99
112
  def images(credentials, opts={} )
100
113
  ec2 = new_client(credentials)
101
114
  img_arr = []
102
- config = { :owner_id => "amazon" }
103
- config.merge!({ :owner_id => opts[:owner_id] }) if opts and opts[:owner_id]
104
- config.merge!({ :image_id => opts[:id] }) if opts and opts[:id]
115
+ # if we know the image_id, we don't want to limit by owner_id, since this
116
+ # will exclude public images
117
+ if (opts and opts[:id])
118
+ config = { :image_id => opts[:id] }
119
+ else
120
+ config = { :owner_id => "amazon" }
121
+ config.merge!({ :owner_id => opts[:owner_id] }) if opts and opts[:owner_id]
122
+ end
105
123
  safely do
106
124
  ec2.describe_images(config).imagesSet.item.each do |image|
107
125
  img_arr << convert_image(image)
@@ -156,10 +174,10 @@ class EC2Driver < Deltacloud::BaseDriver
156
174
  ec2_instances = ec2.run_instances(
157
175
  :image_id => image.id,
158
176
  :user_data => opts[:user_data],
159
- :key_name => opts[:key_name],
177
+ :key_name => opts[:keyname],
160
178
  :availability_zone => realm_id,
161
179
  :monitoring_enabled => true,
162
- :instance_type => hwp.name.tr('-', '.'),
180
+ :instance_type => hwp.name,
163
181
  :disable_api_termination => false,
164
182
  :instance_initiated_shutdown_behavior => 'terminate'
165
183
  )
@@ -235,10 +253,12 @@ class EC2Driver < Deltacloud::BaseDriver
235
253
  private
236
254
 
237
255
  def new_client(credentials)
238
- AWS::EC2::Base.new(
256
+ opts = {
239
257
  :access_key_id => credentials.user,
240
258
  :secret_access_key => credentials.password
241
- )
259
+ }
260
+ opts[:server] = ENV['DCLOUD_EC2_URL'] if ENV['DCLOUD_EC2_URL']
261
+ AWS::EC2::Base.new(opts)
242
262
  end
243
263
 
244
264
  def convert_image(ec2_image)
@@ -265,8 +285,8 @@ class EC2Driver < Deltacloud::BaseDriver
265
285
  state_key = state.downcase.underscore.to_sym
266
286
  realm_id = ec2_instance['placement']['availabilityZone']
267
287
  (realm_id = nil ) if ( realm_id == '' )
268
- hwp_name = ec2_instance['instanceType'].gsub( /\./, '-')
269
- Instance.new( {
288
+ hwp_name = ec2_instance['instanceType']
289
+ instance = Instance.new( {
270
290
  :id=>ec2_instance['instanceId'],
271
291
  :name => ec2_instance['imageId'],
272
292
  :state=>state,
@@ -275,10 +295,12 @@ class EC2Driver < Deltacloud::BaseDriver
275
295
  :realm_id=>realm_id,
276
296
  :public_addresses=>( ec2_instance['dnsName'] == '' ? [] : [ec2_instance['dnsName']] ),
277
297
  :private_addresses=>( ec2_instance['privateDnsName'] == '' ? [] : [ec2_instance['privateDnsName']] ),
278
- :flavor_id=>ec2_instance['instanceType'].gsub( /\./, '-'),
279
298
  :instance_profile =>InstanceProfile.new(hwp_name),
280
299
  :actions=>instance_actions_for( state ),
300
+ :keyname => ec2_instance['keyName']
281
301
  } )
302
+ instance.authn_error = "Key not set for instance" unless ec2_instance['keyName']
303
+ return instance
282
304
  end
283
305
 
284
306
  def convert_volume(ec2_volume)
@@ -307,7 +329,7 @@ class EC2Driver < Deltacloud::BaseDriver
307
329
  rescue AWS::AuthFailure => e
308
330
  raise Deltacloud::AuthException.new
309
331
  rescue Exception => e
310
- puts "ERROR: #{e.message}"
332
+ puts "ERROR: #{e.message}\n#{e.backtrace.join("\n")}"
311
333
  end
312
334
  end
313
335
 
@@ -18,12 +18,24 @@
18
18
  require 'deltacloud/base_driver'
19
19
  require 'deltacloud/drivers/gogrid/gogrid_client'
20
20
 
21
+ class Instance
22
+ attr_accessor :username
23
+ attr_accessor :password
24
+ attr_accessor :authn_error
25
+
26
+ def authn_feature_failed?
27
+ return true unless authn_error.nil?
28
+ end
29
+ end
30
+
21
31
  module Deltacloud
22
32
  module Drivers
23
33
  module Gogrid
24
34
 
25
35
  class GogridDriver < Deltacloud::BaseDriver
26
36
 
37
+ feature :instances, :authentication_password
38
+
27
39
  define_hardware_profile 'server' do
28
40
  cpu 2
29
41
  memory [512, 1024, 2048, 4096, 8192]
@@ -76,30 +88,72 @@ class GogridDriver < Deltacloud::BaseDriver
76
88
  else
77
89
  server_ram = "512MB"
78
90
  end
91
+ client = new_client(credentials)
79
92
  name = (opts[:name] && opts[:name]!='') ? opts[:name] : get_random_instance_name
80
93
  safely do
81
- convert_instance(new_client(credentials).request('grid/server/add', {
94
+ instance = client.request('grid/server/add', {
82
95
  'name' => name,
83
96
  'image' => image_id,
84
97
  'server.ram' => server_ram,
85
98
  'ip' => get_next_free_ip(credentials)
86
- })['list'].first, credentials.user)
99
+ })['list'].first
100
+ if instance
101
+ login_data = get_login_data(client, instance[:id])
102
+ if login_data['username'] and login_data['password']
103
+ instance['username'] = login_data['username']
104
+ instance['password'] = login_data['password']
105
+ inst = convert_instance(instance, credentials.user)
106
+ else
107
+ inst = convert_instance(instance, credentials.user)
108
+ inst.authn_error = "Unable to fetch password"
109
+ end
110
+ return inst
111
+ else
112
+ return nil
113
+ end
87
114
  end
88
115
  end
89
116
 
117
+ def list_instances(credentials, id)
118
+ instances = []
119
+ safely do
120
+ new_client(credentials).request('grid/server/list')['list'].collect do |instance|
121
+ if id.nil? or instance['name'] == id
122
+ instances << convert_instance(instance, credentials.user)
123
+ end
124
+ end
125
+ end
126
+ instances
127
+ end
128
+
90
129
  def instances(credentials, opts=nil)
91
130
  instances = []
92
131
  if opts and opts[:id]
93
- safely do
94
- instance = new_client(credentials).request('grid/server/get', { 'id' => opts[:id]})['list'].first
95
- instances = [convert_instance(instance, credentials.user)]
96
- end
97
- else
98
- safely do
99
- instances = new_client(credentials).request('grid/server/list')['list'].collect do |instance|
100
- convert_instance(instance, credentials.user)
132
+ begin
133
+ client = new_client(credentials)
134
+ instance = client.request('grid/server/get', { 'name' => opts[:id] })['list'].first
135
+ login_data = get_login_data(client, instance['id'])
136
+ if login_data['username'] and login_data['password']
137
+ instance['username'] = login_data['username']
138
+ instance['password'] = login_data['password']
139
+ inst = convert_instance(instance, credentials.user)
140
+ else
141
+ inst = convert_instance(instance, credentials.user)
142
+ inst.authn_error = "Unable to fetch password"
143
+ end
144
+ instances = [inst]
145
+ rescue Exception => e
146
+ if e.message == "400 Bad Request"
147
+ # in the case of a VM that we just made, the grid/server/get method
148
+ # throws a "400 Bad Request error". In this case we try again by
149
+ # getting a full listing a filtering on the id. This could
150
+ # potentially take a long time, but I don't see another way to get
151
+ # information about a newly created instance
152
+ instances = list_instances(credentials, opts[:id])
101
153
  end
102
154
  end
155
+ else
156
+ instances = list_instances(credentials, nil)
103
157
  end
104
158
  instances = filter_on( instances, :state, opts )
105
159
  instances
@@ -111,15 +165,21 @@ class GogridDriver < Deltacloud::BaseDriver
111
165
  end
112
166
  end
113
167
 
168
+ def destroy_instance(credentials, id)
169
+ safely do
170
+ new_client(credentials).request('grid/server/delete', { 'id' => id})
171
+ end
172
+ end
173
+
114
174
  def stop_instance(credentials, id)
115
175
  safely do
116
176
  new_client(credentials).request('grid/server/power', { 'id' => id, 'power' => 'off'})
117
177
  end
118
178
  end
119
179
 
120
- def destroy_instance(credentials, id)
180
+ def start_instance(credentials, id)
121
181
  safely do
122
- new_client(credentials).request('grid/server/delete', { 'id' => id})
182
+ new_client(credentials).request('grid/server/power', { 'id' => id, 'power' => 'on'})
123
183
  end
124
184
  end
125
185
 
@@ -128,7 +188,8 @@ class GogridDriver < Deltacloud::BaseDriver
128
188
  pending.to( :running ) .automatically
129
189
  running.to( :stopped ) .on( :stop )
130
190
  stopped.to( :running ) .on( :start )
131
- stopped.to( :finish ) .automatically
191
+ running.to( :finish ) .on( :destroy )
192
+ stopped.to( :finish ) .on( :destroy )
132
193
  end
133
194
 
134
195
  private
@@ -137,6 +198,22 @@ class GogridDriver < Deltacloud::BaseDriver
137
198
  GoGridClient.new('https://api.gogrid.com/api', credentials.user, credentials.password)
138
199
  end
139
200
 
201
+ def get_login_data(client, instance_id)
202
+ login_data = {}
203
+ begin
204
+ client.request('support/password/list')['list'].each do |passwd|
205
+ next unless passwd['server']
206
+ if passwd['server']['id'] == instance_id
207
+ login_data['username'], login_data['password'] = passwd['username'], passwd['password']
208
+ break
209
+ end
210
+ end
211
+ rescue Exception => e
212
+ login_data[:error] = e.message
213
+ end
214
+ return login_data
215
+ end
216
+
140
217
  def convert_image(gg_image, owner_id=nil)
141
218
  Image.new( {
142
219
  :id=>gg_image['id'],
@@ -190,6 +267,10 @@ class GogridDriver < Deltacloud::BaseDriver
190
267
  prof = InstanceProfile.new("server", opts)
191
268
 
192
269
  Instance.new(
270
+ # note that we use 'name' as the id here, because newly created instances
271
+ # don't get a real ID until later on. The name is good enough; from
272
+ # what I can tell, 'name' per user is unique, so it should be sufficient
273
+ # to uniquely identify this instance.
193
274
  :id => instance['name'],
194
275
  :owner_id => owner_id,
195
276
  :image_id => instance['image']['id'],
@@ -200,7 +281,9 @@ class GogridDriver < Deltacloud::BaseDriver
200
281
  :state => convert_server_state(instance['state']['name'], instance['id']),
201
282
  :actions => instance_actions_for(convert_server_state(instance['state']['name'], instance['id'])),
202
283
  :public_addresses => [ instance['ip']['ip'] ],
203
- :private_addresses => []
284
+ :private_addresses => [],
285
+ :username => instance['username'],
286
+ :password => instance['password']
204
287
  )
205
288
  end
206
289