deltacloud-core 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (110) hide show
  1. data/COPYING +502 -0
  2. data/Rakefile +108 -0
  3. data/bin/deltacloudd +88 -0
  4. data/config.ru +5 -0
  5. data/deltacloud.rb +14 -0
  6. data/lib/converters/xml_converter.rb +133 -0
  7. data/lib/deltacloud/base_driver.rb +19 -0
  8. data/lib/deltacloud/base_driver/base_driver.rb +189 -0
  9. data/lib/deltacloud/base_driver/features.rb +144 -0
  10. data/lib/deltacloud/drivers/ec2/ec2_driver.rb +318 -0
  11. data/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb +170 -0
  12. data/lib/deltacloud/drivers/gogrid/gogrid_client.rb +45 -0
  13. data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +239 -0
  14. data/lib/deltacloud/drivers/mock/mock_driver.rb +275 -0
  15. data/lib/deltacloud/drivers/opennebula/cloud_client.rb +116 -0
  16. data/lib/deltacloud/drivers/opennebula/occi_client.rb +204 -0
  17. data/lib/deltacloud/drivers/opennebula/opennebula_driver.rb +241 -0
  18. data/lib/deltacloud/drivers/rackspace/rackspace_client.rb +129 -0
  19. data/lib/deltacloud/drivers/rackspace/rackspace_driver.rb +150 -0
  20. data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +254 -0
  21. data/lib/deltacloud/drivers/rimu/rimu_hosting_client.rb +87 -0
  22. data/lib/deltacloud/drivers/rimu/rimu_hosting_driver.rb +143 -0
  23. data/lib/deltacloud/hardware_profile.rb +131 -0
  24. data/lib/deltacloud/helpers.rb +5 -0
  25. data/lib/deltacloud/helpers/application_helper.rb +38 -0
  26. data/lib/deltacloud/helpers/conversion_helper.rb +39 -0
  27. data/lib/deltacloud/helpers/hardware_profiles_helper.rb +35 -0
  28. data/lib/deltacloud/models/base_model.rb +58 -0
  29. data/lib/deltacloud/models/image.rb +26 -0
  30. data/lib/deltacloud/models/instance.rb +37 -0
  31. data/lib/deltacloud/models/instance_profile.rb +47 -0
  32. data/lib/deltacloud/models/realm.rb +25 -0
  33. data/lib/deltacloud/models/storage_snapshot.rb +26 -0
  34. data/lib/deltacloud/models/storage_volume.rb +27 -0
  35. data/lib/deltacloud/state_machine.rb +84 -0
  36. data/lib/deltacloud/validation.rb +70 -0
  37. data/lib/drivers.rb +37 -0
  38. data/lib/sinatra/lazy_auth.rb +56 -0
  39. data/lib/sinatra/rabbit.rb +272 -0
  40. data/lib/sinatra/respond_to.rb +262 -0
  41. data/lib/sinatra/static_assets.rb +83 -0
  42. data/lib/sinatra/url_for.rb +44 -0
  43. data/public/favicon.ico +0 -0
  44. data/public/images/grid.png +0 -0
  45. data/public/images/logo-wide.png +0 -0
  46. data/public/images/rails.png +0 -0
  47. data/public/images/topbar-bg.png +0 -0
  48. data/public/javascripts/application.js +2 -0
  49. data/public/javascripts/controls.js +963 -0
  50. data/public/javascripts/dragdrop.js +973 -0
  51. data/public/javascripts/effects.js +1128 -0
  52. data/public/javascripts/prototype.js +4320 -0
  53. data/public/stylesheets/compiled/application.css +613 -0
  54. data/public/stylesheets/compiled/ie.css +31 -0
  55. data/public/stylesheets/compiled/print.css +27 -0
  56. data/public/stylesheets/compiled/screen.css +456 -0
  57. data/server.rb +340 -0
  58. data/tests/deltacloud_test.rb +60 -0
  59. data/tests/images_test.rb +94 -0
  60. data/tests/instances_test.rb +136 -0
  61. data/tests/realms_test.rb +56 -0
  62. data/tests/storage_snapshots_test.rb +48 -0
  63. data/tests/storage_volumes_test.rb +48 -0
  64. data/views/accounts/index.html.haml +11 -0
  65. data/views/accounts/show.html.haml +30 -0
  66. data/views/api/show.html.haml +15 -0
  67. data/views/api/show.xml.haml +5 -0
  68. data/views/docs/collection.html.haml +37 -0
  69. data/views/docs/collection.xml.haml +14 -0
  70. data/views/docs/index.html.haml +15 -0
  71. data/views/docs/index.xml.haml +5 -0
  72. data/views/docs/operation.html.haml +31 -0
  73. data/views/docs/operation.xml.haml +10 -0
  74. data/views/errors/auth_exception.html.haml +8 -0
  75. data/views/errors/auth_exception.xml.haml +2 -0
  76. data/views/errors/backend_error.html.haml +17 -0
  77. data/views/errors/backend_error.xml.haml +8 -0
  78. data/views/errors/validation_failure.html.haml +11 -0
  79. data/views/errors/validation_failure.xml.haml +7 -0
  80. data/views/hardware_profiles/index.html.haml +25 -0
  81. data/views/hardware_profiles/index.xml.haml +4 -0
  82. data/views/hardware_profiles/show.html.haml +19 -0
  83. data/views/hardware_profiles/show.xml.haml +17 -0
  84. data/views/images/index.html.haml +30 -0
  85. data/views/images/index.xml.haml +7 -0
  86. data/views/images/show.html.haml +21 -0
  87. data/views/images/show.xml.haml +5 -0
  88. data/views/instance_states/show.gv.erb +45 -0
  89. data/views/instance_states/show.html.haml +31 -0
  90. data/views/instance_states/show.xml.haml +8 -0
  91. data/views/instances/index.html.haml +29 -0
  92. data/views/instances/index.xml.haml +23 -0
  93. data/views/instances/new.html.haml +49 -0
  94. data/views/instances/show.html.haml +42 -0
  95. data/views/instances/show.xml.haml +28 -0
  96. data/views/layout.html.haml +23 -0
  97. data/views/realms/index.html.haml +29 -0
  98. data/views/realms/index.xml.haml +12 -0
  99. data/views/realms/show.html.haml +15 -0
  100. data/views/realms/show.xml.haml +10 -0
  101. data/views/root/index.html.haml +4 -0
  102. data/views/storage_snapshots/index.html.haml +20 -0
  103. data/views/storage_snapshots/index.xml.haml +11 -0
  104. data/views/storage_snapshots/show.html.haml +14 -0
  105. data/views/storage_snapshots/show.xml.haml +9 -0
  106. data/views/storage_volumes/index.html.haml +21 -0
  107. data/views/storage_volumes/index.xml.haml +13 -0
  108. data/views/storage_volumes/show.html.haml +20 -0
  109. data/views/storage_volumes/show.xml.haml +13 -0
  110. metadata +311 -0
@@ -0,0 +1,136 @@
1
+ require 'tests/deltacloud_test'
2
+
3
+ class InstancesTest < Test::Unit::TestCase
4
+
5
+ def initialize(*args)
6
+ @collection = 'instances'
7
+ @operations = [:index, :show]
8
+ @options = [:id, :architecture, :memory, :storage]
9
+ @params = {}
10
+ self.temp_inst_id = 'inst2'
11
+ super(*args)
12
+ end
13
+
14
+ attr_accessor :temp_inst_id
15
+
16
+ def test_if_instances_are_not_empty
17
+ get '/api/instances.xml', @params, rack_headers
18
+ doc = Nokogiri::XML.parse(last_response.body)
19
+ assert_not_equal 0, doc.xpath('/instances/instance').size
20
+ end
21
+
22
+ [:id, :name, :owner_id, :image, :realm, :state, :actions, :'public-addresses', :'private-addresses'].each do |option|
23
+ method_name = :"test_if_instances_index_contain_#{option}"
24
+ send :define_method, method_name do
25
+ get '/api/instances.xml', @params, rack_headers
26
+ doc = Nokogiri::XML.parse(last_response.body)
27
+ instance = doc.xpath('/instances/instance[1]').first
28
+ assert_not_nil instance.xpath(option.to_s).first
29
+ end
30
+ end
31
+
32
+ [:id, :name, :owner_id, :image, :realm, :state, :actions, :'public-addresses', :'private-addresses'].each do |option|
33
+ method_name = :"test_if_instance_show_contain_#{option}"
34
+ send :define_method, method_name do
35
+ get '/api/instances/inst1.xml', @params, rack_headers
36
+ doc = Nokogiri::XML.parse(last_response.body)
37
+ instance = doc.xpath('/instance').first
38
+ assert_not_nil instance.xpath(option.to_s).first
39
+ end
40
+ end
41
+
42
+ def test_instances_filtering_by_id
43
+ get '/api/instances.xml', { :id => 'inst1'}, rack_headers
44
+ doc = Nokogiri::XML.parse(last_response.body)
45
+ assert_equal 1, doc.xpath('/instances/instance').size
46
+ assert_equal 'inst1', doc.xpath('/instances/instance/id').first.text
47
+ end
48
+
49
+ def test_instances_filtering_by_state
50
+ get '/api/instances.xml', { :state => 'RUNNING'}, rack_headers
51
+ doc = Nokogiri::XML.parse(last_response.body)
52
+ doc.xpath('/instances/instance').each do |instance|
53
+ assert_equal 'RUNNING', instance.xpath('state').first.text
54
+ end
55
+ end
56
+
57
+ def test_instances_filtering_by_unknown_state
58
+ get '/api/instances.xml', { :state => '_TEST_UNKNOWN_STATE'}, rack_headers
59
+ doc = Nokogiri::XML.parse(last_response.body)
60
+ assert_equal 0, doc.xpath('/instances/instance').size
61
+ end
62
+
63
+ def test_001_create_instance
64
+ @params = {
65
+ :name => '_test-instance',
66
+ :image_id => 'img1'
67
+ }
68
+
69
+ post '/api/instances.xml', @params, rack_headers
70
+ doc = Nokogiri::XML.parse(last_response.body)
71
+
72
+ self.temp_inst_id = doc.xpath('/instance/id').text
73
+
74
+ assert_equal @params[:name], doc.xpath('/instance/name').first.text
75
+ image_href = doc.xpath('/instance/image').first[:href].to_s
76
+ image_id = image_href.gsub(/.*\/(\w+)$/, '\1')
77
+ assert_equal @params[:image_id], image_id
78
+ end
79
+
80
+ def test_create_instance_with_hwp_id
81
+
82
+ @params = {
83
+ :name => '_test-instance',
84
+ :image_id => 'img1',
85
+ :hwp_id => 'm1-xlarge'
86
+ }
87
+
88
+ post '/api/instances.xml', @params, rack_headers
89
+ doc = Nokogiri::XML.parse(last_response.body)
90
+ hwp_href = doc.xpath('/instance/hardware_profile').first[:href].to_s
91
+ hwp_id = hwp_href.gsub(/.*\/([\w\-]+)$/, '\1')
92
+ assert_equal @params[:hwp_id], hwp_id
93
+ end
94
+
95
+ def test_create_instance_with_realm_id
96
+
97
+ @params = {
98
+ :name => '_test-instance',
99
+ :image_id => 'img1',
100
+ :realm_id => 'us'
101
+ }
102
+
103
+ post '/api/instances.xml', @params, rack_headers
104
+ doc = Nokogiri::XML.parse(last_response.body)
105
+ realm_href = doc.xpath('/instance/realm').first[:href].to_s
106
+ realm_id = realm_href.gsub(/.*\/([\w\-]+)$/, '\1')
107
+ assert_equal @params[:realm_id], realm_id
108
+ end
109
+
110
+ def test_002_stop_instance
111
+ post '/api/instances/'+self.temp_inst_id+'/stop.xml', rack_headers
112
+ doc = Nokogiri::XML.parse(last_response.body)
113
+ assert_equal 'STOPPED', doc.xpath('/instance/state').first.text
114
+ end
115
+
116
+ def test_003_start_instance
117
+ post '/api/instances/'+self.temp_inst_id+'/start.xml', rack_headers
118
+ doc = Nokogiri::XML.parse(last_response.body)
119
+ assert_equal 'RUNNING', doc.xpath('/instance/state').first.text
120
+ end
121
+
122
+ def test_004_reboot_instance
123
+ post '/api/instances/'+self.temp_inst_id+'/reboot.xml', rack_headers
124
+ doc = Nokogiri::XML.parse(last_response.body)
125
+ assert_equal 'RUNNING', doc.xpath('/instance/state').first.text
126
+ end
127
+
128
+ def test_005_destroy_instance
129
+ delete '/api/instances/'+self.temp_inst_id+'.xml', {}, rack_headers
130
+ doc = Nokogiri::XML.parse(last_response.body)
131
+ assert last_response.ok?
132
+ end
133
+
134
+ include DeltacloudTest
135
+
136
+ end
@@ -0,0 +1,56 @@
1
+ require 'tests/deltacloud_test'
2
+
3
+ class RealmsTest < Test::Unit::TestCase
4
+
5
+ def initialize(*args)
6
+ @collection = 'realms'
7
+ @operations = [:index, :show]
8
+ @options = [:id, :name, :state]
9
+ @params = {}
10
+ super(*args)
11
+ end
12
+
13
+ def test_if_realms_are_not_empty
14
+ get '/api/realms.xml', @params, rack_headers
15
+ doc = Nokogiri::XML.parse(last_response.body)
16
+ assert_not_equal 0, doc.xpath('/realms/realm').size
17
+ end
18
+
19
+ [:id, :name, :state].each do |option|
20
+ method_name = :"test_if_realms_index_contain_#{option}"
21
+ send :define_method, method_name do
22
+ get '/api/realms.xml', @params, rack_headers
23
+ doc = Nokogiri::XML.parse(last_response.body)
24
+ realm = doc.xpath('/realms/realm[1]').first
25
+ assert_not_nil realm.xpath(option.to_s).first
26
+ end
27
+ end
28
+
29
+ [:id, :name, :state].each do |option|
30
+ method_name = :"test_if_realm_show_contain_#{option}"
31
+ send :define_method, method_name do
32
+ get '/api/realms/us.xml', @params, rack_headers
33
+ doc = Nokogiri::XML.parse(last_response.body)
34
+ realm = doc.xpath('/realm').first
35
+ assert_not_nil realm.xpath(option.to_s).first
36
+ end
37
+ end
38
+
39
+ def test_realms_filtering_by_state
40
+ @params[:state] = 'AVAILABLE'
41
+ get '/api/realms.xml', @params, rack_headers
42
+ doc = Nokogiri::XML.parse(last_response.body)
43
+ assert_equal 2, doc.xpath('/realms/realm').size
44
+ assert_equal @params[:state], doc.xpath('/realms/realm/state').first.text
45
+ end
46
+
47
+ def test_realms_filtering_by_id
48
+ get '/api/realms.xml', { :id => 'us'}, rack_headers
49
+ doc = Nokogiri::XML.parse(last_response.body)
50
+ assert_equal 1, doc.xpath('/realms/realm').size
51
+ assert_equal 'us', doc.xpath('/realms/realm/id').first.text
52
+ end
53
+
54
+ include DeltacloudTest
55
+
56
+ end
@@ -0,0 +1,48 @@
1
+ require 'tests/deltacloud_test'
2
+
3
+ class StorageSnapshotsTest < Test::Unit::TestCase
4
+
5
+ def initialize(*args)
6
+ @collection = 'storage_snapshots'
7
+ @operations = [:index, :show]
8
+ @options = [:id, :architecture, :memory, :storage]
9
+ @params = {}
10
+ super(*args)
11
+ end
12
+
13
+ def test_if_storage_snapshots_are_not_empty
14
+ get '/api/storage_snapshots.xml', @params, rack_headers
15
+ doc = Nokogiri::XML.parse(last_response.body)
16
+ assert_not_equal 0, doc.xpath('/storage-snapshots/storage-snapshot').size
17
+ end
18
+
19
+ [:id, :created, :state, :'storage-volume'].each do |option|
20
+ method_name = :"test_if_storage_snapshots_index_contain_#{option}"
21
+ send :define_method, method_name do
22
+ get '/api/storage_snapshots.xml', @params, rack_headers
23
+ doc = Nokogiri::XML.parse(last_response.body)
24
+ storage_volume = doc.xpath('/storage-snapshots/storage-snapshot[1]').first
25
+ assert_not_nil storage_volume.xpath(option.to_s).first
26
+ end
27
+ end
28
+
29
+ [:id, :created, :state, :'storage-volume'].each do |option|
30
+ method_name = :"test_if_storage_volume_show_contain_#{option}"
31
+ send :define_method, method_name do
32
+ get '/api/storage_snapshots/snap3.xml', @params, rack_headers
33
+ doc = Nokogiri::XML.parse(last_response.body)
34
+ storage_volume = doc.xpath('/storage-snapshot').first
35
+ assert_not_nil storage_volume.xpath(option.to_s).first
36
+ end
37
+ end
38
+
39
+ def test_storage_snapshots_filtering_by_id
40
+ get '/api/storage_snapshots.xml', { :id => 'snap3'}, rack_headers
41
+ doc = Nokogiri::XML.parse(last_response.body)
42
+ assert_equal 1, doc.xpath('/storage-snapshots/storage-snapshot').size
43
+ assert_equal 'snap3', doc.xpath('/storage-snapshots/storage-snapshot/id').first.text
44
+ end
45
+
46
+ include DeltacloudTest
47
+
48
+ end
@@ -0,0 +1,48 @@
1
+ require 'tests/deltacloud_test'
2
+
3
+ class StorageVolumesTest < Test::Unit::TestCase
4
+
5
+ def initialize(*args)
6
+ @collection = 'storage_volumes'
7
+ @operations = [:index, :show]
8
+ @options = [:id, :architecture, :memory, :storage]
9
+ @params = {}
10
+ super(*args)
11
+ end
12
+
13
+ def test_if_storage_volumes_are_not_empty
14
+ get '/api/storage_volumes.xml', @params, rack_headers
15
+ doc = Nokogiri::XML.parse(last_response.body)
16
+ assert_not_equal 0, doc.xpath('/storage-volumes/storage-volume').size
17
+ end
18
+
19
+ [:id, :created, :capacity, :device, :state].each do |option|
20
+ method_name = :"test_if_storage_volumes_index_contain_#{option}"
21
+ send :define_method, method_name do
22
+ get '/api/storage_volumes.xml', @params, rack_headers
23
+ doc = Nokogiri::XML.parse(last_response.body)
24
+ storage_volume = doc.xpath('/storage-volumes/storage-volume[1]').first
25
+ assert_not_nil storage_volume.xpath(option.to_s).first
26
+ end
27
+ end
28
+
29
+ [:id, :created, :capacity, :device, :state].each do |option|
30
+ method_name = :"test_if_storage_volume_show_contain_#{option}"
31
+ send :define_method, method_name do
32
+ get '/api/storage_volumes/vol2.xml', @params, rack_headers
33
+ doc = Nokogiri::XML.parse(last_response.body)
34
+ storage_volume = doc.xpath('/storage-volume').first
35
+ assert_not_nil storage_volume.xpath(option.to_s).first
36
+ end
37
+ end
38
+
39
+ def test_storage_volumes_filtering_by_id
40
+ get '/api/storage_volumes.xml', { :id => 'vol2'}, rack_headers
41
+ doc = Nokogiri::XML.parse(last_response.body)
42
+ assert_equal 1, doc.xpath('/storage-volumes/storage-volume').size
43
+ assert_equal 'vol2', doc.xpath('/storage-volumes/storage-volume/id').first.text
44
+ end
45
+
46
+ include DeltacloudTest
47
+
48
+ end
@@ -0,0 +1,11 @@
1
+ %h1 Accounts
2
+
3
+ %table
4
+ %thead
5
+ %tr
6
+ %th ID
7
+ %tbody
8
+ - @accounts.each do |account|
9
+ %tr
10
+ %td
11
+ = link_to account, account
@@ -0,0 +1,30 @@
1
+ %h1
2
+ = @account[:id]
3
+
4
+ %h2 Instances
5
+
6
+ %table
7
+ %thead
8
+ %tr
9
+ %th Instance ID
10
+ %tbody
11
+ - @account[:instance_ids].each do |instance_id|
12
+ %tr
13
+ %td
14
+ = link_to instance_id, instance_url( instance_id )
15
+
16
+ %h2 Images
17
+
18
+ %table
19
+ %thead
20
+ %tr
21
+ %th Image ID
22
+ %th Description
23
+ %tbody
24
+ %tbody
25
+ - @images.each do |image|
26
+ %tr
27
+ %td
28
+ = link_to image[:id], image_url( image[:id] )
29
+ %td
30
+ = image[:description]
@@ -0,0 +1,15 @@
1
+ %h1
2
+ API v#{@version}
3
+
4
+ %ul
5
+ - collections.keys.sort_by { |k| k.to_s }.each do |key|
6
+ %li
7
+ = link_to key.to_s.gsub('_', ' ').titlecase, url_for("/api/#{key}")
8
+ %dl
9
+ - collections[key].operations.each_key do |op|
10
+ - next if [:index, :show].include?(op)
11
+ %dt
12
+ = op
13
+ %li
14
+ %strong
15
+ %a{:href => "/api/docs"} Documentation (v#{@version})
@@ -0,0 +1,5 @@
1
+ %api{ :version=>@version, :driver=>DRIVER }
2
+ - for entry_point in entry_points
3
+ %link{ :rel=>entry_point[0], :href=>entry_point[1] }
4
+ - for feature in driver.features(entry_point[0])
5
+ %feature{ :name=>feature.name }
@@ -0,0 +1,37 @@
1
+ %h2
2
+ = @collection.name.to_s.titlecase
3
+
4
+ %p #{@collection.description}
5
+
6
+ %br
7
+
8
+ %h3 Operations:
9
+
10
+ %table
11
+ %thead
12
+ %tr
13
+ %th Name
14
+ %th Description
15
+ %tbody
16
+ - @operations.keys.sort_by { |k| k.to_s }.each do |operation|
17
+ %tr
18
+ %td{:style => "width:15em"}
19
+ %a{:href => "/api/docs/#{@collection.name.to_s}/#{operation}"} #{operation}
20
+ %td{:style => "width:10em"} #{@operations[operation].description}
21
+
22
+ %h3 Features:
23
+
24
+ %table
25
+ %thead
26
+ %tr
27
+ %th Name
28
+ %th Description
29
+ %th Modified Operations
30
+ %tbody
31
+ - @features.sort_by { |f| f.name.to_s }.each do |feature|
32
+ %tr
33
+ %td= feature.name
34
+ %td= feature.description
35
+ %td
36
+ - feature.operations.each do |op|
37
+ %a{:href => "/api/docs/#{@collection.name.to_s}/#{op.name}"} #{op.name}
@@ -0,0 +1,14 @@
1
+ %docs{:status => "unsupported"}
2
+ %collection{:url => "/api/docs/#{@collection.name}", :name => "#{@collection.name}"}
3
+ %description #{@collection.description}
4
+ %operations
5
+ - @operations.keys.sort_by { |k| k.to_s }.each do |operation|
6
+ %operation{:url => "/api/#{@collection.name.to_s}", :name => "#{operation}", :href => "#{@operations[operation].path}", :method => "#{@operations[operation].method}"}
7
+ %description #{@operations[operation].description}
8
+ - @operations[operation].each_param do |param|
9
+ %parameter{:name => "#{param.name}", :type => "#{param.type}"}
10
+ %class #{param.klass}
11
+ - unless param.options.empty?
12
+ %values
13
+ - param.options.each do |v|
14
+ %value #{v}
@@ -0,0 +1,15 @@
1
+ %h2 API Documentation
2
+
3
+ %h3 Collections:
4
+
5
+ %table
6
+ %thead
7
+ %tr
8
+ %th Name
9
+ %th Description
10
+ %tbody
11
+ - collections.keys.sort_by { |k| k.to_s }.each do |collection|
12
+ %tr
13
+ %td{:style => "width:15em"}
14
+ %a{:href => "/api/docs/#{collection}"} #{collection}
15
+ %td{:style => "width:10em"} #{collections[collection].description}
@@ -0,0 +1,5 @@
1
+ %docs{:status => "unsupported"}
2
+ - collections.keys.sort_by { |k| k.to_s }.each do |collection|
3
+ %collection{:url => "/api/docs/#{collection}"}
4
+ %name #{collection}
5
+ %description #{collections[collection].description}
@@ -0,0 +1,31 @@
1
+ %h2
2
+ %a{:href => "/api/docs/#{@collection.name.to_s}"} #{@collection.name.to_s.titlecase}
3
+ #{'::'}
4
+ #{@operation.name}
5
+
6
+ %p #{@operation.description}
7
+
8
+ %br
9
+ %h3
10
+ URL:
11
+ %u
12
+ = "/api/#{@collection.name.to_s}/#{@operation.name.to_s}"
13
+ %br
14
+ %h3 Parameters:
15
+
16
+
17
+ %table
18
+ %thead
19
+ %tr
20
+ %th Name
21
+ %th Type
22
+ %th Class
23
+ %th Valid values
24
+ %tbody
25
+ - @operation.each_param do |p|
26
+ %tr
27
+ %td{:style => "width:15em"}
28
+ %em #{p.name}
29
+ %td{:style => "width:10em"} #{p.type}
30
+ %td #{p.klass}
31
+ %td{:style => "width:10em"} #{p.options.join(',')}