You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@deltacloud.apache.org by lu...@apache.org on 2011/02/08 01:45:58 UTC
svn commit: r1068240 - in /incubator/deltacloud/trunk/server/lib:
deltacloud/drivers/sbc/ deltacloud/drivers/sbc/sbc_client.rb
deltacloud/drivers/sbc/sbc_driver.rb drivers.rb
Author: lutter
Date: Tue Feb 8 00:45:57 2011
New Revision: 1068240
URL: http://svn.apache.org/viewvc?rev=1068240&view=rev
Log:
SBC driver: new driver for the IBM SBC cloud
Driver contributed by Eric Woods
Fixes https://issues.apache.org/jira/browse/DTACLOUD-15
Added:
incubator/deltacloud/trunk/server/lib/deltacloud/drivers/sbc/
incubator/deltacloud/trunk/server/lib/deltacloud/drivers/sbc/sbc_client.rb
incubator/deltacloud/trunk/server/lib/deltacloud/drivers/sbc/sbc_driver.rb
Modified:
incubator/deltacloud/trunk/server/lib/drivers.rb
Added: incubator/deltacloud/trunk/server/lib/deltacloud/drivers/sbc/sbc_client.rb
URL: http://svn.apache.org/viewvc/incubator/deltacloud/trunk/server/lib/deltacloud/drivers/sbc/sbc_client.rb?rev=1068240&view=auto
==============================================================================
--- incubator/deltacloud/trunk/server/lib/deltacloud/drivers/sbc/sbc_client.rb (added)
+++ incubator/deltacloud/trunk/server/lib/deltacloud/drivers/sbc/sbc_client.rb Tue Feb 8 00:45:57 2011
@@ -0,0 +1,180 @@
+#
+# Copyright (C) 2011 IBM Corporation
+#
+# 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 'base64'
+require 'net/https'
+require 'json'
+
+module Deltacloud
+ module Drivers
+ module SBC
+#
+# Client for the IBM Smart Business Cloud (SBC).
+#
+# 31 January 2011
+#
+class SBCClient
+ API_URL = URI.parse('https://www-147.ibm.com/computecloud/enterprise/api/rest/20100331')
+
+ #
+ # Initialize the client
+ #
+ def initialize(username, password)
+ @username, @password = username, password
+ @rest_base = '/computecloud/enterprise/api/rest/20100331'
+ @service = Net::HTTP.new(API_URL.host, API_URL.port)
+ @service.use_ssl = true
+ end
+
+ #
+ # Retrieve instances
+ #
+ def list_instances(instance_id=nil)
+ if instance_id.nil?
+ JSON.parse(get('/instances', default_headers))['instances']
+ else
+ [ JSON.parse(get('/instances/' + instance_id, default_headers)) ]
+ end
+ end
+
+ #
+ # Reboot an instance
+ #
+ def reboot_instance(instance_id)
+ headers = default_headers
+ headers['Content-Type'] = 'application/x-www-form-urlencoded'
+ put('/instances/' + instance_id, 'state=restart', headers)
+ end
+
+ #
+ # Delete an instance
+ #
+ def delete_instance(instance_id)
+ delete('/instances/' + instance_id, default_headers)
+ end
+
+ #
+ # Retrieve images
+ #
+ def list_images(image_id=nil)
+ if image_id.nil?
+ JSON.parse(get('/offerings/image', default_headers))['images']
+ else
+ [ JSON.parse(get('/offerings/image/' + image_id, default_headers)) ]
+ end
+ end
+
+ #
+ # Retrieve locations; returns an XML document.
+ #
+ def list_locations
+ headers = default_headers
+ headers['Accept'] = 'text/xml' # JSON locations not supported
+ Nokogiri.XML(get('/locations', headers))
+ end
+
+ #
+ # Creates an instance
+ #
+ # body is a name/value hash to configure the instance
+ #
+ def create_instance(body)
+ headers = default_headers
+ headers['Content-Type'] = 'application/x-www-form-urlencoded'
+ JSON.parse(post('/instances', urlencode(body), headers))['instances']
+ end
+
+ #
+ # -------------------- Private Helpers -----------------
+ #
+ private
+
+ #
+ # HTTP GET
+ #
+ def get(path, headers)
+ resp = @service.get(@rest_base + path, headers)
+ unless resp.is_a?(Net::HTTPSuccess)
+ backend_error!(resp)
+ end
+ resp.body
+ end
+
+ #
+ # HTTP PUT
+ #
+ def put(path, body, headers)
+ resp = @service.put(@rest_base + path, body, headers)
+ unless resp.is_a?(Net::HTTPSuccess)
+ backend_error!(resp)
+ end
+ resp.body
+ end
+
+ #
+ # HTTP POST
+ #
+ def post(path, body, headers)
+ resp = @service.post(@rest_base + path, body, headers)
+ unless resp.is_a?(Net::HTTPSuccess)
+ backend_error!(resp)
+ end
+ resp.body
+ end
+
+ #
+ # HTTP DELETE
+ #
+ def delete(path, headers)
+ resp = @service.delete(@rest_base + path, headers)
+ unless resp.is_a?(Net::HTTPSuccess)
+ backend_error!(resp)
+ end
+ resp.body
+ end
+
+ #
+ # Default request headers.
+ #
+ def default_headers
+ {"Accept" => "application/json",
+ "User-Agent" => "deltacloud",
+ "Authorization" => "Basic " + Base64.encode64("#{@username}:#{@password}")}
+ end
+
+ #
+ # Handle request error
+ #
+ def backend_error!(resp)
+ if resp.is_a?(Net::HTTPUnauthorized)
+ raise Deltacloud::AuthException, resp.message
+ else
+ raise Deltacloud::BackendError.new(resp.code, resp.body, resp.message, '')
+ end
+ end
+
+ #
+ # Utility to URL encode a hash.
+ #
+ def urlencode(hash)
+ hash.keys.map { |k| "#{URI.encode(k)}=#{URI.encode(hash[k])}" }.join("&")
+ end
+end
+ end
+ end
+end
Added: incubator/deltacloud/trunk/server/lib/deltacloud/drivers/sbc/sbc_driver.rb
URL: http://svn.apache.org/viewvc/incubator/deltacloud/trunk/server/lib/deltacloud/drivers/sbc/sbc_driver.rb?rev=1068240&view=auto
==============================================================================
--- incubator/deltacloud/trunk/server/lib/deltacloud/drivers/sbc/sbc_driver.rb (added)
+++ incubator/deltacloud/trunk/server/lib/deltacloud/drivers/sbc/sbc_driver.rb Tue Feb 8 00:45:57 2011
@@ -0,0 +1,299 @@
+#
+# Copyright (C) 2011 IBM Corporation
+#
+# 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 'nokogiri'
+require 'deltacloud/drivers/sbc/sbc_client'
+
+module Deltacloud
+ module Drivers
+ module SBC
+#
+# Driver for the IBM Smart Business Cloud (SBC).
+#
+# 31 January 2011
+#
+class SBCDriver < Deltacloud::BaseDriver
+ #
+ # Retrieves images
+ #
+ def images(credentials, opts={})
+ sbc_client = new_client(credentials)
+ opts ||= {}
+ images = []
+ images = sbc_client.list_images(opts[:id]).map do |image|
+ # Cache image for create_instance; hwp is image-specific. In the
+ # current flow of the server, images is always called before a
+ # create_instance, making this caching profitable
+ @last_image = image
+ convert_image(image)
+ end
+ images = filter_on(images, :architecture, opts)
+ images = filter_on(images, :owner_id, opts)
+ images
+ end
+
+ #
+ # Retrieves realms
+ #
+ def realms(credentials, opts={})
+ sbc_client = new_client(credentials)
+ doc = sbc_client.list_locations
+ doc.xpath('ns2:DescribeLocationsResponse/Location').map { |loc| convert_location(loc) }
+ end
+
+ #
+ # Retrieves instances
+ #
+ def instances(credentials, opts={})
+ sbc_client = new_client(credentials)
+ opts ||= {}
+ instances = []
+ instances = sbc_client.list_instances(opts[:id]).map do |instance|
+ convert_instance(instance)
+ end
+ end
+
+ #
+ # Creates an instance
+ #
+ def create_instance(credentials, image_id, opts={})
+ sbc_client = new_client(credentials)
+
+ # Copy opts to body; keywords are mapped later
+ body = opts.dup
+ body.delete('image_id')
+ body.delete('hwp_id')
+ body.delete('realm_id')
+
+ # Lookup image if nil; avoids extra lookup
+ if @last_image.nil? || @last_image['id'] != opts[:image_id]
+ @last_image = sbc_client.list_images(image_id).map[0]
+ end
+
+ # Map DeltaCloud keywords to SBC
+ body['imageID'] = opts[:image_id]
+ body['location'] = opts[:realm_id] || @last_image['location']
+ body['instanceType'] = opts[:hwp_id] || @last_image['supportedInstanceTypes'][0]['id']
+
+ # Submit instance, parse response
+ convert_instance(sbc_client.create_instance(body).map[0])
+ end
+
+ #
+ # Reboots an instance
+ #
+ def reboot_instance(credentials, instance_id)
+ sbc_client = new_client(credentials)
+ sbc_client.reboot_instance(instance_id)
+ instance(credentials, instance_id)
+ end
+
+ #
+ # Stops an instance
+ #
+ def stop_instance(credentials, instance_id)
+ # Stop not supported; rebooting
+ reboot_instance(credentials, instance_id)
+ end
+
+ #
+ # Destroys an instance
+ #
+ def destroy_instance(credentials, instance_id)
+ sbc_client = new_client(credentials)
+ sbc_client.delete_instance(instance_id)
+ instance(credentials, instance_id)
+ end
+
+ #
+ # --------------------- Private helpers ---------------------
+ #
+ private
+
+ # SBC instance states mapped to DeltaCloud
+ @@INSTANCE_STATE_MAP = {
+ 0 => "PENDING", # New
+ 1 => "PENDING", # Provisioning
+ 2 => "STOPPED", # Failed
+ 3 => "STOPPED", # Removed
+ 4 => "STOPPED", # Rejected
+ 5 => "RUNNING", # Active
+ 6 => "STOPPED", # Unknown
+ 7 => "PENDING", # Deprovisioning
+ 8 => "PENDING", # Restarting
+ 9 => "PENDING", # Starting
+ 10 => "SHUTTING_DOWN", # Stopping
+ 11 => "STOPPED", # Stopped
+ 12 => "PENDING", # Deprovision pending
+ 13 => "PENDING", # Restart pending
+ 14 => "PENDING", # Attaching
+ 15 => "PENDING" # Detaching
+ }
+
+ # SBC image states mapped to DeltaCloud
+ @@IMAGE_STATE_MAP = {
+ 0 => "UNAVAILABLE", # New
+ 1 => "AVAILABLE", # Available
+ 2 => "UNAVAILABLE", # Unavailable
+ 3 => "UNAVAILABLE", # Deleted
+ 4 => "UNAVAILABLE" # Capturing
+ }
+
+ # SBC location states mapped to DeltaCloud
+ @@LOCATION_STATE_MAP = {
+ 0 => "UNAVAILABLE", # Unavailable
+ 1 => "AVAILABLE" # Available
+ }
+
+ #
+ # Define state machine for instances
+ #
+ define_instance_states do
+ start.to( :pending ) .automatically
+ pending.to( :running ) .automatically
+ running.to( :running ) .on( :reboot )
+ running.to( :finish ) .on( :destroy )
+ end
+
+ #
+ # Creates an IBM SBC client
+ #
+ def new_client(credentials)
+ safely do
+ return SBCClient.new(credentials.user, credentials.password)
+ end
+ end
+
+ #
+ # Converts JSON to an instance
+ #
+ def convert_instance(instance)
+ state = @@INSTANCE_STATE_MAP[instance["status"]]
+ Instance.new(
+ :id => instance["id"],
+ :owner_id => instance["owner"],
+ :image_id => instance["imageId"],
+ :name => instance["name"],
+ :realm_id => instance["location"],
+ :state => state,
+ :actions => instance_actions_for(state),
+ :public_addresses => [instance["primaryIP"]["ip"]],
+ :private_addresses => [],
+ :instance_profile => InstanceProfile.new(instance["instanceType"]), # TODO: InstanceProfile isn't looking up HW profiles?
+ :launch_time => instance["launchTime"],
+ :keyname => instance["keyName"]
+ )
+ end
+
+ #
+ # Converts JSON to an image
+ #
+ def convert_image(image)
+ Image.new(
+ :id => image["id"],
+ :name => image["name"],
+ :owner_id => image["owner"],
+ :description => image["description"],
+ :architecture => "i386", # TODO: parse this from supportedInstanceType IDs w/ HW profile lookup
+ :state => @@IMAGE_STATE_MAP[image["state"]]
+ )
+ end
+
+ #
+ # Converts XML to a location
+ #
+ def convert_location(location)
+ Realm.new(
+ :id => location.xpath('ID').text,
+ :name => location.xpath('Name').text,
+ :limit => :unlimited,
+ :state => @@LOCATION_STATE_MAP[location.xpath('State').text.to_i]
+ )
+ end
+
+ #
+ # -------------------- Hardware Profiles -----------------
+ #
+ # TODO: HWP IDs contain '/'; results in invalid URL
+ #
+ define_hardware_profile('COP32.1/2048/60') do
+ cpu 1
+ memory 2 * 1024
+ storage 60
+ architecture 'i386'
+ end
+
+ define_hardware_profile('COP64.2/4096/60') do
+ cpu 2
+ memory 4 * 1024
+ storage 60
+ architecture 'i386_x64'
+ end
+
+ define_hardware_profile('BRZ32.1/2048/60*175') do
+ cpu 1
+ memory 2 * 1024
+ storage 175
+ architecture 'i386'
+ end
+
+ define_hardware_profile('BRZ64.2/4096/60*500*350') do
+ cpu 2
+ memory 4 * 1024
+ storage 850
+ architecture 'i386_x64'
+ end
+
+ define_hardware_profile('SLV32.2/4096/60*350') do
+ cpu 3
+ memory 5 * 1024
+ storage 350
+ architecture 'i386'
+ end
+
+ define_hardware_profile('SLV64.4/8192/60*500*500') do
+ cpu 4
+ memory 8 * 1024
+ storage 1024
+ architecture 'i386_x64'
+ end
+
+ define_hardware_profile('GLD32.4/4096/60*350') do
+ cpu 4
+ memory 4 * 1024
+ storage 350
+ architecture 'i386'
+ end
+
+ define_hardware_profile('GLD64.8/16384/60*500*500') do
+ cpu 8
+ memory 16 * 1024
+ storage 1024
+ architecture 'i386_x64'
+ end
+
+ define_hardware_profile('PLT64.16/16384/60*500*500*500*500') do
+ cpu 16
+ memory 16 * 1024
+ storage 2048
+ architecture 'i386_x64'
+ end
+end
+ end
+ end
+end
Modified: incubator/deltacloud/trunk/server/lib/drivers.rb
URL: http://svn.apache.org/viewvc/incubator/deltacloud/trunk/server/lib/drivers.rb?rev=1068240&r1=1068239&r2=1068240&view=diff
==============================================================================
--- incubator/deltacloud/trunk/server/lib/drivers.rb (original)
+++ incubator/deltacloud/trunk/server/lib/drivers.rb Tue Feb 8 00:45:57 2011
@@ -20,6 +20,7 @@
module Deltacloud
DRIVERS = {
:ec2 => { :name => "EC2" },
+ :sbc => { :name => "SBC" },
:rackspace => { :name => "Rackspace" },
:gogrid => { :name => "Gogrid" },
:rhevm => { :name => "RHEVM" },