bbrowning-deltacloud-core 0.0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (113) hide show
  1. data/COPYING +502 -0
  2. data/Rakefile +85 -0
  3. data/bin/deltacloudd +88 -0
  4. data/config.ru +5 -0
  5. data/deltacloud.rb +14 -0
  6. data/lib/deltacloud/base_driver.rb +19 -0
  7. data/lib/deltacloud/base_driver/base_driver.rb +189 -0
  8. data/lib/deltacloud/base_driver/features.rb +159 -0
  9. data/lib/deltacloud/base_driver/mock_driver.rb +37 -0
  10. data/lib/deltacloud/drivers/ec2/ec2_driver.rb +340 -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 +322 -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/rimuhosting/rimuhosting_client.rb +84 -0
  22. data/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb +144 -0
  23. data/lib/deltacloud/drivers/terremark/terremark_driver.rb +261 -0
  24. data/lib/deltacloud/hardware_profile.rb +153 -0
  25. data/lib/deltacloud/helpers.rb +5 -0
  26. data/lib/deltacloud/helpers/application_helper.rb +56 -0
  27. data/lib/deltacloud/helpers/conversion_helper.rb +38 -0
  28. data/lib/deltacloud/helpers/hardware_profiles_helper.rb +35 -0
  29. data/lib/deltacloud/method_serializer.rb +84 -0
  30. data/lib/deltacloud/models/base_model.rb +58 -0
  31. data/lib/deltacloud/models/image.rb +26 -0
  32. data/lib/deltacloud/models/instance.rb +37 -0
  33. data/lib/deltacloud/models/instance_profile.rb +47 -0
  34. data/lib/deltacloud/models/realm.rb +25 -0
  35. data/lib/deltacloud/models/storage_snapshot.rb +26 -0
  36. data/lib/deltacloud/models/storage_volume.rb +27 -0
  37. data/lib/deltacloud/state_machine.rb +84 -0
  38. data/lib/deltacloud/validation.rb +70 -0
  39. data/lib/drivers.rb +38 -0
  40. data/lib/sinatra/accept_media_types.rb +128 -0
  41. data/lib/sinatra/lazy_auth.rb +56 -0
  42. data/lib/sinatra/rabbit.rb +272 -0
  43. data/lib/sinatra/respond_to.rb +269 -0
  44. data/lib/sinatra/static_assets.rb +83 -0
  45. data/lib/sinatra/url_for.rb +51 -0
  46. data/public/favicon.ico +0 -0
  47. data/public/images/grid.png +0 -0
  48. data/public/images/logo-wide.png +0 -0
  49. data/public/images/rails.png +0 -0
  50. data/public/images/topbar-bg.png +0 -0
  51. data/public/javascripts/application.js +32 -0
  52. data/public/javascripts/jquery-1.4.2.min.js +154 -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 +342 -0
  58. data/support/fedora/deltacloudd +68 -0
  59. data/support/fedora/rubygem-deltacloud-core.spec +91 -0
  60. data/tests/deltacloud_test.rb +60 -0
  61. data/tests/images_test.rb +94 -0
  62. data/tests/instances_test.rb +136 -0
  63. data/tests/realms_test.rb +56 -0
  64. data/tests/storage_snapshots_test.rb +48 -0
  65. data/tests/storage_volumes_test.rb +48 -0
  66. data/torquebox-ec2-config.ru +8 -0
  67. data/views/accounts/index.html.haml +11 -0
  68. data/views/accounts/show.html.haml +30 -0
  69. data/views/api/show.html.haml +15 -0
  70. data/views/api/show.xml.haml +5 -0
  71. data/views/docs/collection.html.haml +37 -0
  72. data/views/docs/collection.xml.haml +14 -0
  73. data/views/docs/index.html.haml +15 -0
  74. data/views/docs/index.xml.haml +5 -0
  75. data/views/docs/operation.html.haml +31 -0
  76. data/views/docs/operation.xml.haml +10 -0
  77. data/views/errors/auth_exception.html.haml +8 -0
  78. data/views/errors/auth_exception.xml.haml +2 -0
  79. data/views/errors/backend_error.html.haml +17 -0
  80. data/views/errors/backend_error.xml.haml +8 -0
  81. data/views/errors/validation_failure.html.haml +11 -0
  82. data/views/errors/validation_failure.xml.haml +7 -0
  83. data/views/hardware_profiles/index.html.haml +25 -0
  84. data/views/hardware_profiles/index.xml.haml +4 -0
  85. data/views/hardware_profiles/show.html.haml +19 -0
  86. data/views/hardware_profiles/show.xml.haml +17 -0
  87. data/views/images/index.html.haml +30 -0
  88. data/views/images/index.xml.haml +7 -0
  89. data/views/images/show.html.haml +21 -0
  90. data/views/images/show.xml.haml +5 -0
  91. data/views/instance_states/show.gv.erb +45 -0
  92. data/views/instance_states/show.html.haml +31 -0
  93. data/views/instance_states/show.xml.haml +8 -0
  94. data/views/instances/index.html.haml +30 -0
  95. data/views/instances/index.xml.haml +23 -0
  96. data/views/instances/new.html.haml +55 -0
  97. data/views/instances/show.html.haml +43 -0
  98. data/views/instances/show.xml.haml +41 -0
  99. data/views/layout.html.haml +26 -0
  100. data/views/realms/index.html.haml +29 -0
  101. data/views/realms/index.xml.haml +12 -0
  102. data/views/realms/show.html.haml +15 -0
  103. data/views/realms/show.xml.haml +10 -0
  104. data/views/root/index.html.haml +4 -0
  105. data/views/storage_snapshots/index.html.haml +20 -0
  106. data/views/storage_snapshots/index.xml.haml +11 -0
  107. data/views/storage_snapshots/show.html.haml +14 -0
  108. data/views/storage_snapshots/show.xml.haml +9 -0
  109. data/views/storage_volumes/index.html.haml +21 -0
  110. data/views/storage_volumes/index.xml.haml +13 -0
  111. data/views/storage_volumes/show.html.haml +20 -0
  112. data/views/storage_volumes/show.xml.haml +13 -0
  113. metadata +361 -0
@@ -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,322 @@
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
+ 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
+
31
+ module Deltacloud
32
+ module Drivers
33
+ module Gogrid
34
+
35
+ class GogridDriver < Deltacloud::BaseDriver
36
+
37
+ feature :instances, :authentication_password
38
+
39
+ define_hardware_profile 'server' do
40
+ cpu 2
41
+ memory [512, 1024, 2048, 4096, 8192]
42
+ storage 10
43
+ end
44
+
45
+ # The only valid option for flavors is server RAM for now
46
+ def flavors(credentials, opts=nil)
47
+ flavors = []
48
+ safely do
49
+ flavors=new_client(credentials).request('common/lookup/list', { 'lookup' => 'server.ram' })['list'].collect do |flavor|
50
+ convert_flavor(flavor)
51
+ end
52
+ end
53
+ flavors = filter_on( flavors, :id, opts )
54
+ flavors = filter_on( flavors, :architecture, opts )
55
+ flavors
56
+ end
57
+
58
+ def images(credentials, opts=nil)
59
+ imgs = []
60
+ if opts and opts[:id]
61
+ safely do
62
+ imgs = [convert_image(new_client(credentials).request('grid/image/get', { 'id' => opts[:id] })['list'].first)]
63
+ end
64
+ else
65
+ safely do
66
+ imgs = new_client(credentials).request('grid/image/list', { 'state' => 'Available'})['list'].collect do |image|
67
+ convert_image(image, credentials.user)
68
+ end
69
+ end
70
+ end
71
+ imgs = filter_on( imgs, :architecture, opts )
72
+ imgs.sort_by{|e| [e.owner_id, e.description]}
73
+ end
74
+
75
+ def realms(credentials, opts=nil)
76
+ safely do
77
+ new_client(credentials).request('common/lookup/list', { 'lookup' => 'image.type' })['list'].collect do |realm|
78
+ convert_realm(realm)
79
+ end
80
+ end
81
+ end
82
+
83
+ def create_instance(credentials, image_id, opts=nil)
84
+ server_ram = nil
85
+ if opts[:hwp_memory]
86
+ mem = opts[:hwp_memory].to_i
87
+ server_ram = (mem == 512) ? "512MB" : "#{mem / 1024}GB"
88
+ else
89
+ server_ram = "512MB"
90
+ end
91
+ client = new_client(credentials)
92
+ name = (opts[:name] && opts[:name]!='') ? opts[:name] : get_random_instance_name
93
+ safely do
94
+ instance = client.request('grid/server/add', {
95
+ 'name' => name,
96
+ 'image' => image_id,
97
+ 'server.ram' => server_ram,
98
+ 'ip' => get_next_free_ip(credentials)
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
114
+ end
115
+ end
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
+
129
+ def instances(credentials, opts=nil)
130
+ instances = []
131
+ if opts and opts[:id]
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])
153
+ end
154
+ end
155
+ else
156
+ instances = list_instances(credentials, nil)
157
+ end
158
+ instances = filter_on( instances, :state, opts )
159
+ instances
160
+ end
161
+
162
+ def reboot_instance(credentials, id)
163
+ safely do
164
+ new_client(credentials).request('grid/server/power', { 'id' => id, 'power' => 'reboot'})
165
+ end
166
+ end
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
+
174
+ def stop_instance(credentials, id)
175
+ safely do
176
+ new_client(credentials).request('grid/server/power', { 'id' => id, 'power' => 'off'})
177
+ end
178
+ end
179
+
180
+ def start_instance(credentials, id)
181
+ safely do
182
+ new_client(credentials).request('grid/server/power', { 'id' => id, 'power' => 'on'})
183
+ end
184
+ end
185
+
186
+ define_instance_states do
187
+ start.to( :pending ) .automatically
188
+ pending.to( :running ) .automatically
189
+ running.to( :stopped ) .on( :stop )
190
+ stopped.to( :running ) .on( :start )
191
+ running.to( :finish ) .on( :destroy )
192
+ stopped.to( :finish ) .on( :destroy )
193
+ end
194
+
195
+ private
196
+
197
+ def new_client(credentials)
198
+ GoGridClient.new('https://api.gogrid.com/api', credentials.user, credentials.password)
199
+ end
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
+
217
+ def convert_image(gg_image, owner_id=nil)
218
+ Image.new( {
219
+ :id=>gg_image['id'],
220
+ :name => gg_image['friendlyName'],
221
+ :description=> convert_description(gg_image),
222
+ :owner_id=>gg_image['owner']['name'],
223
+ :architecture=>convert_arch(gg_image['description']),
224
+ } )
225
+ end
226
+
227
+ def convert_description(image)
228
+ if image['price'].eql?(0)
229
+ image['description']
230
+ else
231
+ "#{image['description']} (#{image['price']}$)"
232
+ end
233
+ end
234
+
235
+ def convert_flavor(flavor)
236
+ Flavor.new(
237
+ :id => flavor['id'],
238
+ :architecture => 'x86',
239
+ :memory => flavor['name'].tr('G', ''),
240
+ :storage => '1'
241
+ )
242
+ end
243
+
244
+ def convert_realm(realm)
245
+ Realm.new(
246
+ :id => realm['id'],
247
+ :name => realm['name'],
248
+ :state => :unlimited,
249
+ :storage => :unlimited
250
+ )
251
+ end
252
+
253
+ def convert_arch(description)
254
+ description.include?('64-bit') ? 'x86_64' : 'i386'
255
+ end
256
+
257
+ def convert_instance(instance, owner_id)
258
+ opts = {}
259
+ unless instance['ram']['id'] == "1"
260
+ mem = instance['ram']['name']
261
+ if mem == "512MB"
262
+ opts[:hwp_memory] = "512"
263
+ else
264
+ opts[:hwp_memory] = (mem.to_i * 1024).to_s
265
+ end
266
+ end
267
+ prof = InstanceProfile.new("server", opts)
268
+
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.
274
+ :id => instance['name'],
275
+ :owner_id => owner_id,
276
+ :image_id => instance['image']['id'],
277
+ :flavor_id => instance['ram']['id'],
278
+ :instance_profile => prof,
279
+ :name => instance['name'],
280
+ :realm_id => instance['type']['id'],
281
+ :state => convert_server_state(instance['state']['name'], instance['id']),
282
+ :actions => instance_actions_for(convert_server_state(instance['state']['name'], instance['id'])),
283
+ :public_addresses => [ instance['ip']['ip'] ],
284
+ :private_addresses => [],
285
+ :username => instance['username'],
286
+ :password => instance['password']
287
+ )
288
+ end
289
+
290
+ def get_random_instance_name
291
+ "Server #{Time.now.to_i.to_s.reverse[0..3]}#{rand(9)}"
292
+ end
293
+
294
+ def convert_server_state(state, id)
295
+ return 'PENDING' unless id
296
+ state.eql?('Off') ? 'STOPPED' : 'RUNNING'
297
+ end
298
+
299
+ def get_next_free_ip(credentials)
300
+ ip = ""
301
+ safely do
302
+ ip = new_client(credentials).request('grid/ip/list', {
303
+ 'ip.type' => '1',
304
+ 'ip.state' => '1'
305
+ })['list'].first['ip']
306
+ end
307
+ return ip
308
+ end
309
+
310
+ def safely(&block)
311
+ begin
312
+ block.call
313
+ rescue Exception => e
314
+ puts "ERROR: #{e.message}"
315
+ end
316
+ end
317
+
318
+ end
319
+
320
+ end
321
+ end
322
+ end
@@ -0,0 +1,275 @@
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
+
19
+ require 'deltacloud/base_driver'
20
+
21
+ module Deltacloud
22
+ module Drivers
23
+ module Mock
24
+ class MockDriver < Deltacloud::BaseDriver
25
+
26
+ ( REALMS = [
27
+ Realm.new({
28
+ :id=>'us',
29
+ :name=>'United States',
30
+ :limit=>:unlimited,
31
+ :state=>'AVAILABLE',
32
+ }),
33
+ Realm.new({
34
+ :id=>'eu',
35
+ :name=>'Europe',
36
+ :limit=>:unlimited,
37
+ :state=>'AVAILABLE',
38
+ }),
39
+ ] ) unless defined?( REALMS )
40
+
41
+ define_hardware_profile('m1-small') do
42
+ cpu 1
43
+ memory 1.7 * 1024
44
+ storage 160
45
+ architecture 'i386'
46
+ end
47
+
48
+ define_hardware_profile('m1-large') do
49
+ cpu 2
50
+ memory (7.5*1024 .. 15*1024), :default => 10 * 1024
51
+ storage [ 850, 1024 ]
52
+ architecture 'x86_64'
53
+ end
54
+
55
+ define_hardware_profile('m1-xlarge') do
56
+ cpu 4
57
+ memory (12*1024 .. 32*1024)
58
+ storage [ 1024, 2048, 4096 ]
59
+ architecture 'x86_64'
60
+ end
61
+
62
+ # Some clouds tell us nothing about hardware profiles (e.g., OpenNebula)
63
+ define_hardware_profile 'opaque'
64
+
65
+ define_instance_states do
66
+ start.to( :pending ) .on( :create )
67
+
68
+ pending.to( :running ) .automatically
69
+
70
+ running.to( :running ) .on( :reboot )
71
+ running.to( :stopped ) .on( :stop )
72
+
73
+ stopped.to( :running ) .on( :start )
74
+ stopped.to( :finish ) .on( :destroy )
75
+ end
76
+
77
+ feature :instances, :user_name
78
+
79
+ def initialize
80
+ if ENV["DELTACLOUD_MOCK_STORAGE"]
81
+ @storage_root = ENV["DELTACLOUD_MOCK_STORAGE"]
82
+ elsif ENV["USER"]
83
+ @storage_root = File::join("/var/tmp", "deltacloud-mock-#{ENV["USER"]}")
84
+ else
85
+ raise "Please set either the DELTACLOUD_MOCK_STORAGE or USER environment variable"
86
+ end
87
+ if ! File::directory?(@storage_root)
88
+ FileUtils::rm_rf(@storage_root)
89
+ FileUtils::mkdir_p(@storage_root)
90
+ data = Dir::glob(File::join(File::dirname(__FILE__), "data", "*"))
91
+ FileUtils::cp_r(data, @storage_root)
92
+ end
93
+ end
94
+
95
+ def realms(credentials, opts=nil)
96
+ return REALMS if ( opts.nil? )
97
+ results = REALMS
98
+ results = filter_on( results, :id, opts )
99
+ results
100
+ end
101
+
102
+ #
103
+ # Images
104
+ #
105
+
106
+ def images(credentials, opts=nil )
107
+ check_credentials( credentials )
108
+ images = []
109
+ Dir[ "#{@storage_root}/images/*.yml" ].each do |image_file|
110
+ image = YAML.load( File.read( image_file ) )
111
+ image[:id] = File.basename( image_file, ".yml" )
112
+ image[:name] = image[:description]
113
+ images << Image.new( image )
114
+ end
115
+ images = filter_on( images, :id, opts )
116
+ images = filter_on( images, :architecture, opts )
117
+ if ( opts && opts[:owner_id] == 'self' )
118
+ images = images.select{|e| e.owner_id == credentials.user }
119
+ else
120
+ images = filter_on( images, :owner_id, opts )
121
+ end
122
+ images.sort_by{|e| [e.owner_id,e.description]}
123
+ end
124
+
125
+ #
126
+ # Instances
127
+ #
128
+
129
+ def instances(credentials, opts=nil)
130
+ check_credentials( credentials )
131
+ instances = []
132
+ Dir[ "#{@storage_root}/instances/*.yml" ].each do |instance_file|
133
+ instance = YAML.load( File.read( instance_file ) )
134
+ if ( instance[:owner_id] == credentials.user )
135
+ instance[:id] = File.basename( instance_file, ".yml" )
136
+ instance[:actions] = instance_actions_for( instance[:state] )
137
+ instances << Instance.new( instance )
138
+ end
139
+ end
140
+ instances = filter_on( instances, :id, opts )
141
+ instances = filter_on( instances, :state, opts )
142
+ instances
143
+ end
144
+
145
+ def create_instance(credentials, image_id, opts)
146
+ check_credentials( credentials )
147
+ ids = Dir[ "#{@storage_root}/instances/*.yml" ].collect{|e| File.basename( e, ".yml" )}
148
+
149
+ count = 0
150
+ while true
151
+ next_id = "inst" + count.to_s
152
+ if not ids.include?(next_id)
153
+ break
154
+ end
155
+ count = count + 1
156
+ end
157
+
158
+ realm_id = opts[:realm_id]
159
+ if ( realm_id.nil? )
160
+ realm = realms(credentials).first
161
+ ( realm_id = realm.id ) if realm
162
+ end
163
+
164
+ hwp = find_hardware_profile(credentials, opts[:hwp_id], image_id)
165
+
166
+ name = opts[:name] || "i-#{Time.now.to_i}"
167
+
168
+ instance = {
169
+ :name=>name,
170
+ :state=>'RUNNING',
171
+ :image_id=>image_id,
172
+ :owner_id=>credentials.user,
173
+ :public_addresses=>["#{image_id}.#{next_id}.public.com"],
174
+ :private_addresses=>["#{image_id}.#{next_id}.private.com"],
175
+ :instance_profile => InstanceProfile.new(hwp.name, opts),
176
+ :realm_id=>realm_id,
177
+ :actions=>instance_actions_for( 'RUNNING' )
178
+ }
179
+ File.open( "#{@storage_root}/instances/#{next_id}.yml", 'w' ) {|f|
180
+ YAML.dump( instance, f )
181
+ }
182
+ instance[:id] = next_id
183
+ Instance.new( instance )
184
+ end
185
+
186
+ def start_instance(credentials, id)
187
+ instance_file = "#{@storage_root}/instances/#{id}.yml"
188
+ instance_yml = YAML.load( File.read( instance_file ) )
189
+ instance_yml[:state] = 'RUNNING'
190
+ File.open( instance_file, 'w' ) do |f|
191
+ f << YAML.dump( instance_yml )
192
+ end
193
+ Instance.new( instance_yml )
194
+ end
195
+
196
+ def reboot_instance(credentials, id)
197
+ instance_file = "#{@storage_root}/instances/#{id}.yml"
198
+ instance_yml = YAML.load( File.read( instance_file ) )
199
+ instance_yml[:state] = 'RUNNING'
200
+ File.open( instance_file, 'w' ) do |f|
201
+ f << YAML.dump( instance_yml )
202
+ end
203
+ Instance.new( instance_yml )
204
+ end
205
+
206
+ def stop_instance(credentials, id)
207
+ instance_file = "#{@storage_root}/instances/#{id}.yml"
208
+ instance_yml = YAML.load( File.read( instance_file ) )
209
+ instance_yml[:state] = 'STOPPED'
210
+ File.open( instance_file, 'w' ) do |f|
211
+ f << YAML.dump( instance_yml )
212
+ end
213
+ Instance.new( instance_yml )
214
+ end
215
+
216
+
217
+ def destroy_instance(credentials, id)
218
+ check_credentials( credentials )
219
+ FileUtils.rm( "#{@storage_root}/instances/#{id}.yml" )
220
+ end
221
+
222
+ #
223
+ # Storage Volumes
224
+ #
225
+
226
+ def storage_volumes(credentials, opts=nil)
227
+ check_credentials( credentials )
228
+ volumes = []
229
+ Dir[ "#{@storage_root}/storage_volumes/*.yml" ].each do |storage_volume_file|
230
+ storage_volume = YAML.load( File.read( storage_volume_file ) )
231
+ if ( storage_volume[:owner_id] == credentials.user )
232
+ storage_volume[:id] = File.basename( storage_volume_file, ".yml" )
233
+ volumes << StorageVolume.new( storage_volume )
234
+ end
235
+ end
236
+ volumes = filter_on( volumes, :id, opts )
237
+ volumes
238
+ end
239
+
240
+ #
241
+ # Storage Snapshots
242
+ #
243
+
244
+ def storage_snapshots(credentials, opts=nil)
245
+ check_credentials( credentials )
246
+ snapshots = []
247
+ Dir[ "#{@storage_root}/storage_snapshots/*.yml" ].each do |storage_snapshot_file|
248
+ storage_snapshot = YAML.load( File.read( storage_snapshot_file ) )
249
+ if ( storage_snapshot[:owner_id] == credentials.user )
250
+ storage_snapshot[:id] = File.basename( storage_snapshot_file, ".yml" )
251
+ snapshots << StorageSnapshot.new( storage_snapshot )
252
+ end
253
+ end
254
+ snapshots = filter_on( snapshots, :id, opts )
255
+ snapshots
256
+ end
257
+
258
+ private
259
+
260
+ def check_credentials(credentials)
261
+ if ( credentials.user != 'mockuser' )
262
+ raise Deltacloud::AuthException.new
263
+ end
264
+
265
+ if ( credentials.password != 'mockpassword' )
266
+ raise Deltacloud::AuthException.new
267
+ end
268
+ end
269
+
270
+
271
+ end
272
+
273
+ end
274
+ end
275
+ end