bbrowning-deltacloud-core 0.0.4-java
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.
- data/COPYING +176 -0
- data/Rakefile +99 -0
- data/bin/deltacloudd +120 -0
- data/config.ru +5 -0
- data/deltacloud.rb +18 -0
- data/lib/deltacloud/base_driver/base_driver.rb +229 -0
- data/lib/deltacloud/base_driver/features.rb +166 -0
- data/lib/deltacloud/base_driver/mock_driver.rb +40 -0
- data/lib/deltacloud/base_driver.rb +20 -0
- data/lib/deltacloud/drivers/ec2/ec2_driver.rb +410 -0
- data/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb +170 -0
- data/lib/deltacloud/drivers/gogrid/gogrid_client.rb +50 -0
- data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +332 -0
- data/lib/deltacloud/drivers/gogrid/test.rb +13 -0
- data/lib/deltacloud/drivers/mock/data/images/img1.yml +3 -0
- data/lib/deltacloud/drivers/mock/data/images/img2.yml +3 -0
- data/lib/deltacloud/drivers/mock/data/images/img3.yml +3 -0
- data/lib/deltacloud/drivers/mock/data/instances/inst0.yml +16 -0
- data/lib/deltacloud/drivers/mock/data/instances/inst1.yml +9 -0
- data/lib/deltacloud/drivers/mock/data/instances/inst2.yml +9 -0
- data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap1.yml +4 -0
- data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap2.yml +4 -0
- data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap3.yml +4 -0
- data/lib/deltacloud/drivers/mock/data/storage_volumes/vol1.yml +6 -0
- data/lib/deltacloud/drivers/mock/data/storage_volumes/vol2.yml +6 -0
- data/lib/deltacloud/drivers/mock/data/storage_volumes/vol3.yml +6 -0
- data/lib/deltacloud/drivers/mock/mock_driver.rb +277 -0
- data/lib/deltacloud/drivers/opennebula/cloud_client.rb +116 -0
- data/lib/deltacloud/drivers/opennebula/occi_client.rb +204 -0
- data/lib/deltacloud/drivers/opennebula/opennebula_driver.rb +241 -0
- data/lib/deltacloud/drivers/rackspace/rackspace_client.rb +130 -0
- data/lib/deltacloud/drivers/rackspace/rackspace_driver.rb +182 -0
- data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +255 -0
- data/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb +85 -0
- data/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb +166 -0
- data/lib/deltacloud/drivers/terremark/terremark_driver.rb +286 -0
- data/lib/deltacloud/hardware_profile.rb +153 -0
- data/lib/deltacloud/helpers/application_helper.rb +115 -0
- data/lib/deltacloud/helpers/conversion_helper.rb +39 -0
- data/lib/deltacloud/helpers/hardware_profiles_helper.rb +35 -0
- data/lib/deltacloud/helpers.rb +5 -0
- data/lib/deltacloud/method_serializer.rb +85 -0
- data/lib/deltacloud/models/base_model.rb +59 -0
- data/lib/deltacloud/models/image.rb +27 -0
- data/lib/deltacloud/models/instance.rb +38 -0
- data/lib/deltacloud/models/instance_profile.rb +48 -0
- data/lib/deltacloud/models/key.rb +35 -0
- data/lib/deltacloud/models/realm.rb +26 -0
- data/lib/deltacloud/models/storage_snapshot.rb +27 -0
- data/lib/deltacloud/models/storage_volume.rb +28 -0
- data/lib/deltacloud/state_machine.rb +84 -0
- data/lib/deltacloud/validation.rb +70 -0
- data/lib/drivers.rb +50 -0
- data/lib/sinatra/accept_media_types.rb +128 -0
- data/lib/sinatra/lazy_auth.rb +56 -0
- data/lib/sinatra/rabbit.rb +273 -0
- data/lib/sinatra/respond_to.rb +272 -0
- data/lib/sinatra/static_assets.rb +83 -0
- data/lib/sinatra/url_for.rb +53 -0
- data/public/favicon.ico +0 -0
- data/public/images/grid.png +0 -0
- data/public/images/logo-wide.png +0 -0
- data/public/images/rails.png +0 -0
- data/public/images/topbar-bg.png +0 -0
- data/public/javascripts/application.js +32 -0
- data/public/javascripts/jquery-1.4.2.min.js +154 -0
- data/public/stylesheets/compiled/application.css +613 -0
- data/public/stylesheets/compiled/ie.css +31 -0
- data/public/stylesheets/compiled/print.css +27 -0
- data/public/stylesheets/compiled/screen.css +456 -0
- data/server.rb +354 -0
- data/support/fedora/deltacloudd +68 -0
- data/support/fedora/rubygem-deltacloud-core.spec +91 -0
- data/tests/api_test.rb +37 -0
- data/tests/hardware_profiles_test.rb +120 -0
- data/tests/images_test.rb +111 -0
- data/tests/instance_states_test.rb +52 -0
- data/tests/instances_test.rb +219 -0
- data/tests/realms_test.rb +78 -0
- data/tests/url_for_test.rb +50 -0
- data/views/accounts/index.html.haml +11 -0
- data/views/accounts/show.html.haml +30 -0
- data/views/api/show.html.haml +15 -0
- data/views/api/show.xml.haml +5 -0
- data/views/docs/collection.html.haml +37 -0
- data/views/docs/collection.xml.haml +14 -0
- data/views/docs/index.html.haml +15 -0
- data/views/docs/index.xml.haml +5 -0
- data/views/docs/operation.html.haml +31 -0
- data/views/docs/operation.xml.haml +10 -0
- data/views/errors/auth_exception.html.haml +8 -0
- data/views/errors/auth_exception.xml.haml +2 -0
- data/views/errors/backend_error.html.haml +19 -0
- data/views/errors/backend_error.xml.haml +8 -0
- data/views/errors/not_found.html.haml +6 -0
- data/views/errors/not_found.xml.haml +2 -0
- data/views/errors/validation_failure.html.haml +11 -0
- data/views/errors/validation_failure.xml.haml +7 -0
- data/views/hardware_profiles/index.html.haml +25 -0
- data/views/hardware_profiles/index.xml.haml +4 -0
- data/views/hardware_profiles/show.html.haml +19 -0
- data/views/hardware_profiles/show.xml.haml +18 -0
- data/views/images/index.html.haml +30 -0
- data/views/images/index.xml.haml +8 -0
- data/views/images/show.html.haml +21 -0
- data/views/images/show.xml.haml +5 -0
- data/views/instance_states/show.gv.erb +45 -0
- data/views/instance_states/show.html.haml +31 -0
- data/views/instance_states/show.xml.haml +8 -0
- data/views/instances/index.html.haml +30 -0
- data/views/instances/index.xml.haml +21 -0
- data/views/instances/new.html.haml +55 -0
- data/views/instances/show.html.haml +43 -0
- data/views/instances/show.xml.haml +49 -0
- data/views/keys/index.html.haml +26 -0
- data/views/keys/index.xml.haml +4 -0
- data/views/keys/new.html.haml +8 -0
- data/views/keys/show.html.haml +22 -0
- data/views/keys/show.xml.haml +20 -0
- data/views/layout.html.haml +26 -0
- data/views/realms/index.html.haml +29 -0
- data/views/realms/index.xml.haml +10 -0
- data/views/realms/show.html.haml +15 -0
- data/views/realms/show.xml.haml +9 -0
- data/views/root/index.html.haml +4 -0
- data/views/storage_snapshots/index.html.haml +20 -0
- data/views/storage_snapshots/index.xml.haml +9 -0
- data/views/storage_snapshots/show.html.haml +14 -0
- data/views/storage_snapshots/show.xml.haml +7 -0
- data/views/storage_volumes/index.html.haml +21 -0
- data/views/storage_volumes/index.xml.haml +13 -0
- data/views/storage_volumes/show.html.haml +20 -0
- data/views/storage_volumes/show.xml.haml +11 -0
- metadata +334 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
#--------------------------------------------------------------------------- #
|
|
2
|
+
# Copyright 2002-2009, Distributed Systems Architecture Group, Universidad
|
|
3
|
+
# Complutense de Madrid (dsa-research.org)
|
|
4
|
+
#
|
|
5
|
+
# This library is free software; you can redistribute it and/or
|
|
6
|
+
# modify it under the terms of the GNU Lesser General Public
|
|
7
|
+
# License as published by the Free Software Foundation; either
|
|
8
|
+
# version 2.1 of the License, or (at your option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# This library is distributed in the hope that it will be useful,
|
|
11
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
12
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
13
|
+
# Lesser General Public License for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Lesser General Public
|
|
16
|
+
# License along with this library; if not, write to the Free Software
|
|
17
|
+
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
18
|
+
#--------------------------------------------------------------------------- #
|
|
19
|
+
|
|
20
|
+
require 'deltacloud/base_driver'
|
|
21
|
+
|
|
22
|
+
require 'erb'
|
|
23
|
+
require 'rexml/document'
|
|
24
|
+
|
|
25
|
+
path = File.dirname(__FILE__)
|
|
26
|
+
$: << path
|
|
27
|
+
|
|
28
|
+
require 'occi_client'
|
|
29
|
+
|
|
30
|
+
module Deltacloud
|
|
31
|
+
module Drivers
|
|
32
|
+
module Opennebula
|
|
33
|
+
|
|
34
|
+
class OpennebulaDriver < Deltacloud::BaseDriver
|
|
35
|
+
|
|
36
|
+
######################################################################
|
|
37
|
+
# Hardware profiles
|
|
38
|
+
######################################################################
|
|
39
|
+
|
|
40
|
+
define_hardware_profile 'small'
|
|
41
|
+
|
|
42
|
+
define_hardware_profile 'medium'
|
|
43
|
+
|
|
44
|
+
define_hardware_profile 'large'
|
|
45
|
+
|
|
46
|
+
######################################################################
|
|
47
|
+
# Realms
|
|
48
|
+
######################################################################
|
|
49
|
+
|
|
50
|
+
(REALMS = [
|
|
51
|
+
Realm.new( {
|
|
52
|
+
:id=>'Any id',
|
|
53
|
+
:name=>'Any name',
|
|
54
|
+
:limit=>:unlimited,
|
|
55
|
+
:state=>'Any state',
|
|
56
|
+
} ),
|
|
57
|
+
] ) unless defined?( REALMS )
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def realms(credentials, opts=nil)
|
|
61
|
+
return REALMS if ( opts.nil? )
|
|
62
|
+
results = REALMS
|
|
63
|
+
results = filter_on( results, :id, opts )
|
|
64
|
+
results
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
######################################################################
|
|
69
|
+
# Images
|
|
70
|
+
######################################################################
|
|
71
|
+
|
|
72
|
+
def images(credentials, opts=nil)
|
|
73
|
+
occi_client = new_client(credentials)
|
|
74
|
+
|
|
75
|
+
images = []
|
|
76
|
+
imagesxml = occi_client.get_images
|
|
77
|
+
|
|
78
|
+
storage = REXML::Document.new(imagesxml)
|
|
79
|
+
storage.root.elements.each do |d|
|
|
80
|
+
id = d.attributes['href'].split("/").last
|
|
81
|
+
|
|
82
|
+
diskxml = occi_client.get_image(id)
|
|
83
|
+
|
|
84
|
+
images << convert_image(diskxml.to_s(), credentials)
|
|
85
|
+
end
|
|
86
|
+
images
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
######################################################################
|
|
91
|
+
# Instances
|
|
92
|
+
######################################################################
|
|
93
|
+
|
|
94
|
+
define_instance_states do
|
|
95
|
+
start.to( :pending ) .on( :create )
|
|
96
|
+
|
|
97
|
+
pending.to( :running ) .automatically
|
|
98
|
+
|
|
99
|
+
running.to( :stopped ) .on( :stop )
|
|
100
|
+
|
|
101
|
+
stopped.to( :running ) .on( :start )
|
|
102
|
+
stopped.to( :finish ) .on( :destroy )
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def instances(credentials, opts=nil)
|
|
107
|
+
occi_client = new_client(credentials)
|
|
108
|
+
|
|
109
|
+
instances = []
|
|
110
|
+
instancesxml = occi_client.get_vms
|
|
111
|
+
|
|
112
|
+
computes = REXML::Document.new(instancesxml)
|
|
113
|
+
computes.root.elements.each do |d|
|
|
114
|
+
vm_id = d.attributes['href'].split("/").last
|
|
115
|
+
|
|
116
|
+
computexml = occi_client.get_vm(vm_id)
|
|
117
|
+
|
|
118
|
+
instances << convert_instance(computexml.to_s(), credentials)
|
|
119
|
+
end
|
|
120
|
+
instances = filter_on( instances, :id, opts )
|
|
121
|
+
instances = filter_on( instances, :state, opts )
|
|
122
|
+
instances
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
def create_instance(credentials, image_id, opts=nil)
|
|
127
|
+
occi_client = new_client(credentials)
|
|
128
|
+
|
|
129
|
+
hwp_id = opts[:hwp_id] || 'small'
|
|
130
|
+
|
|
131
|
+
instancexml = ERB.new(OCCI_VM).result(binding)
|
|
132
|
+
instancefile = "|echo '#{instancexml}'"
|
|
133
|
+
|
|
134
|
+
xmlvm = occi_client.post_vms(instancefile)
|
|
135
|
+
|
|
136
|
+
convert_instance(xmlvm.to_s(), credentials)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def start_instance(credentials, id)
|
|
141
|
+
occi_action(credentials, id, 'RESUME')
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
def stop_instance(credentials, id)
|
|
146
|
+
occi_action(credentials, id, 'STOPPED')
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
def destroy_instance(credentials, id)
|
|
151
|
+
occi_action(credentials, id, 'DONE')
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
private
|
|
157
|
+
|
|
158
|
+
def new_client(credentials)
|
|
159
|
+
OCCIClient::Client.new(nil, credentials.user, credentials.password, false)
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
def convert_image(diskxml, credentials)
|
|
164
|
+
disk = REXML::Document.new(diskxml)
|
|
165
|
+
diskhash = disk.root.elements
|
|
166
|
+
|
|
167
|
+
Image.new( {
|
|
168
|
+
:id=>diskhash['ID'].text,
|
|
169
|
+
:name=>diskhash['NAME'].text,
|
|
170
|
+
:description=>diskhash['NAME'].text,
|
|
171
|
+
:owner_id=>credentials.user,
|
|
172
|
+
:architecture=>'Any architecture',
|
|
173
|
+
} )
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
def convert_instance(computexml, credentials)
|
|
178
|
+
compute = REXML::Document.new(computexml)
|
|
179
|
+
computehash = compute.root.elements
|
|
180
|
+
|
|
181
|
+
imageid = computehash['STORAGE/DISK[@type="disk"]'].attributes['href'].split("/").last
|
|
182
|
+
|
|
183
|
+
state = (computehash['STATE'].text == 'ACTIVE') ? 'RUNNING' : computehash['STATE'].text
|
|
184
|
+
|
|
185
|
+
hwp_name = computehash['INSTANCE_TYPE'] || 'small'
|
|
186
|
+
|
|
187
|
+
networks = []
|
|
188
|
+
(computehash['NETWORK'].each do |n|
|
|
189
|
+
networks << n.attributes['ip']
|
|
190
|
+
end) unless computehash['NETWORK'].nil?
|
|
191
|
+
|
|
192
|
+
Instance.new( {
|
|
193
|
+
:id=>computehash['ID'].text,
|
|
194
|
+
:owner_id=>credentials.user,
|
|
195
|
+
:name=>computehash['NAME'].text,
|
|
196
|
+
:image_id=>imageid,
|
|
197
|
+
:instance_profile=>InstanceProfile.new(hwp_name),
|
|
198
|
+
:realm_id=>'Any realm',
|
|
199
|
+
:state=>state,
|
|
200
|
+
:public_addreses=>networks,
|
|
201
|
+
:private_addreses=>networks,
|
|
202
|
+
:actions=> instance_actions_for( state )
|
|
203
|
+
} )
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
|
|
207
|
+
def occi_action(credentials, id, strstate)
|
|
208
|
+
occi_client = new_client(credentials)
|
|
209
|
+
|
|
210
|
+
actionxml = ERB.new(OCCI_ACTION).result(binding)
|
|
211
|
+
actionfile = "|echo '#{actionxml}'"
|
|
212
|
+
|
|
213
|
+
xmlvm = occi_client.put_vm(actionfile)
|
|
214
|
+
|
|
215
|
+
convert_instance(xmlvm.to_s(), credentials)
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
(OCCI_VM = %q{
|
|
220
|
+
<COMPUTE>
|
|
221
|
+
<NAME><%=opts[:name]%></NAME>
|
|
222
|
+
<INSTANCE_TYPE><%= hwp_id %></INSTANCE_TYPE>
|
|
223
|
+
<STORAGE>
|
|
224
|
+
<DISK image="<%= image_id %>" dev="sda1" />
|
|
225
|
+
</STORAGE>
|
|
226
|
+
</COMPUTE>
|
|
227
|
+
}.gsub(/^ /, '') ) unless defined?( OCCI_VM )
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
(OCCI_ACTION = %q{
|
|
231
|
+
<COMPUTE>
|
|
232
|
+
<ID><%= id %></ID>
|
|
233
|
+
<STATE><%= strstate %></STATE>
|
|
234
|
+
</COMPUTE>
|
|
235
|
+
}.gsub(/^ /, '') ) unless defined?( OCCI_ACTION )
|
|
236
|
+
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
end
|
|
240
|
+
end
|
|
241
|
+
end
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (C) 2009 Red Hat, Inc.
|
|
3
|
+
#
|
|
4
|
+
# Licensed to the Apache Software Foundation (ASF) under one or more
|
|
5
|
+
# contributor license agreements. See the NOTICE file distributed with
|
|
6
|
+
# this work for additional information regarding copyright ownership. The
|
|
7
|
+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
8
|
+
# "License"); you may not use this file except in compliance with the
|
|
9
|
+
# License. You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
15
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
16
|
+
# License for the specific language governing permissions and limitations
|
|
17
|
+
# under the License.
|
|
18
|
+
|
|
19
|
+
require "net/http"
|
|
20
|
+
require "net/https"
|
|
21
|
+
require 'rubygems'
|
|
22
|
+
require 'json'
|
|
23
|
+
|
|
24
|
+
#
|
|
25
|
+
# author: Michael Neale
|
|
26
|
+
# TODO: catch generic errors in JSON response and throw (probably)
|
|
27
|
+
#
|
|
28
|
+
module Deltacloud
|
|
29
|
+
module Drivers
|
|
30
|
+
module Rackspace
|
|
31
|
+
|
|
32
|
+
class RackspaceClient
|
|
33
|
+
|
|
34
|
+
@@AUTH_API = URI.parse('https://auth.api.rackspacecloud.com/v1.0')
|
|
35
|
+
|
|
36
|
+
def initialize(username, auth_key)
|
|
37
|
+
http = Net::HTTP.new(@@AUTH_API.host,@@AUTH_API.port)
|
|
38
|
+
http.use_ssl = true
|
|
39
|
+
authed = http.get(@@AUTH_API.path, {'X-Auth-User' => username, 'X-Auth-Key' => auth_key})
|
|
40
|
+
if authed.is_a?(Net::HTTPUnauthorized)
|
|
41
|
+
raise Deltacloud::AuthException, "Failed to authenticate to Rackspace"
|
|
42
|
+
elsif !authed.is_a?(Net::HTTPSuccess)
|
|
43
|
+
backend_error!(resp)
|
|
44
|
+
end
|
|
45
|
+
@auth_token = authed.header['X-Auth-Token']
|
|
46
|
+
@service_uri = URI.parse(authed.header['X-Server-Management-Url'])
|
|
47
|
+
@service = Net::HTTP.new(@service_uri.host, @service_uri.port)
|
|
48
|
+
@service.use_ssl = true
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def list_flavors
|
|
52
|
+
JSON.parse(get('/flavors/detail'))['flavors']
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def list_images
|
|
56
|
+
JSON.parse(get('/images/detail'))['images']
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def list_servers
|
|
60
|
+
JSON.parse(get('/servers/detail'))['servers']
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def load_server_details( server_id )
|
|
65
|
+
JSON.parse(get("/servers/#{server_id}"))['server']
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def start_server(image_id, flavor_id, name)
|
|
70
|
+
json = { :server => { :name => name,
|
|
71
|
+
:imageId => image_id.to_i,
|
|
72
|
+
:flavorId => flavor_id.to_i }}.to_json
|
|
73
|
+
# FIXME: The response has the root password in 'adminPass'; we somehow
|
|
74
|
+
# need to communicate this back since it's the only place where we can
|
|
75
|
+
# get it from
|
|
76
|
+
JSON.parse(post("/servers", json, headers).body)["server"]
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def delete_server(server_id)
|
|
80
|
+
delete("/servers/#{server_id}", headers)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def reboot_server(server_id)
|
|
84
|
+
json = { :reboot => { :type => :SOFT }}.to_json
|
|
85
|
+
post("/servers/#{server_id}/action", json, headers)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def headers
|
|
90
|
+
{"Accept" => "application/json", "X-Auth-Token" => @auth_token, "Content-Type" => "application/json"}
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
private
|
|
94
|
+
def get(path)
|
|
95
|
+
resp = @service.get(@service_uri.path + path, {"Accept" => "application/json", "X-Auth-Token" => @auth_token})
|
|
96
|
+
unless resp.is_a?(Net::HTTPSuccess)
|
|
97
|
+
backend_error!(resp)
|
|
98
|
+
end
|
|
99
|
+
resp.body
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def post(path, json, headers)
|
|
103
|
+
resp = @service.post(@service_uri.path + path, json, headers)
|
|
104
|
+
unless resp.is_a?(Net::HTTPSuccess)
|
|
105
|
+
backend_error!(resp)
|
|
106
|
+
end
|
|
107
|
+
resp
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def delete(path, headers)
|
|
111
|
+
resp = @service.delete(@service_uri.path + path, headers)
|
|
112
|
+
unless resp.is_a?(Net::HTTPSuccess)
|
|
113
|
+
backend_error!(resp)
|
|
114
|
+
end
|
|
115
|
+
resp
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def backend_error!(resp)
|
|
119
|
+
json = JSON.parse(resp.body)
|
|
120
|
+
cause = json.keys[0]
|
|
121
|
+
code = json[cause]["code"]
|
|
122
|
+
message = json[cause]["message"]
|
|
123
|
+
details = json[cause]["details"]
|
|
124
|
+
raise Deltacloud::BackendError.new(code, cause, message, details)
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
end
|
|
130
|
+
end
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
#
|
|
2
|
+
# Copyright (C) 2009 Red Hat, Inc.
|
|
3
|
+
#
|
|
4
|
+
# Licensed to the Apache Software Foundation (ASF) under one or more
|
|
5
|
+
# contributor license agreements. See the NOTICE file distributed with
|
|
6
|
+
# this work for additional information regarding copyright ownership. The
|
|
7
|
+
# ASF licenses this file to you under the Apache License, Version 2.0 (the
|
|
8
|
+
# "License"); you may not use this file except in compliance with the
|
|
9
|
+
# License. You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
|
15
|
+
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
|
16
|
+
# License for the specific language governing permissions and limitations
|
|
17
|
+
# under the License.
|
|
18
|
+
|
|
19
|
+
require 'deltacloud/base_driver'
|
|
20
|
+
require 'deltacloud/drivers/rackspace/rackspace_client'
|
|
21
|
+
|
|
22
|
+
module Deltacloud
|
|
23
|
+
module Drivers
|
|
24
|
+
module Rackspace
|
|
25
|
+
|
|
26
|
+
class RackspaceDriver < Deltacloud::BaseDriver
|
|
27
|
+
|
|
28
|
+
feature :instances, :user_name
|
|
29
|
+
|
|
30
|
+
def hardware_profiles(credentials, opts = nil)
|
|
31
|
+
racks = new_client( credentials )
|
|
32
|
+
safely do
|
|
33
|
+
results = racks.list_flavors.map do |flav|
|
|
34
|
+
HardwareProfile.new(flav["id"].to_s) do
|
|
35
|
+
architecture 'x86_64'
|
|
36
|
+
memory flav["ram"].to_i
|
|
37
|
+
storage flav["disk"].to_i
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
filter_hardware_profiles(results, opts)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def images(credentials, opts=nil)
|
|
45
|
+
racks = new_client( credentials )
|
|
46
|
+
safely do
|
|
47
|
+
results = racks.list_images.map do |img|
|
|
48
|
+
Image.new( {
|
|
49
|
+
:id=>img["id"].to_s,
|
|
50
|
+
:name=>img["name"],
|
|
51
|
+
:description => img["name"] + " " + img["status"] + "",
|
|
52
|
+
:owner_id=>"root",
|
|
53
|
+
:architecture=>'x86_64'
|
|
54
|
+
} )
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
results.sort_by{|e| [e.description]}
|
|
58
|
+
results = filter_on( results, :id, opts )
|
|
59
|
+
results
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
#rackspace does not at this stage have realms... its all US/TX, all the time (at least at time of writing)
|
|
63
|
+
def realms(credentials, opts=nil)
|
|
64
|
+
[Realm.new( {
|
|
65
|
+
:id=>"us",
|
|
66
|
+
:name=>"United States",
|
|
67
|
+
:state=> "AVAILABLE"
|
|
68
|
+
} )]
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def reboot_instance(credentials, id)
|
|
72
|
+
racks = new_client(credentials)
|
|
73
|
+
safely do
|
|
74
|
+
racks.reboot_server(id)
|
|
75
|
+
end
|
|
76
|
+
Instance.new( {
|
|
77
|
+
:id => id,
|
|
78
|
+
:state => "REBOOT",
|
|
79
|
+
:actions => instance_actions_for( state ),
|
|
80
|
+
} )
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def stop_instance(credentials, id)
|
|
84
|
+
destroy_instance(credentials, id)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def destroy_instance(credentials, id)
|
|
88
|
+
racks = new_client(credentials)
|
|
89
|
+
safely do
|
|
90
|
+
racks.delete_server(id)
|
|
91
|
+
end
|
|
92
|
+
Instance.new( {
|
|
93
|
+
:id => id,
|
|
94
|
+
:state => "STOPPED",
|
|
95
|
+
:actions => instance_actions_for( "STOPPED" ),
|
|
96
|
+
} )
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
#
|
|
101
|
+
# create instance. Default to flavor 1 - really need a name though...
|
|
102
|
+
# In rackspace, all flavors work with all images.
|
|
103
|
+
#
|
|
104
|
+
def create_instance(credentials, image_id, opts)
|
|
105
|
+
racks = new_client( credentials )
|
|
106
|
+
hwp_id = opts[:hwp_id] || 1
|
|
107
|
+
name = Time.now.to_s
|
|
108
|
+
if (opts[:name]) then name = opts[:name] end
|
|
109
|
+
safely do
|
|
110
|
+
return convert_srv_to_instance(racks.start_server(image_id, hwp_id, name))
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
#
|
|
115
|
+
# Instances
|
|
116
|
+
#
|
|
117
|
+
def instances(credentials, opts=nil)
|
|
118
|
+
racks = new_client(credentials)
|
|
119
|
+
instances = []
|
|
120
|
+
safely do
|
|
121
|
+
if (opts.nil?)
|
|
122
|
+
instances = racks.list_servers.map do |srv|
|
|
123
|
+
convert_srv_to_instance(srv)
|
|
124
|
+
end
|
|
125
|
+
else
|
|
126
|
+
instances << convert_srv_to_instance(racks.load_server_details(opts[:id]))
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
instances = filter_on( instances, :id, opts )
|
|
130
|
+
instances = filter_on( instances, :state, opts )
|
|
131
|
+
instances
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def convert_srv_to_instance(srv)
|
|
136
|
+
inst = Instance.new(:id => srv["id"].to_s,
|
|
137
|
+
:owner_id => "root",
|
|
138
|
+
:realm_id => "us")
|
|
139
|
+
inst.name = srv["name"]
|
|
140
|
+
inst.state = srv["status"] == "ACTIVE" ? "RUNNING" : "PENDING"
|
|
141
|
+
inst.actions = instance_actions_for(inst.state)
|
|
142
|
+
inst.image_id = srv["imageId"].to_s
|
|
143
|
+
inst.instance_profile = InstanceProfile.new(srv["flavorId"].to_s)
|
|
144
|
+
if srv["addresses"]
|
|
145
|
+
inst.public_addresses = srv["addresses"]["public"]
|
|
146
|
+
inst.private_addresses = srv["addresses"]["private"]
|
|
147
|
+
end
|
|
148
|
+
inst
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
def new_client(credentials)
|
|
152
|
+
safely do
|
|
153
|
+
return RackspaceClient.new(credentials.user, credentials.password)
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
define_instance_states do
|
|
158
|
+
start.to( :pending ) .on( :create )
|
|
159
|
+
|
|
160
|
+
pending.to( :running ) .automatically
|
|
161
|
+
|
|
162
|
+
running.to( :running ) .on( :reboot )
|
|
163
|
+
running.to( :shutting_down ) .on( :stop )
|
|
164
|
+
|
|
165
|
+
shutting_down.to( :stopped ) .automatically
|
|
166
|
+
|
|
167
|
+
stopped.to( :finish ) .automatically
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def safely(&block)
|
|
171
|
+
begin
|
|
172
|
+
block.call
|
|
173
|
+
rescue Exception => e
|
|
174
|
+
raise Deltacloud::BackendError.new(500, e.class.to_s, e.message, e.backtrace)
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
end
|
|
181
|
+
end
|
|
182
|
+
end
|