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
data/server.rb
ADDED
|
@@ -0,0 +1,354 @@
|
|
|
1
|
+
require 'sinatra'
|
|
2
|
+
require 'deltacloud'
|
|
3
|
+
require 'drivers'
|
|
4
|
+
require 'json'
|
|
5
|
+
require 'sinatra/respond_to'
|
|
6
|
+
require 'sinatra/static_assets'
|
|
7
|
+
require 'sinatra/rabbit'
|
|
8
|
+
require 'sinatra/lazy_auth'
|
|
9
|
+
require 'erb'
|
|
10
|
+
require 'haml'
|
|
11
|
+
require 'open3'
|
|
12
|
+
|
|
13
|
+
configure do
|
|
14
|
+
set :raise_errors => false
|
|
15
|
+
set :show_exceptions, false
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
configure :development do
|
|
19
|
+
# So we can just use puts for logging
|
|
20
|
+
$stdout.sync = true
|
|
21
|
+
$stderr.sync = true
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
# You could use $API_HOST environment variable to change your hostname to
|
|
25
|
+
# whatever you want (eg. if you running API behind NAT)
|
|
26
|
+
HOSTNAME=ENV['API_HOST'] ? ENV['API_HOST'] : nil
|
|
27
|
+
|
|
28
|
+
error Deltacloud::Validation::Failure do
|
|
29
|
+
report_error(400, "validation_failure")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
error Deltacloud::AuthException do
|
|
33
|
+
report_error(403, "auth_exception")
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
error Deltacloud::BackendError do
|
|
37
|
+
report_error(500, "backend_error")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Redirect to /api
|
|
41
|
+
get '/' do redirect url_for('/api'); end
|
|
42
|
+
|
|
43
|
+
get '/api\/?' do
|
|
44
|
+
@version = 0.1
|
|
45
|
+
respond_to do |format|
|
|
46
|
+
format.xml { haml :"api/show" }
|
|
47
|
+
format.json do
|
|
48
|
+
{ :api => {
|
|
49
|
+
:version => @version,
|
|
50
|
+
:driver => DRIVER,
|
|
51
|
+
:links => entry_points.collect { |l| { :rel => l[0], :href => l[1]} }
|
|
52
|
+
}
|
|
53
|
+
}.to_json
|
|
54
|
+
end
|
|
55
|
+
format.html { haml :"api/show" }
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# Rabbit DSL
|
|
60
|
+
|
|
61
|
+
collection :realms do
|
|
62
|
+
description <<END
|
|
63
|
+
Within a cloud provider a realm represents a boundary containing resources.
|
|
64
|
+
The exact definition of a realm is left to the cloud provider.
|
|
65
|
+
In some cases, a realm may represent different datacenters, different continents,
|
|
66
|
+
or different pools of resources within a single datacenter.
|
|
67
|
+
A cloud provider may insist that resources must all exist within a single realm in
|
|
68
|
+
order to cooperate. For instance, storage volumes may only be allowed to be mounted to
|
|
69
|
+
instances within the same realm.
|
|
70
|
+
END
|
|
71
|
+
|
|
72
|
+
operation :index do
|
|
73
|
+
description <<END
|
|
74
|
+
Operation will list all available realms. For specific architecture use "architecture" parameter.
|
|
75
|
+
END
|
|
76
|
+
param :id, :string
|
|
77
|
+
param :architecture, :string, :optional, [ 'i386', 'x86_64' ]
|
|
78
|
+
control { filter_all(:realms) }
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
#FIXME: It always shows whole list
|
|
82
|
+
operation :show do
|
|
83
|
+
description 'Show an realm identified by "id" parameter.'
|
|
84
|
+
param :id, :string, :required
|
|
85
|
+
control { show(:realm) }
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
collection :images do
|
|
91
|
+
description <<END
|
|
92
|
+
An image is a platonic form of a machine. Images are not directly executable,
|
|
93
|
+
but are a template for creating actual instances of machines."
|
|
94
|
+
END
|
|
95
|
+
|
|
96
|
+
operation :index do
|
|
97
|
+
description <<END
|
|
98
|
+
The instances collection will return a set of all images
|
|
99
|
+
available to the current use. You can filter images using
|
|
100
|
+
"owner_id" and "architecture" parameter
|
|
101
|
+
END
|
|
102
|
+
param :id, :string
|
|
103
|
+
param :architecture, :string, :optional
|
|
104
|
+
control { filter_all(:images) }
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
operation :show do
|
|
108
|
+
description 'Show an image identified by "id" parameter.'
|
|
109
|
+
param :id, :string, :required
|
|
110
|
+
control { show(:image) }
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
collection :instance_states do
|
|
116
|
+
description "The possible states of an instance, and how to traverse between them "
|
|
117
|
+
|
|
118
|
+
operation :index do
|
|
119
|
+
control do
|
|
120
|
+
@machine = driver.instance_state_machine
|
|
121
|
+
respond_to do |format|
|
|
122
|
+
format.xml { haml :'instance_states/show', :layout => false }
|
|
123
|
+
format.json do
|
|
124
|
+
out = []
|
|
125
|
+
@machine.states.each do |state|
|
|
126
|
+
transitions = state.transitions.collect do |t|
|
|
127
|
+
t.automatically? ? {:to => t.destination, :auto => 'true'} : {:to => t.destination, :action => t.action}
|
|
128
|
+
end
|
|
129
|
+
out << { :name => state, :transitions => transitions }
|
|
130
|
+
end
|
|
131
|
+
out.to_json
|
|
132
|
+
end
|
|
133
|
+
format.html { haml :'instance_states/show'}
|
|
134
|
+
format.gv { erb :"instance_states/show" }
|
|
135
|
+
format.png do
|
|
136
|
+
# Trick respond_to into looking up the right template for the
|
|
137
|
+
# graphviz file
|
|
138
|
+
format(:gv); gv = erb :"instance_states/show"; format(:png)
|
|
139
|
+
png = ''
|
|
140
|
+
cmd = 'dot -Kdot -Gpad="0.2,0.2" -Gsize="5.0,8.0" -Gdpi="180" -Tpng'
|
|
141
|
+
Open3.popen3( cmd ) do |stdin, stdout, stderr|
|
|
142
|
+
stdin.write( gv )
|
|
143
|
+
stdin.close()
|
|
144
|
+
png = stdout.read
|
|
145
|
+
end
|
|
146
|
+
png
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
get "/api/instances/new" do
|
|
154
|
+
@instance = Instance.new( { :id=>params[:id], :image_id=>params[:image_id] } )
|
|
155
|
+
@image = driver.image( credentials, :id => params[:image_id] )
|
|
156
|
+
@hardware_profiles = driver.hardware_profiles(credentials, :architecture => @image.architecture )
|
|
157
|
+
@realms = driver.realms(credentials)
|
|
158
|
+
respond_to do |format|
|
|
159
|
+
format.html { haml :"instances/new" }
|
|
160
|
+
end
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
collection :instances do
|
|
164
|
+
description <<END
|
|
165
|
+
An instance is a concrete machine realized from an image.
|
|
166
|
+
The images collection may be obtained by following the link from the primary entry-point."
|
|
167
|
+
END
|
|
168
|
+
|
|
169
|
+
operation :index do
|
|
170
|
+
description "List all instances"
|
|
171
|
+
param :id, :string, :optional
|
|
172
|
+
param :state, :string, :optional
|
|
173
|
+
control { filter_all(:instances) }
|
|
174
|
+
end
|
|
175
|
+
|
|
176
|
+
operation :show do
|
|
177
|
+
description 'Show an instance identified by "id" parameter.'
|
|
178
|
+
param :id, :string, :required
|
|
179
|
+
control { show(:instance) }
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
operation :create do
|
|
183
|
+
description "Create a new instance"
|
|
184
|
+
param :image_id, :string, :required
|
|
185
|
+
param :realm_id, :string, :optional
|
|
186
|
+
param :hwp_id, :string, :optional
|
|
187
|
+
control do
|
|
188
|
+
@image = driver.image(credentials, :id => params[:image_id])
|
|
189
|
+
instance = driver.create_instance(credentials, @image.id, params)
|
|
190
|
+
respond_to do |format|
|
|
191
|
+
format.xml do
|
|
192
|
+
response.status = 201 # Created
|
|
193
|
+
response['Location'] = instance_url(instance.id)
|
|
194
|
+
@instance = instance
|
|
195
|
+
haml :"instances/show"
|
|
196
|
+
end
|
|
197
|
+
format.html do
|
|
198
|
+
redirect instance_url(instance.id) if instance and instance.id
|
|
199
|
+
redirect instances_url
|
|
200
|
+
end
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
operation :reboot, :method => :post, :member => true do
|
|
206
|
+
description "Reboot running instance"
|
|
207
|
+
param :id, :string, :required
|
|
208
|
+
control { instance_action(:reboot) }
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
operation :start, :method => :post, :member => true do
|
|
212
|
+
description "Start an instance"
|
|
213
|
+
param :id, :string, :required
|
|
214
|
+
control { instance_action(:start) }
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
operation :stop, :method => :post, :member => true do
|
|
218
|
+
description "Stop running instance"
|
|
219
|
+
param :id, :string, :required
|
|
220
|
+
control { instance_action(:stop) }
|
|
221
|
+
end
|
|
222
|
+
|
|
223
|
+
operation :destroy do
|
|
224
|
+
description "Destroy instance"
|
|
225
|
+
param :id, :string, :required
|
|
226
|
+
control { instance_action(:destroy) }
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
collection :hardware_profiles do
|
|
231
|
+
description <<END
|
|
232
|
+
A hardware profile represents a configuration of resources upon which a
|
|
233
|
+
machine may be deployed. It defines aspects such as local disk storage,
|
|
234
|
+
available RAM, and architecture. Each provider is free to define as many
|
|
235
|
+
(or as few) hardware profiles as desired.
|
|
236
|
+
END
|
|
237
|
+
|
|
238
|
+
operation :index do
|
|
239
|
+
description "List of available hardware profiles"
|
|
240
|
+
param :id, :string
|
|
241
|
+
param :architecture, :string, :optional, [ 'i386', 'x86_64' ]
|
|
242
|
+
control do
|
|
243
|
+
@profiles = driver.hardware_profiles(credentials, params)
|
|
244
|
+
respond_to do |format|
|
|
245
|
+
format.xml { haml :'hardware_profiles/index' }
|
|
246
|
+
format.html { haml :'hardware_profiles/index' }
|
|
247
|
+
format.json { convert_to_json(:hardware_profile, @profiles) }
|
|
248
|
+
end
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
operation :show do
|
|
253
|
+
description "Show specific hardware profile"
|
|
254
|
+
param :id, :string, :required
|
|
255
|
+
control do
|
|
256
|
+
@profile = driver.hardware_profile(credentials, params[:id])
|
|
257
|
+
if @profile
|
|
258
|
+
respond_to do |format|
|
|
259
|
+
format.xml { haml :'hardware_profiles/show', :layout => false }
|
|
260
|
+
format.html { haml :'hardware_profiles/show' }
|
|
261
|
+
format.json { convert_to_json(:hardware_profile, @profile) }
|
|
262
|
+
end
|
|
263
|
+
else
|
|
264
|
+
report_error(404, 'not_found')
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
collection :storage_snapshots do
|
|
272
|
+
description "Storage snapshots description here"
|
|
273
|
+
|
|
274
|
+
operation :index do
|
|
275
|
+
description "Listing of storage snapshots"
|
|
276
|
+
param :id, :string
|
|
277
|
+
control { filter_all(:storage_snapshots) }
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
operation :show do
|
|
281
|
+
description "Show storage snapshot"
|
|
282
|
+
param :id, :string, :required
|
|
283
|
+
control { show(:storage_snapshot) }
|
|
284
|
+
end
|
|
285
|
+
end
|
|
286
|
+
|
|
287
|
+
collection :storage_volumes do
|
|
288
|
+
description "Storage volumes description here"
|
|
289
|
+
|
|
290
|
+
operation :index do
|
|
291
|
+
description "Listing of storage volumes"
|
|
292
|
+
param :id, :string
|
|
293
|
+
control { filter_all(:storage_volumes) }
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
operation :show do
|
|
297
|
+
description "Show storage volume"
|
|
298
|
+
param :id, :string, :required
|
|
299
|
+
control { show(:storage_volume) }
|
|
300
|
+
end
|
|
301
|
+
end
|
|
302
|
+
|
|
303
|
+
get '/api/keys/new' do
|
|
304
|
+
respond_to do |format|
|
|
305
|
+
format.html { haml :"keys/new" }
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
|
|
309
|
+
collection :keys do
|
|
310
|
+
description "Instance authentication credentials"
|
|
311
|
+
|
|
312
|
+
operation :index do
|
|
313
|
+
description "List all available credentials which could be used for instance authentication"
|
|
314
|
+
control do
|
|
315
|
+
filter_all :keys
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
operation :show do
|
|
320
|
+
description "Show details about given instance credential"
|
|
321
|
+
param :id, :string, :required
|
|
322
|
+
control { show :key }
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
operation :create do
|
|
326
|
+
description "Create a new instance credential if backend supports this"
|
|
327
|
+
param :name, :string, :required
|
|
328
|
+
control do
|
|
329
|
+
unless driver.respond_to?(:create_key)
|
|
330
|
+
raise Deltacloud::BackendFeatureUnsupported.new('501',
|
|
331
|
+
'Creating instance credentials is not supported in backend')
|
|
332
|
+
end
|
|
333
|
+
@key = driver.create_key(credentials, { :key_name => params[:name] })
|
|
334
|
+
respond_to do |format|
|
|
335
|
+
format.html { haml :"keys/show" }
|
|
336
|
+
format.xml { haml :"keys/show" }
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
end
|
|
340
|
+
|
|
341
|
+
operation :destroy do
|
|
342
|
+
description "Destroy given instance credential if backend supports this"
|
|
343
|
+
param :id, :string, :required
|
|
344
|
+
control do
|
|
345
|
+
unless driver.respond_to?(:destroy_key)
|
|
346
|
+
raise Deltacloud::BackendFeatureUnsupported.new('501',
|
|
347
|
+
'Creating instance credentials is not supported in backend')
|
|
348
|
+
end
|
|
349
|
+
driver.destroy_key(credentials, { :key_name => params[:id]})
|
|
350
|
+
redirect(keys_url)
|
|
351
|
+
end
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
end
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'rubygems'
|
|
4
|
+
require 'optparse'
|
|
5
|
+
require 'thin'
|
|
6
|
+
|
|
7
|
+
options = {
|
|
8
|
+
:env => 'production'
|
|
9
|
+
}
|
|
10
|
+
optparse = OptionParser.new do |opts|
|
|
11
|
+
|
|
12
|
+
opts.banner = <<BANNER
|
|
13
|
+
Usage:
|
|
14
|
+
deltacloudd -i <driver> [options]
|
|
15
|
+
|
|
16
|
+
Options:
|
|
17
|
+
BANNER
|
|
18
|
+
opts.on( '-i', '--driver DRIVER', 'Driver to use') do |driver|
|
|
19
|
+
ENV["API_DRIVER"] = driver
|
|
20
|
+
end
|
|
21
|
+
opts.on( '-r', '--hostname HOSTNAME',
|
|
22
|
+
'Bind to HOST address (default: localhost)') do |host|
|
|
23
|
+
ENV["API_HOST"] = host
|
|
24
|
+
end
|
|
25
|
+
opts.on( '-p', '--port PORT', 'Use PORT (default: 3001)') do |port|
|
|
26
|
+
ENV["API_PORT"] = port
|
|
27
|
+
end
|
|
28
|
+
opts.on( '-e', '--env ENV', 'Environment (default: "development")') { |env| options[:env] = env }
|
|
29
|
+
opts.on( '-h', '--help', '') { options[:help] = true }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
optparse.parse!
|
|
33
|
+
|
|
34
|
+
if options[:help]
|
|
35
|
+
puts optparse
|
|
36
|
+
exit(0)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
unless ENV["API_DRIVER"]
|
|
40
|
+
puts "You need to specify a driver to use (-i <driver>)"
|
|
41
|
+
exit(1)
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
ENV["API_HOST"] = "localhost" unless ENV["API_HOST"]
|
|
45
|
+
ENV["API_PORT"] = "3001" unless ENV["API_PORT"]
|
|
46
|
+
|
|
47
|
+
dirname="#{File.dirname(__FILE__)}/.."
|
|
48
|
+
|
|
49
|
+
argv_opts = ARGV.clone
|
|
50
|
+
argv_opts << ['start'] unless Thin::Runner.commands.include?(options[0])
|
|
51
|
+
argv_opts << ['--address', ENV["API_HOST"] ]
|
|
52
|
+
argv_opts << ['--port', ENV["API_PORT"] ]
|
|
53
|
+
argv_opts << ['--rackup', 'config.ru' ]
|
|
54
|
+
argv_opts << ['--chdir', dirname ]
|
|
55
|
+
argv_opts << ['-e', options[:env] ]
|
|
56
|
+
argv_opts << ['--threaded', '-D', '--stats', '/stats']
|
|
57
|
+
|
|
58
|
+
argv_opts.flatten!
|
|
59
|
+
|
|
60
|
+
puts "Starting Deltacloud API :: #{ENV["API_DRIVER"]} :: http://#{ENV["API_HOST"]}:#{ENV["API_PORT"]}/api"
|
|
61
|
+
puts
|
|
62
|
+
|
|
63
|
+
thin = Thin::Runner.new(argv_opts)
|
|
64
|
+
begin
|
|
65
|
+
thin.run!
|
|
66
|
+
rescue Exception => e
|
|
67
|
+
puts "ERROR: #{e.message}"
|
|
68
|
+
end
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
%global ruby_sitelib %(ruby -rrbconfig -e "puts Config::CONFIG['sitelibdir']")
|
|
2
|
+
%global gemdir %(ruby -rubygems -e 'puts Gem::dir' 2>/dev/null)
|
|
3
|
+
%global gemname deltacloud-core
|
|
4
|
+
%global geminstdir %{gemdir}/gems/%{gemname}-%{version}
|
|
5
|
+
|
|
6
|
+
Summary: Deltacloud REST API
|
|
7
|
+
Name: rubygem-%{gemname}
|
|
8
|
+
Version: 0.0.1
|
|
9
|
+
Release: 2%{?dist}
|
|
10
|
+
Group: Development/Languages
|
|
11
|
+
License: ASL 2.0 and MIT
|
|
12
|
+
URL: http://www.deltacloud.org
|
|
13
|
+
Source0: http://gems.rubyforge.org/gems/%{gemname}-%{version}.gem
|
|
14
|
+
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
|
15
|
+
Requires: rubygems
|
|
16
|
+
Requires: ruby(abi) = 1.8
|
|
17
|
+
Requires: rubygem(eventmachine) >= 0.12.10
|
|
18
|
+
Requires: rubygem(haml) >= 2.2.17
|
|
19
|
+
Requires: rubygem(sinatra) >= 0.9.4
|
|
20
|
+
Requires: rubygem(rack) >= 1.0.0
|
|
21
|
+
Requires: rubygem(thin) >= 1.2.5
|
|
22
|
+
Requires: rubygem(builder) >= 2.1.2
|
|
23
|
+
Requires: rubygem(json) >= 1.2.3
|
|
24
|
+
BuildRequires: ruby-json >= 1.1.9
|
|
25
|
+
BuildRequires: rubygem(rake) >= 0.8.7
|
|
26
|
+
BuildRequires: rubygem(rack-test) >= 0.4.0
|
|
27
|
+
BuildRequires: rubygem(cucumber) >= 0.4.0
|
|
28
|
+
BuildRequires: rubygem(rcov) >= 0.9.6
|
|
29
|
+
BuildRequires: rubygems
|
|
30
|
+
BuildRequires: ruby(abi) = 1.8
|
|
31
|
+
BuildArch: noarch
|
|
32
|
+
Provides: rubygem(%{gemname}) = %{version}
|
|
33
|
+
|
|
34
|
+
%description
|
|
35
|
+
The Deltacloud API is built as a service-based REST API.
|
|
36
|
+
You do not directly link a Deltacloud library into your program to use it.
|
|
37
|
+
Instead, a client speaks the Deltacloud API over HTTP to a server
|
|
38
|
+
which implements the REST interface.
|
|
39
|
+
|
|
40
|
+
%prep
|
|
41
|
+
|
|
42
|
+
%build
|
|
43
|
+
|
|
44
|
+
%install
|
|
45
|
+
rm -rf %{buildroot}
|
|
46
|
+
mkdir -p %{buildroot}%{gemdir}
|
|
47
|
+
gem install --local --install-dir %{buildroot}%{gemdir} \
|
|
48
|
+
--force --rdoc %{SOURCE0}
|
|
49
|
+
mkdir -p %{buildroot}/%{_bindir}
|
|
50
|
+
mv %{buildroot}%{geminstdir}/support/fedora/deltacloudd %{buildroot}/%{geminstdir}/bin
|
|
51
|
+
mv %{buildroot}%{gemdir}/bin/* %{buildroot}/%{_bindir}
|
|
52
|
+
rmdir %{buildroot}%{gemdir}/bin
|
|
53
|
+
find %{buildroot}%{geminstdir}/bin -type f | xargs chmod a+x
|
|
54
|
+
|
|
55
|
+
# Needs json_pure gem / not available in Fedora yet
|
|
56
|
+
#%check
|
|
57
|
+
#pushd %{buildroot}%{geminstdir}
|
|
58
|
+
#cucumber features/*.feature
|
|
59
|
+
#popd
|
|
60
|
+
|
|
61
|
+
%clean
|
|
62
|
+
rm -rf %{buildroot}
|
|
63
|
+
|
|
64
|
+
%files
|
|
65
|
+
%defattr(-, root, root, -)
|
|
66
|
+
%{_bindir}/deltacloudd
|
|
67
|
+
%{gemdir}/gems/%{gemname}-%{version}/bin
|
|
68
|
+
%{gemdir}/gems/%{gemname}-%{version}/lib
|
|
69
|
+
%{gemdir}/gems/%{gemname}-%{version}/public/favicon.ico
|
|
70
|
+
%{gemdir}/gems/%{gemname}-%{version}/public/images
|
|
71
|
+
%{gemdir}/gems/%{gemname}-%{version}/public/stylesheets
|
|
72
|
+
%{gemdir}/gems/%{gemname}-%{version}/tests
|
|
73
|
+
%{gemdir}/gems/%{gemname}-%{version}/views
|
|
74
|
+
%{gemdir}/gems/%{gemname}-%{version}/Rakefile
|
|
75
|
+
%{gemdir}/gems/%{gemname}-%{version}/*.rb
|
|
76
|
+
%{gemdir}/gems/%{gemname}-%{version}/config.ru
|
|
77
|
+
%doc %{gemdir}/gems/%{gemname}-%{version}/support/fedora
|
|
78
|
+
%doc %{gemdir}/gems/%{gemname}-%{version}/COPYING
|
|
79
|
+
%doc %{gemdir}/doc/%{gemname}-%{version}
|
|
80
|
+
%{gemdir}/cache/%{gemname}-%{version}.gem
|
|
81
|
+
%{gemdir}/specifications/%{gemname}-%{version}.gemspec
|
|
82
|
+
# MIT
|
|
83
|
+
%{gemdir}/gems/%{gemname}-%{version}/public/javascripts
|
|
84
|
+
|
|
85
|
+
%changelog
|
|
86
|
+
* Mon Apr 26 2010 Michal Fojtik <mfojtik@packager> - 0.0.1-1
|
|
87
|
+
- Initial package
|
|
88
|
+
|
|
89
|
+
* Mon Apr 26 2010 Michal Fojtik <mfojtik@packager> - 0.0.1-2
|
|
90
|
+
- Fixed broken dependencies
|
|
91
|
+
- Added new launcher for Fedora
|
data/tests/api_test.rb
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
require 'tests/common'
|
|
2
|
+
|
|
3
|
+
module DeltacloudUnitTest
|
|
4
|
+
class ApiTest < Test::Unit::TestCase
|
|
5
|
+
include Rack::Test::Methods
|
|
6
|
+
|
|
7
|
+
def app
|
|
8
|
+
Sinatra::Application
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def test_it_returns_entry_points
|
|
12
|
+
do_xml_request '/api'
|
|
13
|
+
(last_xml_response/'/api/link').map.size.should > 0
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_it_has_correct_attributes_set
|
|
17
|
+
do_xml_request '/api'
|
|
18
|
+
(last_xml_response/'/api/link').each do |link|
|
|
19
|
+
link.attributes.keys.sort.should == [ 'href', 'rel' ]
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_it_responses_to_html
|
|
24
|
+
do_request '/api', {}, false, { :format => :html }
|
|
25
|
+
last_response.status.should == 200
|
|
26
|
+
Nokogiri::HTML(last_response.body).search('html').first.name.should == 'html'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def test_it_responses_to_json
|
|
30
|
+
do_request '/api', {}, false, { :format => :json }
|
|
31
|
+
last_response.status.should == 200
|
|
32
|
+
JSON::parse(last_response.body).class.should == Hash
|
|
33
|
+
JSON::parse(last_response.body)['api'].class.should == Hash
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
require 'tests/common'
|
|
2
|
+
|
|
3
|
+
module DeltacloudUnitTest
|
|
4
|
+
class HardwareProfilesTest < Test::Unit::TestCase
|
|
5
|
+
include Rack::Test::Methods
|
|
6
|
+
|
|
7
|
+
def app
|
|
8
|
+
Sinatra::Application
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def test_it_returns_hardware_profiles
|
|
12
|
+
do_xml_request '/api/hardware_profiles'
|
|
13
|
+
(last_xml_response/'hardware_profiles/hardware_profile').map.size.should > 0
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def test_it_has_correct_attributes_set
|
|
17
|
+
do_xml_request '/api/hardware_profiles'
|
|
18
|
+
(last_xml_response/'hardware_profiles/hardware_profile').each do |profile|
|
|
19
|
+
profile.attributes.keys.sort.should == [ 'href', 'id' ]
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def test_hardware_profiles_have_name
|
|
24
|
+
do_xml_request '/api/hardware_profiles'
|
|
25
|
+
(last_xml_response/'hardware_profiles/hardware_profile').each do |profile|
|
|
26
|
+
(profile/'name').text.should_not == nil
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def test_hardware_profiles_have_unique_name
|
|
31
|
+
do_xml_request '/api/hardware_profiles'
|
|
32
|
+
names = []
|
|
33
|
+
(last_xml_response/'hardware_profiles/hardware_profile').each do |profile|
|
|
34
|
+
names << (profile/'name').text
|
|
35
|
+
end
|
|
36
|
+
names.should == names.uniq
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_hardware_profiles_have_unique_id
|
|
40
|
+
do_xml_request '/api/hardware_profiles'
|
|
41
|
+
ids = []
|
|
42
|
+
(last_xml_response/'hardware_profiles/hardware_profile').each do |profile|
|
|
43
|
+
ids << profile['id']
|
|
44
|
+
end
|
|
45
|
+
ids.should == ids.uniq
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_m1_xlarge_profile_has_correct_attributes
|
|
49
|
+
do_xml_request '/api/hardware_profiles'
|
|
50
|
+
profile = (last_xml_response/'hardware_profiles/hardware_profile[@id="m1-xlarge"]')
|
|
51
|
+
test_profile_properties(profile)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_it_returns_valid_hardware_profile
|
|
55
|
+
do_xml_request '/api/hardware_profiles/m1-xlarge'
|
|
56
|
+
profile = (last_xml_response/'hardware_profile')
|
|
57
|
+
test_profile_properties(profile)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_it_responses_to_json
|
|
61
|
+
do_request '/api/hardware_profiles', {}, false, { :format => :json }
|
|
62
|
+
JSON::parse(last_response.body).class.should == Hash
|
|
63
|
+
JSON::parse(last_response.body)['hardware_profiles'].class.should == Array
|
|
64
|
+
|
|
65
|
+
do_request '/api/hardware_profiles/m1-xlarge', {}, false, { :format => :json }
|
|
66
|
+
last_response.status.should == 200
|
|
67
|
+
JSON::parse(last_response.body).class.should == Hash
|
|
68
|
+
JSON::parse(last_response.body)['hardware_profile'].class.should == Hash
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_it_responses_to_html
|
|
72
|
+
do_request '/api/hardware_profiles', {}, false, { :format => :html }
|
|
73
|
+
last_response.status.should == 200
|
|
74
|
+
Nokogiri::HTML(last_response.body).search('html').first.name.should == 'html'
|
|
75
|
+
|
|
76
|
+
do_request '/api/hardware_profiles/m1-xlarge', {}, false, { :format => :html }
|
|
77
|
+
last_response.status.should == 200
|
|
78
|
+
Nokogiri::HTML(last_response.body).search('html').first.name.should == 'html'
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def test_it_returns_error_on_wrong_name
|
|
82
|
+
do_request '/api/hardware_profiles/m1-unknown-wrongname', {}, false, { :format => :html }
|
|
83
|
+
last_response.status.should == 404
|
|
84
|
+
do_xml_request '/api/hardware_profiles/m1-unknown-wrongname'
|
|
85
|
+
last_response.status.should == 404
|
|
86
|
+
do_request '/api/hardware_profiles/m1-unknown-wrongname', {}, false, { :format => :json }
|
|
87
|
+
last_response.status.should == 404
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
private
|
|
91
|
+
|
|
92
|
+
def test_profile_properties(profile)
|
|
93
|
+
|
|
94
|
+
(profile/'property').each do |properties|
|
|
95
|
+
properties.attributes.keys.sort.should == [ 'kind', 'name', 'unit', 'value' ]
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
(profile/'property[@name="architecture"]').first['kind'].should == 'fixed'
|
|
99
|
+
(profile/'property[@name="architecture"]').first['unit'].should == 'label'
|
|
100
|
+
|
|
101
|
+
(profile/'property[@name="memory"]').first['kind'].should == 'range'
|
|
102
|
+
(profile/'property[@name="memory"]').first['unit'].should == 'MB'
|
|
103
|
+
(profile/'property[@name="memory"]/range').size.should == 1
|
|
104
|
+
(profile/'property[@name="memory"]/range').first.attributes.keys.sort.should == [ 'first', 'last' ]
|
|
105
|
+
|
|
106
|
+
(profile/'property[@name="cpu"]').first['kind'].should == 'fixed'
|
|
107
|
+
(profile/'property[@name="cpu"]').first['unit'].should == 'count'
|
|
108
|
+
|
|
109
|
+
(profile/'property[@name="storage"]').first['kind'].should == 'enum'
|
|
110
|
+
(profile/'property[@name="storage"]').first['unit'].should == 'GB'
|
|
111
|
+
(profile/'property[@name="storage"]/enum').size.should == 1
|
|
112
|
+
(profile/'property[@name="storage"]/enum/entry').map.size.should == 3
|
|
113
|
+
(profile/'property[@name="storage"]/enum/entry').each do |entry|
|
|
114
|
+
entry.attributes.keys.should == [ 'value' ]
|
|
115
|
+
entry['value'].should_not == nil
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
end
|
|
120
|
+
end
|