You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@deltacloud.apache.org by tc...@redhat.com on 2010/12/03 17:44:42 UTC

[PATCH core] Drivers now declare the capabilities they provide by implementing methods for each collection.

From: Tobias Crawley <tc...@redhat.com>

This patch makes the with_capability feature in rabbit actually work - before
this, all drivers would appear to provide most capabilities, since the check
was a simple respond_to?, and most capabilities were defined in the base_driver, 
and overridden by the drivers. With this change, those empty definitions are 
removed from the base_driver.

The next step is to expose the available capabilities with the entry_points.
I've started on that, but it introduces top level api changes, so I'll send 
a separate message to the list for discussion.

Toby

---
 server/lib/deltacloud/backend_capability.rb      |   16 +++-
 server/lib/deltacloud/base_driver/base_driver.rb |  135 ++++++++++------------
 server/lib/deltacloud/base_driver/features.rb    |    6 +
 server/lib/deltacloud/drivers/ec2/ec2_driver.rb  |    4 -
 4 files changed, 83 insertions(+), 78 deletions(-)

diff --git a/server/lib/deltacloud/backend_capability.rb b/server/lib/deltacloud/backend_capability.rb
index bec8714..5594550 100644
--- a/server/lib/deltacloud/backend_capability.rb
+++ b/server/lib/deltacloud/backend_capability.rb
@@ -2,6 +2,7 @@ module Deltacloud::BackendCapability
 
   class Failure < StandardError
     attr_reader :capability
+    
     def initialize(capability, msg='')
       super(msg)
       @capability = capability
@@ -9,13 +10,26 @@ module Deltacloud::BackendCapability
   end
 
   attr_reader :capability
+  
   def with_capability(capability)
     @capability = capability
   end
 
+  def has_capability?(backend)
+    !capability or backend.has_capability?(capability)
+  end
+
   def check_capability(backend)
-    if capability and !backend.respond_to?(capability)
+    if !has_capability?(backend)
       raise Failure.new(capability, "#{capability} capability not supported by backend #{backend.class.name}")
     end
   end
+
+  module Helpers
+    def operations_for_collection(collection)
+      collections[collection].operations.values.select { |op| op.has_capability?(driver) }
+    end
+  end
+
+  helpers Helpers
 end
diff --git a/server/lib/deltacloud/base_driver/base_driver.rb b/server/lib/deltacloud/base_driver/base_driver.rb
index 4419359..7815eb4 100644
--- a/server/lib/deltacloud/base_driver/base_driver.rb
+++ b/server/lib/deltacloud/base_driver/base_driver.rb
@@ -42,7 +42,7 @@ module Deltacloud
   end
 
   class BaseDriver
-
+    
     def self.define_hardware_profile(name,&block)
       @hardware_profiles ||= []
       hw_profile = @hardware_profiles.find{|e| e.name == name}
@@ -126,100 +126,90 @@ module Deltacloud
       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 realm(credentials, opts)
-      realms = realms(credentials, opts)
-      return realms.first unless realms.empty?
-      nil
-    end
-
-    def realms(credentials, opts=nil)
-      []
+      realms = realms(credentials, opts).first if has_capability?(:realms)
     end
 
     def image(credentials, opts)
-      images = images(credentials, opts)
-      return images.first unless images.empty?
-      nil
-    end
-
-    def images(credentials, ops)
-      []
+      images(credentials, opts).first if has_capability?(:images)
     end
 
     def instance(credentials, opts)
-      instances = instances(credentials, opts)
-      return instances.first unless instances.empty?
-      nil
-    end
-
-    def instances(credentials, ops)
-      []
-    end
-
-    def create_instance(credentials, image_id, opts)
-    end
-    def start_instance(credentials, id)
-    end
-    def stop_instance(credentials, id)
-    end
-    def reboot_instance(credentials, id)
+      instances(credentials, opts).first if has_capability?(:instances)
     end
 
     def storage_volume(credentials, opts)
-      volumes = storage_volumes(credentials, opts)
-      return volumes.first unless volumes.empty?
-      nil
-    end
-
-    def storage_volumes(credentials, ops)
-      []
+      storage_volumes(credentials, opts).first if has_capability?(:storage_volumes)
     end
 
     def storage_snapshot(credentials, opts)
-      snapshots = storage_snapshots(credentials, opts)
-      return snapshots.first unless snapshots.empty?
-      nil
-    end
-
-    def storage_snapshots(credentials, ops)
-      []
-    end
-
-    def buckets(credentials, opts = nil)
-      #list of buckets belonging to account
-      []
+      storage_snapshots(credentials, opts).first if has_capability?(:storage_snapshots)
     end
 
     def bucket(credentials, opts = nil)
-    #list of objects within bucket
-      list = buckets(credentials, opts)
-      return list.first unless list.empty?
-      nil
-    end
-
-    def create_bucket(credentials, name, opts=nil)
-    end
-
-    def delete_bucket(credentials, name, opts=nil)
+      #list of objects within bucket
+      buckets(credentials, opts).first if has_capability?(:buckets)
     end
-
-    def blobs(credentials, opts = nil)
-      []
-    end
-
+    
     def blob(credentials, opts = nil)
-       list = blobs(credentials, opts)
-       return list.first unless list.empty?
+      blobs(credentials, opts).first if has_capability?(:blobs)
     end
 
-    def blob_data(credentials, bucket_id, blob_id, opts)
+    def key(credentials, opts=nil)
+      keys(credentials, opts).first if has_capability?(:keys)
     end
 
-    def create_blob(credentials, bucket_id, blob_id, blob_data, opts=nil)  
-    end
+    MEMBER_SHOW_METHODS =
+      [ :realm, :image, :instance, :storage_volume, :bucket, :blob, :key ]
     
-    def delete_blob(credentials, bucket_id, blob_id, opts=nil)
+    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?
@@ -237,8 +227,7 @@ module Deltacloud
     end
 
     def has_collection?(collection)
-      return true if self.supported_collections.include?(collection)
-      return false
+      supported_collections.include?(collection)
     end
 
     def catched_exceptions_list
diff --git a/server/lib/deltacloud/base_driver/features.rb b/server/lib/deltacloud/base_driver/features.rb
index de055de..f20f635 100644
--- a/server/lib/deltacloud/base_driver/features.rb
+++ b/server/lib/deltacloud/base_driver/features.rb
@@ -117,6 +117,12 @@ module Deltacloud
       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
     #
diff --git a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
index d38f8f7..9fc0726 100644
--- a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
+++ b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
@@ -284,10 +284,6 @@ class EC2Driver < Deltacloud::BaseDriver
     snapshots
   end
 
-  def key(credentials, opts=nil)
-    keys(credentials, opts).first
-  end
-
   def keys(credentials, opts=nil)
     ec2 = new_client( credentials )
     opts[:key_name] = opts[:id] if opts and opts[:id]
-- 
1.7.3.2


Re: [PATCH core] Drivers now declare the capabilities they provide by implementing methods for each collection.

Posted by Michal Fojtik <mf...@redhat.com>.
On 03/12/10 11:44 -0500, tcrawley@redhat.com wrote:
>From: Tobias Crawley <tc...@redhat.com>
>
>This patch makes the with_capability feature in rabbit actually work - before
>this, all drivers would appear to provide most capabilities, since the check
>was a simple respond_to?, and most capabilities were defined in the base_driver,
>and overridden by the drivers. With this change, those empty definitions are
>removed from the base_driver.
>
>The next step is to expose the available capabilities with the entry_points.
>I've started on that, but it introduces top level api changes, so I'll send
>a separate message to the list for discussion.

Works perfecly, applied cleanely on latest master. 
Our test suites are perfectly happy with that as well.
This is a great addition to API Tobi, thanks for this work.

ACK && push.

   -- Michal

>
>Toby
>
>---
> server/lib/deltacloud/backend_capability.rb      |   16 +++-
> server/lib/deltacloud/base_driver/base_driver.rb |  135 ++++++++++------------
> server/lib/deltacloud/base_driver/features.rb    |    6 +
> server/lib/deltacloud/drivers/ec2/ec2_driver.rb  |    4 -
> 4 files changed, 83 insertions(+), 78 deletions(-)
>
>diff --git a/server/lib/deltacloud/backend_capability.rb b/server/lib/deltacloud/backend_capability.rb
>index bec8714..5594550 100644
>--- a/server/lib/deltacloud/backend_capability.rb
>+++ b/server/lib/deltacloud/backend_capability.rb
>@@ -2,6 +2,7 @@ module Deltacloud::BackendCapability
>
>   class Failure < StandardError
>     attr_reader :capability
>+
>     def initialize(capability, msg='')
>       super(msg)
>       @capability = capability
>@@ -9,13 +10,26 @@ module Deltacloud::BackendCapability
>   end
>
>   attr_reader :capability
>+
>   def with_capability(capability)
>     @capability = capability
>   end
>
>+  def has_capability?(backend)
>+    !capability or backend.has_capability?(capability)
>+  end
>+
>   def check_capability(backend)
>-    if capability and !backend.respond_to?(capability)
>+    if !has_capability?(backend)
>       raise Failure.new(capability, "#{capability} capability not supported by backend #{backend.class.name}")
>     end
>   end
>+
>+  module Helpers
>+    def operations_for_collection(collection)
>+      collections[collection].operations.values.select { |op| op.has_capability?(driver) }
>+    end
>+  end
>+
>+  helpers Helpers
> end
>diff --git a/server/lib/deltacloud/base_driver/base_driver.rb b/server/lib/deltacloud/base_driver/base_driver.rb
>index 4419359..7815eb4 100644
>--- a/server/lib/deltacloud/base_driver/base_driver.rb
>+++ b/server/lib/deltacloud/base_driver/base_driver.rb
>@@ -42,7 +42,7 @@ module Deltacloud
>   end
>
>   class BaseDriver
>-
>+
>     def self.define_hardware_profile(name,&block)
>       @hardware_profiles ||= []
>       hw_profile = @hardware_profiles.find{|e| e.name == name}
>@@ -126,100 +126,90 @@ module Deltacloud
>       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 realm(credentials, opts)
>-      realms = realms(credentials, opts)
>-      return realms.first unless realms.empty?
>-      nil
>-    end
>-
>-    def realms(credentials, opts=nil)
>-      []
>+      realms = realms(credentials, opts).first if has_capability?(:realms)
>     end
>
>     def image(credentials, opts)
>-      images = images(credentials, opts)
>-      return images.first unless images.empty?
>-      nil
>-    end
>-
>-    def images(credentials, ops)
>-      []
>+      images(credentials, opts).first if has_capability?(:images)
>     end
>
>     def instance(credentials, opts)
>-      instances = instances(credentials, opts)
>-      return instances.first unless instances.empty?
>-      nil
>-    end
>-
>-    def instances(credentials, ops)
>-      []
>-    end
>-
>-    def create_instance(credentials, image_id, opts)
>-    end
>-    def start_instance(credentials, id)
>-    end
>-    def stop_instance(credentials, id)
>-    end
>-    def reboot_instance(credentials, id)
>+      instances(credentials, opts).first if has_capability?(:instances)
>     end
>
>     def storage_volume(credentials, opts)
>-      volumes = storage_volumes(credentials, opts)
>-      return volumes.first unless volumes.empty?
>-      nil
>-    end
>-
>-    def storage_volumes(credentials, ops)
>-      []
>+      storage_volumes(credentials, opts).first if has_capability?(:storage_volumes)
>     end
>
>     def storage_snapshot(credentials, opts)
>-      snapshots = storage_snapshots(credentials, opts)
>-      return snapshots.first unless snapshots.empty?
>-      nil
>-    end
>-
>-    def storage_snapshots(credentials, ops)
>-      []
>-    end
>-
>-    def buckets(credentials, opts = nil)
>-      #list of buckets belonging to account
>-      []
>+      storage_snapshots(credentials, opts).first if has_capability?(:storage_snapshots)
>     end
>
>     def bucket(credentials, opts = nil)
>-    #list of objects within bucket
>-      list = buckets(credentials, opts)
>-      return list.first unless list.empty?
>-      nil
>-    end
>-
>-    def create_bucket(credentials, name, opts=nil)
>-    end
>-
>-    def delete_bucket(credentials, name, opts=nil)
>+      #list of objects within bucket
>+      buckets(credentials, opts).first if has_capability?(:buckets)
>     end
>-
>-    def blobs(credentials, opts = nil)
>-      []
>-    end
>-
>+
>     def blob(credentials, opts = nil)
>-       list = blobs(credentials, opts)
>-       return list.first unless list.empty?
>+      blobs(credentials, opts).first if has_capability?(:blobs)
>     end
>
>-    def blob_data(credentials, bucket_id, blob_id, opts)
>+    def key(credentials, opts=nil)
>+      keys(credentials, opts).first if has_capability?(:keys)
>     end
>
>-    def create_blob(credentials, bucket_id, blob_id, blob_data, opts=nil)
>-    end
>+    MEMBER_SHOW_METHODS =
>+      [ :realm, :image, :instance, :storage_volume, :bucket, :blob, :key ]
>
>-    def delete_blob(credentials, bucket_id, blob_id, opts=nil)
>+    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?
>@@ -237,8 +227,7 @@ module Deltacloud
>     end
>
>     def has_collection?(collection)
>-      return true if self.supported_collections.include?(collection)
>-      return false
>+      supported_collections.include?(collection)
>     end
>
>     def catched_exceptions_list
>diff --git a/server/lib/deltacloud/base_driver/features.rb b/server/lib/deltacloud/base_driver/features.rb
>index de055de..f20f635 100644
>--- a/server/lib/deltacloud/base_driver/features.rb
>+++ b/server/lib/deltacloud/base_driver/features.rb
>@@ -117,6 +117,12 @@ module Deltacloud
>       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
>     #
>diff --git a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
>index d38f8f7..9fc0726 100644
>--- a/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
>+++ b/server/lib/deltacloud/drivers/ec2/ec2_driver.rb
>@@ -284,10 +284,6 @@ class EC2Driver < Deltacloud::BaseDriver
>     snapshots
>   end
>
>-  def key(credentials, opts=nil)
>-    keys(credentials, opts).first
>-  end
>-
>   def keys(credentials, opts=nil)
>     ec2 = new_client( credentials )
>     opts[:key_name] = opts[:id] if opts and opts[:id]
>--
>1.7.3.2
>

-- 
--------------------------------------------------------
Michal Fojtik, mfojtik@redhat.com
Deltacloud API: http://deltacloud.org
--------------------------------------------------------