bbrowning-deltacloud-core 0.0.4-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 (134) hide show
  1. data/COPYING +176 -0
  2. data/Rakefile +99 -0
  3. data/bin/deltacloudd +120 -0
  4. data/config.ru +5 -0
  5. data/deltacloud.rb +18 -0
  6. data/lib/deltacloud/base_driver/base_driver.rb +229 -0
  7. data/lib/deltacloud/base_driver/features.rb +166 -0
  8. data/lib/deltacloud/base_driver/mock_driver.rb +40 -0
  9. data/lib/deltacloud/base_driver.rb +20 -0
  10. data/lib/deltacloud/drivers/ec2/ec2_driver.rb +410 -0
  11. data/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb +170 -0
  12. data/lib/deltacloud/drivers/gogrid/gogrid_client.rb +50 -0
  13. data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +332 -0
  14. data/lib/deltacloud/drivers/gogrid/test.rb +13 -0
  15. data/lib/deltacloud/drivers/mock/data/images/img1.yml +3 -0
  16. data/lib/deltacloud/drivers/mock/data/images/img2.yml +3 -0
  17. data/lib/deltacloud/drivers/mock/data/images/img3.yml +3 -0
  18. data/lib/deltacloud/drivers/mock/data/instances/inst0.yml +16 -0
  19. data/lib/deltacloud/drivers/mock/data/instances/inst1.yml +9 -0
  20. data/lib/deltacloud/drivers/mock/data/instances/inst2.yml +9 -0
  21. data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap1.yml +4 -0
  22. data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap2.yml +4 -0
  23. data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap3.yml +4 -0
  24. data/lib/deltacloud/drivers/mock/data/storage_volumes/vol1.yml +6 -0
  25. data/lib/deltacloud/drivers/mock/data/storage_volumes/vol2.yml +6 -0
  26. data/lib/deltacloud/drivers/mock/data/storage_volumes/vol3.yml +6 -0
  27. data/lib/deltacloud/drivers/mock/mock_driver.rb +277 -0
  28. data/lib/deltacloud/drivers/opennebula/cloud_client.rb +116 -0
  29. data/lib/deltacloud/drivers/opennebula/occi_client.rb +204 -0
  30. data/lib/deltacloud/drivers/opennebula/opennebula_driver.rb +241 -0
  31. data/lib/deltacloud/drivers/rackspace/rackspace_client.rb +130 -0
  32. data/lib/deltacloud/drivers/rackspace/rackspace_driver.rb +182 -0
  33. data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +255 -0
  34. data/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb +85 -0
  35. data/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb +166 -0
  36. data/lib/deltacloud/drivers/terremark/terremark_driver.rb +286 -0
  37. data/lib/deltacloud/hardware_profile.rb +153 -0
  38. data/lib/deltacloud/helpers/application_helper.rb +115 -0
  39. data/lib/deltacloud/helpers/conversion_helper.rb +39 -0
  40. data/lib/deltacloud/helpers/hardware_profiles_helper.rb +35 -0
  41. data/lib/deltacloud/helpers.rb +5 -0
  42. data/lib/deltacloud/method_serializer.rb +85 -0
  43. data/lib/deltacloud/models/base_model.rb +59 -0
  44. data/lib/deltacloud/models/image.rb +27 -0
  45. data/lib/deltacloud/models/instance.rb +38 -0
  46. data/lib/deltacloud/models/instance_profile.rb +48 -0
  47. data/lib/deltacloud/models/key.rb +35 -0
  48. data/lib/deltacloud/models/realm.rb +26 -0
  49. data/lib/deltacloud/models/storage_snapshot.rb +27 -0
  50. data/lib/deltacloud/models/storage_volume.rb +28 -0
  51. data/lib/deltacloud/state_machine.rb +84 -0
  52. data/lib/deltacloud/validation.rb +70 -0
  53. data/lib/drivers.rb +50 -0
  54. data/lib/sinatra/accept_media_types.rb +128 -0
  55. data/lib/sinatra/lazy_auth.rb +56 -0
  56. data/lib/sinatra/rabbit.rb +273 -0
  57. data/lib/sinatra/respond_to.rb +272 -0
  58. data/lib/sinatra/static_assets.rb +83 -0
  59. data/lib/sinatra/url_for.rb +53 -0
  60. data/public/favicon.ico +0 -0
  61. data/public/images/grid.png +0 -0
  62. data/public/images/logo-wide.png +0 -0
  63. data/public/images/rails.png +0 -0
  64. data/public/images/topbar-bg.png +0 -0
  65. data/public/javascripts/application.js +32 -0
  66. data/public/javascripts/jquery-1.4.2.min.js +154 -0
  67. data/public/stylesheets/compiled/application.css +613 -0
  68. data/public/stylesheets/compiled/ie.css +31 -0
  69. data/public/stylesheets/compiled/print.css +27 -0
  70. data/public/stylesheets/compiled/screen.css +456 -0
  71. data/server.rb +354 -0
  72. data/support/fedora/deltacloudd +68 -0
  73. data/support/fedora/rubygem-deltacloud-core.spec +91 -0
  74. data/tests/api_test.rb +37 -0
  75. data/tests/hardware_profiles_test.rb +120 -0
  76. data/tests/images_test.rb +111 -0
  77. data/tests/instance_states_test.rb +52 -0
  78. data/tests/instances_test.rb +219 -0
  79. data/tests/realms_test.rb +78 -0
  80. data/tests/url_for_test.rb +50 -0
  81. data/views/accounts/index.html.haml +11 -0
  82. data/views/accounts/show.html.haml +30 -0
  83. data/views/api/show.html.haml +15 -0
  84. data/views/api/show.xml.haml +5 -0
  85. data/views/docs/collection.html.haml +37 -0
  86. data/views/docs/collection.xml.haml +14 -0
  87. data/views/docs/index.html.haml +15 -0
  88. data/views/docs/index.xml.haml +5 -0
  89. data/views/docs/operation.html.haml +31 -0
  90. data/views/docs/operation.xml.haml +10 -0
  91. data/views/errors/auth_exception.html.haml +8 -0
  92. data/views/errors/auth_exception.xml.haml +2 -0
  93. data/views/errors/backend_error.html.haml +19 -0
  94. data/views/errors/backend_error.xml.haml +8 -0
  95. data/views/errors/not_found.html.haml +6 -0
  96. data/views/errors/not_found.xml.haml +2 -0
  97. data/views/errors/validation_failure.html.haml +11 -0
  98. data/views/errors/validation_failure.xml.haml +7 -0
  99. data/views/hardware_profiles/index.html.haml +25 -0
  100. data/views/hardware_profiles/index.xml.haml +4 -0
  101. data/views/hardware_profiles/show.html.haml +19 -0
  102. data/views/hardware_profiles/show.xml.haml +18 -0
  103. data/views/images/index.html.haml +30 -0
  104. data/views/images/index.xml.haml +8 -0
  105. data/views/images/show.html.haml +21 -0
  106. data/views/images/show.xml.haml +5 -0
  107. data/views/instance_states/show.gv.erb +45 -0
  108. data/views/instance_states/show.html.haml +31 -0
  109. data/views/instance_states/show.xml.haml +8 -0
  110. data/views/instances/index.html.haml +30 -0
  111. data/views/instances/index.xml.haml +21 -0
  112. data/views/instances/new.html.haml +55 -0
  113. data/views/instances/show.html.haml +43 -0
  114. data/views/instances/show.xml.haml +49 -0
  115. data/views/keys/index.html.haml +26 -0
  116. data/views/keys/index.xml.haml +4 -0
  117. data/views/keys/new.html.haml +8 -0
  118. data/views/keys/show.html.haml +22 -0
  119. data/views/keys/show.xml.haml +20 -0
  120. data/views/layout.html.haml +26 -0
  121. data/views/realms/index.html.haml +29 -0
  122. data/views/realms/index.xml.haml +10 -0
  123. data/views/realms/show.html.haml +15 -0
  124. data/views/realms/show.xml.haml +9 -0
  125. data/views/root/index.html.haml +4 -0
  126. data/views/storage_snapshots/index.html.haml +20 -0
  127. data/views/storage_snapshots/index.xml.haml +9 -0
  128. data/views/storage_snapshots/show.html.haml +14 -0
  129. data/views/storage_snapshots/show.xml.haml +7 -0
  130. data/views/storage_volumes/index.html.haml +21 -0
  131. data/views/storage_volumes/index.xml.haml +13 -0
  132. data/views/storage_volumes/show.html.haml +20 -0
  133. data/views/storage_volumes/show.xml.haml +11 -0
  134. metadata +334 -0
@@ -0,0 +1,286 @@
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
+ #--
195
+ # PRIVATE METHODS:
196
+ #--
197
+
198
+ private
199
+
200
+ #--
201
+ # CONVERT IMAGE
202
+ #--
203
+ #gets a vapp_template from a catalog and makes it a Image
204
+ def convert_image(catalog_vapp_template, account_name)
205
+ name = catalog_vapp_template['name']
206
+ #much fudging ensues
207
+ #arch = name.scan(/(36|24).bit/).first
208
+ #k enuf o'that now!
209
+ arch = "n/a" #Leaving out entirely as we don't get one from terremark (could parse but its a fudge)
210
+ Image.new( {
211
+ :id => catalog_vapp_template['href'].split('/').last,
212
+ :name => catalog_vapp_template['name'],
213
+ :architecture => arch,
214
+ :owner_id => account_name,
215
+ :description => catalog_vapp_template['name']
216
+ })
217
+ end
218
+
219
+ #--
220
+ # CONVERT INSTANCE
221
+ #--
222
+ def convert_instance(vapp, terremark_client, account_name)
223
+ vapp_private_ip = vapp.body['IpAddress']
224
+ 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)
225
+ vapp_status = vapp.body['status']
226
+ current_state = VAPP_STATE_MAP[vapp_status] #status == 0->BEING_CREATED 2->OFF 4->ON
227
+ profile = InstanceProfile.new("default")
228
+ name = vapp.body['name']
229
+ if current_state != "PENDING" #can only grab this stuff after instance is created
230
+ profile.cpu = vapp.body['VirtualHardware']['cpu']
231
+ profile.memory = vapp.body['VirtualHardware']['ram']
232
+ #######
233
+ #FIXME# could be more that one disk... but for now capture only first
234
+ #######
235
+ disk = ((vapp.body['VirtualHardware']['disks'].first.to_i) / 1024 / 1024).to_s
236
+ profile.storage = disk
237
+ #######
238
+ #FIXME# this is a hack, shouldn't place this info next to name as some clients may rely on name field... probably will introduce
239
+ ####### a new field in the API for this (e.g. description/text field... human readable)
240
+ #name = "#{name} - [ #{vapp.body['OperatingSystem']['Description']} ]"
241
+ end
242
+ Instance.new( {
243
+ :id => vapp.body['href'].split('/').last,
244
+ :owner_id => "#{account_name}",
245
+ #:image_id => "n/a", #cant get this... see https://community.vcloudexpress.terremark.com/en-us/discussion_forums/f/60/t/376.aspx
246
+ :name => name,
247
+ :realm_id => "US-Miami",
248
+ :state => current_state,
249
+ :actions => instance_actions_for(current_state),
250
+ :public_addresses => vapp_public_ip,
251
+ :private_addresses => vapp_private_ip,
252
+ :instance_profile => profile
253
+ } )
254
+ end
255
+
256
+ #--
257
+ # NEW CLIENT
258
+ #--
259
+ #use supplied credentials to make a new client for talking to terremark
260
+ def new_client(credentials)
261
+ #Fog constructor expecting credentials[:terremark_password] and credentials[:terremark_username]
262
+ terremark_credentials = {:terremark_vcloud_username => "#{credentials.user}", :terremark_vcloud_password => "#{credentials.password}" }
263
+ safely do
264
+ terremark_client = Fog::Terremark::Vcloud.new(terremark_credentials)
265
+ vdc_id = terremark_client.default_vdc_id
266
+ end
267
+ if (vdc_id.nil?)
268
+ raise DeltaCloud::AuthException.new
269
+ end
270
+ terremark_client
271
+ end
272
+
273
+ def safely(&block)
274
+ begin
275
+ block.call
276
+ rescue Exception => e
277
+ raise Deltacloud::BackendError.new(500, e.class.to_s, e.message, e.backtrace)
278
+ end
279
+ end
280
+
281
+
282
+ end
283
+
284
+ end
285
+ end
286
+ 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,115 @@
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 filter_all(model)
58
+ filter = {}
59
+ filter.merge!(:id => params[:id]) if params[:id]
60
+ filter.merge!(:architecture => params[:architecture]) if params[:architecture]
61
+ filter.merge!(:owner_id => params[:owner_id]) if params[:owner_id]
62
+ filter.merge!(:state => params[:state]) if params[:state]
63
+ filter = nil if filter.keys.size.eql?(0)
64
+ singular = model.to_s.singularize.to_sym
65
+ @elements = driver.send(model.to_sym, credentials, filter)
66
+ instance_variable_set(:"@#{model}", @elements)
67
+ respond_to do |format|
68
+ format.html { haml :"#{model}/index" }
69
+ format.xml { haml :"#{model}/index" }
70
+ format.json { convert_to_json(singular, @elements) }
71
+ end
72
+ end
73
+
74
+ def show(model)
75
+ @element = driver.send(model, credentials, { :id => params[:id]} )
76
+ instance_variable_set("@#{model}", @element)
77
+ if @element
78
+ respond_to do |format|
79
+ format.html { haml :"#{model.to_s.pluralize}/show" }
80
+ format.xml { haml :"#{model.to_s.pluralize}/show" }
81
+ format.json { convert_to_json(model, @element) }
82
+ end
83
+ else
84
+ report_error(404, 'not_found')
85
+ end
86
+ end
87
+
88
+ def report_error(status, template)
89
+ @error = request.env['sinatra.error']
90
+ response.status = status
91
+ respond_to do |format|
92
+ format.xml { haml :"errors/#{template}", :layout => false }
93
+ format.html { haml :"errors/#{template}" }
94
+ end
95
+ end
96
+
97
+ def instance_action(name)
98
+ @instance = driver.send(:"#{name}_instance", credentials, params["id"])
99
+
100
+ return redirect(instances_url) if name.eql?(:destroy) or @instance.class!=Instance
101
+
102
+ respond_to do |format|
103
+ format.html { haml :"instances/show" }
104
+ format.xml { haml :"instances/show" }
105
+ format.json {convert_to_json(:instance, @instance) }
106
+ end
107
+ end
108
+
109
+ def cdata(&block)
110
+ text = capture_haml(&block)
111
+ text.gsub!("\n", "\n ")
112
+ "<![CDATA[\n #{text}\n]]>"
113
+ end
114
+
115
+ 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