deltacloud-core 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/deltacloud.rb +1 -0
  2. data/lib/deltacloud/backend_capability.rb +21 -0
  3. data/lib/deltacloud/base_driver/base_driver.rb +6 -0
  4. data/lib/deltacloud/base_driver/features.rb +16 -0
  5. data/lib/deltacloud/base_driver/mock_driver.rb +25 -5
  6. data/lib/deltacloud/drivers/ec2/ec2_driver.rb +137 -15
  7. data/lib/deltacloud/drivers/gogrid/gogrid_client.rb +4 -7
  8. data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +116 -3
  9. data/lib/deltacloud/drivers/mock/mock_driver.rb +56 -2
  10. data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +5 -19
  11. data/lib/deltacloud/helpers/application_helper.rb +22 -2
  12. data/lib/deltacloud/models/instance.rb +22 -5
  13. data/lib/deltacloud/models/key.rb +16 -0
  14. data/lib/deltacloud/models/{tag.rb → load_balancer.rb} +14 -18
  15. data/lib/sinatra/rabbit.rb +3 -0
  16. data/parse.rb +7 -0
  17. data/public/javascripts/application.js +10 -24
  18. data/public/stylesheets/compiled/application.css +2 -0
  19. data/server.rb +141 -15
  20. data/test.rb +3 -0
  21. data/views/blobs/new.html.haml +10 -0
  22. data/views/blobs/show.html.haml +21 -15
  23. data/views/buckets/index.html.haml +1 -1
  24. data/views/buckets/show.html.haml +5 -2
  25. data/views/errors/backend_capability_failure.html.haml +11 -0
  26. data/views/errors/backend_capability_failure.xml.haml +4 -0
  27. data/views/errors/not_allowed.html.haml +6 -0
  28. data/views/errors/not_allowed.xml.haml +2 -0
  29. data/views/instances/index.html.haml +1 -1
  30. data/views/instances/new.html.haml +8 -0
  31. data/views/instances/show.html.haml +1 -1
  32. data/views/keys/index.html.haml +1 -1
  33. data/views/load_balancers/index.html.haml +33 -0
  34. data/views/load_balancers/index.xml.haml +5 -0
  35. data/views/load_balancers/new.html.haml +38 -0
  36. data/views/load_balancers/show.html.haml +37 -0
  37. data/views/load_balancers/show.xml.haml +21 -0
  38. data/views/storage_snapshots/index.xml.haml +0 -2
  39. data/views/storage_snapshots/show.xml.haml +0 -2
  40. data/views/storage_volumes/index.xml.haml +6 -6
  41. data/views/storage_volumes/show.xml.haml +7 -7
  42. metadata +48 -36
  43. data/views/tags/index.html.haml +0 -1
@@ -26,7 +26,7 @@ module Deltacloud
26
26
  class MockDriver < Deltacloud::BaseDriver
27
27
 
28
28
  def supported_collections
29
- DEFAULT_COLLECTIONS + [ :buckets ]
29
+ DEFAULT_COLLECTIONS + [ :buckets, :keys]
30
30
  end
31
31
 
32
32
  ( REALMS = [
@@ -81,6 +81,7 @@ class MockDriver < Deltacloud::BaseDriver
81
81
  end
82
82
 
83
83
  feature :instances, :user_name
84
+ feature :instances, :authentication_key
84
85
 
85
86
  def initialize
86
87
  if ENV["DELTACLOUD_MOCK_STORAGE"]
@@ -131,11 +132,21 @@ class MockDriver < Deltacloud::BaseDriver
131
132
  # Instances
132
133
  #
133
134
 
135
+ def instance(credentials, opts={})
136
+ check_credentials( credentials )
137
+ instance_filename = File.join(@storage_root, 'instances', "#{opts[:id]}.yml")
138
+ return nil unless File.exists?(instance_filename)
139
+ instance = YAML::load_file(instance_filename)
140
+ instance[:actions] = instance_actions_for( instance[:state] )
141
+ instance[:id] = File::basename(instance_filename, ".yml")
142
+ Instance.new(instance)
143
+ end
144
+
134
145
  def instances(credentials, opts=nil)
135
146
  check_credentials( credentials )
136
147
  instances = []
137
148
  Dir[ "#{@storage_root}/instances/*.yml" ].each do |instance_file|
138
- instance = YAML.load( File.read( instance_file ) )
149
+ instance = YAML::load_file(instance_file)
139
150
  if ( instance[:owner_id] == credentials.user )
140
151
  instance[:id] = File.basename( instance_file, ".yml" )
141
152
  instance[:actions] = instance_actions_for( instance[:state] )
@@ -254,6 +265,49 @@ class MockDriver < Deltacloud::BaseDriver
254
265
  snapshots
255
266
  end
256
267
 
268
+ def keys(credentials, opts={})
269
+ check_credentials(credentials)
270
+ result = []
271
+ key_dir = File.join(@storage_root, 'keys')
272
+ Dir[key_dir + '/*.yml'].each do |key_file|
273
+ result << Key.new(YAML::load(File.read(key_file)))
274
+ end
275
+ result = filter_on( result, :id, opts )
276
+ result
277
+ end
278
+
279
+ def key(credentials, opts={})
280
+ keys(credentials, opts).first
281
+ end
282
+
283
+ def create_key(credentials, opts={})
284
+ check_credentials(credentials)
285
+ key_hash = {
286
+ :id => opts[:key_name],
287
+ :credential_type => :key,
288
+ :fingerprint => Key::generate_mock_fingerprint,
289
+ :pem_rsa_key => Key::generate_mock_pem
290
+ }
291
+ key_dir = File.join(@storage_root, 'keys')
292
+ if File.exists?(key_dir + "/#{key_hash[:id]}.yml")
293
+ raise Deltacloud::BackendError.new(403, self.class.to_s, "key-exists",
294
+ ["Key with same name already exists"])
295
+ end
296
+ FileUtils.mkdir_p(key_dir) unless File.directory?(key_dir)
297
+ File.open(key_dir + "/#{key_hash[:id]}.yml", 'w') do |f|
298
+ f.puts(YAML::dump(key_hash))
299
+ end
300
+ return Key.new(key_hash)
301
+ end
302
+
303
+ def destroy_key(credentials, opts={})
304
+ key = key(credentials, opts)
305
+ safely do
306
+ key_dir = File.join(@storage_root, 'keys')
307
+ File.delete(key_dir + "/#{key.id}.yml")
308
+ end
309
+ end
310
+
257
311
  #--
258
312
  # Buckets
259
313
  #--
@@ -35,6 +35,10 @@ class RHEVMDriver < Deltacloud::BaseDriver
35
35
 
36
36
  feature :instances, :user_name
37
37
 
38
+ def supported_collections
39
+ DEFAULT_COLLECTIONS.reject { |c| [ :storage_volumes, :storage_snapshots ].include?(c) }
40
+ end
41
+
38
42
  #
39
43
  # Execute a Powershell command, and convert the output
40
44
  # to YAML in order to get back an array of maps.
@@ -85,6 +89,7 @@ class RHEVMDriver < Deltacloud::BaseDriver
85
89
  "STOPPED"
86
90
  when "POWERING UP"
87
91
  "PENDING"
92
+ end
88
93
  end
89
94
 
90
95
  define_hardware_profile 'rhevm'
@@ -232,25 +237,6 @@ class RHEVMDriver < Deltacloud::BaseDriver
232
237
  vm = execute(credentials, "deleteVm.ps1", image_id)
233
238
  vm_to_instance(vm[0])
234
239
  end
235
-
236
- #
237
- # Storage Volumes
238
- #
239
-
240
- def storage_volumes(credentials, ids=nil)
241
- volumes = []
242
- volumes
243
- end
244
-
245
- #
246
- # Storage Snapshots
247
- #
248
-
249
- def storage_snapshots(credentials, ids=nil)
250
- snapshots = []
251
- snapshots
252
- end
253
-
254
240
  end
255
241
 
256
242
  end
@@ -41,8 +41,8 @@ module ApplicationHelper
41
41
  collections[:instances].operations[action.to_sym].method
42
42
  end
43
43
 
44
- def driver_has_feature?(feature_name)
45
- not driver.features(:instances).select{ |f| f.name.eql?(feature_name) }.empty?
44
+ def driver_has_feature?(feature_name, collection_name = :instances)
45
+ not driver.features(collection_name).select{ |f| f.name.eql?(feature_name) }.empty?
46
46
  end
47
47
 
48
48
  def driver_has_auth_features?
@@ -102,6 +102,14 @@ module ApplicationHelper
102
102
  end
103
103
 
104
104
  def instance_action(name)
105
+ original_instance = driver.instance(credentials, :id => params[:id])
106
+
107
+ # If original instance doesn't include called action
108
+ # return with 405 error (Method is not Allowed)
109
+ unless driver.instance_actions_for(original_instance.state).include?(name.to_sym)
110
+ return report_error(405, 'not_allowed')
111
+ end
112
+
105
113
  @instance = driver.send(:"#{name}_instance", credentials, params["id"])
106
114
 
107
115
  return redirect(instances_url) if name.eql?(:destroy) or @instance.class!=Instance
@@ -122,4 +130,16 @@ module ApplicationHelper
122
130
  "<pem><![CDATA[#{text.strip}]]></pem>"
123
131
  end
124
132
 
133
+ def link_to_action(action, url, method)
134
+ return link_to(action, url) if method.eql? :get
135
+ capture_haml do
136
+ haml_tag :form, :method => :post, :action => url, :class => :link do
137
+ haml_tag :input, :type => :hidden, :name => '_method', :value => method
138
+ haml_tag :button, :type => :submit do
139
+ haml_concat action
140
+ end
141
+ end
142
+ end
143
+ end
144
+
125
145
  end
@@ -29,10 +29,27 @@ class Instance < BaseModel
29
29
  attr_accessor :private_addresses
30
30
  attr_accessor :instance_profile
31
31
  attr_accessor :launch_time
32
- def initialize(init=nil)
33
- super(init)
34
- self.actions = [] if self.actions.nil?
35
- self.public_addresses = [] if self.public_addresses.nil?
36
- self.private_addresses = [] if self.private_addresses.nil?
32
+ attr_accessor :keyname
33
+ attr_accessor :authn_error
34
+
35
+ def initialize(init=nil)
36
+ super(init)
37
+ self.actions = [] if self.actions.nil?
38
+ self.public_addresses = [] if self.public_addresses.nil?
39
+ self.private_addresses = [] if self.private_addresses.nil?
40
+ end
41
+
42
+ def method_missing(name, *args)
43
+ if name =~ /is_(\w+)\?/
44
+ return true if self.state.downcase.eql?($1)
45
+ else
46
+ raise NoMethodError
47
+ end
37
48
  end
49
+
50
+ def authn_feature_failed?
51
+ return true unless authn_error.nil?
52
+ end
53
+
54
+
38
55
  end
@@ -32,4 +32,20 @@ class Key < BaseModel
32
32
  true if @credential_type.eql?(:key)
33
33
  end
34
34
 
35
+ # Mock fingerprint generator
36
+ # 1f:51:ae:28:bf:89:e9:d8:1f:25:5d:37:2d:7d:b8:ca:9f:f5:f1:6f
37
+ def self.generate_mock_fingerprint
38
+ (0..19).map { "%02x" % (rand * 0xff) }.join(':')
39
+ end
40
+
41
+ # Mock PEM file
42
+ # NOTE: This is a fake PEM file, it will not work against SSH
43
+ def self.generate_mock_pem
44
+ chars = (('a'..'z').to_a + ('A'..'Z').to_a + ('0'..'9').to_a + %w(= / + ))
45
+ pem_material = (1..21).map do
46
+ (1..75).collect{|a| chars[rand(chars.size)] }.join
47
+ end.join("\n") + "\n" + (1..68).collect{|a| chars[rand(chars.size)] }.join
48
+ "-----BEGIN RSA PRIVATE KEY-----\n"+pem_material+"-----END RSA PRIVATE KEY-----"
49
+ end
50
+
35
51
  end
@@ -16,28 +16,24 @@
16
16
  # License for the specific language governing permissions and limitations
17
17
  # under the License.
18
18
 
19
- class Tag < BaseModel
20
19
 
21
- attr_accessor :resource_id
22
- attr_accessor :resource_type
23
- attr_accessor :values
20
+ class LoadBalancer < BaseModel
24
21
 
25
- def add_value(name)
26
- self.values << Value.new(name, self)
27
- end
28
-
29
- class Value
30
- attr_accessor :name
31
- attr_accessor :tag_id
32
-
33
- def initialize(name, tag_id)
34
- self.name, self.tag_id = name, tag_id
35
- end
22
+ attr_accessor :realms
23
+ attr_accessor :listeners
24
+ attr_accessor :instances
25
+ attr_accessor :public_addresses
26
+ attr_accessor :created_at
36
27
 
37
- def to_s
38
- self.name
39
- end
28
+ def add_listener(opts)
29
+ @listeners << Listener.new(opts)
30
+ end
40
31
 
32
+ class Listener < BaseModel
33
+ attr_accessor :protocol
34
+ attr_accessor :load_balancer_port
35
+ attr_accessor :instance_port
41
36
  end
42
37
 
43
38
  end
39
+
@@ -1,6 +1,7 @@
1
1
  require 'sinatra/base'
2
2
  require 'sinatra/url_for'
3
3
  require 'deltacloud/validation'
4
+ require 'deltacloud/backend_capability'
4
5
 
5
6
  module Sinatra
6
7
 
@@ -13,6 +14,7 @@ module Sinatra
13
14
  class Operation
14
15
  attr_reader :name, :method
15
16
 
17
+ include ::Deltacloud::BackendCapability
16
18
  include ::Deltacloud::Validation
17
19
 
18
20
  STANDARD = {
@@ -58,6 +60,7 @@ module Sinatra
58
60
  def control(&block)
59
61
  op = self
60
62
  @control = Proc.new do
63
+ op.check_capability(driver)
61
64
  op.validate(params)
62
65
  instance_eval(&block)
63
66
  end
@@ -0,0 +1,7 @@
1
+ require 'rubygems'
2
+ require 'nokogiri'
3
+ require 'ap'
4
+
5
+ doc = Nokogiri::XML(File.read("/home/mfojtik/Autounattend.xml"))
6
+
7
+ ap (doc/"//*[local-name()='component']/*[local-name()='ProductKey']").text
@@ -3,30 +3,16 @@
3
3
 
4
4
  $(document).ready(function() {
5
5
 
6
- $("a.delete").click(function(e) {
7
- var original_url = $(this).attr('href')
8
- $.ajax({
9
- url : original_url,
10
- type : 'DELETE',
11
- cache : false,
12
- success: function(data) {
13
- window.location = original_url.replace(/\/([\w_-]+)$/i, '')
6
+ if ($('select#list_instances').length) {
7
+ $('select#list_instances').html("<option>Loading instances...</option>");
8
+ $.getJSON("/api/instances?state=RUNNING&format=json",
9
+ function(data){
10
+ $('select#list_instances').empty();
11
+ $.each(data.instances, function(i,item){
12
+ $('select#list_instances').append('<option value="'+item.id+'">'+item.id+'</option>');
13
+ });
14
14
  }
15
- })
16
- return false;
17
- })
18
-
19
- $("a.post").click(function(e) {
20
- var original_url = $(this).attr('href')
21
- $.ajax({
22
- url : original_url,
23
- type : 'POST',
24
- dataType : 'xml',
25
- success: function(data) {
26
- window.location = original_url.replace(/\/([\w_-]+)$/i, '')
27
- }
28
- })
29
- return false;
30
- })
15
+ );
16
+ }
31
17
 
32
18
  })
@@ -611,3 +611,5 @@ input[type='radio'] {
611
611
  table.docs { border : 1px solid #ccc }
612
612
  table.docs td { border : 1px solid #ccc }
613
613
  table.docs table td { border : none }
614
+
615
+ td form.link { display : inline }
data/server.rb CHANGED
@@ -32,6 +32,9 @@ error Deltacloud::Validation::Failure do
32
32
  report_error(400, "validation_failure")
33
33
  end
34
34
 
35
+ error Deltacloud::BackendCapability::Failure do
36
+ report_error(405, "backend_capability_failure")
37
+ end
35
38
  error Deltacloud::AuthException do
36
39
  report_error(403, "auth_exception")
37
40
  end
@@ -82,6 +85,7 @@ END
82
85
  Operation will list all available realms. Realms can be filtered using
83
86
  the "architecture" parameter.
84
87
  END
88
+ with_capability :realms
85
89
  param :id, :string
86
90
  param :architecture, :string, :optional, [ 'i386', 'x86_64' ]
87
91
  control { filter_all(:realms) }
@@ -90,6 +94,7 @@ END
90
94
  #FIXME: It always shows whole list
91
95
  operation :show do
92
96
  description 'Show an realm identified by "id" parameter.'
97
+ with_capability :realm
93
98
  param :id, :string, :required
94
99
  control { show(:realm) }
95
100
  end
@@ -108,6 +113,7 @@ END
108
113
  available to the current use. Images can be filtered using the
109
114
  "owner_id" and "architecture" parameters.
110
115
  END
116
+ with_capability :images
111
117
  param :id, :string
112
118
  param :architecture, :string, :optional
113
119
  control { filter_all(:images) }
@@ -115,6 +121,7 @@ END
115
121
 
116
122
  operation :show do
117
123
  description 'Show an image identified by "id" parameter.'
124
+ with_capability :image
118
125
  param :id, :string, :required
119
126
  control { show(:image) }
120
127
  end
@@ -168,11 +175,87 @@ get "/api/instances/new" do
168
175
  @image = driver.image( credentials, :id => params[:image_id] )
169
176
  @hardware_profiles = driver.hardware_profiles(credentials, :architecture => @image.architecture )
170
177
  @realms = driver.realms(credentials)
178
+ if driver_has_feature?(:register_to_load_balancer)
179
+ @load_balancers = driver.load_balancers(credentials)
180
+ end
171
181
  respond_to do |format|
172
182
  format.html { haml :"instances/new" }
173
183
  end
174
184
  end
175
185
 
186
+ get '/api/load_balancers/new' do
187
+ @realms = driver.realms(credentials)
188
+ @instances = driver.instances(credentials) if driver_has_feature?(:register_instance, :load_balancers)
189
+ respond_to do |format|
190
+ format.html { haml :"load_balancers/new" }
191
+ end
192
+ end
193
+
194
+
195
+ collection :load_balancers do
196
+ description "Load balancers"
197
+
198
+ operation :index do
199
+ description "List of all active load balancers"
200
+ control do
201
+ filter_all :load_balancers
202
+ end
203
+ end
204
+
205
+ operation :show do
206
+ description "Show details about given load balancer"
207
+ param :id, :string, :required
208
+ control { show :load_balancer }
209
+ end
210
+
211
+ operation :create do
212
+ description "Create a new load balancer"
213
+ param :name, :string, :required
214
+ param :realm_id, :string, :required
215
+ param :listener_protocol, :string, :required, ['HTTP', 'TCP']
216
+ param :listener_balancer_port, :string, :required
217
+ param :listener_instance_port, :string, :required
218
+ control do
219
+ @load_balancer = driver.create_load_balancer(credentials, params)
220
+ respond_to do |format|
221
+ format.xml { haml :"load_balancers/show" }
222
+ format.html { haml :"load_balancers/show" }
223
+ end
224
+ end
225
+ end
226
+
227
+ operation :register, :method => :post, :member => true do
228
+ description "Add instance to loadbalancer"
229
+ param :id, :string, :required
230
+ param :instance_id, :string, :required
231
+ control do
232
+ driver.lb_register_instance(credentials, params)
233
+ redirect(load_balancer_url(params[:id]))
234
+ end
235
+ end
236
+
237
+ operation :unregister, :method => :post, :member => true do
238
+ description "Remove instance from loadbalancer"
239
+ param :id, :string, :required
240
+ param :instance_id, :string, :required
241
+ control do
242
+ driver.lb_unregister_instance(credentials, params)
243
+ redirect(load_balancer_url(params[:id]))
244
+ end
245
+ end
246
+
247
+ operation :destroy do
248
+ description "Destroy given load balancer"
249
+ param :id, :string, :required
250
+ control do
251
+ driver.destroy_load_balancer(credentials, params[:id])
252
+ redirect(load_balancers_url)
253
+ end
254
+ end
255
+
256
+ end
257
+
258
+
176
259
  collection :instances do
177
260
  description <<END
178
261
  An instance is a concrete machine realized from an image.
@@ -181,6 +264,7 @@ END
181
264
 
182
265
  operation :index do
183
266
  description "List all instances."
267
+ with_capability :instances
184
268
  param :id, :string, :optional
185
269
  param :state, :string, :optional
186
270
  control { filter_all(:instances) }
@@ -188,12 +272,14 @@ END
188
272
 
189
273
  operation :show do
190
274
  description 'Show an instance identified by "id" parameter.'
275
+ with_capability :instance
191
276
  param :id, :string, :required
192
277
  control { show(:instance) }
193
278
  end
194
279
 
195
280
  operation :create do
196
281
  description "Create a new instance."
282
+ with_capability :create_instance
197
283
  param :image_id, :string, :required
198
284
  param :realm_id, :string, :optional
199
285
  param :hwp_id, :string, :optional
@@ -217,24 +303,28 @@ END
217
303
 
218
304
  operation :reboot, :method => :post, :member => true do
219
305
  description "Reboot a running instance."
306
+ with_capability :reboot_instance
220
307
  param :id, :string, :required
221
308
  control { instance_action(:reboot) }
222
309
  end
223
310
 
224
311
  operation :start, :method => :post, :member => true do
225
312
  description "Start an instance."
313
+ with_capability :start_instance
226
314
  param :id, :string, :required
227
315
  control { instance_action(:start) }
228
316
  end
229
317
 
230
318
  operation :stop, :method => :post, :member => true do
231
319
  description "Stop a running instance."
320
+ with_capability :stop_instance
232
321
  param :id, :string, :required
233
322
  control { instance_action(:stop) }
234
323
  end
235
324
 
236
325
  operation :destroy do
237
326
  description "Destroy an instance."
327
+ with_capability :destroy_instance
238
328
  param :id, :string, :required
239
329
  control { instance_action(:destroy) }
240
330
  end
@@ -250,6 +340,7 @@ END
250
340
 
251
341
  operation :index do
252
342
  description "List of available hardware profiles."
343
+ with_capability :hardware_profiles
253
344
  param :id, :string
254
345
  param :architecture, :string, :optional, [ 'i386', 'x86_64' ]
255
346
  control do
@@ -264,6 +355,7 @@ END
264
355
 
265
356
  operation :show do
266
357
  description "Show specific hardware profile."
358
+ with_capability :hardware_profile
267
359
  param :id, :string, :required
268
360
  control do
269
361
  @profile = driver.hardware_profile(credentials, params[:id])
@@ -286,12 +378,14 @@ collection :storage_snapshots do
286
378
 
287
379
  operation :index do
288
380
  description "List of storage snapshots."
381
+ with_capability :storage_snapshots
289
382
  param :id, :string
290
383
  control { filter_all(:storage_snapshots) }
291
384
  end
292
385
 
293
386
  operation :show do
294
387
  description "Show storage snapshot."
388
+ with_capability :storage_snapshot
295
389
  param :id, :string, :required
296
390
  control { show(:storage_snapshot) }
297
391
  end
@@ -302,12 +396,14 @@ collection :storage_volumes do
302
396
 
303
397
  operation :index do
304
398
  description "List of storage volumes."
399
+ with_capability :storage_volumes
305
400
  param :id, :string
306
401
  control { filter_all(:storage_volumes) }
307
402
  end
308
403
 
309
404
  operation :show do
310
405
  description "Show storage volume."
406
+ with_capability :storage_volume
311
407
  param :id, :string, :required
312
408
  control { show(:storage_volume) }
313
409
  end
@@ -324,6 +420,7 @@ collection :keys do
324
420
 
325
421
  operation :index do
326
422
  description "List all available credentials which could be used for instance authentication."
423
+ with_capability :keys
327
424
  control do
328
425
  filter_all :keys
329
426
  end
@@ -331,18 +428,16 @@ collection :keys do
331
428
 
332
429
  operation :show do
333
430
  description "Show details about given instance credential."
431
+ with_capability :key
334
432
  param :id, :string, :required
335
433
  control { show :key }
336
434
  end
337
435
 
338
436
  operation :create do
339
437
  description "Create a new instance credential if backend supports this."
438
+ with_capability :create_key
340
439
  param :name, :string, :required
341
440
  control do
342
- unless driver.respond_to?(:create_key)
343
- raise Deltacloud::BackendFeatureUnsupported.new('501',
344
- 'Creating instance credentials is not supported in backend')
345
- end
346
441
  @key = driver.create_key(credentials, { :key_name => params[:name] })
347
442
  respond_to do |format|
348
443
  format.html { haml :"keys/show" }
@@ -353,12 +448,9 @@ collection :keys do
353
448
 
354
449
  operation :destroy do
355
450
  description "Destroy given instance credential if backend supports this."
451
+ with_capability :destroy_key
356
452
  param :id, :string, :required
357
453
  control do
358
- unless driver.respond_to?(:destroy_key)
359
- raise Deltacloud::BackendFeatureUnsupported.new('501',
360
- 'Creating instance credentials is not supported in backend')
361
- end
362
454
  driver.destroy_key(credentials, { :key_name => params[:id]})
363
455
  redirect(keys_url)
364
456
  end
@@ -366,6 +458,35 @@ collection :keys do
366
458
 
367
459
  end
368
460
 
461
+ #get html form for creating a new blob
462
+ get '/api/buckets/:bucket/new_blob' do
463
+ @bucket_id = params[:bucket]
464
+ respond_to do |format|
465
+ format.html {haml :"blobs/new"}
466
+ end
467
+ end
468
+
469
+ #create a new blob
470
+ post '/api/buckets/:bucket' do
471
+ bucket_id = params[:bucket]
472
+ blob_id = params['blob_id']
473
+ blob_data = params['blob_data']
474
+ @blob = driver.create_blob(credentials, bucket_id, blob_id, blob_data )
475
+ respond_to do |format|
476
+ format.html { haml :"blobs/show"}
477
+ format.xml { haml :"blobs/show" }
478
+ end
479
+ end
480
+
481
+ #delete a blob
482
+ delete '/api/buckets/:bucket/:blob' do
483
+ bucket_id = params[:bucket]
484
+ blob_id = params[:blob]
485
+ driver.delete_blob(credentials, bucket_id, blob_id)
486
+ redirect(bucket_url(bucket_id))
487
+ end
488
+
489
+ #Get a particular blob's particulars (not actual blob data)
369
490
  get '/api/buckets/:bucket/:blob' do
370
491
  @blob = driver.blob(credentials, { :id => params[:blob], 'bucket' => params[:bucket]})
371
492
  if @blob
@@ -379,13 +500,7 @@ get '/api/buckets/:bucket/:blob' do
379
500
  end
380
501
  end
381
502
 
382
- get '/api/buckets/new' do
383
- respond_to do |format|
384
- format.html { haml :"buckets/new" }
385
- end
386
- end
387
-
388
-
503
+ #get the content of a particular blob
389
504
  get '/api/buckets/:bucket/:blob/content' do
390
505
  @blob = driver.blob(credentials, { :id => params[:blob], 'bucket' => params[:bucket]})
391
506
  params['content_length'] = @blob.content_length
@@ -393,11 +508,19 @@ get '/api/buckets/:bucket/:blob/content' do
393
508
  BlobStream.call(env, credentials, params)
394
509
  end
395
510
 
511
+ #Get html form for creating a new bucket
512
+ get '/api/buckets/new' do
513
+ respond_to do |format|
514
+ format.html { haml :"buckets/new" }
515
+ end
516
+ end
517
+
396
518
  collection :buckets do
397
519
  description "Cloud Storage buckets - aka buckets|directories|folders"
398
520
 
399
521
  operation :index do
400
522
  description "List buckets associated with this account"
523
+ with_capability :buckets
401
524
  param :id, :string
402
525
  param :name, :string
403
526
  param :size, :string
@@ -406,12 +529,14 @@ collection :buckets do
406
529
 
407
530
  operation :show do
408
531
  description "Show bucket"
532
+ with_capability :bucket
409
533
  param :id, :string
410
534
  control { show(:bucket) }
411
535
  end
412
536
 
413
537
  operation :create do
414
538
  description "Create a new bucket (POST /api/buckets)"
539
+ with_capability :create_bucket
415
540
  param :name, :string, :required
416
541
  control do
417
542
  @bucket = driver.create_bucket(credentials, params[:name], params)
@@ -431,6 +556,7 @@ collection :buckets do
431
556
 
432
557
  operation :destroy do
433
558
  description "Delete a bucket by name - bucket must be empty"
559
+ with_capability :delete_bucket
434
560
  param :id, :string, :required
435
561
  control do
436
562
  driver.delete_bucket(credentials, params[:id], params)