Write a provider driver

The deltacloud drivers are stored in deltacloud/server/lib/deltacloud/drivers.

  1. To add a driver for a hypotetical Foo cloud, add a directory into /drivers/ and then add a file for a driver itself:

    deltacloud/server/lib/deltacloud/drivers/foo/foo_driver.rb

    You need to define a class Deltacloud::Drivers::Foo::FooDriver to this file. The class has to be a subclass of the Deltacloud::BaseDriver.

  2. Set up which collections the provider for you are writing the driver supports - e.g. images, instances, keys, buckets/blobs (storage), etc.:

    def supported_collections
      DEFAULT_COLLECTIONS + [ :buckets ] - [ :storage_snapshots, :storage_volumes ]
    end
    

    This declares that the driver supports the DEFAULT_COLLECTIONS (defined in deltacloud/server/lib/drivers.rb) except storage_snapshots and storage_volumes and also supports the buckets collection. A storage only cloud provider driver would support only the buckets collection.

  3. Define the methods for each collection that your driver supports. The methods, as well as the routes to them, are defined in deltacloud/server/lib/deltacloud/server.rb. You can look at the existing drivers to get the idea of how to implement a specific method.

  4. Consider how the driver will be communicating with the cloud provider. Many of the existing drivers use external ruby gems for this purpose. For example, the ec2 driver uses the aws gem, the rackspace driver uses the cloudfiles and cloudservers gems. However, other drivers implement their own clients to communicate with the cloud provider, such as the IBM SmartCloud driver and the Gogrid driver. This also explains why some drivers in the /drivers directory contain only the provider _driver.rb file, while the others also define a provider_client.rb file. It is entirely up to you, whether you write your own client or use an existing one.

Thus, your driver for the cloud provider Foo may look like:

require 'deltacloud/base_driver'
require 'foo_lib' # a library for talking to the foo cloud

module Deltacloud
  module Drivers
    module Foo

class FooDriver < Deltacloud::BaseDriver

    def supported_collections
      DEFAULT_COLLECTIONS + [ :buckets ]
    end

    def images(credentials, opts={})
      client = new_foo_client(credentials)
      # Use client to get a list of images from the back-end cloud and then create a Deltacloud Image object for each of these.
      # Filter the result (eg specific image requested) and return to user.
    end

    def realms(credentials, opts={})
      (...)
    end

    def instances(credentials, opts={})
      (...)
    end

    ... ETC

    private

    def new_foo_client(credentials)
      client = FooLib::Service.new({:user => credentials.user,
:pass => credentials.password })
    end

end
        end
      end
    end

An important method for drivers that implement the instances collection is instance_states. This method represents the finite-state-machine for instances which varies across cloud providers. In some clouds an instance may be in the 'running' state after creation, whereas in other clouds an instance may need to be started explicitly. For example:

define_instance_states do
  start.to( :pending )          .on( :create )
  pending.to( :running )        .automatically
  running.to( :running )        .on( :reboot )
  running.to( :shutting_down )  .on( :stop )
  shutting_down.to( :stopped )  .automatically
  stopped.to( :finish )         .automatically
end

The voodoo used here (i.e. definition of .to and .on etc) is defined in /deltacloud/server/lib/deltacloud/state_machine.rb.

Valid states are:

The instance is located in the:begin state before being created. Immediately after being destroyed the instance is removed to the :end state.

Valid transition actions are:

The action :automatically may be used to indicate a tranisition that may occur without an action being triggered (see the example above).

You can implement some other methods according to the collections you will be supporting:

The hardware_profiles(...) method should return an array of HardwareProfile objects. The opts hash, if present, must be inspected for :id and :architecture keys. If these keys are available, the results should be filtered by the value associated with each key. The filter_on(...) helper method is used for the filtering and as you can see from existing driver method definitions, is invoked in many of the driver collection methods:

def hardware_profiles(credentials, opts=nil)
  hardware_profiles = # get all hardware profiles from provider
  hardware_profiles = filter_on( hardware_profiles, :id, opts )
  hardware_profiles = filter_on( hardware_profiles, :architecture, opts )
  return hardware_profiles
end

Once you've implemented some of the methods for your driver you should test if the driver is working correctly. Before you'll do this, you need to create a yaml file for your driver so that the Deltacloud server recognizes the driver. Assuming you've written the driver for cloud Foo and you've created the file foo_driver.rb (containing the class Deltacloud::Drivers::Foo::FooDriver), you need to drop a file into /deltacloud/server/config/drivers called foo.yaml, which contains:

---
:foo:
  :name Foo

Then, you can start the Deltacloud server:

deltacloudd -i foo

Back Test the driver