steamcannon-deltacloud-core 0.0.7.1-java

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 (152) hide show
  1. data/COPYING +176 -0
  2. data/Rakefile +106 -0
  3. data/bin/deltacloudd +120 -0
  4. data/config.ru +5 -0
  5. data/deltacloud.rb +20 -0
  6. data/lib/deltacloud/base_driver/base_driver.rb +259 -0
  7. data/lib/deltacloud/base_driver/features.rb +173 -0
  8. data/lib/deltacloud/base_driver/mock_driver.rb +58 -0
  9. data/lib/deltacloud/base_driver.rb +20 -0
  10. data/lib/deltacloud/drivers/azure/azure_driver.rb +127 -0
  11. data/lib/deltacloud/drivers/ec2/ec2_driver.rb +580 -0
  12. data/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb +170 -0
  13. data/lib/deltacloud/drivers/gogrid/gogrid_client.rb +50 -0
  14. data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +343 -0
  15. data/lib/deltacloud/drivers/gogrid/test.rb +13 -0
  16. data/lib/deltacloud/drivers/mock/data/buckets/blobs/blob1.yml +5 -0
  17. data/lib/deltacloud/drivers/mock/data/buckets/blobs/blob2.yml +5 -0
  18. data/lib/deltacloud/drivers/mock/data/buckets/blobs/blob3.yml +5 -0
  19. data/lib/deltacloud/drivers/mock/data/buckets/blobs/blob4.yml +5 -0
  20. data/lib/deltacloud/drivers/mock/data/buckets/blobs/blob5.yml +5 -0
  21. data/lib/deltacloud/drivers/mock/data/buckets/bucket1.yml +2 -0
  22. data/lib/deltacloud/drivers/mock/data/buckets/bucket2.yml +2 -0
  23. data/lib/deltacloud/drivers/mock/data/images/img1.yml +3 -0
  24. data/lib/deltacloud/drivers/mock/data/images/img2.yml +3 -0
  25. data/lib/deltacloud/drivers/mock/data/images/img3.yml +3 -0
  26. data/lib/deltacloud/drivers/mock/data/instances/inst0.yml +16 -0
  27. data/lib/deltacloud/drivers/mock/data/instances/inst1.yml +9 -0
  28. data/lib/deltacloud/drivers/mock/data/instances/inst2.yml +9 -0
  29. data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap1.yml +4 -0
  30. data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap2.yml +4 -0
  31. data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap3.yml +4 -0
  32. data/lib/deltacloud/drivers/mock/data/storage_volumes/vol1.yml +6 -0
  33. data/lib/deltacloud/drivers/mock/data/storage_volumes/vol2.yml +6 -0
  34. data/lib/deltacloud/drivers/mock/data/storage_volumes/vol3.yml +6 -0
  35. data/lib/deltacloud/drivers/mock/mock_driver.rb +356 -0
  36. data/lib/deltacloud/drivers/opennebula/cloud_client.rb +116 -0
  37. data/lib/deltacloud/drivers/opennebula/occi_client.rb +204 -0
  38. data/lib/deltacloud/drivers/opennebula/opennebula_driver.rb +241 -0
  39. data/lib/deltacloud/drivers/rackspace/rackspace_client.rb +130 -0
  40. data/lib/deltacloud/drivers/rackspace/rackspace_driver.rb +290 -0
  41. data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +258 -0
  42. data/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb +85 -0
  43. data/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb +166 -0
  44. data/lib/deltacloud/drivers/terremark/terremark_driver.rb +295 -0
  45. data/lib/deltacloud/hardware_profile.rb +153 -0
  46. data/lib/deltacloud/helpers/application_helper.rb +122 -0
  47. data/lib/deltacloud/helpers/blob_stream.rb +51 -0
  48. data/lib/deltacloud/helpers/conversion_helper.rb +39 -0
  49. data/lib/deltacloud/helpers/hardware_profiles_helper.rb +35 -0
  50. data/lib/deltacloud/helpers.rb +5 -0
  51. data/lib/deltacloud/method_serializer.rb +85 -0
  52. data/lib/deltacloud/models/base_model.rb +59 -0
  53. data/lib/deltacloud/models/blob.rb +26 -0
  54. data/lib/deltacloud/models/bucket.rb +24 -0
  55. data/lib/deltacloud/models/image.rb +27 -0
  56. data/lib/deltacloud/models/instance.rb +38 -0
  57. data/lib/deltacloud/models/instance_profile.rb +48 -0
  58. data/lib/deltacloud/models/key.rb +35 -0
  59. data/lib/deltacloud/models/realm.rb +26 -0
  60. data/lib/deltacloud/models/storage_snapshot.rb +27 -0
  61. data/lib/deltacloud/models/storage_volume.rb +28 -0
  62. data/lib/deltacloud/state_machine.rb +84 -0
  63. data/lib/deltacloud/validation.rb +70 -0
  64. data/lib/drivers.rb +51 -0
  65. data/lib/sinatra/accept_media_types.rb +128 -0
  66. data/lib/sinatra/lazy_auth.rb +56 -0
  67. data/lib/sinatra/rabbit.rb +279 -0
  68. data/lib/sinatra/respond_to.rb +238 -0
  69. data/lib/sinatra/static_assets.rb +83 -0
  70. data/lib/sinatra/url_for.rb +53 -0
  71. data/public/favicon.ico +0 -0
  72. data/public/images/grid.png +0 -0
  73. data/public/images/logo-wide.png +0 -0
  74. data/public/images/rails.png +0 -0
  75. data/public/images/topbar-bg.png +0 -0
  76. data/public/javascripts/application.js +32 -0
  77. data/public/javascripts/jquery-1.4.2.min.js +154 -0
  78. data/public/stylesheets/compiled/application.css +613 -0
  79. data/public/stylesheets/compiled/ie.css +31 -0
  80. data/public/stylesheets/compiled/print.css +27 -0
  81. data/public/stylesheets/compiled/screen.css +456 -0
  82. data/server.rb +516 -0
  83. data/support/fedora/deltacloudd +68 -0
  84. data/support/fedora/rubygem-deltacloud-core.spec +91 -0
  85. data/tests/api_test.rb +37 -0
  86. data/tests/hardware_profiles_test.rb +120 -0
  87. data/tests/images_test.rb +111 -0
  88. data/tests/instance_states_test.rb +51 -0
  89. data/tests/instances_test.rb +222 -0
  90. data/tests/realms_test.rb +78 -0
  91. data/tests/url_for_test.rb +50 -0
  92. data/views/accounts/index.html.haml +11 -0
  93. data/views/accounts/show.html.haml +30 -0
  94. data/views/api/show.html.haml +15 -0
  95. data/views/api/show.xml.haml +5 -0
  96. data/views/blobs/show.html.haml +20 -0
  97. data/views/blobs/show.xml.haml +7 -0
  98. data/views/buckets/index.html.haml +33 -0
  99. data/views/buckets/index.xml.haml +10 -0
  100. data/views/buckets/new.html.haml +13 -0
  101. data/views/buckets/show.html.haml +19 -0
  102. data/views/buckets/show.xml.haml +8 -0
  103. data/views/docs/collection.html.haml +37 -0
  104. data/views/docs/collection.xml.haml +14 -0
  105. data/views/docs/index.html.haml +15 -0
  106. data/views/docs/index.xml.haml +5 -0
  107. data/views/docs/operation.html.haml +31 -0
  108. data/views/docs/operation.xml.haml +10 -0
  109. data/views/errors/auth_exception.html.haml +8 -0
  110. data/views/errors/auth_exception.xml.haml +2 -0
  111. data/views/errors/backend_error.html.haml +19 -0
  112. data/views/errors/backend_error.xml.haml +8 -0
  113. data/views/errors/not_found.html.haml +6 -0
  114. data/views/errors/not_found.xml.haml +2 -0
  115. data/views/errors/validation_failure.html.haml +11 -0
  116. data/views/errors/validation_failure.xml.haml +7 -0
  117. data/views/hardware_profiles/index.html.haml +25 -0
  118. data/views/hardware_profiles/index.xml.haml +4 -0
  119. data/views/hardware_profiles/show.html.haml +19 -0
  120. data/views/hardware_profiles/show.xml.haml +18 -0
  121. data/views/images/index.html.haml +30 -0
  122. data/views/images/index.xml.haml +8 -0
  123. data/views/images/show.html.haml +21 -0
  124. data/views/images/show.xml.haml +5 -0
  125. data/views/instance_states/show.html.haml +31 -0
  126. data/views/instance_states/show.png.erb +45 -0
  127. data/views/instance_states/show.xml.haml +8 -0
  128. data/views/instances/index.html.haml +30 -0
  129. data/views/instances/index.xml.haml +21 -0
  130. data/views/instances/new.html.haml +55 -0
  131. data/views/instances/show.html.haml +43 -0
  132. data/views/instances/show.xml.haml +49 -0
  133. data/views/keys/index.html.haml +26 -0
  134. data/views/keys/index.xml.haml +4 -0
  135. data/views/keys/new.html.haml +8 -0
  136. data/views/keys/show.html.haml +22 -0
  137. data/views/keys/show.xml.haml +20 -0
  138. data/views/layout.html.haml +26 -0
  139. data/views/realms/index.html.haml +29 -0
  140. data/views/realms/index.xml.haml +10 -0
  141. data/views/realms/show.html.haml +15 -0
  142. data/views/realms/show.xml.haml +9 -0
  143. data/views/root/index.html.haml +4 -0
  144. data/views/storage_snapshots/index.html.haml +20 -0
  145. data/views/storage_snapshots/index.xml.haml +9 -0
  146. data/views/storage_snapshots/show.html.haml +14 -0
  147. data/views/storage_snapshots/show.xml.haml +7 -0
  148. data/views/storage_volumes/index.html.haml +21 -0
  149. data/views/storage_volumes/index.xml.haml +23 -0
  150. data/views/storage_volumes/show.html.haml +20 -0
  151. data/views/storage_volumes/show.xml.haml +24 -0
  152. metadata +367 -0
@@ -0,0 +1,295 @@
1
+ # Copyright (C) 2010 Red Hat, Inc.
2
+ #
3
+ # Licensed to the Apache Software Foundation (ASF) under one or more
4
+ # contributor license agreements. See the NOTICE file distributed with
5
+ # this work for additional information regarding copyright ownership. The
6
+ # ASF licenses this file to you under the Apache License, Version 2.0 (the
7
+ # "License"); you may not use this file except in compliance with the
8
+ # License. You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
+ # License for the specific language governing permissions and limitations
16
+ # under the License.
17
+ #
18
+ # This driver uses the fog library (Geemus - Wesley Beary) to talk to terremark... see
19
+ # http://github.com/geemus/fog
20
+ # see terremark vcloud express api at:
21
+ # https://community.vcloudexpress.terremark.com/en-us/product_docs/w/wiki/d-complete-vcloud-express-api-document.aspx
22
+ #
23
+ # 02 May 2010
24
+ #
25
+ require 'deltacloud/base_driver'
26
+ require 'fog'
27
+ require 'excon'
28
+ require 'nokogiri'
29
+
30
+ module Deltacloud
31
+ module Drivers
32
+ module Terremark
33
+
34
+ class TerremarkDriver < Deltacloud::BaseDriver
35
+
36
+ feature :instances, :user_name
37
+
38
+ #--
39
+ # Vapp State Map... for use with convert_instance (get an integer back from terremark)
40
+ #--
41
+ VAPP_STATE_MAP = { "0" => "PENDING", "1" => "PENDING", "2" => "STOPPED", "4" => "RUNNING" }
42
+
43
+ #--
44
+ # HARDWARE PROFILES
45
+ #--
46
+ define_hardware_profile 'default' do
47
+ cpu [1,2,4,8]
48
+ memory [512, 1024, 2048, 4096, 8192]
49
+ storage (1..500).to_a
50
+ end
51
+ #storage_disks [1..15]
52
+
53
+ #--
54
+ # IMAGES
55
+ #--
56
+ #aka "vapp_templates"
57
+ def images(credentials, opts=nil)
58
+ image_list = []
59
+ terremark_client = new_client(credentials)
60
+ safely do
61
+ vdc_id = terremark_client.default_vdc_id
62
+ catalogItems = terremark_client.get_catalog(vdc_id).body['CatalogItems']
63
+ catalogItems.each{ |catalog_item|
64
+ current_item_id = catalog_item['href'].split('/').last
65
+ current_item = terremark_client.get_catalog_item(current_item_id).body['Entity']
66
+ if(current_item['type'] == 'application/vnd.vmware.vcloud.vAppTemplate+xml')
67
+ image_list << convert_image(current_item, credentials.user)
68
+ end
69
+ } #end of catalogItems.each
70
+ end
71
+ image_list = filter_on( image_list, :id, opts )
72
+ image_list = filter_on( image_list, :architecture, opts )
73
+ image_list = filter_on( image_list, :owner_id, opts )
74
+ image_list
75
+ end
76
+
77
+ #--
78
+ # REALMS
79
+ #--
80
+ #only one realm... everything in US?
81
+ def realms(credentials, opts=nil)
82
+ [Realm.new( {
83
+ :id=>"US-Miami",
84
+ :name=>"United States - Miami",
85
+ :state=> "AVAILABLE"
86
+ } )]
87
+ end
88
+
89
+ #--
90
+ # INSTANCES
91
+ #--
92
+ #aka vApps
93
+ def instances(credentials, opts=nil)
94
+ instances = []
95
+ terremark_client = new_client(credentials)
96
+ safely do
97
+ vdc_items = terremark_client.get_vdc(terremark_client.default_vdc_id()).body['ResourceEntities']
98
+ vdc_items.each{|current_item|
99
+ if(current_item['type'] == 'application/vnd.vmware.vcloud.vApp+xml')
100
+ vapp_id = current_item['href'].split('/').last
101
+ vapp = terremark_client.get_vapp(vapp_id)
102
+ instances << convert_instance(vapp, terremark_client, credentials.user)
103
+ end
104
+ }#end vdc_items.each
105
+ end
106
+ instances = filter_on( instances, :id, opts )
107
+ instances
108
+ end
109
+
110
+ #--
111
+ # FINITE STATE MACHINE
112
+ #--
113
+ #by default new instance --> powered_off
114
+ define_instance_states do
115
+ start.to(:pending) .on( :create )
116
+ pending.to(:stopped) .automatically
117
+ stopped.to(:running) .on( :start )
118
+ running.to(:running) .on( :reboot )
119
+ running.to(:shutting_down) .on( :stop )
120
+ shutting_down.to(:stopped) .automatically
121
+ stopped.to(:finish) .on( :destroy )
122
+ end
123
+
124
+
125
+ #--
126
+ # CREATE INSTANCE
127
+ #--
128
+ #launch a vapp template. Needs a name, ram, no. cpus, id of vapp_template
129
+ def create_instance(credentials, image_id, opts)
130
+ new_vapp = nil
131
+ vapp_opts = {} #assemble options to pass to Fog::Terremark::Real.instantiate_vapp_template
132
+ terremark_hwp = hardware_profiles(credentials, {:name => 'default'}).first #sanity check values against default
133
+ name = opts['name'] #name could be nil or length 0 or too long
134
+ name = "inst#{Time.now.to_i}" if (name.nil? || (name.length == 0))
135
+ name = name.slice(0..13) #name < 15 chars (says terremark)
136
+ unless ( (terremark_hwp.include?(:cpu, opts[:hwp_cpu].to_i)) &&
137
+ (terremark_hwp.include?(:memory, opts[:hwp_memory].to_i)) ) then
138
+ raise Deltacloud::Validation::Failure.new(Deltacloud::Validation::Param.new(["cpu"]), "Error with cpu and/or memory values. you said cpu->#{opts[:hwp_cpu]} and mem->#{opts[:hwp_memory]}")
139
+ end
140
+ vapp_opts['cpus'] = opts[:hwp_cpu]
141
+ vapp_opts['memory'] = opts[:hwp_memory]
142
+ safely do
143
+ terremark_client = new_client(credentials)
144
+ #######
145
+ #FIXME# what happens if there is an issue getting the new vapp id? (eg even though created succesfully)
146
+ #######
147
+ vapp_id = terremark_client.instantiate_vapp_template(name, image_id, vapp_opts).body['href'].split('/').last
148
+ new_vapp = terremark_client.get_vapp(vapp_id)
149
+ return convert_instance(new_vapp, terremark_client, credentials.user) #return an Instance object
150
+ end
151
+ end
152
+
153
+ #--
154
+ # REBOOT INSTANCE
155
+ #--
156
+ def reboot_instance(credentials, id)
157
+ safely do
158
+ terremark_client = new_client(credentials)
159
+ return terremark_client.power_reset(id)
160
+ end
161
+ end
162
+
163
+ #--
164
+ # START INSTANCE
165
+ #--
166
+ def start_instance(credentials, id)
167
+ safely do
168
+ terremark_client = new_client(credentials)
169
+ return terremark_client.power_on(id)
170
+ end
171
+ end
172
+
173
+ #--
174
+ # STOP INSTANCE
175
+ #--
176
+ def stop_instance(credentials, id)
177
+ safely do
178
+ terremark_client = new_client(credentials)
179
+ return terremark_client.power_shutdown(id)
180
+ end
181
+ end
182
+
183
+ #--
184
+ # DESTROY INSTANCE
185
+ #--
186
+ #shuts down... in terremark need to do a futher delete to get rid of a vapp entirely
187
+ def destroy_instance(credentials, id)
188
+ safely do
189
+ terremark_client = new_client(credentials)
190
+ return terremark_client.delete_vapp(id)
191
+ end
192
+ end
193
+
194
+ def valid_credentials?(credentials)
195
+ begin
196
+ new_client(credentials)
197
+ rescue Deltacloud::AuthException
198
+ return false
199
+ end
200
+ true
201
+ end
202
+
203
+ #--
204
+ # PRIVATE METHODS:
205
+ #--
206
+
207
+ private
208
+
209
+ #--
210
+ # CONVERT IMAGE
211
+ #--
212
+ #gets a vapp_template from a catalog and makes it a Image
213
+ def convert_image(catalog_vapp_template, account_name)
214
+ name = catalog_vapp_template['name']
215
+ #much fudging ensues
216
+ #arch = name.scan(/(36|24).bit/).first
217
+ #k enuf o'that now!
218
+ arch = "n/a" #Leaving out entirely as we don't get one from terremark (could parse but its a fudge)
219
+ Image.new( {
220
+ :id => catalog_vapp_template['href'].split('/').last,
221
+ :name => catalog_vapp_template['name'],
222
+ :architecture => arch,
223
+ :owner_id => account_name,
224
+ :description => catalog_vapp_template['name']
225
+ })
226
+ end
227
+
228
+ #--
229
+ # CONVERT INSTANCE
230
+ #--
231
+ def convert_instance(vapp, terremark_client, account_name)
232
+ vapp_private_ip = vapp.body['IpAddress']
233
+ vapp_public_ip = terremark_client.get_public_ips(terremark_client.default_vdc_id).body['PublicIpAddresses'].first['name']#get_public_address(terremark_client, vapp_private_ip)
234
+ vapp_status = vapp.body['status']
235
+ current_state = VAPP_STATE_MAP[vapp_status] #status == 0->BEING_CREATED 2->OFF 4->ON
236
+ profile = InstanceProfile.new("default")
237
+ name = vapp.body['name']
238
+ if current_state != "PENDING" #can only grab this stuff after instance is created
239
+ profile.cpu = vapp.body['VirtualHardware']['cpu']
240
+ profile.memory = vapp.body['VirtualHardware']['ram']
241
+ #######
242
+ #FIXME# could be more that one disk... but for now capture only first
243
+ #######
244
+ disk = ((vapp.body['VirtualHardware']['disks'].first.to_i) / 1024 / 1024).to_s
245
+ profile.storage = disk
246
+ #######
247
+ #FIXME# this is a hack, shouldn't place this info next to name as some clients may rely on name field... probably will introduce
248
+ ####### a new field in the API for this (e.g. description/text field... human readable)
249
+ #name = "#{name} - [ #{vapp.body['OperatingSystem']['Description']} ]"
250
+ end
251
+ Instance.new( {
252
+ :id => vapp.body['href'].split('/').last,
253
+ :owner_id => "#{account_name}",
254
+ #:image_id => "n/a", #cant get this... see https://community.vcloudexpress.terremark.com/en-us/discussion_forums/f/60/t/376.aspx
255
+ :name => name,
256
+ :realm_id => "US-Miami",
257
+ :state => current_state,
258
+ :actions => instance_actions_for(current_state),
259
+ :public_addresses => vapp_public_ip,
260
+ :private_addresses => vapp_private_ip,
261
+ :instance_profile => profile
262
+ } )
263
+ end
264
+
265
+ #--
266
+ # NEW CLIENT
267
+ #--
268
+ #use supplied credentials to make a new client for talking to terremark
269
+ def new_client(credentials)
270
+ #Fog constructor expecting credentials[:terremark_password] and credentials[:terremark_username]
271
+ terremark_credentials = {:terremark_vcloud_username => "#{credentials.user}", :terremark_vcloud_password => "#{credentials.password}" }
272
+ safely do
273
+ terremark_client = Fog::Terremark::Vcloud.new(terremark_credentials)
274
+ vdc_id = terremark_client.default_vdc_id
275
+ end
276
+ if (vdc_id.nil?)
277
+ raise DeltaCloud::AuthException.new
278
+ end
279
+ terremark_client
280
+ end
281
+
282
+ def safely(&block)
283
+ begin
284
+ block.call
285
+ rescue Exception => e
286
+ raise Deltacloud::BackendError.new(500, e.class.to_s, e.message, e.backtrace)
287
+ end
288
+ end
289
+
290
+
291
+ end
292
+
293
+ end
294
+ end
295
+ end
@@ -0,0 +1,153 @@
1
+
2
+ module Deltacloud
3
+ class HardwareProfile
4
+
5
+ UNITS = {
6
+ :memory => "MB",
7
+ :storage => "GB",
8
+ :architecture => "label",
9
+ :cpu => "count"
10
+ }
11
+
12
+ def self.unit(name)
13
+ UNITS[name]
14
+ end
15
+
16
+ class Property
17
+ attr_reader :name, :kind, :default
18
+ # kind == :range
19
+ attr_reader :first, :last
20
+ # kind == :enum
21
+ attr_reader :values
22
+ # kind == :fixed
23
+ attr_reader :value
24
+
25
+ def initialize(name, values, opts = {})
26
+ @name = name
27
+ if values.is_a?(Range)
28
+ @kind = :range
29
+ @first = values.first
30
+ @last = values.last
31
+ @default = values.first
32
+ elsif values.is_a?(Array)
33
+ @kind = :enum
34
+ @values = values
35
+ @default = values.first
36
+ else
37
+ @kind = :fixed
38
+ @value = values
39
+ @default = @value
40
+ end
41
+ @default = opts[:default] if opts[:default]
42
+ end
43
+
44
+ def unit
45
+ HardwareProfile.unit(name)
46
+ end
47
+
48
+ def param
49
+ "hwp_#{name}"
50
+ end
51
+
52
+ def fixed?
53
+ kind == :fixed
54
+ end
55
+
56
+ def to_param
57
+ return nil if kind == :fixed
58
+ if kind == :range
59
+ # FIXME: We can't validate ranges currently
60
+ args = [param, :string, :optional]
61
+ else
62
+ args = [param, :string, :optional, values.collect { |v| v.to_s} ]
63
+ end
64
+ Validation::Param.new(args)
65
+ end
66
+
67
+ def include?(v)
68
+ if kind == :fixed
69
+ return v == value
70
+ elsif kind == :range
71
+ return v >= first && v <= last
72
+ else
73
+ return values.include?(v)
74
+ end
75
+ end
76
+ end
77
+
78
+ class << self
79
+ def property(prop)
80
+ define_method(prop) do |*args|
81
+ values, opts, *ignored = *args
82
+ instvar = :"@#{prop}"
83
+ unless values.nil?
84
+ @properties[prop] = Property.new(prop, values, opts || {})
85
+ end
86
+ @properties[prop]
87
+ end
88
+ end
89
+ end
90
+
91
+ attr_reader :name
92
+ property :cpu
93
+ property :architecture
94
+ property :memory
95
+ property :storage
96
+
97
+ def initialize(name,&block)
98
+ @properties = {}
99
+ @name = name
100
+ instance_eval &block if block_given?
101
+ end
102
+
103
+ def each_property(&block)
104
+ @properties.each_value { |prop| yield prop }
105
+ end
106
+
107
+ def properties
108
+ @properties.values
109
+ end
110
+
111
+ def property(name)
112
+ @properties[name.to_sym]
113
+ end
114
+
115
+ def default?(prop, v)
116
+ p = @properties[prop.to_sym]
117
+ p && p.default.to_s == v
118
+ end
119
+
120
+ def to_hash
121
+ props = []
122
+ self.each_property do |p|
123
+ if p.kind.eql? :fixed
124
+ props << { :kind => p.kind, :value => p.value, :name => p.name, :unit => p.unit }
125
+ else
126
+ param = { :operation => "create", :method => "post", :name => p.name }
127
+ if p.kind.eql? :range
128
+ param[:range] = { :first => p.first, :last => p.last }
129
+ elsif p.kind.eql? :enum
130
+ param[:enum] = p.values.collect { |v| { :entry => v } }
131
+ end
132
+ param
133
+ props << { :kind => p.kind, :value => p.default, :name => p.name, :unit => p.unit, :param => param }
134
+ end
135
+ end
136
+ {
137
+ :id => self.name,
138
+ :properties => props
139
+ }
140
+ end
141
+
142
+ def include?(prop, v)
143
+ p = @properties[prop]
144
+ p.nil? || p.include?(v)
145
+ end
146
+
147
+ def params
148
+ @properties.values.inject([]) { |m, prop|
149
+ m << prop.to_param
150
+ }.compact
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,122 @@
1
+ #
2
+ # Copyright (C) 2009 Red Hat, Inc.
3
+ #
4
+ # Licensed to the Apache Software Foundation (ASF) under one or more
5
+ # contributor license agreements. See the NOTICE file distributed with
6
+ # this work for additional information regarding copyright ownership. The
7
+ # ASF licenses this file to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance with the
9
+ # License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16
+ # License for the specific language governing permissions and limitations
17
+ # under the License.
18
+
19
+ # Methods added to this helper will be available to all templates in the application.
20
+ module ApplicationHelper
21
+
22
+ def bread_crumb
23
+ s = "<ul class='breadcrumb'><li class='first'><a href='#{url_for('/')}'>&#948</a></li>"
24
+ url = request.path_info.split('?') #remove extra query string parameters
25
+ levels = url[0].split('/') #break up url into different levels
26
+ levels.each_with_index do |level, index|
27
+ unless level.blank?
28
+ if index == levels.size-1 ||
29
+ (level == levels[levels.size-2] && levels[levels.size-1].to_i > 0)
30
+ s += "<li class='subsequent'>#{level.gsub(/_/, ' ')}</li>\n" unless level.to_i > 0
31
+ else
32
+ link = levels.slice(0, index+1).join("/")
33
+ s += "<li class='subsequent'><a href=\"#{url_for(link)}\">#{level.gsub(/_/, ' ')}</a></li>\n"
34
+ end
35
+ end
36
+ end
37
+ s+="</ul>"
38
+ end
39
+
40
+ def instance_action_method(action)
41
+ collections[:instances].operations[action.to_sym].method
42
+ end
43
+
44
+ def driver_has_feature?(feature_name)
45
+ not driver.features(:instances).select{ |f| f.name.eql?(feature_name) }.empty?
46
+ end
47
+
48
+ def driver_has_auth_features?
49
+ driver_has_feature?(:authentication_password) || driver_has_feature?(:authentication_key)
50
+ end
51
+
52
+ def driver_auth_feature_name
53
+ return 'key' if driver_has_feature?(:authentication_key)
54
+ return 'password' if driver_has_feature?(:authentication_password)
55
+ end
56
+
57
+ def driver_has_bucket_location_feature?
58
+ driver.features(:buckets).each do |feat|
59
+ return true if feat.name == :bucket_location
60
+ end
61
+ false
62
+ end
63
+
64
+ def filter_all(model)
65
+ filter = {}
66
+ filter.merge!(:id => params[:id]) if params[:id]
67
+ filter.merge!(:architecture => params[:architecture]) if params[:architecture]
68
+ filter.merge!(:owner_id => params[:owner_id]) if params[:owner_id]
69
+ filter.merge!(:state => params[:state]) if params[:state]
70
+ filter = nil if filter.keys.size.eql?(0)
71
+ singular = model.to_s.singularize.to_sym
72
+ @elements = driver.send(model.to_sym, credentials, filter)
73
+ instance_variable_set(:"@#{model}", @elements)
74
+ respond_to do |format|
75
+ format.html { haml :"#{model}/index" }
76
+ format.xml { haml :"#{model}/index" }
77
+ format.json { convert_to_json(singular, @elements) }
78
+ end
79
+ end
80
+
81
+ def show(model)
82
+ @element = driver.send(model, credentials, { :id => params[:id]} )
83
+ instance_variable_set("@#{model}", @element)
84
+ if @element
85
+ respond_to do |format|
86
+ format.html { haml :"#{model.to_s.pluralize}/show" }
87
+ format.xml { haml :"#{model.to_s.pluralize}/show" }
88
+ format.json { convert_to_json(model, @element) }
89
+ end
90
+ else
91
+ report_error(404, 'not_found')
92
+ end
93
+ end
94
+
95
+ def report_error(status, template)
96
+ @error = request.env['sinatra.error']
97
+ response.status = status
98
+ respond_to do |format|
99
+ format.xml { haml :"errors/#{template}", :layout => false }
100
+ format.html { haml :"errors/#{template}" }
101
+ end
102
+ end
103
+
104
+ def instance_action(name)
105
+ @instance = driver.send(:"#{name}_instance", credentials, params["id"])
106
+
107
+ return redirect(instances_url) if name.eql?(:destroy) or @instance.class!=Instance
108
+
109
+ respond_to do |format|
110
+ format.xml { haml :"instances/show" }
111
+ format.html { haml :"instances/show" }
112
+ format.json {convert_to_json(:instance, @instance) }
113
+ end
114
+ end
115
+
116
+ def cdata(&block)
117
+ text = capture_haml(&block)
118
+ text.gsub!("\n", "\n ")
119
+ "<![CDATA[\n #{text}\n]]>"
120
+ end
121
+
122
+ end
@@ -0,0 +1,51 @@
1
+ # Copyright (C) 2010 Red Hat, Inc.
2
+ #
3
+ # Licensed to the Apache Software Foundation (ASF) under one or more
4
+ # contributor license agreements. See the NOTICE file distributed with
5
+ # this work for additional information regarding copyright ownership. The
6
+ # ASF licenses this file to you under the Apache License, Version 2.0 (the
7
+ # "License"); you may not use this file except in compliance with the
8
+ # License. You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15
+ # License for the specific language governing permissions and limitations
16
+ # under the License.
17
+
18
+ #--
19
+ # based on the example from http://macournoyer.com/blog/2009/06/04/pusher-and-async-with-thin/
20
+ #--
21
+ require 'eventmachine'
22
+ class BlobStream
23
+ AsyncResponse = [-1, {}, []].freeze
24
+ def self.call(env, credentials, params)
25
+ body = DeferrableBody.new
26
+ #Get the headers out asap. Don't specify a content-type let
27
+ #the client guess and if they can't they SHOULD default to
28
+ #'application/octet-stream' anyway as per:
29
+ #http://www.w3.org/Protocols/rfc2616/rfc2616-sec7.html#sec7.2.1
30
+ EM.next_tick { env['async.callback'].call [200, {'Content-Type' => "#{params['content_type']}", 'Content-Length' => "#{params['content_length']}"}, body] }
31
+ #call the driver from here. the driver method yields for every chunk of blob it receives. We then
32
+ #use body.call to write that chunk as received.
33
+ driver.blob_data(credentials, params[:bucket], params[:blob], params) {|chunk| body.call ["#{chunk}"]} #close blob_data block
34
+ body.succeed
35
+ AsyncResponse # Tells Thin to not close the connection and continue it's work on other request
36
+ end
37
+ end
38
+
39
+ class DeferrableBody
40
+ include EventMachine::Deferrable
41
+
42
+ def call(body)
43
+ body.each do |chunk|
44
+ @body_callback.call(chunk)
45
+ end
46
+ end
47
+
48
+ def each(&blk)
49
+ @body_callback = blk
50
+ end
51
+ end
@@ -0,0 +1,39 @@
1
+ #
2
+ # Copyright (C) 2009 Red Hat, Inc.
3
+ #
4
+ # Licensed to the Apache Software Foundation (ASF) under one or more
5
+ # contributor license agreements. See the NOTICE file distributed with
6
+ # this work for additional information regarding copyright ownership. The
7
+ # ASF licenses this file to you under the Apache License, Version 2.0 (the
8
+ # "License"); you may not use this file except in compliance with the
9
+ # License. You may obtain a copy of the License at
10
+ #
11
+ # http://www.apache.org/licenses/LICENSE-2.0
12
+ #
13
+ # Unless required by applicable law or agreed to in writing, software
14
+ # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
15
+ # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
16
+ # License for the specific language governing permissions and limitations
17
+ # under the License.
18
+
19
+
20
+ require 'deltacloud/base_driver'
21
+
22
+ module ConversionHelper
23
+
24
+ def convert_to_json(type, obj)
25
+ if ( [ :flavor, :account, :image, :realm, :instance, :storage_volume, :storage_snapshot, :hardware_profile ].include?( type ) )
26
+ if Array.eql?(obj.class)
27
+ data = obj.collect do |o|
28
+ o.to_hash.merge({ :href => self.send(:"#{type}_url", type.eql?(:hardware_profile) ? o.name : o.id ) })
29
+ end
30
+ type = type.to_s.pluralize
31
+ else
32
+ data = obj.to_hash
33
+ data.merge!({ :href => self.send(:"#{type}_url", data[:id]) })
34
+ end
35
+ return { :"#{type}" => data }.to_json
36
+ end
37
+ end
38
+
39
+ end
@@ -0,0 +1,35 @@
1
+ module HardwareProfilesHelper
2
+
3
+ def format_hardware_property(prop)
4
+ return "&empty;" unless prop
5
+ u = hardware_property_unit(prop)
6
+ case prop.kind
7
+ when :range
8
+ "#{prop.first} #{u} - #{prop.last} #{u} (default: #{prop.default} #{u})"
9
+ when :enum
10
+ prop.values.collect{ |v| "#{v} #{u}"}.join(', ') + " (default: #{prop.default} #{u})"
11
+ else
12
+ "#{prop.value} #{u}"
13
+ end
14
+ end
15
+
16
+ def format_instance_profile(ip)
17
+ o = ip.overrides.collect do |p, v|
18
+ u = hardware_property_unit(p)
19
+ "#{p} = #{v} #{u}"
20
+ end
21
+ if o.empty?
22
+ ""
23
+ else
24
+ "with #{o.join(", ")}"
25
+ end
26
+ end
27
+
28
+ private
29
+ def hardware_property_unit(prop)
30
+ u = ::Deltacloud::HardwareProfile::unit(prop)
31
+ u = "" if ["label", "count"].include?(u)
32
+ u = "vcpus" if prop == :cpu
33
+ u
34
+ end
35
+ end
@@ -0,0 +1,5 @@
1
+ require 'deltacloud/helpers/application_helper'
2
+ require 'deltacloud/helpers/conversion_helper'
3
+ require 'deltacloud/helpers/hardware_profiles_helper'
4
+
5
+ helpers ApplicationHelper, ConversionHelper, HardwareProfilesHelper