deltacloud-core 0.1.2 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/DISCLAIMER +8 -0
- data/{COPYING → LICENSE} +0 -0
- data/NOTICE +13 -0
- data/Rakefile +50 -51
- data/bin/deltacloudd +8 -1
- data/config.ru +0 -2
- data/config/drivers.yaml +48 -0
- data/deltacloud-core.gemspec +75 -0
- data/deltacloud.rb +3 -2
- data/lib/deltacloud/backend_capability.rb +15 -3
- data/lib/deltacloud/base_driver.rb +0 -2
- data/lib/deltacloud/base_driver/base_driver.rb +85 -89
- data/lib/deltacloud/base_driver/features.rb +61 -7
- data/lib/deltacloud/base_driver/mock_driver.rb +42 -43
- data/lib/deltacloud/core_ext.rb +18 -0
- data/lib/deltacloud/core_ext/integer.rb +31 -0
- data/lib/deltacloud/core_ext/string.rb +50 -0
- data/lib/deltacloud/drivers/azure/azure_driver.rb +71 -22
- data/lib/deltacloud/drivers/ec2/ec2_driver.rb +641 -584
- data/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb +0 -2
- data/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb +167 -0
- data/lib/deltacloud/drivers/gogrid/gogrid_client.rb +39 -1
- data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +41 -25
- data/lib/deltacloud/drivers/mock/data/buckets/blobs/blob1.yml +6 -3
- data/lib/deltacloud/drivers/mock/data/buckets/blobs/blob2.yml +6 -3
- data/lib/deltacloud/drivers/mock/data/buckets/blobs/blob3.yml +4 -2
- data/lib/deltacloud/drivers/mock/data/buckets/blobs/blob4.yml +5 -2
- data/lib/deltacloud/drivers/mock/data/buckets/blobs/blob5.yml +4 -2
- data/lib/deltacloud/drivers/mock/data/instances/inst0.yml +1 -0
- data/lib/deltacloud/drivers/mock/data/instances/inst1.yml +1 -0
- data/lib/deltacloud/drivers/mock/data/instances/inst2.yml +1 -0
- data/lib/deltacloud/drivers/mock/data/storage_volumes/vol1.yml +1 -0
- data/lib/deltacloud/drivers/mock/data/storage_volumes/vol2.yml +1 -0
- data/lib/deltacloud/drivers/mock/data/storage_volumes/vol3.yml +1 -0
- data/lib/deltacloud/drivers/mock/mock_driver.rb +138 -30
- data/lib/deltacloud/drivers/opennebula/cloud_client.rb +13 -15
- data/lib/deltacloud/drivers/opennebula/occi_client.rb +13 -15
- data/lib/deltacloud/drivers/opennebula/opennebula_driver.rb +13 -15
- data/lib/deltacloud/drivers/rackspace/rackspace_driver.rb +224 -113
- data/lib/deltacloud/drivers/rhevm/rhevm_client.rb +332 -0
- data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +221 -170
- data/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb +0 -1
- data/lib/deltacloud/drivers/sbc/sbc_client.rb +247 -0
- data/lib/deltacloud/drivers/sbc/sbc_driver.rb +297 -0
- data/lib/deltacloud/drivers/terremark/terremark_driver.rb +0 -2
- data/lib/deltacloud/hardware_profile.rb +1 -3
- data/lib/deltacloud/helpers.rb +0 -2
- data/lib/deltacloud/helpers/application_helper.rb +86 -12
- data/lib/deltacloud/helpers/blob_stream.rb +19 -2
- data/lib/deltacloud/helpers/conversion_helper.rb +0 -2
- data/lib/deltacloud/helpers/hardware_profiles_helper.rb +0 -2
- data/lib/deltacloud/method_serializer.rb +0 -2
- data/lib/deltacloud/models/base_model.rb +0 -2
- data/lib/deltacloud/models/blob.rb +1 -2
- data/lib/deltacloud/models/bucket.rb +0 -2
- data/lib/deltacloud/models/image.rb +0 -2
- data/lib/deltacloud/models/instance.rb +19 -2
- data/lib/deltacloud/models/instance_profile.rb +4 -2
- data/lib/deltacloud/models/key.rb +0 -2
- data/lib/deltacloud/models/load_balancer.rb +0 -2
- data/lib/deltacloud/models/realm.rb +0 -2
- data/lib/deltacloud/models/storage_snapshot.rb +0 -2
- data/lib/deltacloud/models/storage_volume.rb +4 -2
- data/lib/deltacloud/runner.rb +132 -0
- data/lib/deltacloud/state_machine.rb +0 -2
- data/lib/deltacloud/validation.rb +9 -7
- data/lib/drivers.rb +36 -48
- data/lib/sinatra/accept_media_types.rb +26 -0
- data/lib/sinatra/lazy_auth.rb +16 -0
- data/lib/sinatra/rabbit.rb +112 -54
- data/lib/sinatra/rack_driver_select.rb +50 -16
- data/lib/sinatra/rack_etag.rb +79 -0
- data/lib/sinatra/rack_matrix_params.rb +84 -0
- data/lib/sinatra/rack_runtime.rb +47 -0
- data/lib/sinatra/static_assets.rb +16 -0
- data/lib/sinatra/url_for.rb +31 -4
- data/public/favicon.ico +0 -0
- data/public/images/bread-bg.png +0 -0
- data/public/images/error.png +0 -0
- data/public/images/pending.png +0 -0
- data/public/images/running.png +0 -0
- data/public/images/stopped.png +0 -0
- data/public/javascripts/application.js +35 -0
- data/public/stylesheets/compiled/application.css +59 -5
- data/public/stylesheets/compiled/screen.css +1 -1
- data/server.rb +293 -29
- data/support/fedora/deltacloud-core +78 -0
- data/support/fedora/deltacloud-core.spec +143 -0
- data/support/fedora/deltacloudd +78 -18
- data/support/fedora/rubygem-deltacloud-core.spec +76 -40
- data/tests/common.rb +172 -0
- data/tests/drivers/mock/api_test.rb +133 -0
- data/tests/drivers/mock/hardware_profiles_test.rb +134 -0
- data/tests/drivers/mock/images_test.rb +126 -0
- data/tests/drivers/mock/instance_states_test.rb +71 -0
- data/tests/drivers/mock/instances_test.rb +236 -0
- data/tests/drivers/mock/realms_test.rb +93 -0
- data/tests/drivers/mock/setup.rb +3 -0
- data/tests/drivers/mock/url_for_test.rb +67 -0
- data/tests/drivers/rackspace/api_test.rb +41 -0
- data/tests/drivers/rackspace/hardware_profiles_test.rb +53 -0
- data/tests/drivers/rackspace/images_test.rb +40 -0
- data/tests/drivers/rackspace/instances_test.rb +161 -0
- data/tests/drivers/rackspace/realms_test.rb +36 -0
- data/tests/drivers/rackspace/setup.rb +14 -0
- data/tests/drivers/rhevm/api_test.rb +39 -0
- data/tests/drivers/rhevm/hardware_profiles_test.rb +53 -0
- data/tests/drivers/rhevm/images_test.rb +42 -0
- data/tests/drivers/rhevm/instances_test.rb +179 -0
- data/tests/drivers/rhevm/realms_test.rb +35 -0
- data/tests/drivers/rhevm/setup.rb +14 -0
- data/tests/rabbit_test.rb +52 -0
- data/views/api/show.html.haml +2 -5
- data/views/blobs/new.html.haml +17 -1
- data/views/blobs/show.html.haml +6 -0
- data/views/blobs/show.xml.haml +5 -1
- data/views/buckets/index.html.haml +1 -12
- data/views/buckets/index.xml.haml +3 -5
- data/views/docs/operation.html.haml +23 -11
- data/views/drivers/index.html.haml +15 -0
- data/views/drivers/index.xml.haml +7 -0
- data/views/drivers/show.html.haml +20 -0
- data/views/drivers/show.xml.haml +7 -0
- data/views/error.html.haml +31 -0
- data/views/errors/auth_exception.xml.haml +2 -1
- data/views/errors/backend_capability_failure.xml.haml +2 -1
- data/views/errors/backend_error.html.haml +3 -0
- data/views/errors/backend_error.xml.haml +2 -2
- data/views/errors/validation_failure.xml.haml +3 -2
- data/views/images/index.html.haml +1 -6
- data/views/images/index.xml.haml +2 -0
- data/views/images/new.html.haml +14 -0
- data/views/images/show.xml.haml +2 -0
- data/views/instances/index.html.haml +8 -6
- data/views/instances/index.xml.haml +4 -0
- data/views/instances/new.html.haml +40 -11
- data/views/instances/run.html.haml +9 -0
- data/views/instances/run.xml.haml +7 -0
- data/views/instances/run_command.html.haml +16 -0
- data/views/instances/show.html.haml +14 -0
- data/views/instances/show.xml.haml +12 -4
- data/views/layout.html.haml +7 -2
- data/views/load_balancers/index.html.haml +1 -1
- data/views/load_balancers/new.html.haml +2 -2
- data/views/load_balancers/show.html.haml +1 -1
- data/views/storage_snapshots/index.html.haml +3 -0
- data/views/storage_snapshots/new.html.haml +9 -0
- data/views/storage_volumes/attach.html.haml +20 -0
- data/views/storage_volumes/index.html.haml +16 -1
- data/views/storage_volumes/index.xml.haml +1 -10
- data/views/storage_volumes/new.html.haml +17 -0
- data/views/storage_volumes/show.html.haml +8 -0
- data/views/storage_volumes/show.xml.haml +25 -3
- metadata +197 -127
- data/lib/deltacloud/drivers/rackspace/rackspace_client.rb +0 -130
- data/parse.rb +0 -7
- data/test.rb +0 -3
- data/views/api/drivers.xml.haml +0 -6
@@ -0,0 +1,247 @@
|
|
1
|
+
#
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one or more
|
3
|
+
# contributor license agreements. See the NOTICE file distributed with
|
4
|
+
# this work for additional information regarding copyright ownership. The
|
5
|
+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
6
|
+
# "License"); you may not use this file except in compliance with the
|
7
|
+
# License. You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
13
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
14
|
+
# License for the specific language governing permissions and limitations
|
15
|
+
# under the License.
|
16
|
+
|
17
|
+
require 'base64'
|
18
|
+
require 'net/https'
|
19
|
+
require 'json'
|
20
|
+
require 'digest/md5'
|
21
|
+
|
22
|
+
module Deltacloud
|
23
|
+
module Drivers
|
24
|
+
module SBC
|
25
|
+
|
26
|
+
class FixtureNotFound < Exception; end
|
27
|
+
|
28
|
+
#
|
29
|
+
# Client for the IBM Smart Business Cloud (SBC).
|
30
|
+
#
|
31
|
+
# 31 January 2011
|
32
|
+
#
|
33
|
+
class SBCClient
|
34
|
+
API_URL = URI.parse('https://www-147.ibm.com/computecloud/enterprise/api/rest/20100331')
|
35
|
+
|
36
|
+
#
|
37
|
+
# Initialize the client
|
38
|
+
#
|
39
|
+
def initialize(username, password)
|
40
|
+
@username, @password = username, password
|
41
|
+
@rest_base = '/computecloud/enterprise/api/rest/20100331'
|
42
|
+
@service = Net::HTTP.new(API_URL.host, API_URL.port)
|
43
|
+
@service.use_ssl = true
|
44
|
+
end
|
45
|
+
|
46
|
+
#
|
47
|
+
# Retrieve instances
|
48
|
+
#
|
49
|
+
def list_instances(instance_id=nil)
|
50
|
+
if instance_id.nil?
|
51
|
+
JSON.parse(get('/instances', default_headers))['instances']
|
52
|
+
else
|
53
|
+
[ JSON.parse(get('/instances/' + instance_id, default_headers)) ]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Reboot an instance
|
59
|
+
#
|
60
|
+
def reboot_instance(instance_id)
|
61
|
+
headers = default_headers
|
62
|
+
headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
63
|
+
put('/instances/' + instance_id, 'state=restart', headers)
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# Delete an instance
|
68
|
+
#
|
69
|
+
def delete_instance(instance_id)
|
70
|
+
delete('/instances/' + instance_id, default_headers)
|
71
|
+
end
|
72
|
+
|
73
|
+
#
|
74
|
+
# Retrieve images
|
75
|
+
#
|
76
|
+
def list_images(image_id=nil)
|
77
|
+
if image_id.nil?
|
78
|
+
JSON.parse(get('/offerings/image', default_headers))['images']
|
79
|
+
else
|
80
|
+
[ JSON.parse(get('/offerings/image/' + image_id, default_headers)) ]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
#
|
85
|
+
# Retrieve locations; returns an XML document.
|
86
|
+
#
|
87
|
+
def list_locations
|
88
|
+
headers = default_headers
|
89
|
+
headers['Accept'] = 'text/xml' # JSON locations not supported
|
90
|
+
Nokogiri.XML(get('/locations', headers))
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# Creates an instance
|
95
|
+
#
|
96
|
+
# body is a name/value hash to configure the instance
|
97
|
+
#
|
98
|
+
def create_instance(body)
|
99
|
+
headers = default_headers
|
100
|
+
headers['Content-Type'] = 'application/x-www-form-urlencoded'
|
101
|
+
JSON.parse(post('/instances', urlencode(body), headers))['instances']
|
102
|
+
end
|
103
|
+
|
104
|
+
#
|
105
|
+
# -------------------- Private Helpers -----------------
|
106
|
+
#
|
107
|
+
private
|
108
|
+
|
109
|
+
#
|
110
|
+
# HTTP GET
|
111
|
+
#
|
112
|
+
def get(path, headers)
|
113
|
+
if ENV['RACK_ENV'] == 'test'
|
114
|
+
mock_request(:get, path, {}, headers)
|
115
|
+
else
|
116
|
+
resp = @service.get(@rest_base + path, headers)
|
117
|
+
unless resp.is_a?(Net::HTTPSuccess)
|
118
|
+
backend_error!(resp)
|
119
|
+
end
|
120
|
+
resp.body
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
#
|
125
|
+
# HTTP PUT
|
126
|
+
#
|
127
|
+
def put(path, body, headers)
|
128
|
+
if ENV['RACK_ENV'] == 'test'
|
129
|
+
mock_request(:get, path, {}, headers)
|
130
|
+
else
|
131
|
+
resp = @service.put(@rest_base + path, body, headers)
|
132
|
+
unless resp.is_a?(Net::HTTPSuccess)
|
133
|
+
backend_error!(resp)
|
134
|
+
end
|
135
|
+
resp.body
|
136
|
+
end
|
137
|
+
end
|
138
|
+
|
139
|
+
#
|
140
|
+
# HTTP POST
|
141
|
+
#
|
142
|
+
def post(path, body, headers)
|
143
|
+
if ENV['RACK_ENV'] == 'test'
|
144
|
+
mock_request(:get, path, {}, headers)
|
145
|
+
else
|
146
|
+
resp = @service.post(@rest_base + path, body, headers)
|
147
|
+
unless resp.is_a?(Net::HTTPSuccess)
|
148
|
+
backend_error!(resp)
|
149
|
+
end
|
150
|
+
resp.body
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
#
|
155
|
+
# HTTP DELETE
|
156
|
+
#
|
157
|
+
def delete(path, headers)
|
158
|
+
if ENV['RACK_ENV'] == 'test'
|
159
|
+
mock_request(:get, path, {}, headers)
|
160
|
+
else
|
161
|
+
resp = @service.delete(@rest_base + path, headers)
|
162
|
+
unless resp.is_a?(Net::HTTPSuccess)
|
163
|
+
backend_error!(resp)
|
164
|
+
end
|
165
|
+
resp.body
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
#
|
170
|
+
# Default request headers.
|
171
|
+
#
|
172
|
+
def default_headers
|
173
|
+
{"Accept" => "application/json",
|
174
|
+
"User-Agent" => "deltacloud",
|
175
|
+
"Authorization" => "Basic " + Base64.encode64("#{@username}:#{@password}")}
|
176
|
+
end
|
177
|
+
|
178
|
+
#
|
179
|
+
# Handle request error
|
180
|
+
#
|
181
|
+
def backend_error!(resp)
|
182
|
+
if resp.is_a?(Net::HTTPUnauthorized)
|
183
|
+
raise Deltacloud::AuthException, resp.message
|
184
|
+
else
|
185
|
+
raise Deltacloud::BackendError.new(resp.code, resp.body, resp.message, '')
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
#
|
190
|
+
# Utility to URL encode a hash.
|
191
|
+
#
|
192
|
+
def urlencode(hash)
|
193
|
+
hash.keys.map { |k| "#{URI.encode(k)}=#{URI.encode(hash[k])}" }.join("&")
|
194
|
+
end
|
195
|
+
|
196
|
+
#
|
197
|
+
# Reads a fake URL from local fixtures
|
198
|
+
#
|
199
|
+
def read_fake_url(filename)
|
200
|
+
fixture_file = "../tests/sbc/support/fixtures/#{filename}"
|
201
|
+
if File.exists?(fixture_file)
|
202
|
+
puts "Using fixture: #{fixture_file}"
|
203
|
+
return JSON::parse(File.read(fixture_file))
|
204
|
+
else
|
205
|
+
raise FixtureNotFound.new
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
#
|
210
|
+
# Executes a fake request from local fixtures
|
211
|
+
#
|
212
|
+
def mock_request(*args)
|
213
|
+
http_method, request_uri, params, headers = args[0].to_sym, args[1], args[2], args[3]
|
214
|
+
params ||= {}
|
215
|
+
fixture_filename = fixture_filename = "#{Digest::MD5.hexdigest("#{http_method}#{request_uri}#{params.inspect}#{headers.reject{|key, value| key == "Authorization"}}")}.fixture"
|
216
|
+
puts "fixture filename: " + fixture_filename
|
217
|
+
begin
|
218
|
+
return read_fake_url(fixture_filename)[2]["body"]
|
219
|
+
rescue FixtureNotFound
|
220
|
+
if http_method.eql?(:get)
|
221
|
+
r = @service.get(@rest_base + request_uri, headers)
|
222
|
+
elsif http_method.eql?(:post)
|
223
|
+
r = @service.post(@rest_base + request_uri, body, headers)
|
224
|
+
elsif http_method.eql?(:put)
|
225
|
+
r = @service.put(@rest_base + request_uri, params, headers)
|
226
|
+
elsif http_method.eql?(:delete)
|
227
|
+
r = @service.delete(@rest_base + request_uri, headers)
|
228
|
+
end
|
229
|
+
response = {
|
230
|
+
"body" => r.body,
|
231
|
+
"status" => r.code,
|
232
|
+
"Content-Type" => r["Content-Type"]
|
233
|
+
}
|
234
|
+
fixtures_dir = "../tests/sbc/support/fixtures/"
|
235
|
+
FileUtils.mkdir_p(fixtures_dir)
|
236
|
+
puts "Saving fixture #{fixture_filename}"
|
237
|
+
File.open(File::join(fixtures_dir, fixture_filename), 'w') do |f|
|
238
|
+
f.puts [request_uri, http_method, response].to_json
|
239
|
+
end
|
240
|
+
retry
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
end
|
245
|
+
end
|
246
|
+
end
|
247
|
+
end
|
@@ -0,0 +1,297 @@
|
|
1
|
+
#
|
2
|
+
# Licensed to the Apache Software Foundation (ASF) under one or more
|
3
|
+
# contributor license agreements. See the NOTICE file distributed with
|
4
|
+
# this work for additional information regarding copyright ownership. The
|
5
|
+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
6
|
+
# "License"); you may not use this file except in compliance with the
|
7
|
+
# License. You may obtain a copy of the License at
|
8
|
+
#
|
9
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
10
|
+
#
|
11
|
+
# Unless required by applicable law or agreed to in writing, software
|
12
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
13
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
14
|
+
# License for the specific language governing permissions and limitations
|
15
|
+
# under the License.
|
16
|
+
|
17
|
+
require 'nokogiri'
|
18
|
+
require 'deltacloud/drivers/sbc/sbc_client'
|
19
|
+
|
20
|
+
module Deltacloud
|
21
|
+
module Drivers
|
22
|
+
module SBC
|
23
|
+
#
|
24
|
+
# Driver for the IBM Smart Business Cloud (SBC).
|
25
|
+
#
|
26
|
+
# 31 January 2011
|
27
|
+
#
|
28
|
+
class SBCDriver < Deltacloud::BaseDriver
|
29
|
+
#
|
30
|
+
# Retrieves images
|
31
|
+
#
|
32
|
+
def images(credentials, opts={})
|
33
|
+
sbc_client = new_client(credentials)
|
34
|
+
opts ||= {}
|
35
|
+
images = []
|
36
|
+
images = sbc_client.list_images(opts[:id]).map do |image|
|
37
|
+
# Cache image for create_instance; hwp is image-specific. In the
|
38
|
+
# current flow of the server, images is always called before a
|
39
|
+
# create_instance, making this caching profitable
|
40
|
+
@last_image = image
|
41
|
+
convert_image(image)
|
42
|
+
end
|
43
|
+
images = filter_on(images, :architecture, opts)
|
44
|
+
images = filter_on(images, :owner_id, opts)
|
45
|
+
images
|
46
|
+
end
|
47
|
+
|
48
|
+
#
|
49
|
+
# Retrieves realms
|
50
|
+
#
|
51
|
+
def realms(credentials, opts={})
|
52
|
+
sbc_client = new_client(credentials)
|
53
|
+
doc = sbc_client.list_locations
|
54
|
+
doc.xpath('ns2:DescribeLocationsResponse/Location').map { |loc| convert_location(loc) }
|
55
|
+
end
|
56
|
+
|
57
|
+
#
|
58
|
+
# Retrieves instances
|
59
|
+
#
|
60
|
+
def instances(credentials, opts={})
|
61
|
+
sbc_client = new_client(credentials)
|
62
|
+
opts ||= {}
|
63
|
+
instances = []
|
64
|
+
instances = sbc_client.list_instances(opts[:id]).map do |instance|
|
65
|
+
convert_instance(instance)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
#
|
70
|
+
# Creates an instance
|
71
|
+
#
|
72
|
+
def create_instance(credentials, image_id, opts={})
|
73
|
+
sbc_client = new_client(credentials)
|
74
|
+
|
75
|
+
# Copy opts to body; keywords are mapped later
|
76
|
+
body = opts.dup
|
77
|
+
body.delete('image_id')
|
78
|
+
body.delete('hwp_id')
|
79
|
+
body.delete('realm_id')
|
80
|
+
|
81
|
+
# Lookup image if nil; tries to avoids extra lookup
|
82
|
+
if @last_image.nil? || @last_image['id'] != opts[:image_id]
|
83
|
+
@last_image = sbc_client.list_images(image_id).map[0]
|
84
|
+
end
|
85
|
+
|
86
|
+
# Map DeltaCloud keywords to SBC
|
87
|
+
body['imageID'] = opts[:image_id]
|
88
|
+
body['location'] = opts[:realm_id] || @last_image['location']
|
89
|
+
body['instanceType'] = opts[:hwp_id].gsub('-', '/') || @last_image['supportedInstanceTypes'][0]['id']
|
90
|
+
|
91
|
+
# Submit instance, parse response
|
92
|
+
convert_instance(sbc_client.create_instance(body).map[0])
|
93
|
+
end
|
94
|
+
|
95
|
+
#
|
96
|
+
# Reboots an instance
|
97
|
+
#
|
98
|
+
def reboot_instance(credentials, instance_id)
|
99
|
+
sbc_client = new_client(credentials)
|
100
|
+
sbc_client.reboot_instance(instance_id)
|
101
|
+
instance(credentials, instance_id)
|
102
|
+
end
|
103
|
+
|
104
|
+
#
|
105
|
+
# Stops an instance
|
106
|
+
#
|
107
|
+
def stop_instance(credentials, instance_id)
|
108
|
+
# Stop not supported; rebooting
|
109
|
+
reboot_instance(credentials, instance_id)
|
110
|
+
end
|
111
|
+
|
112
|
+
#
|
113
|
+
# Destroys an instance
|
114
|
+
#
|
115
|
+
def destroy_instance(credentials, instance_id)
|
116
|
+
sbc_client = new_client(credentials)
|
117
|
+
sbc_client.delete_instance(instance_id)
|
118
|
+
instance(credentials, instance_id)
|
119
|
+
end
|
120
|
+
|
121
|
+
#
|
122
|
+
# --------------------- Private helpers ---------------------
|
123
|
+
#
|
124
|
+
private
|
125
|
+
|
126
|
+
# SBC instance states mapped to DeltaCloud
|
127
|
+
@@INSTANCE_STATE_MAP = {
|
128
|
+
0 => "PENDING", # New
|
129
|
+
1 => "PENDING", # Provisioning
|
130
|
+
2 => "STOPPED", # Failed
|
131
|
+
3 => "STOPPED", # Removed
|
132
|
+
4 => "STOPPED", # Rejected
|
133
|
+
5 => "RUNNING", # Active
|
134
|
+
6 => "STOPPED", # Unknown
|
135
|
+
7 => "PENDING", # Deprovisioning
|
136
|
+
8 => "PENDING", # Restarting
|
137
|
+
9 => "PENDING", # Starting
|
138
|
+
10 => "SHUTTING_DOWN", # Stopping
|
139
|
+
11 => "STOPPED", # Stopped
|
140
|
+
12 => "PENDING", # Deprovision pending
|
141
|
+
13 => "PENDING", # Restart pending
|
142
|
+
14 => "PENDING", # Attaching
|
143
|
+
15 => "PENDING" # Detaching
|
144
|
+
}
|
145
|
+
|
146
|
+
# SBC image states mapped to DeltaCloud
|
147
|
+
@@IMAGE_STATE_MAP = {
|
148
|
+
0 => "UNAVAILABLE", # New
|
149
|
+
1 => "AVAILABLE", # Available
|
150
|
+
2 => "UNAVAILABLE", # Unavailable
|
151
|
+
3 => "UNAVAILABLE", # Deleted
|
152
|
+
4 => "UNAVAILABLE" # Capturing
|
153
|
+
}
|
154
|
+
|
155
|
+
# SBC location states mapped to DeltaCloud
|
156
|
+
@@LOCATION_STATE_MAP = {
|
157
|
+
0 => "UNAVAILABLE", # Unavailable
|
158
|
+
1 => "AVAILABLE" # Available
|
159
|
+
}
|
160
|
+
|
161
|
+
#
|
162
|
+
# Define state machine for instances
|
163
|
+
#
|
164
|
+
define_instance_states do
|
165
|
+
start.to( :pending ) .automatically
|
166
|
+
pending.to( :running ) .automatically
|
167
|
+
running.to( :running ) .on( :reboot )
|
168
|
+
running.to( :finish ) .on( :destroy )
|
169
|
+
end
|
170
|
+
|
171
|
+
#
|
172
|
+
# Creates an IBM SBC client
|
173
|
+
#
|
174
|
+
def new_client(credentials)
|
175
|
+
safely do
|
176
|
+
return SBCClient.new(credentials.user, credentials.password)
|
177
|
+
end
|
178
|
+
end
|
179
|
+
|
180
|
+
#
|
181
|
+
# Converts JSON to an instance
|
182
|
+
#
|
183
|
+
def convert_instance(instance)
|
184
|
+
state = @@INSTANCE_STATE_MAP[instance["status"]]
|
185
|
+
Instance.new(
|
186
|
+
:id => instance["id"],
|
187
|
+
:owner_id => instance["owner"],
|
188
|
+
:image_id => instance["imageId"],
|
189
|
+
:name => instance["name"],
|
190
|
+
:realm_id => instance["location"],
|
191
|
+
:state => state,
|
192
|
+
:actions => instance_actions_for(state),
|
193
|
+
:public_addresses => [instance["primaryIP"]["ip"]],
|
194
|
+
:private_addresses => [],
|
195
|
+
:instance_profile => InstanceProfile.new(instance["instanceType"].gsub('/', '-')),
|
196
|
+
:launch_time => instance["launchTime"],
|
197
|
+
:keyname => instance["keyName"]
|
198
|
+
)
|
199
|
+
end
|
200
|
+
|
201
|
+
#
|
202
|
+
# Converts JSON to an image
|
203
|
+
#
|
204
|
+
def convert_image(image)
|
205
|
+
Image.new(
|
206
|
+
:id => image["id"],
|
207
|
+
:name => image["name"],
|
208
|
+
:owner_id => image["owner"],
|
209
|
+
:description => image["description"],
|
210
|
+
:architecture => "i386", # TODO: parse this from supportedInstanceType IDs w/ HW profile lookup
|
211
|
+
:state => @@IMAGE_STATE_MAP[image["state"]]
|
212
|
+
)
|
213
|
+
end
|
214
|
+
|
215
|
+
#
|
216
|
+
# Converts XML to a location
|
217
|
+
#
|
218
|
+
def convert_location(location)
|
219
|
+
Realm.new(
|
220
|
+
:id => location.xpath('ID').text,
|
221
|
+
:name => location.xpath('Name').text,
|
222
|
+
:limit => :unlimited,
|
223
|
+
:state => @@LOCATION_STATE_MAP[location.xpath('State').text.to_i]
|
224
|
+
)
|
225
|
+
end
|
226
|
+
|
227
|
+
#
|
228
|
+
# -------------------- Hardware Profiles -----------------
|
229
|
+
#
|
230
|
+
# TODO: HWP IDs contain '/'; results in invalid URL
|
231
|
+
#
|
232
|
+
define_hardware_profile('COP32.1-2048-60') do
|
233
|
+
cpu 1
|
234
|
+
memory 2 * 1024
|
235
|
+
storage 60
|
236
|
+
architecture 'i386'
|
237
|
+
end
|
238
|
+
|
239
|
+
define_hardware_profile('COP64.2-4096-60') do
|
240
|
+
cpu 2
|
241
|
+
memory 4 * 1024
|
242
|
+
storage 60
|
243
|
+
architecture 'i386_x64'
|
244
|
+
end
|
245
|
+
|
246
|
+
define_hardware_profile('BRZ32.1-2048-60*175') do
|
247
|
+
cpu 1
|
248
|
+
memory 2 * 1024
|
249
|
+
storage 175
|
250
|
+
architecture 'i386'
|
251
|
+
end
|
252
|
+
|
253
|
+
define_hardware_profile('BRZ64.2-4096-60*500*350') do
|
254
|
+
cpu 2
|
255
|
+
memory 4 * 1024
|
256
|
+
storage 850
|
257
|
+
architecture 'i386_x64'
|
258
|
+
end
|
259
|
+
|
260
|
+
define_hardware_profile('SLV32.2-4096-60*350') do
|
261
|
+
cpu 3
|
262
|
+
memory 5 * 1024
|
263
|
+
storage 350
|
264
|
+
architecture 'i386'
|
265
|
+
end
|
266
|
+
|
267
|
+
define_hardware_profile('SLV64.4-8192-60*500*500') do
|
268
|
+
cpu 4
|
269
|
+
memory 8 * 1024
|
270
|
+
storage 1024
|
271
|
+
architecture 'i386_x64'
|
272
|
+
end
|
273
|
+
|
274
|
+
define_hardware_profile('GLD32.4-4096-60*350') do
|
275
|
+
cpu 4
|
276
|
+
memory 4 * 1024
|
277
|
+
storage 350
|
278
|
+
architecture 'i386'
|
279
|
+
end
|
280
|
+
|
281
|
+
define_hardware_profile('GLD64.8-16384-60*500*500') do
|
282
|
+
cpu 8
|
283
|
+
memory 16 * 1024
|
284
|
+
storage 1024
|
285
|
+
architecture 'i386_x64'
|
286
|
+
end
|
287
|
+
|
288
|
+
define_hardware_profile('PLT64.16-16384-60*500*500*500*500') do
|
289
|
+
cpu 16
|
290
|
+
memory 16 * 1024
|
291
|
+
storage 2048
|
292
|
+
architecture 'i386_x64'
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|