You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@deltacloud.apache.org by mf...@redhat.com on 2012/04/17 15:39:50 UTC
[PATCH core 11/32] Core: Moved base_driver and exception handling API to drivers directory
From: Michal Fojtik <mf...@redhat.com>
Signed-off-by: Michal fojtik <mf...@redhat.com>
---
server/lib/deltacloud/base_driver/base_driver.rb | 250 --------------------
server/lib/deltacloud/base_driver/exceptions.rb | 191 ---------------
server/lib/deltacloud/base_driver/features.rb | 276 ----------------------
server/lib/deltacloud/drivers/base_driver.rb | 265 +++++++++++++++++++++
server/lib/deltacloud/drivers/exceptions.rb | 191 +++++++++++++++
5 files changed, 456 insertions(+), 717 deletions(-)
delete mode 100644 server/lib/deltacloud/base_driver/base_driver.rb
delete mode 100644 server/lib/deltacloud/base_driver/exceptions.rb
delete mode 100644 server/lib/deltacloud/base_driver/features.rb
create mode 100644 server/lib/deltacloud/drivers/base_driver.rb
create mode 100644 server/lib/deltacloud/drivers/exceptions.rb
diff --git a/server/lib/deltacloud/base_driver/base_driver.rb b/server/lib/deltacloud/base_driver/base_driver.rb
deleted file mode 100644
index 01dd5e7..0000000
--- a/server/lib/deltacloud/base_driver/base_driver.rb
+++ /dev/null
@@ -1,250 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership. The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'deltacloud/base_driver/exceptions'
-
-module Deltacloud
-
- class BaseDriver
-
- include ExceptionHandler
-
- STATE_MACHINE_OPTS = {
- :all_states => [:start, :pending, :running, :stopping, :stopped, :finish],
- :all_actions => [:create, :reboot, :stop, :start, :destroy]
- }
-
- def name
- self.class.name.split('::').last.gsub('Driver', '').downcase
- end
-
- def self.exceptions(&block)
- ExceptionHandler::exceptions(&block)
- end
-
- def self.define_hardware_profile(name,&block)
- @hardware_profiles ||= []
- hw_profile = @hardware_profiles.find{|e| e.name == name}
- return if hw_profile
- hw_profile = ::Deltacloud::HardwareProfile.new( name, &block )
- @hardware_profiles << hw_profile
- hw_params = hw_profile.params
- unless hw_params.empty?
- feature :instances, :hardware_profiles do
- decl.operation(:create) { add_params(hw_params) }
- end
- end
- end
-
- def self.hardware_profiles
- @hardware_profiles ||= []
- @hardware_profiles
- end
-
- def hardware_profiles(credentials, opts = nil)
- results = self.class.hardware_profiles
- filter_hardware_profiles(results, opts)
- end
-
- def hardware_profile(credentials, name)
- hardware_profiles(credentials, :id => name).first
- end
-
- def filter_hardware_profiles(profiles, opts)
- if opts
- if v = opts[:architecture]
- profiles = profiles.select { |hwp| hwp.include?(:architecture, v) }
- end
- # As a request param, we call 'name' 'id'
- if v = opts[:id]
- profiles = profiles.select { |hwp| hwp.name == v }
- end
- end
- profiles
- end
-
- def find_hardware_profile(credentials, name, image_id)
- hwp = nil
- if name
- unless hwp = hardware_profiles(credentials, :id => name).first
- raise BackendError.new(400, "bad-hardware-profile-name",
- "Hardware profile '#{name}' does not exist", nil)
- end
- else
- unless image = image(credentials, :id=>image_id)
- raise BackendError.new(400, "bad-image-id",
- "Image with ID '#{image_id}' does not exist", nil)
- end
- hwp = hardware_profiles(credentials,
- :architecture=>image.architecture).first
- end
- return hwp
- end
-
- def self.define_instance_states(&block)
- machine = ::Deltacloud::StateMachine.new(STATE_MACHINE_OPTS, &block)
- @instance_state_machine = machine
- end
-
- def self.instance_state_machine
- @instance_state_machine
- end
-
- def instance_state_machine
- self.class.instance_state_machine
- end
-
- def instance_actions_for(state)
- actions = []
- state_key = state.downcase.to_sym
- states = instance_state_machine.states()
- current_state = states.find{|e| e.name == state.underscore.to_sym }
- if ( current_state )
- actions = current_state.transitions.collect{|e|e.action}
- actions.reject!{|e| e.nil?}
- end
- actions
- end
-
- ## Capabilities
- # The rabbit dsl supports declaring a capability that is required
- # in the backend driver for the call to succeed. A driver can
- # provide a capability by implementing the method with the same
- # name as the capability. Below is a list of the capabilities as
- # the expected method signatures.
- #
- # Following the capability list are the resource member show
- # methods. They each require that the corresponding collection
- # method be defined
- #
- # TODO: standardize all of these to the same signature (credentials, opts)
- #
- # def realms(credentials, opts=nil)
- #
- # def images(credentials, ops)
- #
- # def instances(credentials, ops)
- # def create_instance(credentials, image_id, opts)
- # def start_instance(credentials, id)
- # def stop_instance(credentials, id)
- # def reboot_instance(credentials, id)
- #
- # def storage_volumes(credentials, ops)
- #
- # def storage_snapshots(credentials, ops)
- #
- # def buckets(credentials, opts = nil)
- # def create_bucket(credentials, name, opts=nil)
- # def delete_bucket(credentials, name, opts=nil)
- #
- # def blobs(credentials, opts = nil)
- # def blob_data(credentials, bucket_id, blob_id, opts)
- # def create_blob(credentials, bucket_id, blob_id, blob_data, opts=nil)
- # def delete_blob(credentials, bucket_id, blob_id, opts=nil)
- #
- # def keys(credentials, opts)
- # def create_key(credentials, opts)
- # def destroy_key(credentials, opts)
- #
- # def firewalls(credentials, opts)
- # def create_firewall(credentials, opts)
- # def delete_firewall(credentials, opts)
- # def create_firewall_rule(credentials, opts)
- # def delete_firewall_rule(credentials, opts)
- # def providers(credentials)
- def realm(credentials, opts)
- realms = realms(credentials, opts).first if has_capability?(:realms)
- end
-
- def image(credentials, opts)
- images(credentials, opts).first if has_capability?(:images)
- end
-
- def instance(credentials, opts)
- instances(credentials, opts).first if has_capability?(:instances)
- end
-
- def storage_volume(credentials, opts)
- storage_volumes(credentials, opts).first if has_capability?(:storage_volumes)
- end
-
- def storage_snapshot(credentials, opts)
- storage_snapshots(credentials, opts).first if has_capability?(:storage_snapshots)
- end
-
- def bucket(credentials, opts = {})
- #list of objects within bucket
- buckets(credentials, opts).first if has_capability?(:buckets)
- end
-
- def blob(credentials, opts = {})
- blobs(credentials, opts).first if has_capability?(:blobs)
- end
-
- def key(credentials, opts=nil)
- keys(credentials, opts).first if has_capability?(:keys)
- end
-
- def firewall(credentials, opts={})
- firewalls(credentials, opts).first if has_capability?(:firewalls)
- end
-
- MEMBER_SHOW_METHODS =
- [ :realm, :image, :instance, :storage_volume, :bucket, :blob, :key, :firewall ]
-
- def has_capability?(capability)
- if MEMBER_SHOW_METHODS.include?(capability.to_sym)
- has_capability?(capability.to_s.pluralize)
- else
- respond_to?(capability)
- end
- end
-
- def filter_on(collection, attribute, opts)
- return collection if opts.nil?
- return collection if opts[attribute].nil?
- filter = opts[attribute]
- if ( filter.is_a?( Array ) )
- return collection.select{|e| filter.include?( e.send(attribute) ) }
- else
- return collection.select{|e| filter == e.send(attribute) }
- end
- end
-
- def supported_collections
- DEFAULT_COLLECTIONS
- end
-
- def has_collection?(collection)
- supported_collections.include?(collection)
- end
-
- def catched_exceptions_list
- { :error => [], :auth => [], :glob => [] }
- end
-
- def api_provider
- Thread.current[:provider] || ENV['API_PROVIDER']
- end
-
- # Return an array of the providers statically configured
- # in the driver's YAML file
- def configured_providers
- []
- end
- end
-
-end
diff --git a/server/lib/deltacloud/base_driver/exceptions.rb b/server/lib/deltacloud/base_driver/exceptions.rb
deleted file mode 100644
index a89b05f..0000000
--- a/server/lib/deltacloud/base_driver/exceptions.rb
+++ /dev/null
@@ -1,191 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership. The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-#
-
-module Deltacloud
- module ExceptionHandler
-
- class DeltacloudException < StandardError
-
- attr_accessor :code, :name, :message, :backtrace, :request
-
- def initialize(code, name, message, backtrace, request=nil)
- @code, @name, @message = code, name, message
- @backtrace = backtrace
- @request = request
- self
- end
-
- end
-
- class AuthenticationFailure < DeltacloudException
- def initialize(e, message=nil)
- message ||= e.message
- super(401, e.class.name, message, e.backtrace)
- end
- end
-
- class UnknownMediaTypeError < DeltacloudException
- def initialize(e, message=nil)
- message ||= e.message
- super(406, e.class.name, message, e.backtrace)
- end
- end
-
- class MethodNotAllowed < DeltacloudException
- def initialize(e, message=nil)
- message ||= e.message
- super(405, e.class.name, message, e.backtrace)
- end
- end
-
- class ValidationFailure < DeltacloudException
- def initialize(e, message=nil)
- message ||= e.message
- super(400, e.class.name, message, e.backtrace)
- end
- end
-
- class BackendError < DeltacloudException
- def initialize(e, message=nil)
- message ||= e.message
- super(500, e.class.name, message, e.backtrace, message)
- end
- end
-
- class ProviderError < DeltacloudException
- def initialize(e, message)
- message ||= e.message
- super(502, e.class.name, message, e.backtrace)
- end
- end
-
- class ProviderTimeout < DeltacloudException
- def initialize(e, message)
- message ||= e.message
- super(504, e.class.name, message, e.backtrace)
- end
- end
-
- class NotImplemented < DeltacloudException
- def initialize(e, message)
- message ||= e.message
- super(501, e.class.name, message, e.backtrace)
- end
- end
-
- class ObjectNotFound < DeltacloudException
- def initialize(e, message)
- message ||= e.message
- super(404, e.class.name, message, e.backtrace)
- end
- end
-
- class NotSupported < DeltacloudException
- def initialize(message)
- super(501, self.class.name, message, self.backtrace)
- end
- end
-
- class ExceptionDef
- attr_accessor :status
- attr_accessor :message
- attr_reader :conditions
- attr_reader :handler
-
- def initialize(conditions, &block)
- @conditions = conditions
- instance_eval(&block) if block_given?
- end
-
- def status(code)
- self.status = code
- end
-
- def message(message)
- self.message = message
- end
-
- def exception(handler)
- self.handler = handler
- end
-
- # Condition can be class or regexp
- #
- def match?(e)
- @conditions.each do |c|
- return true if c.class == Class && e.class == c
- return true if c.class == Regexp && (e.class.name =~ c or e.message =~ c)
- end
- return false
- end
-
- def handler(e)
- return @handler if @handler
- case @status
- when 401 then Deltacloud::ExceptionHandler::AuthenticationFailure.new(e, @message)
- when 404 then Deltacloud::ExceptionHandler::ObjectNotFound.new(e, @message)
- when 406 then Deltacloud::ExceptionHandler::UnknownMediaTypeError.new(e, @message)
- when 405 then Deltacloud::ExceptionHandler::MethodNotAllowed.new(e, @message)
- when 400 then Deltacloud::ExceptionHandler::ValidationFailure.new(e, @message)
- when 500 then Deltacloud::ExceptionHandler::BackendError.new(e, @message)
- when 501 then Deltacloud::ExceptionHandler::NotImplemented.new(e, @message)
- when 502 then Deltacloud::ExceptionHandler::ProviderError.new(e, @message)
- when 504 then Deltacloud::ExceptionHandler::ProviderTimeout.new(e, @message)
- end
- end
-
- end
-
- class Exceptions
- attr_reader :exception_definitions
-
- def initialize(&block)
- @exception_definitions = []
- instance_eval(&block) if block_given?
- self
- end
-
- def on(*conditions, &block)
- @exception_definitions << ExceptionDef::new(conditions, &block) if block_given?
- end
- end
-
- def self.exceptions(&block)
- @definitions = Exceptions.new(&block).exception_definitions if block_given?
- @definitions
- end
-
- def safely(&block)
- begin
- block.call
- rescue
- report_method = $stderr.respond_to?(:err) ? :err : :puts
- Deltacloud::ExceptionHandler::exceptions.each do |exdef|
- if exdef.match?($!)
- new_exception = exdef.handler($!)
- m = new_exception.message.nil? ? $!.message : new_exception.message
- $stderr.send(report_method, "#{[$!.class.to_s, m].join(':')}\n#{$!.backtrace[0..10].join("\n")}")
- raise exdef.handler($!) unless new_exception.nil?
- end
- end
- $stderr.send(report_method, "[NO HANDLED] #{[$!.class.to_s, $!.message].join(': ')}\n#{$!.backtrace.join("\n")}")
- raise Deltacloud::ExceptionHandler::BackendError.new($!, "Unhandled exception or status code (#{$!.message})")
- end
- end
-
- end
-
-end
diff --git a/server/lib/deltacloud/base_driver/features.rb b/server/lib/deltacloud/base_driver/features.rb
deleted file mode 100644
index 37e5ef0..0000000
--- a/server/lib/deltacloud/base_driver/features.rb
+++ /dev/null
@@ -1,276 +0,0 @@
-#
-# Licensed to the Apache Software Foundation (ASF) under one or more
-# contributor license agreements. See the NOTICE file distributed with
-# this work for additional information regarding copyright ownership. The
-# ASF licenses this file to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance with the
-# License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
-# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
-# License for the specific language governing permissions and limitations
-# under the License.
-
-require 'deltacloud/validation'
-
-# Add advertising of optional features to the base driver
-module Deltacloud
-
- class FeatureError < StandardError; end
- class DuplicateFeatureDeclError < FeatureError; end
- class UndeclaredFeatureError < FeatureError; end
-
- class BaseDriver
-
- # An operation on a collection like cretae or show. Features
- # can add parameters to operations
- class Operation
- attr_reader :name
-
- include Deltacloud::Validation
-
- def initialize(name, &block)
- @name = name
- @params = {}
- instance_eval &block
- end
- end
-
- # The declaration of a feature, defines what operations
- # are modified by it
- class FeatureDecl
- attr_reader :name, :operations
-
- def initialize(name, &block)
- @name = name
- @operations = []
- instance_eval &block
- end
-
- def description(text=nil)
- @description = text if text
- @description
- end
-
- # Add/modify an operation or look up an existing one. If +block+ is
- # provided, create a new operation if none exists with name
- # +name+. Evaluate the +block+ against this instance. If no +block+
- # is provided, look up the operation with name +name+
- def operation(name, &block)
- op = @operations.find { |op| op.name == name }
- if block_given?
- if op.nil?
- op = Operation.new(name, &block)
- @operations << op
- else
- op.instance_eval(&block)
- end
- end
- op
- end
- end
-
- # A specific feature enabled by a driver (see +feature+)
- class Feature
- attr_reader :decl, :constraints
-
- def initialize(decl, &block)
- @decl = decl
- @constraints = {}
- instance_eval &block if block_given?
- end
-
- def name
- decl.name
- end
-
- def operations
- decl.operations
- end
-
- def description
- decl.description
- end
-
- def constraint(name, value)
- @constraints[name] = value
- end
- end
-
- def self.feature_decls
- @@feature_decls ||= {}
- end
-
- def self.feature_decl_for(collection, name)
- decls = feature_decls[collection]
- if decls
- decls.find { |dcl| dcl.name == name }
- else
- nil
- end
- end
-
- # Declare a new feature
- def self.declare_feature(collection, name, &block)
- feature_decls[collection] ||= []
- raise DuplicateFeatureDeclError if feature_decl_for(collection, name)
- feature_decls[collection] << FeatureDecl.new(name, &block)
- end
-
- def self.features
- @features ||= {}
- end
-
- # Declare in a driver that it supports a specific feature
- #
- # The same feature can be declared multiple times in a driver, so that
- # it can be changed successively by passing in different blocks.
- def self.feature(collection, name, &block)
- features[collection] ||= []
- if f = features[collection].find { |f| f.name == name }
- f.instance_eval(&block) if block_given?
- return f
- end
- unless decl = feature_decl_for(collection, name)
- raise UndeclaredFeatureError, "No feature #{name} for #{collection}"
- end
- features[collection] << Feature.new(decl, &block)
- end
-
- def features(collection)
- self.class.features[collection] || []
- end
-
- def features_for_operation(collection, operation)
- features(collection).select do |f|
- f.operations.detect { |o| o.name == operation }
- end
- end
-
- #
- # Declaration of optional features
- #
- declare_feature :images, :owner_id do
- description "Filter images using owner id"
- operation :index do
- param :owner_id, :string, :optional, [], "Owner ID"
- end
- end
-
- declare_feature :images, :user_name do
- description "Allow specifying user name for created image"
- operation :create do
- param :name, :string, :optional, [], "Image name"
- end
- end
-
- declare_feature :images, :user_description do
- description "Allow specifying user description for created image"
- operation :create do
- param :description, :string, :optional, [], "Image description"
- end
- end
-
- declare_feature :instances, :user_name do
- description "Accept a user-defined name on instance creation"
- operation :create do
- param :name, :string, :optional, [], "The user-defined name"
- end
- end
-
- declare_feature :instances, :user_data do
- description "Make user-defined data available on a special webserver"
- operation :create do
- param :user_data, :string, :optional, [],
- "Base64 encoded user data will be published to internal webserver"
- end
- end
-
- declare_feature :instances, :user_iso do
- description "Make user-defined ISO available inside instance"
- operation :create do
- param :user_iso, :string, :optional, [],
- "Base64 encoded gzipped ISO file will be accessible as CD-ROM drive in instance"
- end
- end
-
- declare_feature :instances, :user_files do
- description "Accept up to 5 files to be placed into the instance before launch."
- operation :create do
- 1.upto(5) do |i|
- param :"path#{i}", :string, :optional, [],
- "Path where to place the #{i.ordinalize} file, up to 255 characters"
- param :"content#{i}", :string, :optional, nil,
- "Contents for the #{i.ordinalize} file, up to 10 kB, Base64 encoded"
- end
- end
- end
-
- declare_feature :instances, :firewalls do
- description "Put instance in one or more firewalls (security groups) on launch"
- operation :create do
- param :firewalls, :array, :optional, nil, "Array of firewall ID strings"
- "Array of firewall (security group) id"
- end
- end
-
- declare_feature :instances, :authentication_key do
- operation :create do
- param :keyname, :string, :optional, [], "Key authentification method"
- end
- operation :show do
- end
- end
-
- declare_feature :instances, :authentication_password do
- operation :create do
- param :password, :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
- end
-
- declare_feature :buckets, :bucket_location do
- description "Take extra location parameter for Bucket creation (e.g. S3, 'eu' or 'us-west-1')"
- operation :create do
- param :location, :string, :optional
- end
- end
-
- declare_feature :instances, :register_to_load_balancer do
- description "Register instance to load balancer"
- operation :create do
- param :load_balancer_id, :string, :optional
- end
- end
-
- declare_feature :instances, :instance_count do
- description "Number of instances to be launch with at once"
- operation :create do
- param :instance_count, :string, :optional
- end
- end
-
- declare_feature :instances, :attach_snapshot do
- description "Attach an snapshot to instance on create"
- operation :create do
- param :snapshot_id, :string, :optional
- param :device_name, :string, :optional
- end
- end
-
- declare_feature :instances, :sandboxing do
- description "Allow lanuching sandbox images"
- operation :create do
- param :sandbox, :string, :optional
- end
- end
-
- end
-end
diff --git a/server/lib/deltacloud/drivers/base_driver.rb b/server/lib/deltacloud/drivers/base_driver.rb
new file mode 100644
index 0000000..5fb1a79
--- /dev/null
+++ b/server/lib/deltacloud/drivers/base_driver.rb
@@ -0,0 +1,265 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership. The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+module Deltacloud
+
+ class BaseDriver
+
+ include ExceptionHandler
+
+ def self.driver_name
+ name.split('::').last.gsub('Driver', '').downcase
+ end
+
+ def self.features
+ @features ||= []
+ end
+
+ def self.features_for(entity)
+ features.inject([]) do |result, item|
+ result << item[entity] if item.has_key? entity
+ result
+ end
+ end
+
+ def self.feature(collection, feature_name)
+ return if has_feature?(collection, feature_name)
+ features << { collection => feature_name }
+ end
+
+ def self.has_feature?(collection, feature_name)
+ features.any? { |f| (f.values.first == feature_name) && (f.keys.first == collection) }
+ end
+
+ def name
+ self.class.name.split('::').last.gsub('Driver', '').downcase
+ end
+
+ def self.exceptions(&block)
+ ExceptionHandler::exceptions(&block)
+ end
+
+ def self.define_hardware_profile(name,&block)
+ @hardware_profiles ||= []
+ hw_profile = @hardware_profiles.find{|e| e.name == name}
+ return if hw_profile
+ hw_profile = ::Deltacloud::HardwareProfile.new( name, &block )
+ @hardware_profiles << hw_profile
+ hw_params = hw_profile.params
+ # FIXME: Features
+ #unless hw_params.empty?
+ # feature :instances, :hardware_profiles do
+ # decl.operation(:create) { add_params(hw_params) }
+ # end
+ #end
+ end
+
+ def self.hardware_profiles
+ @hardware_profiles ||= []
+ @hardware_profiles
+ end
+
+ def hardware_profiles(credentials, opts = nil)
+ results = self.class.hardware_profiles
+ filter_hardware_profiles(results, opts)
+ end
+
+ def hardware_profile(credentials, name)
+ name = name[:id] if name.kind_of? Hash
+ hardware_profiles(credentials, :id => name).first
+ end
+
+ def filter_hardware_profiles(profiles, opts)
+ if opts
+ if v = opts[:architecture]
+ profiles = profiles.select { |hwp| hwp.include?(:architecture, v) }
+ end
+ # As a request param, we call 'name' 'id'
+ if v = opts[:id]
+ profiles = profiles.select { |hwp| hwp.name == v }
+ end
+ end
+ profiles
+ end
+
+ def find_hardware_profile(credentials, name, image_id)
+ hwp = nil
+ if name
+ unless hwp = hardware_profiles(credentials, :id => name).first
+ raise BackendError.new(400, "bad-hardware-profile-name",
+ "Hardware profile '#{name}' does not exist", nil)
+ end
+ else
+ unless image = image(credentials, :id=>image_id)
+ raise BackendError.new(400, "bad-image-id",
+ "Image with ID '#{image_id}' does not exist", nil)
+ end
+ hwp = hardware_profiles(credentials,
+ :architecture=>image.architecture).first
+ end
+ return hwp
+ end
+
+ def self.define_instance_states(&block)
+ machine = ::Deltacloud::StateMachine.new(&block)
+ @instance_state_machine = machine
+ end
+
+ def self.instance_state_machine
+ @instance_state_machine
+ end
+
+ def instance_state_machine
+ self.class.instance_state_machine
+ end
+
+ def instance_actions_for(state)
+ actions = []
+ state_key = state.downcase.to_sym
+ states = instance_state_machine.states()
+ current_state = states.find{|e| e.name == state.underscore.to_sym }
+ if ( current_state )
+ actions = current_state.transitions.collect{|e|e.action}
+ actions.reject!{|e| e.nil?}
+ end
+ actions
+ end
+
+ def has_capability?(method)
+ (self.class.instance_methods - self.class.superclass.methods).include? method
+ end
+
+ ## Capabilities
+ # The rabbit dsl supports declaring a capability that is required
+ # in the backend driver for the call to succeed. A driver can
+ # provide a capability by implementing the method with the same
+ # name as the capability. Below is a list of the capabilities as
+ # the expected method signatures.
+ #
+ # Following the capability list are the resource member show
+ # methods. They each require that the corresponding collection
+ # method be defined
+ #
+ # TODO: standardize all of these to the same signature (credentials, opts)
+ #
+ # def realms(credentials, opts=nil)
+ #
+ # def images(credentials, ops)
+ #
+ # def instances(credentials, ops)
+ # def create_instance(credentials, image_id, opts)
+ # def start_instance(credentials, id)
+ # def stop_instance(credentials, id)
+ # def reboot_instance(credentials, id)
+ #
+ # def storage_volumes(credentials, ops)
+ #
+ # def storage_snapshots(credentials, ops)
+ #
+ # def buckets(credentials, opts = nil)
+ # def create_bucket(credentials, name, opts=nil)
+ # def delete_bucket(credentials, name, opts=nil)
+ #
+ # def blobs(credentials, opts = nil)
+ # def blob_data(credentials, bucket_id, blob_id, opts)
+ # def create_blob(credentials, bucket_id, blob_id, blob_data, opts=nil)
+ # def delete_blob(credentials, bucket_id, blob_id, opts=nil)
+ #
+ # def keys(credentials, opts)
+ # def create_key(credentials, opts)
+ # def destroy_key(credentials, opts)
+ #
+ # def firewalls(credentials, opts)
+ # def create_firewall(credentials, opts)
+ # def delete_firewall(credentials, opts)
+ # def create_firewall_rule(credentials, opts)
+ # def delete_firewall_rule(credentials, opts)
+ # def providers(credentials)
+ def realm(credentials, opts)
+ realms = realms(credentials, opts).first if has_capability?(:realms)
+ end
+
+ def image(credentials, opts)
+ images(credentials, opts).first if has_capability?(:images)
+ end
+
+ def instance(credentials, opts)
+ instances(credentials, opts).first if has_capability?(:instances)
+ end
+
+ def storage_volume(credentials, opts)
+ storage_volumes(credentials, opts).first if has_capability?(:storage_volumes)
+ end
+
+ def storage_snapshot(credentials, opts)
+ storage_snapshots(credentials, opts).first if has_capability?(:storage_snapshots)
+ end
+
+ def bucket(credentials, opts = {})
+ #list of objects within bucket
+ buckets(credentials, opts).first if has_capability?(:buckets)
+ end
+
+ def blob(credentials, opts = {})
+ blobs(credentials, opts).first if has_capability?(:blobs)
+ end
+
+ def key(credentials, opts=nil)
+ keys(credentials, opts).first if has_capability?(:keys)
+ end
+
+ def firewall(credentials, opts={})
+ firewalls(credentials, opts).first if has_capability?(:firewalls)
+ end
+
+ MEMBER_SHOW_METHODS =
+ [ :realm, :image, :instance, :storage_volume, :bucket, :blob, :key, :firewall ]
+
+ def filter_on(collection, attribute, opts)
+ return collection if opts.nil?
+ return collection if opts[attribute].nil?
+ filter = opts[attribute]
+ if ( filter.is_a?( Array ) )
+ return collection.select{|e| filter.include?( e.send(attribute) ) }
+ else
+ return collection.select{|e| filter == e.send(attribute) }
+ end
+ end
+
+ def supported_collections
+ DEFAULT_COLLECTIONS
+ end
+
+ def has_collection?(collection)
+ supported_collections.include?(collection)
+ end
+
+ def catched_exceptions_list
+ { :error => [], :auth => [], :glob => [] }
+ end
+
+ def api_provider
+ Thread.current[:provider] || ENV['API_PROVIDER']
+ end
+
+ # Return an array of the providers statically configured
+ # in the driver's YAML file
+ def configured_providers
+ []
+ end
+ end
+
+end
diff --git a/server/lib/deltacloud/drivers/exceptions.rb b/server/lib/deltacloud/drivers/exceptions.rb
new file mode 100644
index 0000000..a89b05f
--- /dev/null
+++ b/server/lib/deltacloud/drivers/exceptions.rb
@@ -0,0 +1,191 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership. The
+# ASF licenses this file to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance with the
+# License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+
+module Deltacloud
+ module ExceptionHandler
+
+ class DeltacloudException < StandardError
+
+ attr_accessor :code, :name, :message, :backtrace, :request
+
+ def initialize(code, name, message, backtrace, request=nil)
+ @code, @name, @message = code, name, message
+ @backtrace = backtrace
+ @request = request
+ self
+ end
+
+ end
+
+ class AuthenticationFailure < DeltacloudException
+ def initialize(e, message=nil)
+ message ||= e.message
+ super(401, e.class.name, message, e.backtrace)
+ end
+ end
+
+ class UnknownMediaTypeError < DeltacloudException
+ def initialize(e, message=nil)
+ message ||= e.message
+ super(406, e.class.name, message, e.backtrace)
+ end
+ end
+
+ class MethodNotAllowed < DeltacloudException
+ def initialize(e, message=nil)
+ message ||= e.message
+ super(405, e.class.name, message, e.backtrace)
+ end
+ end
+
+ class ValidationFailure < DeltacloudException
+ def initialize(e, message=nil)
+ message ||= e.message
+ super(400, e.class.name, message, e.backtrace)
+ end
+ end
+
+ class BackendError < DeltacloudException
+ def initialize(e, message=nil)
+ message ||= e.message
+ super(500, e.class.name, message, e.backtrace, message)
+ end
+ end
+
+ class ProviderError < DeltacloudException
+ def initialize(e, message)
+ message ||= e.message
+ super(502, e.class.name, message, e.backtrace)
+ end
+ end
+
+ class ProviderTimeout < DeltacloudException
+ def initialize(e, message)
+ message ||= e.message
+ super(504, e.class.name, message, e.backtrace)
+ end
+ end
+
+ class NotImplemented < DeltacloudException
+ def initialize(e, message)
+ message ||= e.message
+ super(501, e.class.name, message, e.backtrace)
+ end
+ end
+
+ class ObjectNotFound < DeltacloudException
+ def initialize(e, message)
+ message ||= e.message
+ super(404, e.class.name, message, e.backtrace)
+ end
+ end
+
+ class NotSupported < DeltacloudException
+ def initialize(message)
+ super(501, self.class.name, message, self.backtrace)
+ end
+ end
+
+ class ExceptionDef
+ attr_accessor :status
+ attr_accessor :message
+ attr_reader :conditions
+ attr_reader :handler
+
+ def initialize(conditions, &block)
+ @conditions = conditions
+ instance_eval(&block) if block_given?
+ end
+
+ def status(code)
+ self.status = code
+ end
+
+ def message(message)
+ self.message = message
+ end
+
+ def exception(handler)
+ self.handler = handler
+ end
+
+ # Condition can be class or regexp
+ #
+ def match?(e)
+ @conditions.each do |c|
+ return true if c.class == Class && e.class == c
+ return true if c.class == Regexp && (e.class.name =~ c or e.message =~ c)
+ end
+ return false
+ end
+
+ def handler(e)
+ return @handler if @handler
+ case @status
+ when 401 then Deltacloud::ExceptionHandler::AuthenticationFailure.new(e, @message)
+ when 404 then Deltacloud::ExceptionHandler::ObjectNotFound.new(e, @message)
+ when 406 then Deltacloud::ExceptionHandler::UnknownMediaTypeError.new(e, @message)
+ when 405 then Deltacloud::ExceptionHandler::MethodNotAllowed.new(e, @message)
+ when 400 then Deltacloud::ExceptionHandler::ValidationFailure.new(e, @message)
+ when 500 then Deltacloud::ExceptionHandler::BackendError.new(e, @message)
+ when 501 then Deltacloud::ExceptionHandler::NotImplemented.new(e, @message)
+ when 502 then Deltacloud::ExceptionHandler::ProviderError.new(e, @message)
+ when 504 then Deltacloud::ExceptionHandler::ProviderTimeout.new(e, @message)
+ end
+ end
+
+ end
+
+ class Exceptions
+ attr_reader :exception_definitions
+
+ def initialize(&block)
+ @exception_definitions = []
+ instance_eval(&block) if block_given?
+ self
+ end
+
+ def on(*conditions, &block)
+ @exception_definitions << ExceptionDef::new(conditions, &block) if block_given?
+ end
+ end
+
+ def self.exceptions(&block)
+ @definitions = Exceptions.new(&block).exception_definitions if block_given?
+ @definitions
+ end
+
+ def safely(&block)
+ begin
+ block.call
+ rescue
+ report_method = $stderr.respond_to?(:err) ? :err : :puts
+ Deltacloud::ExceptionHandler::exceptions.each do |exdef|
+ if exdef.match?($!)
+ new_exception = exdef.handler($!)
+ m = new_exception.message.nil? ? $!.message : new_exception.message
+ $stderr.send(report_method, "#{[$!.class.to_s, m].join(':')}\n#{$!.backtrace[0..10].join("\n")}")
+ raise exdef.handler($!) unless new_exception.nil?
+ end
+ end
+ $stderr.send(report_method, "[NO HANDLED] #{[$!.class.to_s, $!.message].join(': ')}\n#{$!.backtrace.join("\n")}")
+ raise Deltacloud::ExceptionHandler::BackendError.new($!, "Unhandled exception or status code (#{$!.message})")
+ end
+ end
+
+ end
+
+end
--
1.7.10