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
@@ -1,6 +1,4 @@
1
1
  #
2
- # Copyright (C) 2009,2010 Red Hat, Inc.
3
- #
4
2
  # Licensed to the Apache Software Foundation (ASF) under one or more
5
3
  # contributor license agreements. See the NOTICE file distributed with
6
4
  # this work for additional information regarding copyright ownership. The
@@ -1,6 +1,4 @@
1
1
  #
2
- # Copyright (C) 2009,2010 Red Hat, Inc.
3
- #
4
2
  # Licensed to the Apache Software Foundation (ASF) under one or more
5
3
  # contributor license agreements. See the NOTICE file distributed with
6
4
  # this work for additional information regarding copyright ownership. The
@@ -37,8 +35,12 @@ module Deltacloud::Validation
37
35
  @name = args[0]
38
36
  @klass = args[1] || :string
39
37
  @type = args[2] || :optional
40
- @options = args[3] || []
41
- @description = args[4] || ''
38
+ if args[3] and args[3].class.eql?(String)
39
+ @description = args[3]
40
+ @options = []
41
+ end
42
+ @options ||= args[3] || []
43
+ @description ||= args[4] || ''
42
44
  end
43
45
 
44
46
  def required?
@@ -51,7 +53,7 @@ module Deltacloud::Validation
51
53
  end
52
54
 
53
55
  def param(*args)
54
- raise DuplicateParamException if params[args[0]]
56
+ raise "Duplicate param #{args[0]} #{params.inspect} #{self.class.name}" if params[args[0]]
55
57
  p = Param.new(args)
56
58
  params[p.name] = p
57
59
  end
@@ -74,8 +76,8 @@ module Deltacloud::Validation
74
76
  params.each_value { |p| yield p }
75
77
  end
76
78
 
77
- def validate(values)
78
- each_param do |p|
79
+ def validate(all_params, values)
80
+ all_params.each_value do |p|
79
81
  if p.required? and not values[p.name]
80
82
  raise Failure.new(p, "Required parameter #{p.name} not found")
81
83
  end
@@ -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
@@ -16,62 +14,52 @@
16
14
  # under the License.
17
15
 
18
16
  module Deltacloud
19
- DRIVERS = {
20
- :ec2 => { :name => "EC2" },
21
- :rackspace => { :name => "Rackspace" },
22
- :gogrid => { :name => "Gogrid" },
23
- :rhevm => { :name => "RHEVM" },
24
- :rimuhosting => { :name => "RimuHosting"},
25
- :opennebula => { :name => "Opennebula", :class => "OpennebulaDriver" },
26
- :terremark => { :name => "Terremark"},
27
- :azure => { :name => "Azure" },
28
- :mock => { :name => "Mock" }
29
- }
30
17
 
31
- DEFAULT_COLLECTIONS = [
32
- :hardware_profiles,
33
- :images,
34
- :instances,
35
- :instance_states,
36
- :realms,
37
- :storage_volumes,
38
- :storage_snapshots
39
- ]
18
+ module Drivers
40
19
 
41
- DRIVER=ENV['API_DRIVER'] ? ENV['API_DRIVER'].to_sym : :mock
20
+ require 'yaml'
42
21
 
43
- def driver_symbol
44
- (Thread.current[:driver] || DRIVER).to_sym
45
- end
22
+ DEFAULT_COLLECTIONS = [
23
+ :hardware_profiles,
24
+ :images,
25
+ :instances,
26
+ :instance_states,
27
+ :realms,
28
+ :storage_volumes,
29
+ :storage_snapshots
30
+ ]
46
31
 
47
- def driver_name
48
- DRIVERS[:"#{driver_symbol}"][:name]
49
- end
32
+ DRIVER=ENV['API_DRIVER'] ? ENV['API_DRIVER'].to_sym : :mock
50
33
 
51
- def driver_class_name
52
- basename = DRIVERS[:"#{driver_symbol}"][:class] || "#{driver_name}Driver"
53
- "Deltacloud::Drivers::#{driver_name}::#{basename}"
54
- end
34
+ def driver_config
35
+ YAML::load(File.read(File.join(File.dirname(__FILE__), '..', 'config', 'drivers.yaml')))
36
+ end
55
37
 
56
- def driver_source_name
57
- File.join("deltacloud", "drivers", "#{driver_symbol}", "#{driver_symbol}_driver.rb")
58
- end
38
+ def driver_symbol
39
+ (Thread.current[:driver] || DRIVER).to_sym
40
+ end
59
41
 
60
- def driver_mock_source_name
61
- return File.join('deltacloud', 'drivers', "#{driver_symbol}",
62
- "#{driver_symbol}_driver.rb") if driver_name.eql? 'Mock'
63
- end
42
+ def driver_name
43
+ driver_config[:"#{driver_symbol}"][:name]
44
+ end
64
45
 
65
- def driver
66
- require driver_source_name
67
- #require 'deltacloud/base_driver/mock_driver.rb'
46
+ def driver_class
47
+ basename = driver_config[:"#{driver_symbol}"][:class] || "#{driver_name}Driver"
48
+ Deltacloud::Drivers.const_get(driver_name).const_get(basename)
49
+ end
68
50
 
69
- if Sinatra::Application.environment.eql? :test
70
- require driver_mock_source_name if driver_mock_source_name
51
+ def driver_source_name
52
+ File.join("deltacloud", "drivers", "#{driver_symbol}", "#{driver_symbol}_driver.rb")
71
53
  end
72
54
 
73
- @driver ||= eval( driver_class_name ).new
55
+ def driver_mock_source_name
56
+ return File.join('deltacloud', 'drivers', "#{driver_symbol}",
57
+ "#{driver_symbol}_driver.rb") if driver_name.eql? 'Mock'
58
+ end
59
+
60
+ def driver
61
+ require driver_source_name
62
+ @driver ||= driver_class.new
63
+ end
74
64
  end
75
65
  end
76
-
77
- include Deltacloud
@@ -1,3 +1,29 @@
1
+ #
2
+ # Based on https://github.com/mynyml/rack-accept-media-types
3
+ # Commit 3d0f38882a466cc72043
4
+ #
5
+ # Original license:
6
+ # Copyright (C) 2009 Martin Aumont (mynyml)
7
+ #
8
+ # Permission is hereby granted, free of charge, to any person obtaining a
9
+ # copy of this software and associated documentation files (the
10
+ # "Software"), to deal in the Software without restriction, including
11
+ # without limitation the rights to use, copy, modify, merge, publish,
12
+ # distribute, sublicense, and/or sell copies of the Software, and to permit
13
+ # persons to whom the Software is furnished to do so, subject to the
14
+ # following conditions:
15
+ #
16
+ # The above copyright notice and this permission notice shall be included
17
+ # in all copies or substantial portions of the Software.
18
+ #
19
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20
+ # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
22
+ # NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
23
+ # DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
24
+ # OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
25
+ # USE OR OTHER DEALINGS IN THE SOFTWARE.
26
+
1
27
  module Rack
2
28
  class Request
3
29
  # The media types of the HTTP_ACCEPT header ordered according to their
@@ -1,3 +1,19 @@
1
+ #
2
+ # Licensed to the Apache Software Foundation (ASF) under one or more
3
+ # contributor license agreements. See the NOTICE file distributed with
4
+ # this work for additional information regarding copyright ownership. The
5
+ # ASF licenses this file to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance with the
7
+ # License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ # License for the specific language governing permissions and limitations
15
+ # under the License.
16
+
1
17
  require 'sinatra/base'
2
18
 
3
19
  # Lazy Basic HTTP authentication. Authentication is only forced when the
@@ -1,3 +1,19 @@
1
+ #
2
+ # Licensed to the Apache Software Foundation (ASF) under one or more
3
+ # contributor license agreements. See the NOTICE file distributed with
4
+ # this work for additional information regarding copyright ownership. The
5
+ # ASF licenses this file to you under the Apache License, Version 2.0 (the
6
+ # "License"); you may not use this file except in compliance with the
7
+ # License. You may obtain a copy of the License at
8
+ #
9
+ # http://www.apache.org/licenses/LICENSE-2.0
10
+ #
11
+ # Unless required by applicable law or agreed to in writing, software
12
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
13
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
14
+ # License for the specific language governing permissions and limitations
15
+ # under the License.
16
+
1
17
  require 'sinatra/base'
2
18
  require 'sinatra/url_for'
3
19
  require 'deltacloud/validation'
@@ -10,9 +26,10 @@ module Sinatra
10
26
  class DuplicateParamException < Exception; end
11
27
  class DuplicateOperationException < Exception; end
12
28
  class DuplicateCollectionException < Exception; end
29
+ class UnsupportedCollectionException < Exception; end
13
30
 
14
31
  class Operation
15
- attr_reader :name, :method
32
+ attr_reader :name, :method, :collection
16
33
 
17
34
  include ::Deltacloud::BackendCapability
18
35
  include ::Deltacloud::Validation
@@ -35,6 +52,11 @@ module Sinatra
35
52
  @description = ""
36
53
  instance_eval(&block) if block_given?
37
54
  generate_documentation
55
+ generate_options
56
+ end
57
+
58
+ def http_method
59
+ @method
38
60
  end
39
61
 
40
62
  def standard?
@@ -50,6 +72,7 @@ module Sinatra
50
72
  coll, oper = @collection, self
51
73
  ::Sinatra::Application.get("/api/docs/#{@collection.name}/#{@name}") do
52
74
  @collection, @operation = coll, oper
75
+ @features = driver.features_for_operation(coll.name, oper.name)
53
76
  respond_to do |format|
54
77
  format.html { haml :'docs/operation' }
55
78
  format.xml { haml :'docs/operation' }
@@ -57,11 +80,27 @@ module Sinatra
57
80
  end
58
81
  end
59
82
 
83
+ def generate_options
84
+ current_operation = self
85
+ ::Sinatra::Application.options("/api/#{current_operation.collection.name}/#{current_operation.name}") do
86
+ required_params = current_operation.effective_params(driver).collect do |name, validation|
87
+ name.to_s if validation.type.eql?(:required)
88
+ end.compact.join(',')
89
+ optional_params = current_operation.effective_params(driver).collect do |name, validation|
90
+ name.to_s if validation.type.eql?(:optional)
91
+ end.compact.join(',')
92
+ headers 'X-Required-Parameters' => required_params
93
+ headers 'X-Optional-Parameters' => optional_params
94
+ [200, '']
95
+ end
96
+ end
97
+
60
98
  def control(&block)
61
99
  op = self
62
100
  @control = Proc.new do
63
- op.check_capability(Deltacloud::driver)
64
- op.validate(params)
101
+ op.collection.check_supported(driver)
102
+ op.check_capability(driver)
103
+ op.validate(op.effective_params(driver), params)
65
104
  instance_eval(&block)
66
105
  end
67
106
  end
@@ -72,7 +111,7 @@ module Sinatra
72
111
  end
73
112
 
74
113
  def path(args = {})
75
- l_prefix = args[:prefix] ? args[:prefix] : prefix
114
+ l_prefix = args[:prefix] || prefix
76
115
  if @member
77
116
  if standard?
78
117
  "#{l_prefix}/#{@collection.name}/:id"
@@ -96,6 +135,24 @@ module Sinatra
96
135
  end
97
136
  end
98
137
 
138
+ # Return a hash of all params, the params statically defined for this
139
+ # operation plus the params defined by any features in the +driver+
140
+ # that might modify this operation
141
+ def effective_params(driver)
142
+ driver.features(@collection.name).collect do |f|
143
+ f.decl.operation(@name)
144
+ end.flatten.select { |op| op }.inject(params.dup) do |result, fop|
145
+ fop.params.each_key do |k|
146
+ if result.has_key?(k)
147
+ raise DuplicateParamException, "Parameter '#{k}' for operation #{fop.name} in collection #{@collection.name}"
148
+ else
149
+ result[k] = fop.params[k]
150
+ end
151
+ end
152
+ result
153
+ end
154
+ end
155
+
99
156
  private
100
157
  def gen_route(name)
101
158
  route_url = path
@@ -120,8 +177,11 @@ module Sinatra
120
177
  @name = name
121
178
  @description = ""
122
179
  @operations = {}
180
+ @global = false
123
181
  instance_eval(&block) if block_given?
124
182
  generate_documentation
183
+ generate_head
184
+ generate_options
125
185
  end
126
186
 
127
187
  # Set/Return description for collection
@@ -132,10 +192,43 @@ module Sinatra
132
192
  @description = text
133
193
  end
134
194
 
195
+ # Mark this collection as global, i.e. independent of any specific
196
+ # driver
197
+ def global!
198
+ @global = true
199
+ end
200
+
201
+ # Return +true+ if this collection is global, i.e. independent of any
202
+ # specific driver
203
+ def global?
204
+ @global
205
+ end
206
+
207
+ def generate_head
208
+ current_collection = self
209
+ ::Sinatra::Application.head("/api/#{name}") do
210
+ methods_allowed = current_collection.operations.collect { |o| o[1].method.to_s.upcase }.uniq.join(',')
211
+ headers 'Allow' => "HEAD,OPTIONS,#{methods_allowed}"
212
+ [200, '']
213
+ end
214
+ end
215
+
216
+ def generate_options
217
+ current_collection = self
218
+ ::Sinatra::Application.options("/api/#{name}") do
219
+ operations_allowed = current_collection.operations.collect { |o| o[0] }.join(',')
220
+ headers 'X-Operations-Allowed' => operations_allowed
221
+ [200, '']
222
+ end
223
+ end
224
+
135
225
  def generate_documentation
136
- coll, oper, features = self, @operations, Deltacloud::driver.features(name)
226
+ coll = self
137
227
  ::Sinatra::Application.get("/api/docs/#{@name}") do
138
- @collection, @operations, @features = coll, oper, features
228
+ coll.check_supported(driver)
229
+ @collection = coll
230
+ @operations = coll.operations
231
+ @features = driver.features(coll.name)
139
232
  respond_to do |format|
140
233
  format.html { haml :'docs/collection' }
141
234
  format.xml { haml :'docs/collection' }
@@ -178,19 +271,10 @@ module Sinatra
178
271
  end
179
272
  end
180
273
 
181
- def add_feature_params(features)
182
- features.each do |f|
183
- f.operations.each do |fop|
184
- if cop = operations[fop.name]
185
- fop.params.each_key do |k|
186
- if cop.params.has_key?(k)
187
- raise DuplicateParamException, "Parameter '#{k}' for operation #{fop.name} defined by collection #{@name} and by feature #{f.name}"
188
- else
189
- cop.params[k] = fop.params[k]
190
- end
191
- end
192
- end
193
- end
274
+ def check_supported(driver)
275
+ unless global? || driver.has_collection?(@name)
276
+ raise UnsupportedCollectionException,
277
+ "Collection #{@name} not supported by this driver"
194
278
  end
195
279
  end
196
280
  end
@@ -206,9 +290,7 @@ module Sinatra
206
290
  # operation on this collection.
207
291
  def collection(name, &block)
208
292
  raise DuplicateCollectionException if collections[name]
209
- return unless Deltacloud::driver.has_collection?(name.to_sym)
210
293
  collections[name] = Collection.new(name, &block)
211
- collections[name].add_feature_params(Deltacloud::driver.features(name))
212
294
  collections[name].generate
213
295
  end
214
296
 
@@ -229,7 +311,9 @@ module Sinatra
229
311
  end
230
312
 
231
313
  def entry_points
232
- collections.values.inject([]) do |m, coll|
314
+ collections.values.select { |coll|
315
+ coll.global? || driver.has_collection?(coll.name)
316
+ }.inject([]) do |m, coll|
233
317
  url = url_for coll.operations[:index].path, :full
234
318
  m << [ coll.name, url ]
235
319
  end
@@ -240,37 +324,11 @@ module Sinatra
240
324
  helpers RabbitHelper
241
325
  end
242
326
 
243
- class String
244
- # Rails defines this for a number of other classes, including Object
245
- # see activesupport/lib/active_support/core_ext/object/blank.rb
246
- def blank?
247
- self !~ /\S/
248
- end
249
-
250
- # Title case.
251
- #
252
- # "this is a string".titlecase
253
- # => "This Is A String"
254
- #
255
- # CREDIT: Eliazar Parra
256
- # Copied from facets
257
- def titlecase
258
- gsub(/\b\w/){ $`[-1,1] == "'" ? $& : $&.upcase }
259
- end
260
-
261
- def pluralize
262
- self + "s"
263
- end
264
-
265
- def singularize
266
- self.gsub(/s$/, '')
267
- end
268
-
269
- def underscore
270
- gsub(/::/, '/').
271
- gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
272
- gsub(/([a-z\d])([A-Z])/,'\1_\2').
273
- tr("-", "_").
274
- downcase
327
+ configure do
328
+ class << Sinatra::Base
329
+ def options(path, opts={}, &block)
330
+ route 'OPTIONS', path, opts, &block
331
+ end
275
332
  end
333
+ Sinatra::Delegator.delegate :options
276
334
  end