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.
Files changed (134) hide show
  1. data/COPYING +176 -0
  2. data/Rakefile +99 -0
  3. data/bin/deltacloudd +120 -0
  4. data/config.ru +5 -0
  5. data/deltacloud.rb +18 -0
  6. data/lib/deltacloud/base_driver/base_driver.rb +229 -0
  7. data/lib/deltacloud/base_driver/features.rb +166 -0
  8. data/lib/deltacloud/base_driver/mock_driver.rb +40 -0
  9. data/lib/deltacloud/base_driver.rb +20 -0
  10. data/lib/deltacloud/drivers/ec2/ec2_driver.rb +410 -0
  11. data/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb +170 -0
  12. data/lib/deltacloud/drivers/gogrid/gogrid_client.rb +50 -0
  13. data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +332 -0
  14. data/lib/deltacloud/drivers/gogrid/test.rb +13 -0
  15. data/lib/deltacloud/drivers/mock/data/images/img1.yml +3 -0
  16. data/lib/deltacloud/drivers/mock/data/images/img2.yml +3 -0
  17. data/lib/deltacloud/drivers/mock/data/images/img3.yml +3 -0
  18. data/lib/deltacloud/drivers/mock/data/instances/inst0.yml +16 -0
  19. data/lib/deltacloud/drivers/mock/data/instances/inst1.yml +9 -0
  20. data/lib/deltacloud/drivers/mock/data/instances/inst2.yml +9 -0
  21. data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap1.yml +4 -0
  22. data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap2.yml +4 -0
  23. data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap3.yml +4 -0
  24. data/lib/deltacloud/drivers/mock/data/storage_volumes/vol1.yml +6 -0
  25. data/lib/deltacloud/drivers/mock/data/storage_volumes/vol2.yml +6 -0
  26. data/lib/deltacloud/drivers/mock/data/storage_volumes/vol3.yml +6 -0
  27. data/lib/deltacloud/drivers/mock/mock_driver.rb +277 -0
  28. data/lib/deltacloud/drivers/opennebula/cloud_client.rb +116 -0
  29. data/lib/deltacloud/drivers/opennebula/occi_client.rb +204 -0
  30. data/lib/deltacloud/drivers/opennebula/opennebula_driver.rb +241 -0
  31. data/lib/deltacloud/drivers/rackspace/rackspace_client.rb +130 -0
  32. data/lib/deltacloud/drivers/rackspace/rackspace_driver.rb +182 -0
  33. data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +255 -0
  34. data/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb +85 -0
  35. data/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb +166 -0
  36. data/lib/deltacloud/drivers/terremark/terremark_driver.rb +286 -0
  37. data/lib/deltacloud/hardware_profile.rb +153 -0
  38. data/lib/deltacloud/helpers/application_helper.rb +115 -0
  39. data/lib/deltacloud/helpers/conversion_helper.rb +39 -0
  40. data/lib/deltacloud/helpers/hardware_profiles_helper.rb +35 -0
  41. data/lib/deltacloud/helpers.rb +5 -0
  42. data/lib/deltacloud/method_serializer.rb +85 -0
  43. data/lib/deltacloud/models/base_model.rb +59 -0
  44. data/lib/deltacloud/models/image.rb +27 -0
  45. data/lib/deltacloud/models/instance.rb +38 -0
  46. data/lib/deltacloud/models/instance_profile.rb +48 -0
  47. data/lib/deltacloud/models/key.rb +35 -0
  48. data/lib/deltacloud/models/realm.rb +26 -0
  49. data/lib/deltacloud/models/storage_snapshot.rb +27 -0
  50. data/lib/deltacloud/models/storage_volume.rb +28 -0
  51. data/lib/deltacloud/state_machine.rb +84 -0
  52. data/lib/deltacloud/validation.rb +70 -0
  53. data/lib/drivers.rb +50 -0
  54. data/lib/sinatra/accept_media_types.rb +128 -0
  55. data/lib/sinatra/lazy_auth.rb +56 -0
  56. data/lib/sinatra/rabbit.rb +273 -0
  57. data/lib/sinatra/respond_to.rb +272 -0
  58. data/lib/sinatra/static_assets.rb +83 -0
  59. data/lib/sinatra/url_for.rb +53 -0
  60. data/public/favicon.ico +0 -0
  61. data/public/images/grid.png +0 -0
  62. data/public/images/logo-wide.png +0 -0
  63. data/public/images/rails.png +0 -0
  64. data/public/images/topbar-bg.png +0 -0
  65. data/public/javascripts/application.js +32 -0
  66. data/public/javascripts/jquery-1.4.2.min.js +154 -0
  67. data/public/stylesheets/compiled/application.css +613 -0
  68. data/public/stylesheets/compiled/ie.css +31 -0
  69. data/public/stylesheets/compiled/print.css +27 -0
  70. data/public/stylesheets/compiled/screen.css +456 -0
  71. data/server.rb +354 -0
  72. data/support/fedora/deltacloudd +68 -0
  73. data/support/fedora/rubygem-deltacloud-core.spec +91 -0
  74. data/tests/api_test.rb +37 -0
  75. data/tests/hardware_profiles_test.rb +120 -0
  76. data/tests/images_test.rb +111 -0
  77. data/tests/instance_states_test.rb +52 -0
  78. data/tests/instances_test.rb +219 -0
  79. data/tests/realms_test.rb +78 -0
  80. data/tests/url_for_test.rb +50 -0
  81. data/views/accounts/index.html.haml +11 -0
  82. data/views/accounts/show.html.haml +30 -0
  83. data/views/api/show.html.haml +15 -0
  84. data/views/api/show.xml.haml +5 -0
  85. data/views/docs/collection.html.haml +37 -0
  86. data/views/docs/collection.xml.haml +14 -0
  87. data/views/docs/index.html.haml +15 -0
  88. data/views/docs/index.xml.haml +5 -0
  89. data/views/docs/operation.html.haml +31 -0
  90. data/views/docs/operation.xml.haml +10 -0
  91. data/views/errors/auth_exception.html.haml +8 -0
  92. data/views/errors/auth_exception.xml.haml +2 -0
  93. data/views/errors/backend_error.html.haml +19 -0
  94. data/views/errors/backend_error.xml.haml +8 -0
  95. data/views/errors/not_found.html.haml +6 -0
  96. data/views/errors/not_found.xml.haml +2 -0
  97. data/views/errors/validation_failure.html.haml +11 -0
  98. data/views/errors/validation_failure.xml.haml +7 -0
  99. data/views/hardware_profiles/index.html.haml +25 -0
  100. data/views/hardware_profiles/index.xml.haml +4 -0
  101. data/views/hardware_profiles/show.html.haml +19 -0
  102. data/views/hardware_profiles/show.xml.haml +18 -0
  103. data/views/images/index.html.haml +30 -0
  104. data/views/images/index.xml.haml +8 -0
  105. data/views/images/show.html.haml +21 -0
  106. data/views/images/show.xml.haml +5 -0
  107. data/views/instance_states/show.gv.erb +45 -0
  108. data/views/instance_states/show.html.haml +31 -0
  109. data/views/instance_states/show.xml.haml +8 -0
  110. data/views/instances/index.html.haml +30 -0
  111. data/views/instances/index.xml.haml +21 -0
  112. data/views/instances/new.html.haml +55 -0
  113. data/views/instances/show.html.haml +43 -0
  114. data/views/instances/show.xml.haml +49 -0
  115. data/views/keys/index.html.haml +26 -0
  116. data/views/keys/index.xml.haml +4 -0
  117. data/views/keys/new.html.haml +8 -0
  118. data/views/keys/show.html.haml +22 -0
  119. data/views/keys/show.xml.haml +20 -0
  120. data/views/layout.html.haml +26 -0
  121. data/views/realms/index.html.haml +29 -0
  122. data/views/realms/index.xml.haml +10 -0
  123. data/views/realms/show.html.haml +15 -0
  124. data/views/realms/show.xml.haml +9 -0
  125. data/views/root/index.html.haml +4 -0
  126. data/views/storage_snapshots/index.html.haml +20 -0
  127. data/views/storage_snapshots/index.xml.haml +9 -0
  128. data/views/storage_snapshots/show.html.haml +14 -0
  129. data/views/storage_snapshots/show.xml.haml +7 -0
  130. data/views/storage_volumes/index.html.haml +21 -0
  131. data/views/storage_volumes/index.xml.haml +13 -0
  132. data/views/storage_volumes/show.html.haml +20 -0
  133. data/views/storage_volumes/show.xml.haml +11 -0
  134. 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