You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@deltacloud.apache.org by mf...@redhat.com on 2011/02/14 16:19:35 UTC
[PATCH core 1/2] Revamped using 'cloudservers' gem (thanks Rackspace!)
From: Michal Fojtik <mf...@redhat.com>
---
.../drivers/rackspace/rackspace_client.rb | 130 --------------
.../drivers/rackspace/rackspace_driver.rb | 180 +++++++++++---------
server/lib/deltacloud/models/instance.rb | 2 +
server/views/instances/show.html.haml | 9 +
4 files changed, 109 insertions(+), 212 deletions(-)
delete mode 100644 server/lib/deltacloud/drivers/rackspace/rackspace_client.rb
diff --git a/server/lib/deltacloud/drivers/rackspace/rackspace_client.rb b/server/lib/deltacloud/drivers/rackspace/rackspace_client.rb
deleted file mode 100644
index d803302..0000000
--- a/server/lib/deltacloud/drivers/rackspace/rackspace_client.rb
+++ /dev/null
@@ -1,130 +0,0 @@
-#
-# Copyright (C) 2009, 2010 Red Hat, Inc.
-#
-# 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 "net/http"
-require "net/https"
-require 'rubygems'
-require 'json'
-
-#
-# author: Michael Neale
-# TODO: catch generic errors in JSON response and throw (probably)
-#
-module Deltacloud
- module Drivers
- module Rackspace
-
-class RackspaceClient
-
- @@AUTH_API = URI.parse('https://auth.api.rackspacecloud.com/v1.0')
-
- def initialize(username, auth_key)
- http = Net::HTTP.new(@@AUTH_API.host,@@AUTH_API.port)
- http.use_ssl = true
- authed = http.get(@@AUTH_API.path, {'X-Auth-User' => username, 'X-Auth-Key' => auth_key})
- if authed.is_a?(Net::HTTPUnauthorized)
- raise Deltacloud::AuthException, "Failed to authenticate to Rackspace"
- elsif !authed.is_a?(Net::HTTPSuccess)
- backend_error!(resp)
- end
- @auth_token = authed.header['X-Auth-Token']
- @service_uri = URI.parse(authed.header['X-Server-Management-Url'])
- @service = Net::HTTP.new(@service_uri.host, @service_uri.port)
- @service.use_ssl = true
- end
-
- def list_flavors
- JSON.parse(get('/flavors/detail'))['flavors']
- end
-
- def list_images
- JSON.parse(get('/images/detail'))['images']
- end
-
- def list_servers
- JSON.parse(get('/servers/detail'))['servers']
- end
-
-
- def load_server_details( server_id )
- JSON.parse(get("/servers/#{server_id}"))['server']
- end
-
-
- def start_server(image_id, flavor_id, name)
- json = { :server => { :name => name,
- :imageId => image_id.to_i,
- :flavorId => flavor_id.to_i }}.to_json
- # FIXME: The response has the root password in 'adminPass'; we somehow
- # need to communicate this back since it's the only place where we can
- # get it from
- JSON.parse(post("/servers", json, headers).body)["server"]
- end
-
- def delete_server(server_id)
- delete("/servers/#{server_id}", headers)
- end
-
- def reboot_server(server_id)
- json = { :reboot => { :type => :SOFT }}.to_json
- post("/servers/#{server_id}/action", json, headers)
- end
-
-
- def headers
- {"Accept" => "application/json", "X-Auth-Token" => @auth_token, "Content-Type" => "application/json"}
- end
-
- private
- def get(path)
- resp = @service.get(@service_uri.path + path, {"Accept" => "application/json", "X-Auth-Token" => @auth_token})
- unless resp.is_a?(Net::HTTPSuccess)
- backend_error!(resp)
- end
- resp.body
- end
-
- def post(path, json, headers)
- resp = @service.post(@service_uri.path + path, json, headers)
- unless resp.is_a?(Net::HTTPSuccess)
- backend_error!(resp)
- end
- resp
- end
-
- def delete(path, headers)
- resp = @service.delete(@service_uri.path + path, headers)
- unless resp.is_a?(Net::HTTPSuccess)
- backend_error!(resp)
- end
- resp
- end
-
- def backend_error!(resp)
- json = JSON.parse(resp.body)
- cause = json.keys[0]
- code = json[cause]["code"]
- message = json[cause]["message"]
- details = json[cause]["details"]
- raise Deltacloud::BackendError.new(code, cause, message, details)
- end
-
-end
- end
- end
-end
diff --git a/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb b/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
index 8d743aa..028b63a 100644
--- a/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
+++ b/server/lib/deltacloud/drivers/rackspace/rackspace_driver.rb
@@ -17,8 +17,8 @@
# under the License.
require 'deltacloud/base_driver'
-require 'deltacloud/drivers/rackspace/rackspace_client'
require 'cloudfiles'
+require 'cloudservers'
module Deltacloud
module Drivers
@@ -27,20 +27,21 @@ module Deltacloud
class RackspaceDriver < Deltacloud::BaseDriver
feature :instances, :user_name
+ feature :instances, :authentication_password
def supported_collections
DEFAULT_COLLECTIONS + [ :buckets ]
end
- def hardware_profiles(credentials, opts = nil)
- racks = new_client( credentials )
- results=""
+ def hardware_profiles(credentials, opts = {})
+ rs = new_client( credentials )
+ results = []
safely do
- results = racks.list_flavors.map do |flav|
- HardwareProfile.new(flav["id"].to_s) do
+ results = rs.list_flavors.collect do |f|
+ HardwareProfile.new(f[:id].to_s) do
architecture 'x86_64'
- memory flav["ram"].to_i
- storage flav["disk"].to_i
+ memory f[:ram].to_i
+ storage f[:disk].to_i
end
end
end
@@ -48,22 +49,21 @@ class RackspaceDriver < Deltacloud::BaseDriver
end
def images(credentials, opts=nil)
- racks = new_client( credentials )
- results=""
+ rs = new_client(credentials)
+ results = []
safely do
- results = racks.list_images.map do |img|
- Image.new( {
- :id=>img["id"].to_s,
- :name=>img["name"],
- :description => img["name"] + " " + img["status"] + "",
- :owner_id=>"root",
- :architecture=>'x86_64'
- } )
+ results = rs.list_images.collect do |img|
+ Image.new(
+ :id => img[:id].to_s,
+ :name => img[:name],
+ :description => img[:name],
+ :owner_id => credentials.user,
+ :state => img[:status],
+ :architecture => 'x86_64'
+ )
end
end
- results.sort_by{|e| [e.description]}
- results = filter_on( results, :id, opts )
- results
+ filter_on( results, :id, opts )
end
#rackspace does not at this stage have realms... its all US/TX, all the time (at least at time of writing)
@@ -75,67 +75,102 @@ class RackspaceDriver < Deltacloud::BaseDriver
} )]
end
- def reboot_instance(credentials, id)
- racks = new_client(credentials)
+ #
+ # create instance. Default to flavor 1 - really need a name though...
+ # In rackspace, all flavors work with all images.
+ #
+ def create_instance(credentials, image_id, opts)
+ rs = new_client( credentials )
+ result = nil
safely do
- racks.reboot_server(id)
+ server = rs.create_server(:name => opts[:name] || Time.now.to_s,
+ :imageId => image_id.to_i,
+ :flavorId => opts[:hwp_id].to_i || hardware_profiles(credentials).first.id.to_i)
+ result = convert_instance_after_create(server, credentials.user, server.adminPass)
end
- Instance.new( {
- :id => id,
- :state => "RUNNING",
- :actions => instance_actions_for( "RUNNING" ),
- } )
+ result
end
- def stop_instance(credentials, id)
- destroy_instance(credentials, id)
+ def reboot_instance(credentials, instance_id)
+ rs = new_client(credentials)
+ safely do
+ server = rs.get_server(instance_id.to_i)
+ server.reboot!
+ convert_instance_after_create(server, credentials.user)
+ end
end
- def destroy_instance(credentials, id)
- racks = new_client(credentials)
+ def destroy_instance(credentials, instance_id)
+ rs = new_client(credentials)
safely do
- racks.delete_server(id)
+ server = rs.get_server(instance_id.to_i)
+ server.delete!
+ convert_instance_after_create(server, credentials.user)
end
- Instance.new( {
- :id => id,
- :state => "STOPPED",
- :actions => instance_actions_for( "STOPPED" ),
- } )
end
+ alias_method :stop_instance, :destroy_instance
+
+ def convert_instance_after_create(server, user_name, password='')
+ inst = Instance.new(
+ :id => server.id.to_s,
+ :realm_id => 'us',
+ :owner_id => user_name,
+ :description => server.name,
+ :name => server.name,
+ :state => (server.status == 'ACTIVE') ? 'RUNNING' : 'PENDING',
+ :architecture => 'x86_64',
+ :image_id => server.imageId.to_s,
+ :instance_profile => InstanceProfile::new(server.flavorId.to_s),
+ :public_addresses => server.addresses[:public],
+ :private_addresses => server.addresses[:private],
+ :username => 'root',
+ :password => password ? password : nil
+ )
+ inst.actions = instance_actions_for(inst.state)
+ inst
+ end
- #
- # create instance. Default to flavor 1 - really need a name though...
- # In rackspace, all flavors work with all images.
- #
- def create_instance(credentials, image_id, opts)
- racks = new_client( credentials )
- hwp_id = opts[:hwp_id] || 1
- name = Time.now.to_s
- if (opts[:name]) then name = opts[:name] end
- safely do
- return convert_srv_to_instance(racks.start_server(image_id, hwp_id, name))
- end
+ def convert_instance(server, user_name = '')
+ inst = Instance.new(
+ :id => server[:id].to_s,
+ :realm_id => 'us',
+ :owner_id => user_name,
+ :description => server[:name],
+ :name => server[:name],
+ :state => (server[:status] == 'ACTIVE') ? 'RUNNING' : 'PENDING',
+ :architecture => 'x86_64',
+ :image_id => server[:imageId].to_s,
+ :instance_profile => InstanceProfile::new(server[:flavorId].to_s),
+ :public_addresses => server[:addresses][:public],
+ :private_addresses => server[:addresses][:private]
+ )
+ inst.actions = instance_actions_for(inst.state)
+ inst
end
#
# Instances
#
- def instances(credentials, opts=nil)
- racks = new_client(credentials)
- instances = []
+ def instances(credentials, opts={})
+
+ rs = new_client(credentials)
+ insts = []
+
safely do
- if (opts.nil?)
- instances = racks.list_servers.map do |srv|
- convert_srv_to_instance(srv)
- end
+ if opts[:id]
+ server = rs.get_server(opts[:id].to_i)
+ insts << convert_instance_after_create(server, credentials.user)
else
- instances << convert_srv_to_instance(racks.load_server_details(opts[:id]))
+ insts = rs.list_servers_detail.collect do |server|
+ convert_instance(server, credentials.user)
+ end
end
end
- instances = filter_on( instances, :id, opts )
- instances = filter_on( instances, :state, opts )
- instances
+
+ insts = filter_on( insts, :id, opts )
+ insts = filter_on( insts, :state, opts )
+ insts
end
def valid_credentials?(credentials)
@@ -149,14 +184,10 @@ class RackspaceDriver < Deltacloud::BaseDriver
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
@@ -290,25 +321,10 @@ class RackspaceDriver < Deltacloud::BaseDriver
private
- def convert_srv_to_instance(srv)
- inst = Instance.new(:id => srv["id"].to_s,
- :owner_id => "root",
- :realm_id => "us")
- inst.name = srv["name"]
- inst.state = srv["status"] == "ACTIVE" ? "RUNNING" : "PENDING"
- inst.actions = instance_actions_for(inst.state)
- inst.image_id = srv["imageId"].to_s
- inst.instance_profile = InstanceProfile.new(srv["flavorId"].to_s)
- if srv["addresses"]
- inst.public_addresses = srv["addresses"]["public"]
- inst.private_addresses = srv["addresses"]["private"]
- end
- inst
- end
def new_client(credentials)
safely do
- return RackspaceClient.new(credentials.user, credentials.password)
+ CloudServers::Connection.new(:username => credentials.user, :api_key => credentials.password)
end
end
diff --git a/server/lib/deltacloud/models/instance.rb b/server/lib/deltacloud/models/instance.rb
index 467d93f..6345590 100644
--- a/server/lib/deltacloud/models/instance.rb
+++ b/server/lib/deltacloud/models/instance.rb
@@ -30,6 +30,8 @@ class Instance < BaseModel
attr_accessor :launch_time
attr_accessor :keyname
attr_accessor :authn_error
+ attr_accessor :username
+ attr_accessor :password
def to_s
name
diff --git a/server/views/instances/show.html.haml b/server/views/instances/show.html.haml
index 0a6e115..76d77ba 100644
--- a/server/views/instances/show.html.haml
+++ b/server/views/instances/show.html.haml
@@ -36,6 +36,15 @@
%dt Private Addresses
%dd
= @instance.private_addresses.collect { |address| "<div>#{address}</div>" }.join
+ - if @instance.password
+ %di
+ %dt Username
+ %dd
+ = @instance.username
+ %di
+ %dt Password
+ %dd
+ = @instance.password
%di
%dt
%dd
--
1.7.4
Re: [PATCH core 1/2] Revamped using 'cloudservers' gem (thanks
Rackspace!)
Posted by David Lutterkort <lu...@redhat.com>.
On Tue, 2011-02-15 at 11:15 +0100, Michal Fojtik wrote:
> On 14/02/11 17:20 -0800, David Lutterkort wrote:
> >Make sure you also update the gemspec/Gemfile to reflect the new
> >dependencies.
>
> Sure, thanks for noticing this.
> Btw. David we should create some wrapper for our drivers, which will
> check if all needed gems are present and if they are not, they should
> be installed using Bundler or just throw some notification to user to
> indicate that they are needed.
We should just produce a correct Gemfile/gemspec ;) Of course, that
could be greatly aided by a doodad that intercepts require and records
what libraries/gems are needed by what driver.
David
Re: [PATCH core 1/2] Revamped using 'cloudservers' gem (thanks
Rackspace!)
Posted by Michal Fojtik <mf...@redhat.com>.
On 14/02/11 17:20 -0800, David Lutterkort wrote:
>On Mon, 2011-02-14 at 16:19 +0100, mfojtik@redhat.com wrote:
>> From: Michal Fojtik <mf...@redhat.com>
>>
>> ---
>> .../drivers/rackspace/rackspace_client.rb | 130 --------------
>> .../drivers/rackspace/rackspace_driver.rb | 180 +++++++++++---------
>> server/lib/deltacloud/models/instance.rb | 2 +
>> server/views/instances/show.html.haml | 9 +
>> 4 files changed, 109 insertions(+), 212 deletions(-)
>> delete mode 100644 server/lib/deltacloud/drivers/rackspace/rackspace_client.rb
>
>Make sure you also update the gemspec/Gemfile to reflect the new
>dependencies.
Sure, thanks for noticing this.
Btw. David we should create some wrapper for our drivers, which will
check if all needed gems are present and if they are not, they should
be installed using Bundler or just throw some notification to user to
indicate that they are needed.
-- Michal
>
>David
>
>
--
--------------------------------------------------------
Michal Fojtik, mfojtik@redhat.com
Deltacloud API: http://deltacloud.org
--------------------------------------------------------
Re: [PATCH core 1/2] Revamped using 'cloudservers' gem (thanks
Rackspace!)
Posted by David Lutterkort <lu...@redhat.com>.
On Mon, 2011-02-14 at 16:19 +0100, mfojtik@redhat.com wrote:
> From: Michal Fojtik <mf...@redhat.com>
>
> ---
> .../drivers/rackspace/rackspace_client.rb | 130 --------------
> .../drivers/rackspace/rackspace_driver.rb | 180 +++++++++++---------
> server/lib/deltacloud/models/instance.rb | 2 +
> server/views/instances/show.html.haml | 9 +
> 4 files changed, 109 insertions(+), 212 deletions(-)
> delete mode 100644 server/lib/deltacloud/drivers/rackspace/rackspace_client.rb
Make sure you also update the gemspec/Gemfile to reflect the new
dependencies.
David