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.
- data/COPYING +176 -0
- data/Rakefile +99 -0
- data/bin/deltacloudd +120 -0
- data/config.ru +5 -0
- data/deltacloud.rb +18 -0
- data/lib/deltacloud/base_driver/base_driver.rb +229 -0
- data/lib/deltacloud/base_driver/features.rb +166 -0
- data/lib/deltacloud/base_driver/mock_driver.rb +40 -0
- data/lib/deltacloud/base_driver.rb +20 -0
- data/lib/deltacloud/drivers/ec2/ec2_driver.rb +410 -0
- data/lib/deltacloud/drivers/ec2/ec2_mock_driver.rb +170 -0
- data/lib/deltacloud/drivers/gogrid/gogrid_client.rb +50 -0
- data/lib/deltacloud/drivers/gogrid/gogrid_driver.rb +332 -0
- data/lib/deltacloud/drivers/gogrid/test.rb +13 -0
- data/lib/deltacloud/drivers/mock/data/images/img1.yml +3 -0
- data/lib/deltacloud/drivers/mock/data/images/img2.yml +3 -0
- data/lib/deltacloud/drivers/mock/data/images/img3.yml +3 -0
- data/lib/deltacloud/drivers/mock/data/instances/inst0.yml +16 -0
- data/lib/deltacloud/drivers/mock/data/instances/inst1.yml +9 -0
- data/lib/deltacloud/drivers/mock/data/instances/inst2.yml +9 -0
- data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap1.yml +4 -0
- data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap2.yml +4 -0
- data/lib/deltacloud/drivers/mock/data/storage_snapshots/snap3.yml +4 -0
- data/lib/deltacloud/drivers/mock/data/storage_volumes/vol1.yml +6 -0
- data/lib/deltacloud/drivers/mock/data/storage_volumes/vol2.yml +6 -0
- data/lib/deltacloud/drivers/mock/data/storage_volumes/vol3.yml +6 -0
- data/lib/deltacloud/drivers/mock/mock_driver.rb +277 -0
- data/lib/deltacloud/drivers/opennebula/cloud_client.rb +116 -0
- data/lib/deltacloud/drivers/opennebula/occi_client.rb +204 -0
- data/lib/deltacloud/drivers/opennebula/opennebula_driver.rb +241 -0
- data/lib/deltacloud/drivers/rackspace/rackspace_client.rb +130 -0
- data/lib/deltacloud/drivers/rackspace/rackspace_driver.rb +182 -0
- data/lib/deltacloud/drivers/rhevm/rhevm_driver.rb +255 -0
- data/lib/deltacloud/drivers/rimuhosting/rimuhosting_client.rb +85 -0
- data/lib/deltacloud/drivers/rimuhosting/rimuhosting_driver.rb +166 -0
- data/lib/deltacloud/drivers/terremark/terremark_driver.rb +286 -0
- data/lib/deltacloud/hardware_profile.rb +153 -0
- data/lib/deltacloud/helpers/application_helper.rb +115 -0
- data/lib/deltacloud/helpers/conversion_helper.rb +39 -0
- data/lib/deltacloud/helpers/hardware_profiles_helper.rb +35 -0
- data/lib/deltacloud/helpers.rb +5 -0
- data/lib/deltacloud/method_serializer.rb +85 -0
- data/lib/deltacloud/models/base_model.rb +59 -0
- data/lib/deltacloud/models/image.rb +27 -0
- data/lib/deltacloud/models/instance.rb +38 -0
- data/lib/deltacloud/models/instance_profile.rb +48 -0
- data/lib/deltacloud/models/key.rb +35 -0
- data/lib/deltacloud/models/realm.rb +26 -0
- data/lib/deltacloud/models/storage_snapshot.rb +27 -0
- data/lib/deltacloud/models/storage_volume.rb +28 -0
- data/lib/deltacloud/state_machine.rb +84 -0
- data/lib/deltacloud/validation.rb +70 -0
- data/lib/drivers.rb +50 -0
- data/lib/sinatra/accept_media_types.rb +128 -0
- data/lib/sinatra/lazy_auth.rb +56 -0
- data/lib/sinatra/rabbit.rb +273 -0
- data/lib/sinatra/respond_to.rb +272 -0
- data/lib/sinatra/static_assets.rb +83 -0
- data/lib/sinatra/url_for.rb +53 -0
- data/public/favicon.ico +0 -0
- data/public/images/grid.png +0 -0
- data/public/images/logo-wide.png +0 -0
- data/public/images/rails.png +0 -0
- data/public/images/topbar-bg.png +0 -0
- data/public/javascripts/application.js +32 -0
- data/public/javascripts/jquery-1.4.2.min.js +154 -0
- data/public/stylesheets/compiled/application.css +613 -0
- data/public/stylesheets/compiled/ie.css +31 -0
- data/public/stylesheets/compiled/print.css +27 -0
- data/public/stylesheets/compiled/screen.css +456 -0
- data/server.rb +354 -0
- data/support/fedora/deltacloudd +68 -0
- data/support/fedora/rubygem-deltacloud-core.spec +91 -0
- data/tests/api_test.rb +37 -0
- data/tests/hardware_profiles_test.rb +120 -0
- data/tests/images_test.rb +111 -0
- data/tests/instance_states_test.rb +52 -0
- data/tests/instances_test.rb +219 -0
- data/tests/realms_test.rb +78 -0
- data/tests/url_for_test.rb +50 -0
- data/views/accounts/index.html.haml +11 -0
- data/views/accounts/show.html.haml +30 -0
- data/views/api/show.html.haml +15 -0
- data/views/api/show.xml.haml +5 -0
- data/views/docs/collection.html.haml +37 -0
- data/views/docs/collection.xml.haml +14 -0
- data/views/docs/index.html.haml +15 -0
- data/views/docs/index.xml.haml +5 -0
- data/views/docs/operation.html.haml +31 -0
- data/views/docs/operation.xml.haml +10 -0
- data/views/errors/auth_exception.html.haml +8 -0
- data/views/errors/auth_exception.xml.haml +2 -0
- data/views/errors/backend_error.html.haml +19 -0
- data/views/errors/backend_error.xml.haml +8 -0
- data/views/errors/not_found.html.haml +6 -0
- data/views/errors/not_found.xml.haml +2 -0
- data/views/errors/validation_failure.html.haml +11 -0
- data/views/errors/validation_failure.xml.haml +7 -0
- data/views/hardware_profiles/index.html.haml +25 -0
- data/views/hardware_profiles/index.xml.haml +4 -0
- data/views/hardware_profiles/show.html.haml +19 -0
- data/views/hardware_profiles/show.xml.haml +18 -0
- data/views/images/index.html.haml +30 -0
- data/views/images/index.xml.haml +8 -0
- data/views/images/show.html.haml +21 -0
- data/views/images/show.xml.haml +5 -0
- data/views/instance_states/show.gv.erb +45 -0
- data/views/instance_states/show.html.haml +31 -0
- data/views/instance_states/show.xml.haml +8 -0
- data/views/instances/index.html.haml +30 -0
- data/views/instances/index.xml.haml +21 -0
- data/views/instances/new.html.haml +55 -0
- data/views/instances/show.html.haml +43 -0
- data/views/instances/show.xml.haml +49 -0
- data/views/keys/index.html.haml +26 -0
- data/views/keys/index.xml.haml +4 -0
- data/views/keys/new.html.haml +8 -0
- data/views/keys/show.html.haml +22 -0
- data/views/keys/show.xml.haml +20 -0
- data/views/layout.html.haml +26 -0
- data/views/realms/index.html.haml +29 -0
- data/views/realms/index.xml.haml +10 -0
- data/views/realms/show.html.haml +15 -0
- data/views/realms/show.xml.haml +9 -0
- data/views/root/index.html.haml +4 -0
- data/views/storage_snapshots/index.html.haml +20 -0
- data/views/storage_snapshots/index.xml.haml +9 -0
- data/views/storage_snapshots/show.html.haml +14 -0
- data/views/storage_snapshots/show.xml.haml +7 -0
- data/views/storage_volumes/index.html.haml +21 -0
- data/views/storage_volumes/index.xml.haml +13 -0
- data/views/storage_volumes/show.html.haml +20 -0
- data/views/storage_volumes/show.xml.haml +11 -0
- 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('/')}'>δ</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 "∅" 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
|