blob: 5d54cb37bf0de4650d04b4b4e6a1d2bc2cd57cb8 [file] [log] [blame]
---
site_name: Deltacloud API
title: Write New Provider Driver
---
<br/>
<h3>Writing a provider driver</h3>
<p>The deltacloud drivers are stored in <strong>deltacloud/server/lib/deltacloud/drivers</strong></p> To ad a driver for hypotetical <strong>Foo</strong> cloud, add a directory into /drivers/ and then a file for a driver itself:
<pre>deltacloud/server/lib/deltacloud/drivers/foo/foo_driver.rb</pre>
<p>You need to define a class <strong>Deltacloud::Drivers::Foo::FooDriver</strong> to this file. The class must be a subclass of the <strong>Deltacloud::BaseDriver</strong>.
</p>
<p>Set up which <a href="/rest-api.html#">collections</a> the provider for you are writing the driver supports - e.g. images, instances, keys, buckets/blobs (storage), etc.:</p>
<pre>
def supported_collections
DEFAULT_COLLECTIONS + [ :buckets ] - [ :storage_snapshots, :storage_volumes ]
end
</pre>
<p>This declares that the driver supports the <strong>DEFAULT_COLLECTIONS</strong> (defined in <strong>deltacloud/server/lib/drivers.rb</strong>) except <a href="/rest-api.html#">storage_snapshots</a> and <a href="/rest-api.html#">storage_volumes</a> and also the <a href="/rest-api.html#">buckets</a> collection. A storage only cloud provider driver would support only the buckets colletion.</p>
<p>
Then, you can define the methods for each collection that your driver supports. The methods, as well as the routes to them, are defined in <strong>deltacloud/server/lib/deltacloud/server.rb</strong>. In general, you can look at the existing drivers to have the idea of how to implement any specific method.
</p>
<p>
You should 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 <strong>ec2</strong> driver uses the <a href="https://github.com/appoxy/aws/">aws</a> gem, the <strong>rackspace</strong> driver uses the <a href="https://github.com/rackspace/ruby-cloudfiles">cloudfiles</a> and <a href="https://github.com/rackspace/ruby-cloudservers">cloudservers</a> gems. However, other drivers implement their own clients to communicate with the cloud provider, such as the IBM SBC driver and the Gogrid driver. This also explains why, under the <strong>/drivers</strong> directory, some drivers contain only the provider <strong>_driver.rb</strong> file, whilst others also define a <strong>provider_client.rb</strong> file. It is entirely up to you, whether you write your own client or use an existing one.
</p>
<p>Thus, your driver for the cloud provider foo may look like:</p>
<pre>
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
</pre>
<p>
An important method for drivers that implement the <a href="/rest-api.html#">instances</a> collection is <strong>instance_states</strong>. 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:
</p>
<pre>
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
</pre>
<p>
The definiton of .to and on. etc is defined in <strong>/deltacloud/server/lib/deltacloud/state_machine.rb</strong>.
</p>
<p>Valid states are:</p>
<ul>
<li><strong>:begin</strong></li>
<li><strong>:pending</strong></li>
<li><strong>:running</strong></li>
<li><strong>:shutting_down</strong></li>
<li><strong>:stopped</strong></li>
<li><strong>:end</strong></li>
</ul>
<p>The instance is located in the<strong>:begin</strong> state before being created. Immediately after being destroyed the instance is removed to the <strong>:end</strong> state.</p>
<p>Valid transition actions are:</p>
<ul>
<li><strong>:stop</strong></li>
<li><strong>:start</strong></li>
<li><strong>:reboot</strong></li>
</ul>
<p>The action <strong>:automatically</strong> may be used to indicate a tranisition that may occur without an action being triggered (see the example above).</p>
<p>You can implement some other methods according to the collections you will be supporting:</p>
<ul>
<li><strong>hardware_profiles(credentials, opts=nil)</strong></li>
<li><strong>images(credentials, opts=nil)</strong></li>
<li><strong>realms(credentials, opts=nil)</strong></li>
<li><strong>instances(credentials, opts=nil)</strong></li>
<li><strong>create_instance(credentials, image_id, opts)</strong></li>
<li><strong>reboot_instance(credentials, id)</strong></li>
<li><strong>stop_instance(credentials, id)</strong></li>
<li><strong>destroy_instance(credentials, id)</strong></li>
</ul>
<p>
The <strong>hardware_profiles(...)</strong> method should return an array of HardwareProfile objects. The <strong>opts</strong> hash, if present, must be inspected for <strong>:id</strong> and <strong>:architecture</strong> keys. If these keys are present, the results should be filtered by the value associated with each key. The <strong>filter_on(...)</strong> helper method is used for this filtering and as you can see from existing driver method definitions, is invoked in many of the driver collection methods:
</p>