bbrowning-deltacloud-core 0.0.4-java
Sign up to get free protection for your applications and to get access to all the features.
- 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
|