Hi,
I added few more patches to go:
4/7: Fixed missing ID elements in storage_volumes and hardware_profiles 5/7: Added comments to feature for brief listing. I want to keep these features commented here just for testing in future. 6/7: This will be a little bit longer patch :) I removed old client completely and rewrote it from scratch. I used some meta magic to get auto-generated classes and methods. This approach will allow us to add a new elements/attribute in future to API and 'client' library will update itself. Also REXML was removed completely and replaced by faster Nokogiri. Just one small thing is still missing here. I don't have '.to_plain' methods implemented yet, so command line client will not work... (Need +1 day ;) 7/7: As a bonus, *all* RSpec tests now pass nicely.
There are +2 incompatibilities:
instance.instance_profile => instance.hardware_profile realm.limit => NoMethod exception (when no limit is set for realm)
-- Michal
PS: Apply this patch to latest 'master'.
--- server/lib/deltacloud/base_driver/features.rb | 12 +++++ server/lib/deltacloud/drivers/mock/mock_driver.rb | 2 + .../lib/deltacloud/helpers/application_helper.rb | 12 +++++- server/views/images/index.xml.haml | 11 +++-- server/views/instances/index.xml.haml | 43 ++++++++++--------- 5 files changed, 54 insertions(+), 26 deletions(-)
diff --git a/server/lib/deltacloud/base_driver/features.rb b/server/lib/deltacloud/base_driver/features.rb index 8ad354a..39f0a94 100644 --- a/server/lib/deltacloud/base_driver/features.rb +++ b/server/lib/deltacloud/base_driver/features.rb @@ -151,6 +151,18 @@ module Deltacloud end end
+ declare_feature :images, :brief_listing_mode do + operation :index do + param :listing_mode, :string, :optional + end + end + + declare_feature :instances, :brief_listing_mode do + operation :index do + param :listing_mode, :string, :optional + end + end + declare_feature :instances, :hardware_profiles do description "Size instances according to changes to a hardware profile" # The parameters are filled in from the hardware profiles diff --git a/server/lib/deltacloud/drivers/mock/mock_driver.rb b/server/lib/deltacloud/drivers/mock/mock_driver.rb index 9671f02..3096cd6 100644 --- a/server/lib/deltacloud/drivers/mock/mock_driver.rb +++ b/server/lib/deltacloud/drivers/mock/mock_driver.rb @@ -75,6 +75,8 @@ class MockDriver < Deltacloud::BaseDriver end
feature :instances, :user_name + feature :images, :brief_listing_mode + feature :instances, :brief_listing_mode
def initialize if ENV["DELTACLOUD_MOCK_STORAGE"] diff --git a/server/lib/deltacloud/helpers/application_helper.rb b/server/lib/deltacloud/helpers/application_helper.rb index 850fab4..1428ec0 100644 --- a/server/lib/deltacloud/helpers/application_helper.rb +++ b/server/lib/deltacloud/helpers/application_helper.rb @@ -40,8 +40,8 @@ module ApplicationHelper collections[:instances].operations[action.to_sym].method end
- def driver_has_feature?(feature_name) - not driver.features(:instances).select{ |f| f.name.eql?(feature_name) }.empty? + def driver_has_feature?(feature_name, default_collection = :instances) + not driver.features(default_collection).select{ |f| f.name.eql?(feature_name) }.empty? end
def driver_has_auth_features? @@ -53,4 +53,12 @@ module ApplicationHelper return 'password' if driver_has_feature?(:authentication_password) end
+ def full_listing_mode?(collection) + if driver_has_feature?(:brief_listing_mode, collection) and not params[:listing_mode]=='full' + return false + else + return true + end + end + end diff --git a/server/views/images/index.xml.haml b/server/views/images/index.xml.haml index 6d14b21..a86cc5b 100644 --- a/server/views/images/index.xml.haml +++ b/server/views/images/index.xml.haml @@ -1,7 +1,10 @@ !!! XML %images - @elements.each do |image| - %image{:href => image_url(image.id)} - - image.attributes.each do |attribute| - - haml_tag(attribute, :<) do - - haml_concat image.send(attribute) + - if full_listing_mode?(:images) + %image{:href => image_url(image.id)} + - image.attributes.each do |attribute| + - haml_tag(attribute, :<) do + - haml_concat image.send(attribute) + - else + %image{ :href => image_url(image.id), :id => image.id } diff --git a/server/views/instances/index.xml.haml b/server/views/instances/index.xml.haml index f2bb8f0..176d706 100644 --- a/server/views/instances/index.xml.haml +++ b/server/views/instances/index.xml.haml @@ -1,23 +1,26 @@ !!! XML %instances - @elements.each do |instance| - %instance{:href => instance_url(instance.id)} - %id #{instance.id} - %name #{instance.name} - %owner_id #{instance.owner_id} - %image{:href => image_url(instance.image_id)} - %realm{:href => realm_url(instance.realm_id)} - %state #{instance.state} - - haml_tag :"hardware-profile", { :href => hardware_profile_url(instance.instance_profile.id)} do - %id #{instance.instance_profile.id} - - instance.instance_profile.overrides.each do |p, v| - %property{:kind => 'fixed', :name => p, :value => v, :unit => Deltacloud::HardwareProfile::unit(p)} - %actions - - instance.actions.compact.each do |action| - %link{:rel => action, :href => self.send("#{action}_instance_url", instance.id), :method => instance_action_method(action)} - %public-addresses - - instance.public_addresses.each do |address| - %address #{address} - %private-addresses - - instance.private_addresses.each do |address| - %address #{address} + - if full_listing_mode?(:instances) + %instance{:href => instance_url(instance.id)} + %id #{instance.id} + %name #{instance.name} + %owner_id #{instance.owner_id} + %image{:href => image_url(instance.image_id)} + %realm{:href => realm_url(instance.realm_id)} + %state #{instance.state} + - haml_tag :"hardware-profile", { :href => hardware_profile_url(instance.instance_profile.id)} do + %id #{instance.instance_profile.id} + - instance.instance_profile.overrides.each do |p, v| + %property{:kind => 'fixed', :name => p, :value => v, :unit => Deltacloud::HardwareProfile::unit(p)} + %actions + - instance.actions.compact.each do |action| + %link{:rel => action, :href => self.send("#{action}_instance_url", instance.id), :method => instance_action_method(action)} + %public-addresses + - instance.public_addresses.each do |address| + %address #{address} + %private-addresses + - instance.private_addresses.each do |address| + %address #{address} + - else + %instance{ :id => instance.id, :href => instance_url(instance.id)}
--- server/views/hardware_profiles/index.xml.haml | 2 +- server/views/hardware_profiles/show.xml.haml | 2 +- server/views/images/index.xml.haml | 2 +- server/views/instances/index.xml.haml | 6 +++--- server/views/instances/show.xml.haml | 6 +++--- server/views/storage_snapshots/index.xml.haml | 6 +++--- server/views/storage_snapshots/show.xml.haml | 4 ++-- server/views/storage_volumes/index.xml.haml | 4 ++-- server/views/storage_volumes/show.xml.haml | 2 +- 9 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/server/views/hardware_profiles/index.xml.haml b/server/views/hardware_profiles/index.xml.haml index 52f91a4..cf0a69f 100644 --- a/server/views/hardware_profiles/index.xml.haml +++ b/server/views/hardware_profiles/index.xml.haml @@ -1,4 +1,4 @@ !!! XML -%hardware-profiles +%hardware_profiles - @profiles.each do |prof| = haml :'hardware_profiles/show', :locals => { :@profile => prof, :partial => true } diff --git a/server/views/hardware_profiles/show.xml.haml b/server/views/hardware_profiles/show.xml.haml index 4a289a1..b39d6f0 100644 --- a/server/views/hardware_profiles/show.xml.haml +++ b/server/views/hardware_profiles/show.xml.haml @@ -1,6 +1,6 @@ - unless defined?(partial) !!! XML -%hardware-profile{ :href => hardware_profile_url(@profile.name) } +%hardware_profile{ :href => hardware_profile_url(@profile.name) } %id= @profile.name - @profile.each_property do |prop| - attr = { :name => prop.name, :kind => prop.kind, :unit => prop.unit } diff --git a/server/views/images/index.xml.haml b/server/views/images/index.xml.haml index a86cc5b..9236d02 100644 --- a/server/views/images/index.xml.haml +++ b/server/views/images/index.xml.haml @@ -4,7 +4,7 @@ - if full_listing_mode?(:images) %image{:href => image_url(image.id)} - image.attributes.each do |attribute| - - haml_tag(attribute, :<) do + - haml_tag("#{attribute}".tr('-', '_'), :<) do - haml_concat image.send(attribute) - else %image{ :href => image_url(image.id), :id => image.id } diff --git a/server/views/instances/index.xml.haml b/server/views/instances/index.xml.haml index 176d706..c6a208a 100644 --- a/server/views/instances/index.xml.haml +++ b/server/views/instances/index.xml.haml @@ -9,17 +9,17 @@ %image{:href => image_url(instance.image_id)} %realm{:href => realm_url(instance.realm_id)} %state #{instance.state} - - haml_tag :"hardware-profile", { :href => hardware_profile_url(instance.instance_profile.id)} do + - haml_tag :"hardware_profile", { :href => hardware_profile_url(instance.instance_profile.id)} do %id #{instance.instance_profile.id} - instance.instance_profile.overrides.each do |p, v| %property{:kind => 'fixed', :name => p, :value => v, :unit => Deltacloud::HardwareProfile::unit(p)} %actions - instance.actions.compact.each do |action| %link{:rel => action, :href => self.send("#{action}_instance_url", instance.id), :method => instance_action_method(action)} - %public-addresses + %public_addresses - instance.public_addresses.each do |address| %address #{address} - %private-addresses + %private_addresses - instance.private_addresses.each do |address| %address #{address} - else diff --git a/server/views/instances/show.xml.haml b/server/views/instances/show.xml.haml index cfe5e80..2881100 100644 --- a/server/views/instances/show.xml.haml +++ b/server/views/instances/show.xml.haml @@ -10,7 +10,7 @@ %realm{:href => realm_url(@instance.realm_id)} %state< =@instance.state - - haml_tag :"hardware-profile", {:href => hardware_profile_url(@instance.instance_profile.id)} do + - haml_tag :"hardware_profile", {:href => hardware_profile_url(@instance.instance_profile.id)} do %id< =@instance.instance_profile.id - @instance.instance_profile.overrides.each do |p, v| @@ -18,11 +18,11 @@ %actions - @instance.actions.compact.each do |instance_action| %link{:rel => instance_action, :method => instance_action_method(instance_action), :href => self.send("#{instance_action}_instance_url", @instance.id)} - %public-addresses + %public_addresses - @instance.public_addresses.each do |address| %address< =address - %private-addresses + %private_addresses - @instance.private_addresses.each do |address| %address< =address diff --git a/server/views/storage_snapshots/index.xml.haml b/server/views/storage_snapshots/index.xml.haml index 734e00f..46b362f 100644 --- a/server/views/storage_snapshots/index.xml.haml +++ b/server/views/storage_snapshots/index.xml.haml @@ -1,11 +1,11 @@ !!!XML -%storage-snapshots +%storage_snapshots - @elements.each do |snapshot| - %storage-snapshot{ :href => storage_snapshot_url(snapshot.id)} + %storage_snapshot{ :href => storage_snapshot_url(snapshot.id)} %id< =snapshot.id %created< =snapshot.created %state< =snapshot.state - %storage-volume{ :href => storage_volume_url(snapshot.storage_volume_id)} + %storage_volume{ :href => storage_volume_url(snapshot.storage_volume_id)} diff --git a/server/views/storage_snapshots/show.xml.haml b/server/views/storage_snapshots/show.xml.haml index 49e3f00..912f97a 100644 --- a/server/views/storage_snapshots/show.xml.haml +++ b/server/views/storage_snapshots/show.xml.haml @@ -1,9 +1,9 @@ !!!XML -%storage-snapshot{:href => storage_snapshot_url(@storage_snapshot.id)} +%storage_snapshot{:href => storage_snapshot_url(@storage_snapshot.id)} %id< =@storage_snapshot.id %created< =@storage_snapshot.created %state< =@storage_snapshot.state - %storage-volume{:href => storage_volume_url(@storage_snapshot.storage_volume_id)} + %storage_volume{:href => storage_volume_url(@storage_snapshot.storage_volume_id)} diff --git a/server/views/storage_volumes/index.xml.haml b/server/views/storage_volumes/index.xml.haml index e07596f..bc55ff4 100644 --- a/server/views/storage_volumes/index.xml.haml +++ b/server/views/storage_volumes/index.xml.haml @@ -1,7 +1,7 @@ !!!XML -%storage-volumes +%storage_volumes - @elements.each do |volume| - %storage-volume{ :href => storage_volume_url(volume.id)} + %storage_volume{ :href => storage_volume_url(volume.id)} %id< =volume.id %created< diff --git a/server/views/storage_volumes/show.xml.haml b/server/views/storage_volumes/show.xml.haml index 18f2e42..b6b1088 100644 --- a/server/views/storage_volumes/show.xml.haml +++ b/server/views/storage_volumes/show.xml.haml @@ -1,5 +1,5 @@ !!!XML -%storage-volume{ :href => storage_volume_url(@storage_volume.id)} +%storage_volume{ :href => storage_volume_url(@storage_volume.id)} %id< =@storage_volume.id %created<
--- server/views/images/index.xml.haml | 4 ++-- server/views/images/show.xml.haml | 4 ++-- server/views/instances/index.xml.haml | 10 ++++------ server/views/instances/show.xml.haml | 12 ++++-------- server/views/realms/index.xml.haml | 4 +--- server/views/realms/show.xml.haml | 9 ++++----- server/views/storage_snapshots/index.xml.haml | 6 ++---- server/views/storage_snapshots/show.xml.haml | 6 ++---- server/views/storage_volumes/index.xml.haml | 12 ++++++------ 9 files changed, 27 insertions(+), 40 deletions(-)
diff --git a/server/views/images/index.xml.haml b/server/views/images/index.xml.haml index 9236d02..82dd6bd 100644 --- a/server/views/images/index.xml.haml +++ b/server/views/images/index.xml.haml @@ -2,8 +2,8 @@ %images - @elements.each do |image| - if full_listing_mode?(:images) - %image{:href => image_url(image.id)} - - image.attributes.each do |attribute| + %image{:href => image_url(image.id), :id => image.id} + - image.attributes.select{ |attr| attr!=:id }.each do |attribute| - haml_tag("#{attribute}".tr('-', '_'), :<) do - haml_concat image.send(attribute) - else diff --git a/server/views/images/show.xml.haml b/server/views/images/show.xml.haml index fbb5d07..c3e2cc4 100644 --- a/server/views/images/show.xml.haml +++ b/server/views/images/show.xml.haml @@ -1,5 +1,5 @@ !!! XML -%image{:href => image_url(@image.id)} - - @image.attributes.each do |attribute| +%image{:href => image_url(@image.id), :id => @image.id} + - @image.attributes.select{ |attr| attr!=:id }.each do |attribute| - haml_tag(attribute, :<) do - haml_concat @image.send(attribute) diff --git a/server/views/instances/index.xml.haml b/server/views/instances/index.xml.haml index c6a208a..72672bc 100644 --- a/server/views/instances/index.xml.haml +++ b/server/views/instances/index.xml.haml @@ -2,15 +2,13 @@ %instances - @elements.each do |instance| - if full_listing_mode?(:instances) - %instance{:href => instance_url(instance.id)} - %id #{instance.id} + %instance{:href => instance_url(instance.id), :id => instance.id} %name #{instance.name} %owner_id #{instance.owner_id} - %image{:href => image_url(instance.image_id)} - %realm{:href => realm_url(instance.realm_id)} + %image{:href => image_url(instance.image_id), :id => instance.image_id } + %realm{:href => realm_url(instance.realm_id), :id => instance.realm_id } %state #{instance.state} - - haml_tag :"hardware_profile", { :href => hardware_profile_url(instance.instance_profile.id)} do - %id #{instance.instance_profile.id} + - haml_tag :"hardware_profile", { :id => instance.instance_profile.id, :href => hardware_profile_url(instance.instance_profile.id)} do - instance.instance_profile.overrides.each do |p, v| %property{:kind => 'fixed', :name => p, :value => v, :unit => Deltacloud::HardwareProfile::unit(p)} %actions diff --git a/server/views/instances/show.xml.haml b/server/views/instances/show.xml.haml index 2881100..18f563e 100644 --- a/server/views/instances/show.xml.haml +++ b/server/views/instances/show.xml.haml @@ -1,18 +1,14 @@ !!! XML -%instance{:href => instance_url(@instance.id)} - %id< - =@instance.id +%instance{:href => instance_url(@instance.id), :id => @instance.id} %name< =@instance.name %owner_id< =@instance.owner_id - %image{:href => image_url(@instance.image_id)} - %realm{:href => realm_url(@instance.realm_id)} + %image{:href => image_url(@instance.image_id), :id => @instance.image_id } + %realm{:href => realm_url(@instance.realm_id), :id => @instance.realm_id } %state< =@instance.state - - haml_tag :"hardware_profile", {:href => hardware_profile_url(@instance.instance_profile.id)} do - %id< - =@instance.instance_profile.id + - haml_tag :"hardware_profile", {:id => @instance.instance_profile.id, :href => hardware_profile_url(@instance.instance_profile.id)} do - @instance.instance_profile.overrides.each do |p, v| %property{:kind => 'fixed', :name => p, :value => v, :unit => Deltacloud::HardwareProfile::unit(p)} %actions diff --git a/server/views/realms/index.xml.haml b/server/views/realms/index.xml.haml index 03dd3df..e67f282 100644 --- a/server/views/realms/index.xml.haml +++ b/server/views/realms/index.xml.haml @@ -1,9 +1,7 @@ !!!XML %realms - @elements.each do |realm| - %realm{:href => realm_url(realm.id)} - %id< - =realm.id + %realm{:href => realm_url(realm.id), :id => realm.id } %name< =realm.name %state< diff --git a/server/views/realms/show.xml.haml b/server/views/realms/show.xml.haml index 21ab97f..f53c46a 100644 --- a/server/views/realms/show.xml.haml +++ b/server/views/realms/show.xml.haml @@ -1,10 +1,9 @@ !!!XML -%realm{:href => realm_url(@realm.id)} - %id< - =@realm.id +%realm{:href => realm_url(@realm.id), :id => @realm.id } %name< =@realm.name %state< =@realm.state - %limit< - =@realm.limit.eql?(:unlimited) ? '' : @realm.limit + - unless @realm.limit.eql?(:unlimited) + %limit< + =@realm.limit diff --git a/server/views/storage_snapshots/index.xml.haml b/server/views/storage_snapshots/index.xml.haml index 46b362f..4813798 100644 --- a/server/views/storage_snapshots/index.xml.haml +++ b/server/views/storage_snapshots/index.xml.haml @@ -1,11 +1,9 @@ !!!XML %storage_snapshots - @elements.each do |snapshot| - %storage_snapshot{ :href => storage_snapshot_url(snapshot.id)} - %id< - =snapshot.id + %storage_snapshot{ :href => storage_snapshot_url(snapshot.id), :id => snapshot.id } %created< =snapshot.created %state< =snapshot.state - %storage_volume{ :href => storage_volume_url(snapshot.storage_volume_id)} + %storage_volume{ :href => storage_volume_url(snapshot.storage_volume_id), :id => snapshot.storage_volume_id } diff --git a/server/views/storage_snapshots/show.xml.haml b/server/views/storage_snapshots/show.xml.haml index 912f97a..8043d1b 100644 --- a/server/views/storage_snapshots/show.xml.haml +++ b/server/views/storage_snapshots/show.xml.haml @@ -1,9 +1,7 @@ !!!XML -%storage_snapshot{:href => storage_snapshot_url(@storage_snapshot.id)} - %id< - =@storage_snapshot.id +%storage_snapshot{:href => storage_snapshot_url(@storage_snapshot.id), :id => @storage_snapshot.id } %created< =@storage_snapshot.created %state< =@storage_snapshot.state - %storage_volume{:href => storage_volume_url(@storage_snapshot.storage_volume_id)} + %storage_volume{:href => storage_volume_url(@storage_snapshot.storage_volume_id), :id => @storage_snapshot.storage_volume_id} diff --git a/server/views/storage_volumes/index.xml.haml b/server/views/storage_volumes/index.xml.haml index bc55ff4..a96ab61 100644 --- a/server/views/storage_volumes/index.xml.haml +++ b/server/views/storage_volumes/index.xml.haml @@ -1,13 +1,13 @@ !!!XML %storage_volumes - @elements.each do |volume| - %storage_volume{ :href => storage_volume_url(volume.id)} - %id< - =volume.id + %storage_volume{ :href => storage_volume_url(volume.id), :id => volume.id } %created< =volume.created %capacity< =volume.capacity - %device< - =volume.device - %instance{:href => volume.instance_id} + - unless volume.device.nil? + %device< + =volume.device + - unless volume.instance_id.nil? + %instance{:href => instance_url(volume.instance_id), :id => volume.instance_id}
--- server/views/hardware_profiles/show.xml.haml | 3 +-- server/views/storage_volumes/show.xml.haml | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/server/views/hardware_profiles/show.xml.haml b/server/views/hardware_profiles/show.xml.haml index b39d6f0..50f918e 100644 --- a/server/views/hardware_profiles/show.xml.haml +++ b/server/views/hardware_profiles/show.xml.haml @@ -1,7 +1,6 @@ - unless defined?(partial) !!! XML -%hardware_profile{ :href => hardware_profile_url(@profile.name) } - %id= @profile.name +%hardware_profile{ :href => hardware_profile_url(@profile.name), :id => @profile.name } - @profile.each_property do |prop| - attr = { :name => prop.name, :kind => prop.kind, :unit => prop.unit } - if prop.kind == :fixed diff --git a/server/views/storage_volumes/show.xml.haml b/server/views/storage_volumes/show.xml.haml index b6b1088..5ab6748 100644 --- a/server/views/storage_volumes/show.xml.haml +++ b/server/views/storage_volumes/show.xml.haml @@ -10,4 +10,4 @@ =@storage_volume.device %state< =@storage_volume.state - %instance{:href => @storage_volume.instance_id} + %instance{:href => @storage_volume.instance_id, :id => @storage_volume.instance_id}
--- server/lib/deltacloud/drivers/mock/mock_driver.rb | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/server/lib/deltacloud/drivers/mock/mock_driver.rb b/server/lib/deltacloud/drivers/mock/mock_driver.rb index 3096cd6..a81d608 100644 --- a/server/lib/deltacloud/drivers/mock/mock_driver.rb +++ b/server/lib/deltacloud/drivers/mock/mock_driver.rb @@ -75,8 +75,8 @@ class MockDriver < Deltacloud::BaseDriver end
feature :instances, :user_name - feature :images, :brief_listing_mode - feature :instances, :brief_listing_mode + #feature :images, :brief_listing_mode + #feature :instances, :brief_listing_mode
def initialize if ENV["DELTACLOUD_MOCK_STORAGE"]
--- client/lib/dcloud/base_model.rb | 80 ---- client/lib/dcloud/hardware_profile.rb | 124 ------- client/lib/dcloud/image.rb | 56 --- client/lib/dcloud/instance.rb | 142 ------- client/lib/dcloud/realm.rb | 57 --- client/lib/dcloud/state.rb | 30 -- client/lib/dcloud/storage_snapshot.rb | 59 --- client/lib/dcloud/storage_volume.rb | 63 ---- client/lib/dcloud/transition.rb | 35 -- client/lib/deltacloud.rb | 647 ++++++++++++++++----------------- 10 files changed, 321 insertions(+), 972 deletions(-) delete mode 100644 client/lib/dcloud/base_model.rb delete mode 100644 client/lib/dcloud/hardware_profile.rb delete mode 100644 client/lib/dcloud/image.rb delete mode 100644 client/lib/dcloud/instance.rb delete mode 100644 client/lib/dcloud/realm.rb delete mode 100644 client/lib/dcloud/state.rb delete mode 100644 client/lib/dcloud/storage_snapshot.rb delete mode 100644 client/lib/dcloud/storage_volume.rb delete mode 100644 client/lib/dcloud/transition.rb
diff --git a/client/lib/dcloud/base_model.rb b/client/lib/dcloud/base_model.rb deleted file mode 100644 index 0f210a4..0000000 --- a/client/lib/dcloud/base_model.rb +++ /dev/null @@ -1,80 +0,0 @@ -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - -module DCloud - class BaseModel - - def self.xml_tag_name(name=nil) - unless ( name.nil? ) - @xml_tag_name = name - end - @xml_tag_name || self.class.name.downcase.to_sym - end - - - def self.attribute(attr) - build_reader attr - end - - def self.build_reader(attr) - eval " - def #{attr} - check_load_payload - @#{attr} - end - " - end - - attr_reader :uri - - def initialize(client, uri=nil, xml=nil) - @client = client - @uri = uri - @loaded = false - load_payload( xml ) - end - - def id() - check_load_payload - @id - end - - - protected - - attr_reader :client - - def check_load_payload() - return if @loaded - xml = @client.fetch_resource( self.class.xml_tag_name.to_sym, @uri ) - load_payload(xml) - end - - def load_payload(xml=nil) - unless ( xml.nil? ) - @loaded = true - @id = xml.text( 'id' ) - end - end - - def unload - @loaded = false - end - - end -end diff --git a/client/lib/dcloud/hardware_profile.rb b/client/lib/dcloud/hardware_profile.rb deleted file mode 100644 index 02ee303..0000000 --- a/client/lib/dcloud/hardware_profile.rb +++ /dev/null @@ -1,124 +0,0 @@ -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - -require 'dcloud/base_model' - -module DCloud - class HardwareProfile < BaseModel - - class Property - class Range - attr_reader :first, :last - def initialize(element) - if element - @first = element.attributes['first'] - @last = element.attributes['last'] - end - end - def present? - ! @first.nil? - end - end - class Enum - attr_reader :entries - def initialize(element) - @entries = [] - if element - element.get_elements( 'entry' ).each do |entry| - @entries << entry.attributes['value'] - end - end - end - def present? - ! @entries.empty? - end - end - attr_reader :name, :kind, :unit, :value, :range, :enum - - def initialize(xml, name) - @name = name - p = REXML::XPath.first(xml, "property[@name = '#{name}']") - if p - @value = p.attributes['value'] - @unit = p.attributes['unit'] - @kind = p.attributes['kind'] - @range = Range.new(p.get_elements('range')[0]) if @kind=='range' - @enum = Enum.new(p.get_elements('enum')[0]) if @kind=='enum' - end - end - - def present? - ! @value.nil? - end - - # FIXME: how to range/enum/kind bits fit into this? - def to_s - v = @value || "---" - u = @unit || "" - u = "" if ["label", "count"].include?(u) - "#{v} #{u}" - end - end - - class FloatProperty < Property - def initialize(xml, name) - super(xml, name) - @value = @value.to_f if @value - end - end - - class IntegerProperty < Property - def initialize(xml, name) - super(xml, name) - @value = @value.to_i if @value - end - end - - xml_tag_name :hardware_profile - - attribute :memory - attribute :storage - attribute :cpu - attribute :architecture - - def initialize(client, uri, xml=nil) - super( client, uri, xml ) - end - - def load_payload(xml=nil) - super(xml) - unless xml.nil? - @memory = FloatProperty.new(xml, 'memory') - @storage = FloatProperty.new(xml, 'storage') - @cpu = IntegerProperty.new(xml, 'cpu') - @architecture = Property.new(xml, 'architecture') - end - end - - def to_plain - sprintf("%-15s | %-6s | %10s | %10s ", id[0, 15], - architecture.to_s[0,6], memory.to_s[0,10], storage.to_s[0,10]) - end - - private - def property_value(xml, name) - p = REXML::XPath.first(xml, "property[@name = '#{name}']") - p ? p.attributes['value'] : "" - end - end -end diff --git a/client/lib/dcloud/image.rb b/client/lib/dcloud/image.rb deleted file mode 100644 index a44f873..0000000 --- a/client/lib/dcloud/image.rb +++ /dev/null @@ -1,56 +0,0 @@ -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - -require 'dcloud/base_model' - -module DCloud - class Image < BaseModel - - xml_tag_name :image - - attribute :description - attribute :owner_id - attribute :architecture - attribute :name - - def initialize(client, uri, xml=nil) - super( client, uri, xml ) - end - - def load_payload(xml) - super( xml ) - unless xml.nil? - @description = xml.text( 'description' ) - @owner_id = xml.text( 'owner_id' ) - @name = xml.text( 'name' ) - @architecture = xml.text( 'architecture' ) - end - end - - def to_plain - sprintf("%-10s | %-20s | %-6s | %-20s | %15s", - self.id[0,10], - self.name ? self.name[0, 20]: 'unknown', - self.architecture[0,6], - self.description[0,20], - self.owner_id[0,15] - ) - end - - end -end diff --git a/client/lib/dcloud/instance.rb b/client/lib/dcloud/instance.rb deleted file mode 100644 index 4898083..0000000 --- a/client/lib/dcloud/instance.rb +++ /dev/null @@ -1,142 +0,0 @@ -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - -require 'dcloud/base_model' - -module DCloud - - class InstanceProfile - attr_reader :hardware_profile, :id - - def initialize(client, xml) - @hardware_profile = HardwareProfile.new(client, xml.attributes['href']) - @properties = {} - @id = xml.text("id") - xml.get_elements('property').each do |prop| - @properties[prop.attributes['name'].to_sym] = { - :value => prop.attributes['value'], - :unit => prop.attributes['unit'], - :kind => prop.attributes['kind'].to_sym - } - end - end - - def [](prop) - p = @properties[prop] - p ? p[:value] : nil - end - - def property(prop) - @properties[prop] - end - end - - class Instance < BaseModel - - xml_tag_name :instance - - attribute :name - attribute :owner_id - attribute :public_addresses - attribute :private_addresses - attribute :state - attribute :actions - attribute :image - attribute :realm - attribute :action_urls - attribute :instance_profile - - def initialize(client, uri, xml=nil) - @action_urls = {} - super( client, uri, xml ) - end - - def to_plain - sprintf("%-15s | %-15s | %-15s | %10s | %32s | %32s", - self.id ? self.id[0,15] : '-', - self.name ? self.name[0,15] : 'unknown', - self.image.name ? self.image.name[0,15] : 'unknown', - self.state ? self.state.to_s[0,10] : 'unknown', - self.public_addresses.join(',')[0,32], - self.private_addresses.join(',')[0,32] - ) - end - - def start!() - url = action_urls['start'] - throw Exception.new( "Unable to start" ) unless url - client.post_instance( url ) - unload - end - - def reboot!() - url = action_urls['reboot'] - throw Exception.new( "Unable to reboot" ) unless url - client.post_instance( url ) - unload - end - - def stop!() - url = action_urls['stop'] - throw Exception.new( "Unable to stop" ) unless url - client.post_instance( url ) - unload - end - - def destroy!() - url = action_urls['destroy'] - throw Exception.new( "Unable to destroy" ) unless url - client.post_instance( url ) - unload - end - - def load_payload(xml=nil) - super(xml) - unless xml.nil? - @owner_id = xml.text('owner_id') - @name = xml.text('name') - @public_addresses = [] - xml.get_elements( 'public-addresses/address' ).each do |address| - @public_addresses << address.text - end - @private_addresses = [] - xml.get_elements( 'private-addresses/address' ).each do |address| - @private_addresses << address.text - end - image_uri = xml.get_elements( 'image' )[0].attributes['href'] - @image = Image.new( @client, image_uri ) - # Only use realms if they are there - if (!xml.get_elements( 'realm' ).empty?) - realm_uri = xml.get_elements( 'realm' )[0].attributes['href'] - @realm = Realm.new( @client, realm_uri ) - end - instance_profile = xml.get_elements( 'hardware-profile' ).first - @instance_profile = InstanceProfile.new( @client, instance_profile ) - @state = xml.text( 'state' ) - @actions = [] - xml.get_elements( 'actions/link' ).each do |link| - action_name = link.attributes['rel'] - if ( action_name ) - @actions << link.attributes['rel'] - @action_urls[ link.attributes['rel'] ] = link.attributes['href'] - end - end - end - end - end -end diff --git a/client/lib/dcloud/realm.rb b/client/lib/dcloud/realm.rb deleted file mode 100644 index b5ae8ea..0000000 --- a/client/lib/dcloud/realm.rb +++ /dev/null @@ -1,57 +0,0 @@ -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -require 'dcloud/base_model' - -module DCloud - class Realm < BaseModel - - xml_tag_name :realm - - attribute :name - attribute :state - attribute :limit - - def initialize(client, uri, xml=nil) - super( client, uri, xml ) - end - - def load_payload(xml=nil) - super(xml) - unless xml.nil? - @name = xml.text( 'name' ) - @state = xml.text( 'state' ) - @limit = xml.text( 'limit' ) - if ( @limit.nil? || @limit == '' ) - @limit = :unlimited - else - @limit = @limit.to_f - end - end - end - - def to_plain - sprintf("%-10s | %-15s | %-5s | %10s GB", - self.id[0, 10], - self.name[0, 15], - self.state[0,5], - self.limit.to_s[0,10] - ) - end - - end -end diff --git a/client/lib/dcloud/state.rb b/client/lib/dcloud/state.rb deleted file mode 100644 index 131b6d9..0000000 --- a/client/lib/dcloud/state.rb +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -module DCloud - class State - - attr_accessor :name - attr_accessor :transitions - - def initialize(name) - @name = name - @transitions = [] - end - - end -end diff --git a/client/lib/dcloud/storage_snapshot.rb b/client/lib/dcloud/storage_snapshot.rb deleted file mode 100644 index 107f0d7..0000000 --- a/client/lib/dcloud/storage_snapshot.rb +++ /dev/null @@ -1,59 +0,0 @@ -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - -require 'dcloud/base_model' - -module DCloud - class StorageSnapshot < BaseModel - - xml_tag_name :storage_snapshot - - attribute :created - attribute :state - attribute :storage_volume - - def to_plain - sprintf("%-10s | %-15s | %-6s | %15s", - self.id[0,10], - self.storage_volume.name ? self.storage_volume.name[0, 15] : 'unknown', - self.state ? self.state[0,6] : 'unknown', - self.created ? self.created[0,15] : 'unknown' - ) - end - - def initialize(client, uri, xml=nil) - super( client, uri, xml ) - end - - def load_payload(xml=nil) - super(xml) - unless xml.nil? - @created = xml.text( 'created' ) - @state = xml.text( 'state' ) - storage_volumes = xml.get_elements( 'storage-volume' ) - if ( ! storage_volumes.empty? ) - storage_volume = storage_volumes.first - storage_volume_href = storage_volume.attributes['href'] - if ( storage_volume_href ) - @storage_volume = StorageVolume.new( @client, storage_volume_href ) - end - end - end - end - end -end diff --git a/client/lib/dcloud/storage_volume.rb b/client/lib/dcloud/storage_volume.rb deleted file mode 100644 index 7effd2d..0000000 --- a/client/lib/dcloud/storage_volume.rb +++ /dev/null @@ -1,63 +0,0 @@ -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - -require 'dcloud/base_model' - -module DCloud - class StorageVolume < BaseModel - - xml_tag_name :storage_volume - - attribute :created - attribute :state - attribute :capacity - attribute :device - attribute :instance - - def initialize(client, uri, xml=nil) - super( client, uri, xml ) - end - - def to_plain - sprintf("%-10s | %15s GB | %-10s | %-10s | %-15s", - self.id[0,10], - self.capacity ? self.capacity.to_s[0,15] : 'unknown', - self.device ? self.device[0,10] : 'unknown', - self.state ? self.state[0,10] : 'unknown', - self.instance ? self.instance.name[0,15] : 'unknown' - ) - end - - def load_payload(xml=nil) - super(xml) - unless xml.nil? - @created = xml.text( 'created' ) - @state = xml.text( 'state' ) - @capacity = xml.text( 'capacity' ).to_f - @device = xml.text( 'device' ) - instances = xml.get_elements( 'instance' ) - if ( ! instances.empty? ) - instance = instances.first - instance_href = instance.attributes['href'] - if ( instance_href ) - @instance = Instance.new( @client, instance_href ) - end - end - end - end - end -end diff --git a/client/lib/dcloud/transition.rb b/client/lib/dcloud/transition.rb deleted file mode 100644 index cde4598..0000000 --- a/client/lib/dcloud/transition.rb +++ /dev/null @@ -1,35 +0,0 @@ -# -# Copyright (C) 2009 Red Hat, Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General Public -# License along with this library; if not, write to the Free Software -# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - - -module DCloud - class Transition - - attr_accessor :to - attr_accessor :action - - def initialize(to, action) - @to = to - @action = action - end - - def auto?() - @action.nil? - end - - end -end diff --git a/client/lib/deltacloud.rb b/client/lib/deltacloud.rb index 7593a56..25da777 100644 --- a/client/lib/deltacloud.rb +++ b/client/lib/deltacloud.rb @@ -15,404 +15,399 @@ # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+require 'nokogiri' require 'rest_client' -require 'rexml/document' -require 'logger' -require 'dcloud/hardware_profile' -require 'dcloud/realm' -require 'dcloud/image' -require 'dcloud/instance' -require 'dcloud/storage_volume' -require 'dcloud/storage_snapshot' -require 'dcloud/state' -require 'dcloud/transition' require 'base64' +require 'logger'
-class DeltaCloud +module DeltaCloud
- attr_accessor :logger - attr_reader :api_uri - attr_reader :entry_points - attr_reader :driver_name - attr_reader :last_request_xml - attr_reader :features + def self.new(user_name, password, api_url, &block) + API.new(user_name, password, api_url, &block) + end
def self.driver_name(url) - DeltaCloud.new( nil, nil, url) do |client| - return client.driver_name + API.new(nil, nil, url).driver_name + end + + class API + attr_accessor :logger + attr_reader :api_uri, :driver_name, :api_version, :features, :entry_points + + def initialize(user_name, password, api_url, opts={}, &block) + @logger = opts[:verbose] ? Logger.new(STDERR) : [] + @username, @password = user_name, password + @api_uri = URI.parse(api_url) + @entry_points = {} + @verbose = opts[:verbose] || false + @features = {} + discover_entry_points unless discovered? + yield self if block_given? end - end - - def initialize(name, password, api_uri, opts={}, &block) - @logger = Logger.new( STDERR ) - @name = name - @password = password - @api_uri = URI.parse( api_uri ) - @entry_points = {} - @verbose = opts[:verbose] - @features = {} - discover_entry_points - connect( &block ) - self - end - - - def connect(&block) - @http = RestClient::Resource.new( api_uri.to_s , :accept => 'application/xml' ) - discover_entry_points - block.call( self ) if block - self - end
- def api_host - @api_uri.host - end - - def api_port - @api_uri.port - end - - def api_path - @api_uri.path - end - - def feature?(collection, name) - @features.has_key?(collection) && @features[collection].include?(name) - end + def connect(&block) + yield self + end
- def hardware_profiles(opts={}) - hardware_profiles = [] - request(entry_points[:hardware_profiles], :get, opts) do |response| - doc = REXML::Document.new( response ) - doc.get_elements( 'hardware-profiles/hardware-profile' ).each do |hwp| - uri = hwp.attributes['href'] - hardware_profiles << DCloud::HardwareProfile.new( self, uri, hwp ) + # Define API URL fragment methods + [:host, :port, :path].each do |item| + define_method :"api_#{item}" do + @api_uri.send(item) end end - hardware_profiles - end
- def hardware_profile(id) - request( entry_points[:hardware_profiles], :get, {:id=>id } ) do |response| - doc = REXML::Document.new( response ) - doc.get_elements( '/hardware-profile' ).each do |hwp| - uri = hwp.attributes['href'] - return DCloud::HardwareProfile.new( self, uri, hwp ) + # Define methods based on 'rel' attribute in entry point + # Two methods are declared: 'images' and 'image' + def declare_entry_points_methods(entry_points) + logger = @logger + API.instance_eval do + entry_points.keys.select {|k| [:instance_states].include?(k)==false }.each do |model| + define_method model do |*args| + request(:get, "/#{model}", args.first) do |response| + # Define a new class based on model name + c = Kernel.define_class("#{model.to_s.classify}") + # Create collection from index operation + base_object_collection(c, model, response) + end + end + logger << "[API] Added method #{model}\n" + define_method :"#{model.to_s.singularize}" do |*args| + request(:get, "/#{model}/#{args[0]}") do |response| + # Define a new class based on model name + c = Kernel.define_class("#{model.to_s.classify}") + # Build class for returned object + base_object(c, model, response) + end + end + logger << "[API] Added method #{model.to_s.singularize}\n" + define_method :"fetch_#{model.to_s.singularize}" do |url| + id = url.grep(//#{model}/(.*)$/) + self.send(model.to_s.singularize.to_sym, $1) + end + end end end - end
- def fetch_hardware_profile(uri) - xml = fetch_resource( :hardware_profile, uri ) - return DCloud::HardwareProfile.new( self, uri, xml ) if xml - nil - end + def base_object_collection(c, model, response) + collection = [] + Nokogiri::XML(response).xpath("#{model}/#{model.to_s.singularize}").each do |item| + c.instance_eval do + attr_accessor :id + attr_accessor :uri + end + collection << xml_to_class(c, item) + end + return collection + end
- def fetch_resource(type, uri) - request( uri ) do |response| - doc = REXML::Document.new( response ) - if ( doc.root && ( doc.root.name == type.to_s.gsub( /_/, '-' ) ) ) - return doc.root + # Add default attributes [id and href] to class + def base_object(c, model, response) + obj = nil + Nokogiri::XML(response).xpath("#{model.to_s.singularize}").each do |item| + c.instance_eval do + attr_accessor :id + attr_accessor :uri + end + obj = xml_to_class(c, item) end + return obj end - nil - end
- def fetch_documentation(collection, operation=nil) - response = @http["docs/#{collection}#{operation ? "/#{operation}" : ''}"].get(:accept => "application/xml") - doc = REXML::Document.new( response.to_s ) - if operation.nil? - docs = { - :name => doc.get_elements('docs/collection').first.attributes['name'], - :description => doc.get_elements('docs/collection/description').first.text, - :operations => [] - } - doc.get_elements('docs/collection/operations/operation').each do |operation| - p = {} - p[:name] = operation.attributes['name'] - p[:description] = operation.get_elements('description').first.text - p[:parameters] = [] - operation.get_elements('parameter').each do |param| - p[:parameters] << param.attributes['name'] + # Convert XML response to defined Ruby Class + def xml_to_class(c, item) + obj = c.new + # Set default attributes + obj.id = item['id'] + api = self + c.instance_eval do + define_method :client do + api end - docs[:operations] << p end - else - docs = { - :name => doc.get_elements('docs/operation').attributes['name'], - :description => doc.get_elements('docs/operation/description').first.text, - :parameters => [] - } - doc.get_elements('docs/operation/parameter').each do |param| - docs[:parameters] << param.attributes['name'] + obj.uri = item['href'] + logger = @logger + logger << "[DC] Creating class #{obj.class.name}\n" + obj.instance_eval do + # Declare methods for all attributes in object + item.xpath('./*').each do |attribute| + # If attribute is a link to another object then + # create a method which request this object from API + if api.entry_points.keys.include?(:"#{attribute.name}s") + c.instance_eval do + define_method :"#{attribute.name}" do + client.send(:"#{attribute.name}", attribute['id'] ) + end + logger << "[DC] Added #{attribute.name} to class #{obj.class.name}\n" + end + else + # Define methods for other attributes + c.instance_eval do + case attribute.name + # When response cointains 'link' block, declare + # methods to call links inside. This is used for instance + # to dynamicaly create .stop!, .start! methods + when "actions": + actions = [] + attribute.xpath('link').each do |link| + actions << [link['rel'], link[:href]] + define_method :"#{link['rel']}!" do + client.request(:"#{link['method']}", link['href'], {}, {}) + client.send(:"#{item.name}", item['id']) + end + end + define_method :actions do + actions.collect { |a| a.first } + end + define_method :actions_urls do + urls = {} + actions.each { |a| urls[a.first] = a.last } + urls + end + # Property attribute is handled differently + when "property": + define_method :"#{attribute['name']}" do + if attribute['value'] =~ /^(\d+)$/ + DeltaCloud::HWP::FloatProperty.new(attribute, attribute['name']) + else + DeltaCloud::HWP::Property.new(attribute, attribute['name']) + end + end + # Public and private addresses are returned as Array + when "public_addresses", "private_addresses": + define_method :"#{attribute.name}" do + attribute.xpath('address').collect { |address| address.text } + end + # Value for other attributes are just returned using + # method with same name as attribute (eg. .owner_id, .state) + else + define_method :"#{attribute.name}" do + attribute.text.convert + end + logger << "[DC] Added method #{attribute.name} to #{obj.class.name}\n" + end + end + end + end end + return obj end - docs - end
- def instance_states - states = [] - request( entry_points[:instance_states] ) do |response| - doc = REXML::Document.new( response ) - doc.get_elements( 'states/state' ).each do |state_elem| - state = DCloud::State.new( state_elem.attributes['name'] ) - state_elem.get_elements( 'transition' ).each do |transition_elem| - state.transitions << DCloud::Transition.new( - transition_elem.attributes['to'], - transition_elem.attributes['action'] - ) + # Get /api and parse entry points + def discover_entry_points + return if discovered? + request(:get, @api_uri.to_s) do |response| + api_xml = Nokogiri::XML(response) + @driver_name = api_xml.xpath('/api').first['driver'] + @api_version = api_xml.xpath('/api').first['version'] + logger << "[API] Version #{@api_version}\n" + logger << "[API] Driver #{@driver_name}\n" + api_xml.css("api > link").each do |entry_point| + rel, href = entry_point['rel'].to_sym, entry_point['href'] + @entry_points.store(rel, href) + logger << "[API] Entry point '#{rel}' added\n" + entry_point.css("feature").each do |feature| + @features[rel] ||= [] + @features[rel] << feature['name'].to_sym + logger << "[API] Feature #{feature['name']} added to #{rel}\n" + end end - states << state end + declare_entry_points_methods(@entry_points) end - states - end
- def instance_state(name) - found = instance_states.find{|e| e.name.to_s == name.to_s} - found - end - - def realms(opts={}) - realms = [] - request( entry_points[:realms], :get, opts ) do |response| - doc = REXML::Document.new( response ) - doc.get_elements( 'realms/realm' ).each do |realm| - uri = realm.attributes['href'] - realms << DCloud::Realm.new( self, uri, realm ) - end + # Skip parsing /api when we already got entry points + def discovered? + true if @entry_points!={} end - realms - end
- def realm(id) - request( entry_points[:realms], :get, {:id=>id } ) do |response| - doc = REXML::Document.new( response ) - doc.get_elements( 'realm' ).each do |realm| - uri = realm.attributes['href'] - return DCloud::Realm.new( self, uri, realm ) + # Create a new instance, using image +image_id+. Possible optiosn are + # + # name - a user-defined name for the instance + # realm - a specific realm for placement of the instance + # hardware_profile - either a string giving the name of the + # hardware profile or a hash. The hash must have an + # entry +id+, giving the id of the hardware profile, + # and may contain additional names of properties, + # e.g. 'storage', to override entries in the + # hardware profile + def create_instance(image_id, opts={}, &block) + name = opts[:name] + realm_id = opts[:realm] + + params = {} + ( params[:realm_id] = realm_id ) if realm_id + ( params[:name] = name ) if name + + if opts[:hardware_profile].is_a?(String) + params[:hwp_id] = opts[:hardware_profile] + elsif opts[:hardware_profile].is_a?(Hash) + opts[:hardware_profile].each do |k,v| + params[:"hwp_#{k}"] = v + end end - end - nil - end
- def fetch_realm(uri) - xml = fetch_resource( :realm, uri ) - return DCloud::Realm.new( self, uri, xml ) if xml - nil - end + params[:image_id] = image_id + instance = nil
- def images(opts={}) - images = [] - request_path = entry_points[:images] - request( request_path, :get, opts ) do |response| - doc = REXML::Document.new( response ) - doc.get_elements( 'images/image' ).each do |image| - uri = image.attributes['href'] - images << DCloud::Image.new( self, uri, image ) + request(:post, entry_points[:instances], {}, params) do |response| + c = Kernel.define_class("Instance") + instance = base_object(c, :instance, response) + yield instance if block_given? end + + return instance end - images - end
- def image(id) - request( entry_points[:images], :get, {:id=>id } ) do |response| - doc = REXML::Document.new( response ) - doc.get_elements( 'image' ).each do |instance| - uri = instance.attributes['href'] - return DCloud::Image.new( self, uri, instance ) - end + def feature?(collection, name) + @feature.has_key?(collection) && @feature[collection].include?(name) end - nil - end
- def instances(opts={}) - instances = [] - request( entry_points[:instances], :get, opts ) do |response| - doc = REXML::Document.new( response ) - doc.get_elements( 'instances/instance' ).each do |instance| - uri = instance.attributes['href'] - instances << DCloud::Instance.new( self, uri, instance ) + def instance_states + states = [] + request(:get, entry_points[:instance_states]) do |response| + Nokogiri::XML(response).xpath('states/state').each do |state_el| + state = DeltaCloud::InstanceState::State.new(state_el['name']) + state_el.xpath('transition').each do |transition_el| + state.transitions << DeltaCloud::InstanceState::Transition.new( + transition_el['to'], + transition_el['action'] + ) + end + states << state + end end + states end - instances - end
- def instance(id) - request( entry_points[:instances], :get, {:id=>id } ) do |response| - doc = REXML::Document.new( response ) - doc.get_elements( 'instance' ).each do |instance| - uri = instance.attributes['href'] - return DCloud::Instance.new( self, uri, instance ) + def instance_state(name) + instance_states.select { |s| s.name.to_s.eql?(name.to_s) }.first + end + + # Basic request method + # Usage: + # => request(:get, '/api/images', { :architecture => 'i386' }) + # => request(:get, '/api/images', { :architecture => 'i386' }) + # + def request(*args, &block) + conf = { + :method => (args[0] || 'get').to_sym, + :path => (args[1]=~/^http/) ? args[1] : "#{api_uri.to_s}#{args[1]}", + :query_args => args[2] || {}, + :form_data => args[3] || {} + } + if conf[:query_args] != {} + conf[:path] += '?' + URI.escape(conf[:query_args].collect{ |key, value| "#{key}=#{value}" }.join('&')).to_s + end + logger << "[#{conf[:method].to_s.upcase}] #{conf[:path]}\n" + if conf[:method].eql?(:post) + RestClient.send(:post, conf[:path], conf[:form_data], default_headers) do |response| + yield response.body if block_given? + end + else + RestClient.send(conf[:method], conf[:path], default_headers) do |response| + yield response.body if block_given? + end end end - nil - end
- def post_instance(uri) - request( uri, :post ) do |response| - return true + private + + def default_headers + { + :authorization => "Basic "+Base64.encode64("#{@username}:#{@password}"), + :accept => "application/xml" + } end - return false - end
- def fetch_instance(uri) - xml = fetch_resource( :instance, uri ) - return DCloud::Instance.new( self, uri, xml ) if xml - nil end
- # Create a new instance, using image +image_id+. Possible optiosn are - # - # name - a user-defined name for the instance - # realm - a specific realm for placement of the instance - # hardware_profile - either a string giving the name of the - # hardware profile or a hash. The hash must have an - # entry +id+, giving the id of the hardware profile, - # and may contain additional names of properties, - # e.g. 'storage', to override entries in the - # hardware profile - def create_instance(image_id, opts={}) - name = opts[:name] - realm_id = opts[:realm] - - params = {} - ( params[:realm_id] = realm_id ) if realm_id - ( params[:name] = name ) if name - - if opts[:hardware_profile].is_a?(String) - params[:hwp_id] = opts[:hardware_profile] - elsif opts[:hardware_profile].is_a?(Hash) - opts[:hardware_profile].each do |k,v| - params[:"hwp_#{k}"] = v + module InstanceState + class State + attr_reader :name + attr_reader :transitions + + def initialize(name) + @name, @transitions = name, [] end end + class Transition + attr_reader :to + attr_reader :action
- params[:image_id] = image_id - request( entry_points[:instances], :post, {}, params ) do |response| - doc = REXML::Document.new( response ) - instance = doc.root - uri = instance.attributes['href'] - return DCloud::Instance.new( self, uri, instance ) - end - end + def initialize(to, action) + @to = to + @action = action + end
- def storage_volumes(opts={}) - storage_volumes = [] - request( entry_points[:storage_volumes] ) do |response| - doc = REXML::Document.new( response ) - doc.get_elements( 'storage-volumes/storage-volume' ).each do |instance| - uri = instance.attributes['href'] - storage_volumes << DCloud::StorageVolume.new( self, uri, instance ) + def auto? + @action.nil? end end - storage_volumes end
- def storage_volume(id) - request( entry_points[:storage_volumes], :get, {:id=>id } ) do |response| - doc = REXML::Document.new( response ) - doc.get_elements( 'storage-volume' ).each do |storage_volume| - uri = storage_volume.attributes['href'] - return DCloud::StorageVolume.new( self, uri, storage_volume ) + module HWP + class Property + attr_reader :name, :unit, :value, :kind + + def initialize(xml, name) + @kind, @value, @unit = xml['kind'].to_sym, xml['value'], xml['unit'] + declare_ranges(xml) + self end - end - nil - end
- def fetch_storage_volume(uri) - xml = fetch_resource( :storage_volume, uri ) - return DCloud::StorageVolume.new( self, uri, xml ) if xml - nil - end + def declare_ranges(xml) + case xml['kind'] + when 'range': + self.class.instance_eval do + attr_reader :range + end + @range = { :from => xml.xpath('range').first['first'], :to => xml.xpath('range').first['last'] } + when 'enum': + self.class.instance_eval do + attr_reader :options + end + @options = xml.xpath('enum/entry').collect { |e| e['value'] } + end + end
- def storage_snapshots(opts={}) - storage_snapshots = [] - request( entry_points[:storage_snapshots] ) do |response| - doc = REXML::Document.new( response ) - doc.get_elements( 'storage-snapshots/storage-snapshot' ).each do |instance| - uri = instance.attributes['href'] - storage_snapshots << DCloud::StorageSnapshot.new( self, uri, instance ) + def present? + ! @value.nil? end end - storage_snapshots - end
- def storage_snapshot(id) - request( entry_points[:storage_snapshots], :get, {:id=>id } ) do |response| - doc = REXML::Document.new( response ) - doc.get_elements( 'storage-snapshot' ).each do |storage_snapshot| - uri = storage_snapshot.attributes['href'] - return DCloud::StorageSnapshot.new( self, uri, storage_snapshot ) + class FloatProperty < Property + def initialize(xml, name) + super(xml, name) + @value = @value.to_f if @value end end - nil end
- def fetch_storage_snapshot(uri) - xml = fetch_resource( :storage_snapshot, uri ) - return DCloud::StorageSnapshot.new( self, uri, xml ) if xml - nil +end + +class String + def classify + self.singularize.camelize end
- def fetch_image(uri) - xml = fetch_resource( :image, uri ) - return DCloud::Image.new( self, uri, xml ) if xml - nil + def camelize + self.to_s.gsub(//(.?)/) { "::#{$1.upcase}" }.gsub(/(?:^|_)(.)/) { $1.upcase } end
- private - - attr_reader :http - - def discover_entry_points - return if @discovered - request(api_uri.to_s) do |response| - doc = REXML::Document.new( response ) - @driver_name = doc.root.attributes['driver'] - doc.get_elements( 'api/link' ).each do |link| - rel = link.attributes['rel'].to_sym - uri = link.attributes['href'] - @entry_points[rel] = uri - @features[rel] ||= [] - link.get_elements('feature').each do |feature| - @features[rel] << feature.attributes['name'].to_sym - end - end - end - @discovered = true + def singularize + self.gsub(/s$/, '') end
- def request(path='', method=:get, query_args={}, form_data={}, &block) - if ( path =~ /^http/ ) - request_path = path - else - request_path = "#{api_uri.to_s}#{path}" - end - if query_args[:id] - request_path += "/#{query_args[:id]}" - query_args.delete(:id) - end - query_string = URI.escape(query_args.collect{|k,v| "#{k}=#{v}"}.join('&')) - request_path += "?#{query_string}" unless query_string=='' - headers = { - :authorization => "Basic "+Base64.encode64("#{@name}:#{@password}"), - :accept => "application/xml" - } - - logger << "Request [#{method.to_s.upcase}] #{request_path}]\n" if @verbose - - if method.eql?(:get) - RestClient.send(method, request_path, headers) do |response| - @last_request_xml = response - yield response.to_s - end - else - RestClient.send(method, request_path, form_data, headers) do |response| - @last_request_xml = response - yield response.to_s - end - end + def convert + return self.to_f if self.strip =~ /^([\d.]+$)/ + self end
end + +module Kernel + # Get defined class or declare a new one, when class was not declared before + def define_class(name) + DeltaCloud.const_get(name) rescue DeltaCloud.const_set(name, Class.new) + end +end
--- client/specs/instances_spec.rb | 26 ++++++++++++-------------- client/specs/realms_spec.rb | 2 -- client/specs/storage_volume_spec.rb | 8 ++++---- 3 files changed, 16 insertions(+), 20 deletions(-)
diff --git a/client/specs/instances_spec.rb b/client/specs/instances_spec.rb index 2e90e99..2f5032a 100644 --- a/client/specs/instances_spec.rb +++ b/client/specs/instances_spec.rb @@ -32,9 +32,7 @@ describe "instances" do instance.owner_id.should_not be_nil instance.owner_id.should be_a( String ) instance.image.should_not be_nil - instance.image.should be_a( DCloud::Image ) - instance.instance_profile.should_not be_nil - instance.instance_profile.should be_a( DCloud::InstanceProfile ) + instance.hardware_profile.should_not be_nil instance.state.should_not be_nil instance.state.should be_a( String ) instance.public_addresses.should_not be_nil @@ -70,11 +68,11 @@ describe "instances" do instance.public_addresses.first.should eql( "img1.inst0.public.com" ) instance.image.should_not be_nil instance.image.uri.should eql( API_URL + "/images/img1" ) - instance.instance_profile.should_not be_nil - instance.instance_profile.hardware_profile.should_not be_nil - instance.instance_profile.hardware_profile.uri.should eql( API_URL + "/hardware_profiles/m1-large" ) - instance.instance_profile[:memory].should eql( "12288" ) - instance.instance_profile[:storage].should be_nil + instance.hardware_profile.should_not be_nil + instance.hardware_profile.should_not be_nil + instance.hardware_profile.uri.should eql( API_URL + "/hardware_profiles/m1-large" ) + instance.hardware_profile.memory.value.should eql(10240.0) + instance.hardware_profile.storage.value.should eql(850.0) instance.state.should eql( "RUNNING" ) instance.actions.should_not be_nil end @@ -88,7 +86,7 @@ describe "instances" do instance.id.should match( /inst[0-9]+/ ) instance.name.should eql( 'TestInstance' ) instance.image.id.should eql( 'img1' ) - instance.instance_profile.id.should eql( 'm1-large' ) + instance.hardware_profile.id.should eql( 'm1-large' ) instance.realm.id.should eql( 'us' ) end end @@ -100,7 +98,7 @@ describe "instances" do instance.uri.should match( %r{#{API_URL}/instances/inst[0-9]+} ) instance.id.should match( /inst[0-9]+/ ) instance.image.id.should eql( 'img1' ) - instance.instance_profile.id.should eql( 'm1-large' ) + instance.hardware_profile.id.should eql( 'm1-large' ) instance.realm.id.should eql( 'eu' ) end end @@ -113,7 +111,7 @@ describe "instances" do instance.uri.should match( %r{#{API_URL}/instances/inst[0-9]+} ) instance.id.should match( /inst[0-9]+/ ) instance.image.id.should eql( 'img1' ) - instance.instance_profile.id.should eql( 'm1-xlarge' ) + instance.hardware_profile.id.should eql( 'm1-xlarge' ) instance.realm.id.should eql( 'us' ) end end @@ -126,8 +124,8 @@ describe "instances" do instance.uri.should match( %r{#{API_URL}/instances/inst[0-9]+} ) instance.id.should match( /inst[0-9]+/ ) instance.image.id.should eql( 'img1' ) - instance.instance_profile.id.should eql( 'm1-xlarge' ) - instance.instance_profile[:memory].should eql( "32768" ) + instance.hardware_profile.id.should eql( 'm1-xlarge' ) + instance.hardware_profile.memory.value.should eql(12288.0) instance.realm.id.should eql( 'us' ) end end @@ -140,7 +138,7 @@ describe "instances" do instance.uri.should match( %r{#{API_URL}/instances/inst[0-9]+} ) instance.id.should match( /inst[0-9]+/ ) instance.image.id.should eql( 'img1' ) - instance.instance_profile.id.should eql( 'm1-xlarge' ) + instance.hardware_profile.id.should eql( 'm1-xlarge' ) instance.realm.id.should eql( 'eu' ) end end diff --git a/client/specs/realms_spec.rb b/client/specs/realms_spec.rb index 6f5199f..bd3ec24 100644 --- a/client/specs/realms_spec.rb +++ b/client/specs/realms_spec.rb @@ -44,13 +44,11 @@ describe "realms" do realm.id.should eql( 'us' ) realm.name.should eql( 'United States' ) realm.state.should eql( 'AVAILABLE' ) - realm.limit.should eql( :unlimited ) realm = client.realm( 'eu' ) realm.should_not be_nil realm.id.should eql( 'eu' ) realm.name.should eql( 'Europe' ) realm.state.should eql( 'AVAILABLE' ) - realm.limit.should eql( :unlimited ) end end
diff --git a/client/specs/storage_volume_spec.rb b/client/specs/storage_volume_spec.rb index ff461d7..fe66f8e 100644 --- a/client/specs/storage_volume_spec.rb +++ b/client/specs/storage_volume_spec.rb @@ -46,8 +46,8 @@ describe "storage volumes" do storage_volume.device.should eql( '/dev/sda1' ) storage_volume.instance.should_not be_nil storage_volume.instance.id.should eql( 'inst1' ) - ip = storage_volume.instance.instance_profile - ip.hardware_profile.architecture.value.should eql( 'i386' ) + ip = storage_volume.instance.hardware_profile + ip.architecture.value.should eql( 'i386' ) end end
@@ -63,8 +63,8 @@ describe "storage volumes" do storage_volume.device.should eql( '/dev/sda1' ) storage_volume.instance.should_not be_nil storage_volume.instance.id.should eql( 'inst1' ) - ip = storage_volume.instance.instance_profile - ip.hardware_profile.architecture.value.should eql( 'i386' ) + ip = storage_volume.instance.hardware_profile + ip.architecture.value.should eql( 'i386' ) end end
ack
the brief listing stuff is very very cool... solves the timeouts with image listing in terremark. I didn't test the Client stuff but all 7 applied cleanly and build/work fine.
Why do you remove the feature from mock driver in patch 5/7? Also, sorry if this is obvious, but how do we check from within the driver methods (e.g. in 'def images') if a feature is enabled? I want to put a conditional in terremark for brief_listing or full_listing.
marios
On 03/06/10 11:37, mfojtik@redhat.com wrote:
Hi,
I added few more patches to go:
4/7: Fixed missing ID elements in storage_volumes and hardware_profiles 5/7: Added comments to feature for brief listing. I want to keep these features commented here just for testing in future. 6/7: This will be a little bit longer patch :) I removed old client completely and rewrote it from scratch. I used some meta magic to get auto-generated classes and methods. This approach will allow us to add a new elements/attribute in future to API and 'client' library will update itself. Also REXML was removed completely and replaced by faster Nokogiri. Just one small thing is still missing here. I don't have '.to_plain' methods implemented yet, so command line client will not work... (Need +1 day ;) 7/7: As a bonus, *all* RSpec tests now pass nicely.
There are +2 incompatibilities:
instance.instance_profile => instance.hardware_profile realm.limit => NoMethod exception (when no limit is set for realm)
-- Michal
PS: Apply this patch to latest 'master'.
deltacloud-devel mailing list deltacloud-devel@lists.fedorahosted.org https://fedorahosted.org/mailman/listinfo/deltacloud-devel
On 04/06/10 20:55 +0100, marios@redhat.com wrote:
ack
the brief listing stuff is very very cool... solves the timeouts with image listing in terremark. I didn't test the Client stuff but all 7 applied cleanly and build/work fine.
Why do you remove the feature from mock driver in patch 5/7? Also,
I remove that, because it unfortunatelly breaks Cucumber tests ;-) But your are right, I should include this feature and also update cucumber.
sorry if this is obvious, but how do we check from within the driver methods (e.g. in 'def images') if a feature is enabled? I want to put a conditional in terremark for brief_listing or full_listing.
Good question actually. We have a helper method for that in application_helper.rb:
def driver_has_feature?(feature_name) not driver.features(:instances).select{ |f| f.name.eql?(feature_name) }.empty? end
As you can see, this helper should test if instance have some feature. I modified this slightly to:
def driver_has_feature?(feature_name, default_collection = :instances) not driver.features(default_collection).select{ |f| f.name.eql?(feature_name) }.empty? end
So now you can check, if some feature is available for a specific collection (eg. :images in your case). Modification should be included in this patchset. It should be accessible from inside driver, but I didn't test that yet.
-- Michal
On 03/06/10 11:37, mfojtik@redhat.com wrote:
Hi,
I added few more patches to go:
4/7: Fixed missing ID elements in storage_volumes and hardware_profiles 5/7: Added comments to feature for brief listing. I want to keep these features commented here just for testing in future. 6/7: This will be a little bit longer patch :) I removed old client completely and rewrote it from scratch. I used some meta magic to get auto-generated classes and methods. This approach will allow us to add a new elements/attribute in future to API and 'client' library will update itself. Also REXML was removed completely and replaced by faster Nokogiri. Just one small thing is still missing here. I don't have '.to_plain' methods implemented yet, so command line client will not work... (Need +1 day ;) 7/7: As a bonus, *all* RSpec tests now pass nicely.
There are +2 incompatibilities:
instance.instance_profile => instance.hardware_profile realm.limit => NoMethod exception (when no limit is set for realm)
-- Michal
PS: Apply this patch to latest 'master'.
deltacloud-devel mailing list deltacloud-devel@lists.fedorahosted.org https://fedorahosted.org/mailman/listinfo/deltacloud-devel
Hi,
First additional patch. I added new validation option for parameters in Rabbit. Now you can define param rule in this way:
param :name, :string, :required, { :format => /(\w{20})/}
etc...
I hope it will be usefull. (eg. for GoGrid name limit)
-- Michal
--- server/lib/deltacloud/validation.rb | 13 ++++++++++--- 1 files changed, 10 insertions(+), 3 deletions(-)
diff --git a/server/lib/deltacloud/validation.rb b/server/lib/deltacloud/validation.rb index b4eb3ae..b26a52d 100644 --- a/server/lib/deltacloud/validation.rb +++ b/server/lib/deltacloud/validation.rb @@ -61,9 +61,16 @@ module Deltacloud::Validation if p.required? and not values[p.name] raise Failure.new(p, "Required parameter #{p.name} not found") end - if values[p.name] and not p.options.empty? and - not p.options.include?(values[p.name]) - raise Failure.new(p, "Parameter #{p.name} has value #{values[p.name]} which is not in #{p.options.join(", ")}") + if values[p.name] and not p.options.empty? + if p.options.class == Hash + if p.options[:format] + if values[p.name].match(Regexp.new(p.options[:format])).nil? + raise Failure.new(p, "Parameter #{p.name} has invalid format (#{p.options[:format].inspect})") + end + end + elsif p.options.class == Array + raise Failure.new(p, "Parameter #{p.name} has value #{values[p.name]} which is not in #{p.options.join(',')}") unless p.options.include?(values[p.name]) + end end end end
Hi,
Last one is just cosmetic. I removed 'exception' when you request for something which doesn't exists.
-- Michal
--- server/server.rb | 2 ++ 1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/server/server.rb b/server/server.rb index b5bdfac..feffd45 100644 --- a/server/server.rb +++ b/server/server.rb @@ -56,6 +56,7 @@ end
def show(model) @element = driver.send(model, credentials, { :id => params[:id]} ) + not_found if @element.nil? instance_variable_set("@#{model}", @element) respond_to do |format| format.html { haml :"#{model.to_s.pluralize}/show" } @@ -198,6 +199,7 @@ end
def instance_action(name) @instance = driver.send(:"#{name}_instance", credentials, params["id"]) + return not_found if @instance.nil?
return redirect(instances_url) if name.eql?(:destroy) or @instance.class!=Instance
-- 1.7.1
deltacloud-devel@lists.fedorahosted.org