Apache Deltacloud is a cross-cloud abstraction server written in ruby and providing a RESTful API. We look at a particular aspect of Deltacloud in detail, showing how a Deltacloud cloud 'driver' works and how to extend the driver to implement a new cloud 'collection'. The idea is to provide lower level detail for developers that are interested in participating in the Deltacloud community.
Apache Deltacloud is a cross-cloud abstraction server written in ruby and providing a RESTful API. This talk looks at a particular aspect of Deltacloud in detail. We will show how a Deltacloud cloud 'driver' works and how one would go about extending the driver to implement a new cloud 'collection'. The idea is to provide lower level detail for developers that are interested in participating in the Deltacloud community.
A Deltacloud driver requires 3 key ingredients:
1) the HTTP 'route' handlers (e.g. GET /foo, POST /derp/herp etc) for the driver collections you are implementing.
2) some way of "speaking" to the given cloud provider (this happens in the driver file itself),
3) the driver file implementing the Deltacloud API (or a subset, depending on what your driver supports),
The first you get 'for free' - as the HTTP routes are already defined by the Deltacloud code and are common across all cloud providers (that's the point - a common API). The second you also get 'for free' - in most cases - you will find ruby gems for talking to various cloud providers; the 'problem' is usually choosing the 'best' one to use. So all that is left is working on the cloud provider driver itself.
46 operation :create, :with_capability => :create_instance do
47 param :image_id, :string, :required
48 param :realm_id, :string, :optional
49 param :hwp_id, :string, :optional
50 param :keyname, :string, :optional
51 control do
52 @instance = driver.create_instance(credentials, params[:image_id], params)
60 status 201 # Created
61 respond_to do |format|
62 format.xml { haml :"instances/#{action_handler}" }
63 format.json { xml_to_json("instances/#{action_handler}") }
64 format.html { haml :"instances/show" }
134 def create_instance(credentials, image_id, opts)
135 os = new_client( credentials )
138 params = {}
139 params[:personality] = extract_personality(opts)
140 params[:name] = (opts[:name] && opts[:name].length>0)? opts[:name] : Time.now.to_s
141 params[:imageRef] = image_id
142 params[:flavorRef] = (opts[:hwp_id] && opts[:hwp_id].length>0) ?
143 opts[:hwp_id] : hardware_profiles(credentials).first.name
150 safely do
151 server = os.create_server(params)
152 result = convert_from_server(server, os.connection.authuser)
153 end
154 result
155 end
The Deltacloud API defines four 'routes' of keys:
We focus on the first - the 'index' operation GET /api/keys. The flow is always the same for all collections:
1) get a handle for talking to the back-end cloud
2) make the request and get a response from the back-end cloud
3) format the response into a Deltacloud object
Every driver has this "new_client" method:
17 require 'openstack' #the rubygem we are using to talk to openstack
(...)
320 def new_client(credentials, type = :compute)
(...)
330 OpenStack::Connection.create(:username => user_name, :api_key => credentials.password, :authtenant => tenant_name, :auth_url => api_provider)
338 end
293 def keys(credentials, opts={})
294 os = new_client(credentials)
295 keys = []
296 safely do
297 os.keypairs.values.each{|key| keys << convert_key(key)}
298 end
299 filter_on(keys, :id, opts)
300 end
444 def convert_key(key)
445 Key.new(
446 :id => key[:name],
447 :fingerprint => key[:fingerprint],
448 :credential_type => :key,
449 :pem_rsa_key => key[:private_key], # only available once, on create_key
450 :state => "AVAILABLE"
451 )
452 end
The 'Key' object model is defined in server/lib/deltacloud/models/key.rb:
17 class Key < BaseModel
18
19 attr_accessor :credential_type
20 attr_accessor :fingerprint
21 attr_accessor :username
22 attr_accessor :password
23 attr_accessor :pem_rsa_key
24 attr_accessor :state