deltacloud-core 0.1.2 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. data/DISCLAIMER +8 -0
  2. data/{COPYING → LICENSE} +0 -0
  3. data/NOTICE +13 -0
  4. data/Rakefile +50 -51
  5. data/bin/deltacloudd +8 -1
  6. data/config.ru +0 -2
  7. data/config/drivers.yaml +48 -0
  8. data/deltacloud-core.gemspec +75 -0
  9. data/deltacloud.rb +3 -2
  10. data/lib/deltacloud/backend_capability.rb +15 -3
  11. data/lib/deltacloud/base_driver.rb +0 -2
  12. data/lib/deltacloud/base_driver/base_driver.rb +85 -89
  13. data/lib/deltacloud/base_driver/features.rb +61 -7
  14. data/lib/deltacloud/base_driver/mock_driver.rb +42 -43
  15. data/lib/deltacloud/core_ext.rb +18 -0
  16. data/lib/deltacloud/core_ext/integer.rb +31 -0
  17. data/lib/deltacloud/core_ext/string.rb +50 -0
  18. data/lib/deltacloud/drivers/azure/azure_driver.rb +71 -22
  19. data/lib/deltacloud/drivers/ec2/ec2_driver.rb +641 -584
  20. data/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb +0 -2
  21. data/lib/deltacloud/drivers/eucalyptus/eucalyptus_driver.rb +167 -0
  22. data/lib/deltacloud/drivers/gogrid/gogrid_client.rb +39 -1
  23. data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +41 -25
  24. data/lib/deltacloud/drivers/mock/data/buckets/blobs/blob1.yml +6 -3
  25. data/lib/deltacloud/drivers/mock/data/buckets/blobs/blob2.yml +6 -3
  26. data/lib/deltacloud/drivers/mock/data/buckets/blobs/blob3.yml +4 -2
  27. data/lib/deltacloud/drivers/mock/data/buckets/blobs/blob4.yml +5 -2
  28. data/lib/deltacloud/drivers/mock/data/buckets/blobs/blob5.yml +4 -2
  29. data/lib/deltacloud/drivers/mock/data/instances/inst0.yml +1 -0
  30. data/lib/deltacloud/drivers/mock/data/instances/inst1.yml +1 -0
  31. data/lib/deltacloud/drivers/mock/data/instances/inst2.yml +1 -0
  32. data/lib/deltacloud/drivers/mock/data/storage_volumes/vol1.yml +1 -0
  33. data/lib/deltacloud/drivers/mock/data/storage_volumes/vol2.yml +1 -0
  34. data/lib/deltacloud/drivers/mock/data/storage_volumes/vol3.yml +1 -0
  35. data/lib/deltacloud/drivers/mock/mock_driver.rb +138 -30
  36. data/lib/deltacloud/drivers/opennebula/cloud_client.rb +13 -15
  37. data/lib/deltacloud/drivers/opennebula/occi_client.rb +13 -15
  38. data/lib/deltacloud/drivers/opennebula/opennebula_driver.rb +13 -15
  39. data/lib/deltacloud/drivers/rackspace/rackspace_driver.rb +224 -113
  40. data/lib/deltacloud/drivers/rhevm/rhevm_client.rb +332 -0
  41. data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +221 -170
  42. data/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb +0 -1
  43. data/lib/deltacloud/drivers/sbc/sbc_client.rb +247 -0
  44. data/lib/deltacloud/drivers/sbc/sbc_driver.rb +297 -0
  45. data/lib/deltacloud/drivers/terremark/terremark_driver.rb +0 -2
  46. data/lib/deltacloud/hardware_profile.rb +1 -3
  47. data/lib/deltacloud/helpers.rb +0 -2
  48. data/lib/deltacloud/helpers/application_helper.rb +86 -12
  49. data/lib/deltacloud/helpers/blob_stream.rb +19 -2
  50. data/lib/deltacloud/helpers/conversion_helper.rb +0 -2
  51. data/lib/deltacloud/helpers/hardware_profiles_helper.rb +0 -2
  52. data/lib/deltacloud/method_serializer.rb +0 -2
  53. data/lib/deltacloud/models/base_model.rb +0 -2
  54. data/lib/deltacloud/models/blob.rb +1 -2
  55. data/lib/deltacloud/models/bucket.rb +0 -2
  56. data/lib/deltacloud/models/image.rb +0 -2
  57. data/lib/deltacloud/models/instance.rb +19 -2
  58. data/lib/deltacloud/models/instance_profile.rb +4 -2
  59. data/lib/deltacloud/models/key.rb +0 -2
  60. data/lib/deltacloud/models/load_balancer.rb +0 -2
  61. data/lib/deltacloud/models/realm.rb +0 -2
  62. data/lib/deltacloud/models/storage_snapshot.rb +0 -2
  63. data/lib/deltacloud/models/storage_volume.rb +4 -2
  64. data/lib/deltacloud/runner.rb +132 -0
  65. data/lib/deltacloud/state_machine.rb +0 -2
  66. data/lib/deltacloud/validation.rb +9 -7
  67. data/lib/drivers.rb +36 -48
  68. data/lib/sinatra/accept_media_types.rb +26 -0
  69. data/lib/sinatra/lazy_auth.rb +16 -0
  70. data/lib/sinatra/rabbit.rb +112 -54
  71. data/lib/sinatra/rack_driver_select.rb +50 -16
  72. data/lib/sinatra/rack_etag.rb +79 -0
  73. data/lib/sinatra/rack_matrix_params.rb +84 -0
  74. data/lib/sinatra/rack_runtime.rb +47 -0
  75. data/lib/sinatra/static_assets.rb +16 -0
  76. data/lib/sinatra/url_for.rb +31 -4
  77. data/public/favicon.ico +0 -0
  78. data/public/images/bread-bg.png +0 -0
  79. data/public/images/error.png +0 -0
  80. data/public/images/pending.png +0 -0
  81. data/public/images/running.png +0 -0
  82. data/public/images/stopped.png +0 -0
  83. data/public/javascripts/application.js +35 -0
  84. data/public/stylesheets/compiled/application.css +59 -5
  85. data/public/stylesheets/compiled/screen.css +1 -1
  86. data/server.rb +293 -29
  87. data/support/fedora/deltacloud-core +78 -0
  88. data/support/fedora/deltacloud-core.spec +143 -0
  89. data/support/fedora/deltacloudd +78 -18
  90. data/support/fedora/rubygem-deltacloud-core.spec +76 -40
  91. data/tests/common.rb +172 -0
  92. data/tests/drivers/mock/api_test.rb +133 -0
  93. data/tests/drivers/mock/hardware_profiles_test.rb +134 -0
  94. data/tests/drivers/mock/images_test.rb +126 -0
  95. data/tests/drivers/mock/instance_states_test.rb +71 -0
  96. data/tests/drivers/mock/instances_test.rb +236 -0
  97. data/tests/drivers/mock/realms_test.rb +93 -0
  98. data/tests/drivers/mock/setup.rb +3 -0
  99. data/tests/drivers/mock/url_for_test.rb +67 -0
  100. data/tests/drivers/rackspace/api_test.rb +41 -0
  101. data/tests/drivers/rackspace/hardware_profiles_test.rb +53 -0
  102. data/tests/drivers/rackspace/images_test.rb +40 -0
  103. data/tests/drivers/rackspace/instances_test.rb +161 -0
  104. data/tests/drivers/rackspace/realms_test.rb +36 -0
  105. data/tests/drivers/rackspace/setup.rb +14 -0
  106. data/tests/drivers/rhevm/api_test.rb +39 -0
  107. data/tests/drivers/rhevm/hardware_profiles_test.rb +53 -0
  108. data/tests/drivers/rhevm/images_test.rb +42 -0
  109. data/tests/drivers/rhevm/instances_test.rb +179 -0
  110. data/tests/drivers/rhevm/realms_test.rb +35 -0
  111. data/tests/drivers/rhevm/setup.rb +14 -0
  112. data/tests/rabbit_test.rb +52 -0
  113. data/views/api/show.html.haml +2 -5
  114. data/views/blobs/new.html.haml +17 -1
  115. data/views/blobs/show.html.haml +6 -0
  116. data/views/blobs/show.xml.haml +5 -1
  117. data/views/buckets/index.html.haml +1 -12
  118. data/views/buckets/index.xml.haml +3 -5
  119. data/views/docs/operation.html.haml +23 -11
  120. data/views/drivers/index.html.haml +15 -0
  121. data/views/drivers/index.xml.haml +7 -0
  122. data/views/drivers/show.html.haml +20 -0
  123. data/views/drivers/show.xml.haml +7 -0
  124. data/views/error.html.haml +31 -0
  125. data/views/errors/auth_exception.xml.haml +2 -1
  126. data/views/errors/backend_capability_failure.xml.haml +2 -1
  127. data/views/errors/backend_error.html.haml +3 -0
  128. data/views/errors/backend_error.xml.haml +2 -2
  129. data/views/errors/validation_failure.xml.haml +3 -2
  130. data/views/images/index.html.haml +1 -6
  131. data/views/images/index.xml.haml +2 -0
  132. data/views/images/new.html.haml +14 -0
  133. data/views/images/show.xml.haml +2 -0
  134. data/views/instances/index.html.haml +8 -6
  135. data/views/instances/index.xml.haml +4 -0
  136. data/views/instances/new.html.haml +40 -11
  137. data/views/instances/run.html.haml +9 -0
  138. data/views/instances/run.xml.haml +7 -0
  139. data/views/instances/run_command.html.haml +16 -0
  140. data/views/instances/show.html.haml +14 -0
  141. data/views/instances/show.xml.haml +12 -4
  142. data/views/layout.html.haml +7 -2
  143. data/views/load_balancers/index.html.haml +1 -1
  144. data/views/load_balancers/new.html.haml +2 -2
  145. data/views/load_balancers/show.html.haml +1 -1
  146. data/views/storage_snapshots/index.html.haml +3 -0
  147. data/views/storage_snapshots/new.html.haml +9 -0
  148. data/views/storage_volumes/attach.html.haml +20 -0
  149. data/views/storage_volumes/index.html.haml +16 -1
  150. data/views/storage_volumes/index.xml.haml +1 -10
  151. data/views/storage_volumes/new.html.haml +17 -0
  152. data/views/storage_volumes/show.html.haml +8 -0
  153. data/views/storage_volumes/show.xml.haml +25 -3
  154. metadata +197 -127
  155. data/lib/deltacloud/drivers/rackspace/rackspace_client.rb +0 -130
  156. data/parse.rb +0 -7
  157. data/test.rb +0 -3
  158. data/views/api/drivers.xml.haml +0 -6
@@ -6,7 +6,7 @@ html, body {
6
6
  font-weight: inherit;
7
7
  font-style: inherit;
8
8
  font-size: 100%;
9
- font-family: inherit;
9
+ font-family : "Helvetica Neue","Liberation Sans",Arial,sans-serif;
10
10
  vertical-align: baseline; }
11
11
 
12
12
  /* line 12, ../../../../../../../.gem/ruby/1.8/gems/compass-0.8.17/frameworks/blueprint/stylesheets/blueprint/modules/_reset.sass */
data/server.rb CHANGED
@@ -1,5 +1,3 @@
1
- # Copyright (C) 2009, 2010 Red Hat, Inc.
2
- #
3
1
  # Licensed to the Apache Software Foundation (ASF) under one or more
4
2
  # contributor license agreements. See the NOTICE file distributed with
5
3
  # this work for additional information regarding copyright ownership. The
@@ -28,11 +26,19 @@ require 'haml'
28
26
  require 'open3'
29
27
  require 'lib/deltacloud/helpers/blob_stream'
30
28
  require 'sinatra/rack_driver_select'
29
+ require 'sinatra/rack_runtime'
30
+ require 'sinatra/rack_etag'
31
+ require 'sinatra/rack_matrix_params'
31
32
 
32
- set :version, '0.1.0'
33
+ set :version, '0.3.0'
33
34
 
35
+ include Deltacloud::Drivers
36
+ set :drivers, Proc.new { driver_config }
34
37
 
35
- use RackDriverSelect
38
+ use Rack::ETag
39
+ use Rack::Runtime
40
+ use Rack::MatrixParams
41
+ use Rack::DriverSelect
36
42
 
37
43
  configure do
38
44
  set :raise_errors => false
@@ -58,29 +64,29 @@ end
58
64
  error Deltacloud::BackendCapability::Failure do
59
65
  report_error(405, "backend_capability_failure")
60
66
  end
67
+
61
68
  error Deltacloud::AuthException do
62
- report_error(403, "auth_exception")
69
+ report_error(401, "auth_exception")
63
70
  end
64
71
 
65
72
  error Deltacloud::BackendError do
66
73
  report_error(500, "backend_error")
67
74
  end
68
75
 
76
+ error Sinatra::Rabbit::UnsupportedCollectionException do
77
+ report_error(404, "not_found")
78
+ end
79
+
69
80
  Sinatra::Application.register Sinatra::RespondTo
70
81
 
71
82
  # Redirect to /api
72
- get '/' do redirect url_for('/api'); end
73
-
74
- get '/api/drivers\/?' do
75
- respond_to do |format|
76
- format.xml { haml :"api/drivers" }
77
- end
78
- end
83
+ get '/' do redirect url_for('/api'), 301; end
79
84
 
80
85
  get '/api\/?' do
81
86
  if params[:force_auth]
82
87
  return [401, 'Authentication failed'] unless driver.valid_credentials?(credentials)
83
88
  end
89
+ @collections = [:drivers] + driver.supported_collections
84
90
  respond_to do |format|
85
91
  format.xml { haml :"api/show" }
86
92
  format.json do
@@ -97,6 +103,41 @@ end
97
103
 
98
104
  # Rabbit DSL
99
105
 
106
+ collection :drivers do
107
+ global!
108
+
109
+ description <<EOS
110
+ List all the drivers supported by this server.
111
+ EOS
112
+
113
+ operation :index do
114
+ description "List all drivers"
115
+ control do
116
+ @drivers = settings.drivers
117
+ respond_to do |format|
118
+ format.xml { haml :"drivers/index" }
119
+ format.json { @drivers.to_json }
120
+ format.html { haml :"drivers/index" }
121
+ end
122
+ end
123
+ end
124
+
125
+ operation :show do
126
+ description "Show details for a driver"
127
+ param :id, :string
128
+ control do
129
+ @name = params[:id].to_sym
130
+ @driver = settings.drivers[@name]
131
+ return [404, "Driver #{@name} not found"] unless @driver
132
+ respond_to do |format|
133
+ format.xml { haml :"drivers/show" }
134
+ format.json { @driver.to_json }
135
+ format.html { haml :"drivers/show" }
136
+ end
137
+ end
138
+ end
139
+ end
140
+
100
141
  collection :realms do
101
142
  description <<END
102
143
  Within a cloud provider a realm represents a boundary containing resources.
@@ -129,6 +170,13 @@ END
129
170
 
130
171
  end
131
172
 
173
+ get "/api/images/new" do
174
+ @instance = Instance.new( :id => params[:instance_id] )
175
+ respond_to do |format|
176
+ format.html { haml :"images/new" }
177
+ end
178
+ end
179
+
132
180
  collection :images do
133
181
  description <<END
134
182
  An image is a platonic form of a machine. Images are not directly executable,
@@ -154,6 +202,28 @@ END
154
202
  control { show(:image) }
155
203
  end
156
204
 
205
+ operation :create do
206
+ description 'Create image from instance'
207
+ with_capability :create_image
208
+ param :instance_id, :string, :required
209
+ param :name, :string, :optional
210
+ param :description, :string, :optional
211
+ control do
212
+ @image = driver.create_image(credentials, {
213
+ :id => params[:instance_id],
214
+ :name => params[:name],
215
+ :description => params[:description]
216
+ })
217
+ respond_to do |format|
218
+ format.xml do
219
+ response.status = 201 # Created
220
+ haml :"images/show"
221
+ end
222
+ format.html { haml :"images/show" }
223
+ end
224
+ end
225
+ end
226
+
157
227
  end
158
228
 
159
229
  collection :instance_states do
@@ -203,6 +273,7 @@ get "/api/instances/new" do
203
273
  @image = driver.image( credentials, :id => params[:image_id] )
204
274
  @hardware_profiles = driver.hardware_profiles(credentials, :architecture => @image.architecture )
205
275
  @realms = driver.realms(credentials)
276
+ @keys = driver.keys(credentials) if driver_has_feature?(:authentication_key)
206
277
  if driver_has_feature?(:register_to_load_balancer)
207
278
  @load_balancers = driver.load_balancers(credentials)
208
279
  end
@@ -211,6 +282,13 @@ get "/api/instances/new" do
211
282
  end
212
283
  end
213
284
 
285
+ get '/api/instances/:id/run' do
286
+ @instance = driver.instance(credentials, :id => params[:id])
287
+ respond_to do |format|
288
+ format.html { haml :"instances/run_command" }
289
+ end
290
+ end
291
+
214
292
  get '/api/load_balancers/new' do
215
293
  @realms = driver.realms(credentials)
216
294
  @instances = driver.instances(credentials) if driver_has_feature?(:register_instance, :load_balancers)
@@ -246,7 +324,10 @@ collection :load_balancers do
246
324
  control do
247
325
  @load_balancer = driver.create_load_balancer(credentials, params)
248
326
  respond_to do |format|
249
- format.xml { haml :"load_balancers/show" }
327
+ format.xml do
328
+ response.status = 201 # Created
329
+ haml :"load_balancers/show"
330
+ end
250
331
  format.html { haml :"load_balancers/show" }
251
332
  end
252
333
  end
@@ -277,7 +358,11 @@ collection :load_balancers do
277
358
  param :id, :string, :required
278
359
  control do
279
360
  driver.destroy_load_balancer(credentials, params[:id])
280
- redirect(load_balancers_url)
361
+ respond_to do |format|
362
+ format.xml { return 204 }
363
+ format.json { return 204 }
364
+ format.html { return redirect(load_balancers_url) }
365
+ end
281
366
  end
282
367
  end
283
368
 
@@ -312,17 +397,15 @@ END
312
397
  param :realm_id, :string, :optional
313
398
  param :hwp_id, :string, :optional
314
399
  control do
315
- @image = driver.image(credentials, :id => params[:image_id])
316
- instance = driver.create_instance(credentials, @image.id, params)
400
+ @instance = driver.create_instance(credentials, params[:image_id], params)
317
401
  respond_to do |format|
318
402
  format.xml do
319
403
  response.status = 201 # Created
320
- response['Location'] = instance_url(instance.id)
321
- @instance = instance
404
+ response['Location'] = instance_url(@instance.id)
322
405
  haml :"instances/show"
323
406
  end
324
407
  format.html do
325
- redirect instance_url(instance.id) if instance and instance.id
408
+ redirect instance_url(@instance.id) if @instance and @instance.id
326
409
  redirect instances_url
327
410
  end
328
411
  end
@@ -356,6 +439,26 @@ END
356
439
  param :id, :string, :required
357
440
  control { instance_action(:destroy) }
358
441
  end
442
+
443
+ operation :run, :method => :post, :member => true do
444
+ description <<END
445
+ Run command on instance. Either password or private key must be send
446
+ in order to execute command. Authetication method should be advertised
447
+ in instance.
448
+ END
449
+ with_capability :run_on_instance
450
+ param :id, :string, :required
451
+ param :cmd, :string, :required, "Shell command to run on instance"
452
+ param :private_key, :string, :optional, "Private key in PEM format for authentication"
453
+ param :password, :string, :optional, "Password used for authentication"
454
+ control do
455
+ @output = driver.run_on_instance(credentials, params)
456
+ respond_to do |format|
457
+ format.xml { haml :"instances/run" }
458
+ format.html { haml :"instances/run" }
459
+ end
460
+ end
461
+ end
359
462
  end
360
463
 
361
464
  collection :hardware_profiles do
@@ -401,6 +504,12 @@ END
401
504
 
402
505
  end
403
506
 
507
+ get '/api/storage_snapshots/new' do
508
+ respond_to do |format|
509
+ format.html { haml :"storage_snapshots/new" }
510
+ end
511
+ end
512
+
404
513
  collection :storage_snapshots do
405
514
  description "Storage snapshots description here"
406
515
 
@@ -417,6 +526,44 @@ collection :storage_snapshots do
417
526
  param :id, :string, :required
418
527
  control { show(:storage_snapshot) }
419
528
  end
529
+
530
+ operation :create do
531
+ description "Create a new snapshot from volume"
532
+ with_capability :create_storage_snapshot
533
+ param :volume_id, :string, :required
534
+ control do
535
+ response.status = 201 # Created
536
+ @storage_snapshot = driver.create_storage_snapshot(credentials, params)
537
+ show(:storage_snapshot)
538
+ end
539
+ end
540
+
541
+ operation :destroy do
542
+ description "Delete storage snapshot"
543
+ with_capability :destroy_storage_snapshot
544
+ param :id, :string, :required
545
+ control do
546
+ driver.destroy_storage_snapshot(credentials, params)
547
+ respond_to do |format|
548
+ format.xml { return 204 }
549
+ format.json { return 204 }
550
+ format.html { return redirect(storage_snapshots_url) }
551
+ end
552
+ end
553
+ end
554
+ end
555
+
556
+ get '/api/storage_volumes/new' do
557
+ respond_to do |format|
558
+ format.html { haml :"storage_volumes/new" }
559
+ end
560
+ end
561
+
562
+ get '/api/storage_volumes/attach' do
563
+ respond_to do |format|
564
+ @instances = driver.instances(credentials)
565
+ format.html { haml :"storage_volumes/attach" }
566
+ end
420
567
  end
421
568
 
422
569
  collection :storage_volumes do
@@ -435,6 +582,63 @@ collection :storage_volumes do
435
582
  param :id, :string, :required
436
583
  control { show(:storage_volume) }
437
584
  end
585
+
586
+ operation :create do
587
+ description "Create a new storage volume"
588
+ with_capability :create_storage_volume
589
+ param :snapshot_id, :string, :optional
590
+ param :capacity, :string, :optional
591
+ param :realm_id, :string, :optional
592
+ control do
593
+ @storage_volume = driver.create_storage_volume(credentials, params)
594
+ respond_to do |format|
595
+ format.html { haml :"storage_volumes/show" }
596
+ format.xml do
597
+ response.status = 201 # Created
598
+ haml :"storage_volumes/show"
599
+ end
600
+ end
601
+ end
602
+ end
603
+
604
+ operation :attach, :method => :post, :member => true do
605
+ description "Attach storage volume to instance"
606
+ with_capability :attach_storage_volume
607
+ param :id, :string, :required
608
+ param :instance_id,:string, :required
609
+ param :device, :string, :required
610
+ control do
611
+ driver.attach_storage_volume(credentials, params)
612
+ redirect(storage_volume_url(params[:id]))
613
+ end
614
+ end
615
+
616
+ operation :detach, :method => :post, :member => true do
617
+ description "Detach storage volume to instance"
618
+ with_capability :detach_storage_volume
619
+ param :id, :string, :required
620
+ control do
621
+ volume = driver.storage_volume(credentials, :id => params[:id])
622
+ driver.detach_storage_volume(credentials, :id => volume.id, :instance_id => volume.instance_id,
623
+ :device => volume.device)
624
+ redirect(storage_volume_url(params[:id]))
625
+ end
626
+ end
627
+
628
+ operation :destroy do
629
+ description "Destroy storage volume"
630
+ with_capability :destroy_storage_volume
631
+ param :id, :string, :optional
632
+ control do
633
+ driver.destroy_storage_volume(credentials, params)
634
+ respond_to do |format|
635
+ format.xml { return 204 }
636
+ format.json { return 204 }
637
+ format.html { return redirect(storage_volumes_url) }
638
+ end
639
+ end
640
+ end
641
+
438
642
  end
439
643
 
440
644
  get '/api/keys/new' do
@@ -469,7 +673,10 @@ collection :keys do
469
673
  @key = driver.create_key(credentials, { :key_name => params[:name] })
470
674
  respond_to do |format|
471
675
  format.html { haml :"keys/show" }
472
- format.xml { haml :"keys/show", :ugly => true }
676
+ format.xml do
677
+ response.status = 201 # Created
678
+ haml :"keys/show", :ugly => true
679
+ end
473
680
  end
474
681
  end
475
682
  end
@@ -479,8 +686,12 @@ collection :keys do
479
686
  with_capability :destroy_key
480
687
  param :id, :string, :required
481
688
  control do
482
- driver.destroy_key(credentials, { :key_name => params[:id]})
483
- redirect(keys_url)
689
+ driver.destroy_key(credentials, { :id => params[:id]})
690
+ respond_to do |format|
691
+ format.xml { 204 }
692
+ format.json { 204 }
693
+ format.html { redirect(keys_url) }
694
+ end
484
695
  end
485
696
  end
486
697
 
@@ -499,7 +710,21 @@ post '/api/buckets/:bucket' do
499
710
  bucket_id = params[:bucket]
500
711
  blob_id = params['blob_id']
501
712
  blob_data = params['blob_data']
502
- @blob = driver.create_blob(credentials, bucket_id, blob_id, blob_data )
713
+ user_meta = {}
714
+ #first try get blob_metadata from params (i.e., passed by http form post, e.g. browser)
715
+ max = params[:meta_params]
716
+ if(max)
717
+ (1..max.to_i).each do |i|
718
+ key = params[:"meta_name#{i}"]
719
+ key = "HTTP_X_Deltacloud_Blobmeta_#{key}"
720
+ value = params[:"meta_value#{i}"]
721
+ user_meta[key] = value
722
+ end #max.each do
723
+ else #can try to get blob_metadata from http headers
724
+ meta_array = request.env.select{|k,v| k.match(/^HTTP[-_]X[-_]Deltacloud[-_]Blobmeta[-_]/i)}
725
+ meta_array.inject({}){ |result, array| user_meta[array.first.upcase] = array.last}
726
+ end #end if
727
+ @blob = driver.create_blob(credentials, bucket_id, blob_id, blob_data, user_meta)
503
728
  respond_to do |format|
504
729
  format.html { haml :"blobs/show"}
505
730
  format.xml { haml :"blobs/show" }
@@ -511,7 +736,38 @@ delete '/api/buckets/:bucket/:blob' do
511
736
  bucket_id = params[:bucket]
512
737
  blob_id = params[:blob]
513
738
  driver.delete_blob(credentials, bucket_id, blob_id)
514
- redirect(bucket_url(bucket_id))
739
+ respond_to do |format|
740
+ format.xml { 204 }
741
+ format.json { 204 }
742
+ format.html { bucket_url(bucket_id) }
743
+ end
744
+ end
745
+
746
+ #get blob metadata
747
+ head '/api/buckets/:bucket/:blob' do
748
+ @blob_id = params[:blob]
749
+ @blob_metadata = driver.blob_metadata(credentials, {:id => params[:blob], 'bucket' => params[:bucket]})
750
+ if @blob_metadata
751
+ @blob_metadata.each do |k,v|
752
+ headers["X-Deltacloud-Blobmeta-#{k}"] = v
753
+ end
754
+ else
755
+ report_error(404, 'not_found')
756
+ end
757
+ end
758
+
759
+ #update blob metadata
760
+ post '/api/buckets/:bucket/:blob' do
761
+ meta_hash = {}
762
+ request.env.inject({}){|current, (k,v)| meta_hash[k] = v if k.match(/^HTTP[-_]X[-_]Deltacloud[-_]Blobmeta[-_]/i)}
763
+ success = driver.update_blob_metadata(credentials, {'bucket'=>params[:bucket], :id =>params[:blob], 'meta_hash' => meta_hash})
764
+ if(success)
765
+ meta_hash.each do |k,v|
766
+ headers["X-Deltacloud-Blobmeta-#{k}"] = v
767
+ end
768
+ else
769
+ report_error(404, 'not_found') #FIXME is this the right error code?
770
+ end
515
771
  end
516
772
 
517
773
  #Get a particular blob's particulars (not actual blob data)
@@ -531,10 +787,14 @@ end
531
787
  #get the content of a particular blob
532
788
  get '/api/buckets/:bucket/:blob/content' do
533
789
  @blob = driver.blob(credentials, { :id => params[:blob], 'bucket' => params[:bucket]})
534
- params['content_length'] = @blob.content_length
535
- params['content_type'] = @blob.content_type
536
- params['content_disposition'] = "attachment; filename=#{@blob.id}"
537
- BlobStream.call(env, credentials, params)
790
+ if @blob
791
+ params['content_length'] = @blob.content_length
792
+ params['content_type'] = @blob.content_type
793
+ params['content_disposition'] = "attachment; filename=#{@blob.id}"
794
+ BlobStream.call(env, credentials, params)
795
+ else
796
+ report_error(404, 'not_found')
797
+ end
538
798
  end
539
799
 
540
800
  #Get html form for creating a new bucket
@@ -589,7 +849,11 @@ collection :buckets do
589
849
  param :id, :string, :required
590
850
  control do
591
851
  driver.delete_bucket(credentials, params[:id], params)
592
- redirect(buckets_url)
852
+ respond_to do |format|
853
+ format.xml { 204 }
854
+ format.json { 204 }
855
+ format.html { redirect(buckets_url) }
856
+ end
593
857
  end
594
858
  end
595
859