deltacloud-core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. data/COPYING +502 -0
  2. data/Rakefile +108 -0
  3. data/bin/deltacloudd +88 -0
  4. data/config.ru +5 -0
  5. data/deltacloud.rb +14 -0
  6. data/lib/converters/xml_converter.rb +133 -0
  7. data/lib/deltacloud/base_driver.rb +19 -0
  8. data/lib/deltacloud/base_driver/base_driver.rb +189 -0
  9. data/lib/deltacloud/base_driver/features.rb +144 -0
  10. data/lib/deltacloud/drivers/ec2/ec2_driver.rb +318 -0
  11. data/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb +170 -0
  12. data/lib/deltacloud/drivers/gogrid/gogrid_client.rb +45 -0
  13. data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +239 -0
  14. data/lib/deltacloud/drivers/mock/mock_driver.rb +275 -0
  15. data/lib/deltacloud/drivers/opennebula/cloud_client.rb +116 -0
  16. data/lib/deltacloud/drivers/opennebula/occi_client.rb +204 -0
  17. data/lib/deltacloud/drivers/opennebula/opennebula_driver.rb +241 -0
  18. data/lib/deltacloud/drivers/rackspace/rackspace_client.rb +129 -0
  19. data/lib/deltacloud/drivers/rackspace/rackspace_driver.rb +150 -0
  20. data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +254 -0
  21. data/lib/deltacloud/drivers/rimu/rimu_hosting_client.rb +87 -0
  22. data/lib/deltacloud/drivers/rimu/rimu_hosting_driver.rb +143 -0
  23. data/lib/deltacloud/hardware_profile.rb +131 -0
  24. data/lib/deltacloud/helpers.rb +5 -0
  25. data/lib/deltacloud/helpers/application_helper.rb +38 -0
  26. data/lib/deltacloud/helpers/conversion_helper.rb +39 -0
  27. data/lib/deltacloud/helpers/hardware_profiles_helper.rb +35 -0
  28. data/lib/deltacloud/models/base_model.rb +58 -0
  29. data/lib/deltacloud/models/image.rb +26 -0
  30. data/lib/deltacloud/models/instance.rb +37 -0
  31. data/lib/deltacloud/models/instance_profile.rb +47 -0
  32. data/lib/deltacloud/models/realm.rb +25 -0
  33. data/lib/deltacloud/models/storage_snapshot.rb +26 -0
  34. data/lib/deltacloud/models/storage_volume.rb +27 -0
  35. data/lib/deltacloud/state_machine.rb +84 -0
  36. data/lib/deltacloud/validation.rb +70 -0
  37. data/lib/drivers.rb +37 -0
  38. data/lib/sinatra/lazy_auth.rb +56 -0
  39. data/lib/sinatra/rabbit.rb +272 -0
  40. data/lib/sinatra/respond_to.rb +262 -0
  41. data/lib/sinatra/static_assets.rb +83 -0
  42. data/lib/sinatra/url_for.rb +44 -0
  43. data/public/favicon.ico +0 -0
  44. data/public/images/grid.png +0 -0
  45. data/public/images/logo-wide.png +0 -0
  46. data/public/images/rails.png +0 -0
  47. data/public/images/topbar-bg.png +0 -0
  48. data/public/javascripts/application.js +2 -0
  49. data/public/javascripts/controls.js +963 -0
  50. data/public/javascripts/dragdrop.js +973 -0
  51. data/public/javascripts/effects.js +1128 -0
  52. data/public/javascripts/prototype.js +4320 -0
  53. data/public/stylesheets/compiled/application.css +613 -0
  54. data/public/stylesheets/compiled/ie.css +31 -0
  55. data/public/stylesheets/compiled/print.css +27 -0
  56. data/public/stylesheets/compiled/screen.css +456 -0
  57. data/server.rb +340 -0
  58. data/tests/deltacloud_test.rb +60 -0
  59. data/tests/images_test.rb +94 -0
  60. data/tests/instances_test.rb +136 -0
  61. data/tests/realms_test.rb +56 -0
  62. data/tests/storage_snapshots_test.rb +48 -0
  63. data/tests/storage_volumes_test.rb +48 -0
  64. data/views/accounts/index.html.haml +11 -0
  65. data/views/accounts/show.html.haml +30 -0
  66. data/views/api/show.html.haml +15 -0
  67. data/views/api/show.xml.haml +5 -0
  68. data/views/docs/collection.html.haml +37 -0
  69. data/views/docs/collection.xml.haml +14 -0
  70. data/views/docs/index.html.haml +15 -0
  71. data/views/docs/index.xml.haml +5 -0
  72. data/views/docs/operation.html.haml +31 -0
  73. data/views/docs/operation.xml.haml +10 -0
  74. data/views/errors/auth_exception.html.haml +8 -0
  75. data/views/errors/auth_exception.xml.haml +2 -0
  76. data/views/errors/backend_error.html.haml +17 -0
  77. data/views/errors/backend_error.xml.haml +8 -0
  78. data/views/errors/validation_failure.html.haml +11 -0
  79. data/views/errors/validation_failure.xml.haml +7 -0
  80. data/views/hardware_profiles/index.html.haml +25 -0
  81. data/views/hardware_profiles/index.xml.haml +4 -0
  82. data/views/hardware_profiles/show.html.haml +19 -0
  83. data/views/hardware_profiles/show.xml.haml +17 -0
  84. data/views/images/index.html.haml +30 -0
  85. data/views/images/index.xml.haml +7 -0
  86. data/views/images/show.html.haml +21 -0
  87. data/views/images/show.xml.haml +5 -0
  88. data/views/instance_states/show.gv.erb +45 -0
  89. data/views/instance_states/show.html.haml +31 -0
  90. data/views/instance_states/show.xml.haml +8 -0
  91. data/views/instances/index.html.haml +29 -0
  92. data/views/instances/index.xml.haml +23 -0
  93. data/views/instances/new.html.haml +49 -0
  94. data/views/instances/show.html.haml +42 -0
  95. data/views/instances/show.xml.haml +28 -0
  96. data/views/layout.html.haml +23 -0
  97. data/views/realms/index.html.haml +29 -0
  98. data/views/realms/index.xml.haml +12 -0
  99. data/views/realms/show.html.haml +15 -0
  100. data/views/realms/show.xml.haml +10 -0
  101. data/views/root/index.html.haml +4 -0
  102. data/views/storage_snapshots/index.html.haml +20 -0
  103. data/views/storage_snapshots/index.xml.haml +11 -0
  104. data/views/storage_snapshots/show.html.haml +14 -0
  105. data/views/storage_snapshots/show.xml.haml +9 -0
  106. data/views/storage_volumes/index.html.haml +21 -0
  107. data/views/storage_volumes/index.xml.haml +13 -0
  108. data/views/storage_volumes/show.html.haml +20 -0
  109. data/views/storage_volumes/show.xml.haml +13 -0
  110. metadata +311 -0
@@ -0,0 +1,170 @@
1
+ module RightAws
2
+ class MockEc2
3
+
4
+ def initialize(opts={})
5
+ end
6
+
7
+ def describe_images(id)
8
+ load_fixtures_for(:images).select { |i| i[:aws_id].eql?(id) }
9
+ end
10
+
11
+ def describe_images_by_owner(id)
12
+ load_fixtures_for(:images).select { |i| i[:aws_owner].eql?(id) }
13
+ end
14
+
15
+ def describe_images(opts={})
16
+ load_fixtures_for(:images)
17
+ end
18
+
19
+ def describe_availability_zones(opts={})
20
+ load_fixtures_for(:realms)
21
+ end
22
+
23
+ def describe_instances(opts={})
24
+ instances = load_fixtures_for(:instances)
25
+ instances.each_with_index do |instance, i|
26
+ instances[i] = update_delayed_state(instance)
27
+ return [instance] if opts and opts[:id] and instance[:aws_instance_id].eql?(opts[:id])
28
+ end
29
+ update_fixtures_for(:instances, instances)
30
+ instances
31
+ end
32
+
33
+ def run_instances(image_id, min_count, max_count, group_ids, key_name, user_data='', addressing_type = nil, instance_type = nil, kernel_id = nil, ramdisk_id = nil, availability_zone = nil, block_device_mappings = nil)
34
+
35
+ instances = load_fixtures_for(:instances)
36
+ image = load_fixtures_for(:images).select { |img| img[:aws_id].eql?(image_id) }.first
37
+
38
+ if availability_zone
39
+ realm = load_fixtures_for(:realms).select { |realm| realm[:zone_name].eql?(availability_zone) }.first
40
+ else
41
+ realm = load_fixtures_for(:realms).first
42
+ end
43
+
44
+ raise Exception unless image
45
+ raise Exception unless realm
46
+
47
+ instance = { }
48
+ instance[:aws_image_id] = image[:aws_id]
49
+ instance[:aws_availability_zone] = realm[:zone_name]
50
+ instance[:aws_instance_type] = instance_type
51
+ instance[:aws_owner] = user_data
52
+ instance[:aws_state] = 'pending'
53
+ instance[:aws_reason] = ''
54
+ instance[:dns_name] = "#{random_dns}-01-C9.usma2.compute.amazonaws.com"
55
+ instance[:private_dns_name] = "#{random_dns}-02-P9.usma2.compute.amazonaws.com"
56
+ instance[:aws_state_code] = "0"
57
+ instance[:aws_key_name] = "staging"
58
+ instance[:aws_kernel_id] = "aki-be3adfd7"
59
+ instance[:aws_ramdisk_id] = "ari-ce34gad7"
60
+ instance[:aws_groups] = ["default"]
61
+ instance[:aws_instance_id] = random_instance_id
62
+ instance[:aws_reservation_id] = "r-aabbccdd"
63
+ instance[:aws_launch_time] = instance_time_format
64
+
65
+ instances << instance
66
+
67
+ update_fixtures_for(:instances, instances)
68
+
69
+ return [instance]
70
+ end
71
+
72
+
73
+ def terminate_instances(id)
74
+ update_instance_state(id, 'stopping', '80')
75
+ end
76
+
77
+ def reboot_instances(id)
78
+ update_instance_state(id, 'pending', '0')
79
+ end
80
+
81
+ alias :destroy_instance :terminate_instances
82
+
83
+ def describe_snapshots(opts={})
84
+ load_fixtures_for(:storage_snapshot)
85
+ end
86
+
87
+ def describe_volumes(opts={})
88
+ load_fixtures_for(:storage_volume)
89
+ end
90
+
91
+ private
92
+
93
+ def driver_dir
94
+ File::expand_path(File::join(File::dirname(__FILE__), '../../../../features/support/ec2'))
95
+ end
96
+
97
+ def fixtures_path
98
+ File::expand_path(File::join(driver_dir, 'fixtures'))
99
+ end
100
+
101
+ def load_fixtures_for(collection)
102
+ YAML.load_file(File::join(fixtures_path, "#{collection}.yaml"))
103
+ end
104
+
105
+ def update_fixtures_for(collection, new_data)
106
+ File.open(File::join(fixtures_path, "#{collection}.yaml"), 'w' ) do |out|
107
+ YAML.dump(new_data, out)
108
+ end
109
+ return new_data
110
+ end
111
+
112
+ def instance_time_format
113
+ DateTime.now.to_s.gsub(/\+(.+)$/, '.000Z')
114
+ end
115
+
116
+ def random_instance_id
117
+ id_1 = ("%.4s" % Time.now.to_i.to_s.reverse).reverse
118
+ id_2 = ("%.3s" % Time.now.to_i.to_s.reverse)
119
+ "i-#{id_1}f#{id_2}"
120
+ end
121
+
122
+ def random_dns
123
+ "domU-#{rand(90)+10}-#{rand(90)+10}-#{rand(90)+10}-#{rand(90)+10}"
124
+ end
125
+
126
+ def update_delayed_state(instance)
127
+ time = DateTime.now - DateTime.parse(instance[:aws_launch_time])
128
+ hours, minutes, seconds, frac = Date.day_fraction_to_time(time)
129
+
130
+ if (minutes>(rand(2)+1) or hours>0) and instance[:aws_state].eql?('pending')
131
+ instance[:aws_state], instance[:aws_state_code] = 'running', '16'
132
+ end
133
+
134
+ if (minutes>(rand(1)+1) or hours>0) and instance[:aws_state].eql?('stopping')
135
+ instance[:aws_state], instance[:aws_state_code] = 'stopped', '80'
136
+ end
137
+
138
+ return instance
139
+ end
140
+
141
+ def update_instance_state(id, state, state_code)
142
+ instance = describe_instances(:id => id).first
143
+ if instance
144
+ instance[:aws_state], instance[:aws_state_code] = state, state_code
145
+ instance[:aws_launch_time] = instance_time_format
146
+ instances = load_fixtures_for(:instances)
147
+ instances.each_with_index do |inst, i|
148
+ instances[i] = instance if inst[:aws_instance_id].eql?(id)
149
+ end
150
+ update_fixtures_for(:instances, instances)
151
+ return instance
152
+ else
153
+ raise Exception
154
+ end
155
+ end
156
+
157
+ end
158
+ end
159
+
160
+ Deltacloud::Drivers::EC2::EC2Driver.class_eval do
161
+ alias_method :original_new_client, :new_client
162
+
163
+ def new_client(credentials, opts={})
164
+ if credentials.user != 'mockuser' and credentials.password != 'mockpassword'
165
+ raise Deltacloud::AuthException.new
166
+ end
167
+ RightAws::MockEc2.new
168
+ end
169
+
170
+ end
@@ -0,0 +1,45 @@
1
+ require 'digest/md5'
2
+ require 'cgi'
3
+ require 'open-uri'
4
+ require 'json'
5
+
6
+ class GoGridClient
7
+
8
+ def initialize(server='https://api.gogrid.com/api',
9
+ apikey='YOUR API KEY',
10
+ secret='YOUR SHARED SECRET',
11
+ format='json',
12
+ version='1.4')
13
+ @server = server
14
+ @secret = secret
15
+ @default_params = {'format'=>format, 'v'=>version,'api_key' => apikey}
16
+ end
17
+
18
+ def getRequestURL(method,params)
19
+ requestURL = @server+'/'+method+'?'
20
+ call_params = @default_params.merge(params)
21
+ call_params['sig']=getSignature(@default_params['api_key'],@secret)
22
+ requestURL = requestURL+encode_params(call_params)
23
+ end
24
+
25
+ def getSignature(key,secret)
26
+ Digest::MD5.hexdigest(key+secret+"%.0f"%Time.new.to_f)
27
+ end
28
+
29
+ def sendAPIRequest(method,params={})
30
+ open(getRequestURL(method,params)).read
31
+ end
32
+
33
+ def request(method, params={})
34
+ begin
35
+ JSON::parse(sendAPIRequest(method, params))
36
+ rescue Exception => e
37
+ STDERR.puts("ERROR: #{e.message}")
38
+ end
39
+ end
40
+
41
+ def encode_params(params)
42
+ params.map {|k,v| "#{CGI.escape(k.to_s)}=#{CGI.escape(v.to_s)}" }.join("&")
43
+ end
44
+
45
+ end
@@ -0,0 +1,239 @@
1
+ #
2
+ # Copyright (C) 2009 Red Hat, Inc.
3
+ #
4
+ # This library is free software; you can redistribute it and/or
5
+ # modify it under the terms of the GNU Lesser General Public
6
+ # License as published by the Free Software Foundation; either
7
+ # version 2.1 of the License, or (at your option) any later version.
8
+ #
9
+ # This library is distributed in the hope that it will be useful,
10
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
+ # Lesser General Public License for more details.
13
+ #
14
+ # You should have received a copy of the GNU Lesser General Public
15
+ # License along with this library; if not, write to the Free Software
16
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17
+
18
+ require 'deltacloud/base_driver'
19
+ require 'deltacloud/drivers/gogrid/gogrid_client'
20
+
21
+ module Deltacloud
22
+ module Drivers
23
+ module Gogrid
24
+
25
+ class GogridDriver < Deltacloud::BaseDriver
26
+
27
+ define_hardware_profile 'server' do
28
+ cpu 2
29
+ memory [512, 1024, 2048, 4096, 8192]
30
+ storage 10
31
+ end
32
+
33
+ # The only valid option for flavors is server RAM for now
34
+ def flavors(credentials, opts=nil)
35
+ flavors = []
36
+ safely do
37
+ flavors=new_client(credentials).request('common/lookup/list', { 'lookup' => 'server.ram' })['list'].collect do |flavor|
38
+ convert_flavor(flavor)
39
+ end
40
+ end
41
+ flavors = filter_on( flavors, :id, opts )
42
+ flavors = filter_on( flavors, :architecture, opts )
43
+ flavors
44
+ end
45
+
46
+ def images(credentials, opts=nil)
47
+ imgs = []
48
+ if opts and opts[:id]
49
+ safely do
50
+ imgs = [convert_image(new_client(credentials).request('grid/image/get', { 'id' => opts[:id] })['list'].first)]
51
+ end
52
+ else
53
+ safely do
54
+ imgs = new_client(credentials).request('grid/image/list', { 'state' => 'Available'})['list'].collect do |image|
55
+ convert_image(image, credentials.user)
56
+ end
57
+ end
58
+ end
59
+ imgs = filter_on( imgs, :architecture, opts )
60
+ imgs.sort_by{|e| [e.owner_id, e.description]}
61
+ end
62
+
63
+ def realms(credentials, opts=nil)
64
+ safely do
65
+ new_client(credentials).request('common/lookup/list', { 'lookup' => 'image.type' })['list'].collect do |realm|
66
+ convert_realm(realm)
67
+ end
68
+ end
69
+ end
70
+
71
+ def create_instance(credentials, image_id, opts=nil)
72
+ server_ram = nil
73
+ if opts[:hwp_memory]
74
+ mem = opts[:hwp_memory].to_i
75
+ server_ram = (mem == 512) ? "512MB" : "#{mem / 1024}GB"
76
+ else
77
+ server_ram = "512MB"
78
+ end
79
+ name = (opts[:name] && opts[:name]!='') ? opts[:name] : get_random_instance_name
80
+ safely do
81
+ convert_instance(new_client(credentials).request('grid/server/add', {
82
+ 'name' => name,
83
+ 'image' => image_id,
84
+ 'server.ram' => server_ram,
85
+ 'ip' => get_next_free_ip(credentials)
86
+ })['list'].first, credentials.user)
87
+ end
88
+ end
89
+
90
+ def instances(credentials, opts=nil)
91
+ instances = []
92
+ 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)
101
+ end
102
+ end
103
+ end
104
+ instances = filter_on( instances, :state, opts )
105
+ instances
106
+ end
107
+
108
+ def reboot_instance(credentials, id)
109
+ safely do
110
+ new_client(credentials).request('grid/server/power', { 'id' => id, 'power' => 'reboot'})
111
+ end
112
+ end
113
+
114
+ def stop_instance(credentials, id)
115
+ safely do
116
+ new_client(credentials).request('grid/server/power', { 'id' => id, 'power' => 'off'})
117
+ end
118
+ end
119
+
120
+ def destroy_instance(credentials, id)
121
+ safely do
122
+ new_client(credentials).request('grid/server/delete', { 'id' => id})
123
+ end
124
+ end
125
+
126
+ define_instance_states do
127
+ start.to( :pending ) .automatically
128
+ pending.to( :running ) .automatically
129
+ running.to( :stopped ) .on( :stop )
130
+ stopped.to( :running ) .on( :start )
131
+ stopped.to( :finish ) .automatically
132
+ end
133
+
134
+ private
135
+
136
+ def new_client(credentials)
137
+ GoGridClient.new('https://api.gogrid.com/api', credentials.user, credentials.password)
138
+ end
139
+
140
+ def convert_image(gg_image, owner_id=nil)
141
+ Image.new( {
142
+ :id=>gg_image['id'],
143
+ :name => gg_image['friendlyName'],
144
+ :description=> convert_description(gg_image),
145
+ :owner_id=>gg_image['owner']['name'],
146
+ :architecture=>convert_arch(gg_image['description']),
147
+ } )
148
+ end
149
+
150
+ def convert_description(image)
151
+ if image['price'].eql?(0)
152
+ image['description']
153
+ else
154
+ "#{image['description']} (#{image['price']}$)"
155
+ end
156
+ end
157
+
158
+ def convert_flavor(flavor)
159
+ Flavor.new(
160
+ :id => flavor['id'],
161
+ :architecture => 'x86',
162
+ :memory => flavor['name'].tr('G', ''),
163
+ :storage => '1'
164
+ )
165
+ end
166
+
167
+ def convert_realm(realm)
168
+ Realm.new(
169
+ :id => realm['id'],
170
+ :name => realm['name'],
171
+ :state => :unlimited,
172
+ :storage => :unlimited
173
+ )
174
+ end
175
+
176
+ def convert_arch(description)
177
+ description.include?('64-bit') ? 'x86_64' : 'i386'
178
+ end
179
+
180
+ def convert_instance(instance, owner_id)
181
+ opts = {}
182
+ unless instance['ram']['id'] == "1"
183
+ mem = instance['ram']['name']
184
+ if mem == "512MB"
185
+ opts[:hwp_memory] = "512"
186
+ else
187
+ opts[:hwp_memory] = (mem.to_i * 1024).to_s
188
+ end
189
+ end
190
+ prof = InstanceProfile.new("server", opts)
191
+
192
+ Instance.new(
193
+ :id => instance['name'],
194
+ :owner_id => owner_id,
195
+ :image_id => instance['image']['id'],
196
+ :flavor_id => instance['ram']['id'],
197
+ :instance_profile => prof,
198
+ :name => instance['name'],
199
+ :realm_id => instance['type']['id'],
200
+ :state => convert_server_state(instance['state']['name'], instance['id']),
201
+ :actions => instance_actions_for(convert_server_state(instance['state']['name'], instance['id'])),
202
+ :public_addresses => [ instance['ip']['ip'] ],
203
+ :private_addresses => []
204
+ )
205
+ end
206
+
207
+ def get_random_instance_name
208
+ "Server #{Time.now.to_i.to_s.reverse[0..3]}#{rand(9)}"
209
+ end
210
+
211
+ def convert_server_state(state, id)
212
+ return 'PENDING' unless id
213
+ state.eql?('Off') ? 'STOPPED' : 'RUNNING'
214
+ end
215
+
216
+ def get_next_free_ip(credentials)
217
+ ip = ""
218
+ safely do
219
+ ip = new_client(credentials).request('grid/ip/list', {
220
+ 'ip.type' => '1',
221
+ 'ip.state' => '1'
222
+ })['list'].first['ip']
223
+ end
224
+ return ip
225
+ end
226
+
227
+ def safely(&block)
228
+ begin
229
+ block.call
230
+ rescue Exception => e
231
+ puts "ERROR: #{e.message}"
232
+ end
233
+ end
234
+
235
+ end
236
+
237
+ end
238
+ end
239
+ end