From: Michal Fojtik <[email protected]>
Signed-off-by: Michal fojtik <[email protected]> --- 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
