openstack-compute 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -1,8 +1,10 @@
1
- = Ruby OpenStack
1
+ = Ruby OpenStack Compute
2
2
 
3
3
  == Description
4
4
 
5
- Ruby Openstack Compute binding.
5
+ Ruby Openstack Compute binding for the v1.0 OSAPI.
6
+
7
+ Currently supports both v1.0 and v2.0 (keystone) auth.
6
8
 
7
9
  == Examples
8
10
 
@@ -10,7 +12,7 @@ See the class definitions for documentation on specific methods and operations.
10
12
 
11
13
  require 'openstack/compute'
12
14
 
13
- cs = OpenStack::Compute::Connection.new(:username => USERNAME, :api_key => API_KEY, :api_url => API_URL)
15
+ cs = OpenStack::Compute::Connection.new(:username => USERNAME, :api_key => API_KEY, :auth_url => API_URL)
14
16
 
15
17
  # Get a listing of all current servers
16
18
  >> cs.servers
@@ -63,7 +65,7 @@ See the class definitions for documentation on specific methods and operations.
63
65
 
64
66
  == Authors
65
67
 
66
- By Dan Prince <dan.prince@rackspace.com>.
68
+ By Dan Prince <dan.prince@rackspace.com>, Naveed Massjouni <naveedm9@gmail.com>
67
69
 
68
70
  Based on the Rackspace Cloud Servers Ruby API.
69
71
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.0.0
1
+ 1.0.1
@@ -9,7 +9,7 @@
9
9
  # To begin reviewing the available methods and examples, view the README.rdoc file, or begin by looking at documentation for the OpenStack::Compute::Connection class.
10
10
  #
11
11
  # Example:
12
- # OpenStack::Compute::Connection.new(:username => USERNAME, :api_key => API_KEY, :api_url => API_URL) method.
12
+ # OpenStack::Compute::Connection.new(:username => USERNAME, :api_key => API_KEY, :auth_url => API_URL) method.
13
13
  module OpenStack
14
14
  module Compute
15
15
 
@@ -1,19 +1,70 @@
1
1
  module OpenStack
2
2
  module Compute
3
+
3
4
  class Authentication
5
+
6
+ # Performs an authentication to the OpenStack auth server.
7
+ # If it succeeds, it sets the svrmgmthost, svrmgtpath, svrmgmtport,
8
+ # svrmgmtscheme, authtoken, and authok variables on the connection.
9
+ # If it fails, it raises an exception.
10
+ def self.init(conn)
11
+ if conn.auth_path =~ /.*v2.0\/tokens$/
12
+ AuthV20.new(conn)
13
+ else
14
+ AuthV10.new(conn)
15
+ end
16
+ end
17
+
18
+ end
19
+
20
+ private
21
+ class AuthV20
22
+
23
+ def initialize(connection)
24
+ begin
25
+ server = Net::HTTP::Proxy(connection.proxy_host, connection.proxy_port).new(connection.auth_host, connection.auth_port)
26
+ if connection.auth_scheme == "https"
27
+ server.use_ssl = true
28
+ server.verify_mode = OpenSSL::SSL::VERIFY_NONE
29
+ end
30
+ server.start
31
+ rescue
32
+ raise OpenStack::Compute::Exception::Connection, "Unable to connect to #{server}"
33
+ end
34
+
35
+ auth_data = JSON.generate({ "passwordCredentials" => { "username" => connection.authuser, "password" => connection.authkey }})
36
+ response = server.post(connection.auth_path, auth_data, {'Content-Type' => 'application/json'})
37
+ if (response.code =~ /^20./)
38
+ resp_data=JSON.parse(response.body)
39
+ connection.authtoken = resp_data['auth']['token']['id']
40
+ if resp_data['auth']['serviceCatalog'] and resp_data['auth']['serviceCatalog'][connection.service_name] and resp_data['auth']['serviceCatalog'][connection.service_name][0] then
41
+ uri = URI.parse(resp_data['auth']['serviceCatalog'][connection.service_name][0]['publicURL'])
42
+ connection.svrmgmthost = uri.host
43
+ connection.svrmgmtpath = uri.path
44
+ # Force the path into the v1.0 URL space
45
+ connection.svrmgmtpath.sub!(/\/.*\/?/, '/v1.0/')
46
+ connection.svrmgmtport = uri.port
47
+ connection.svrmgmtscheme = uri.scheme
48
+ connection.authok = true
49
+ else
50
+ connection.authok = false
51
+ end
52
+ else
53
+ connection.authtoken = false
54
+ raise OpenStack::Compute::Exception::Authentication, "Authentication failed with response code #{response.code}"
55
+ end
56
+ server.finish
57
+ end
58
+ end
59
+
60
+ class AuthV10
4
61
 
5
- # Performs an authentication to the OpenStack authorization servers. Opens a new HTTP connection to the API server,
6
- # sends the credentials, and looks for a successful authentication. If it succeeds, it sets the svrmgmthost,
7
- # svrmgtpath, svrmgmtport, svrmgmtscheme, authtoken, and authok variables on the connection. If it fails, it raises
8
- # an exception.
9
- #
10
- # Should probably never be called directly.
11
62
  def initialize(connection)
12
63
  path = '/v1.0'
13
64
  hdrhash = { "X-Auth-User" => connection.authuser, "X-Auth-Key" => connection.authkey }
14
65
  begin
15
- server = Net::HTTP::Proxy(connection.proxy_host, connection.proxy_port).new(connection.api_host, connection.api_port)
16
- if connection.api_scheme == "https"
66
+ server = Net::HTTP::Proxy(connection.proxy_host, connection.proxy_port).new(connection.auth_host, connection.auth_port)
67
+ if connection.auth_scheme == "https"
17
68
  server.use_ssl = true
18
69
  server.verify_mode = OpenSSL::SSL::VERIFY_NONE
19
70
  end
@@ -24,12 +75,13 @@ module Compute
24
75
  response = server.get(path,hdrhash)
25
76
  if (response.code =~ /^20./)
26
77
  connection.authtoken = response["x-auth-token"]
27
- connection.svrmgmthost = URI.parse(response["x-server-management-url"]).host
28
- connection.svrmgmtpath = URI.parse(response["x-server-management-url"]).path
78
+ uri = URI.parse(response["x-server-management-url"])
79
+ connection.svrmgmthost = uri.host
80
+ connection.svrmgmtpath = uri.path
29
81
  # Force the path into the v1.0 URL space
30
- connection.svrmgmtpath.sub!(/\/.*?\//, '/v1.0/')
31
- connection.svrmgmtport = URI.parse(response["x-server-management-url"]).port
32
- connection.svrmgmtscheme = URI.parse(response["x-server-management-url"]).scheme
82
+ connection.svrmgmtpath.sub!(/\/.*\/?/, '/v1.0/')
83
+ connection.svrmgmtport = uri.port
84
+ connection.svrmgmtscheme = uri.scheme
33
85
  connection.authok = true
34
86
  else
35
87
  connection.authtoken = false
@@ -38,5 +90,6 @@ module Compute
38
90
  server.finish
39
91
  end
40
92
  end
93
+
41
94
  end
42
95
  end
@@ -10,9 +10,11 @@ module Compute
10
10
  attr_accessor :svrmgmtpath
11
11
  attr_accessor :svrmgmtport
12
12
  attr_accessor :svrmgmtscheme
13
- attr_reader :api_host
14
- attr_reader :api_port
15
- attr_reader :api_scheme
13
+ attr_reader :auth_host
14
+ attr_reader :auth_port
15
+ attr_reader :auth_scheme
16
+ attr_reader :auth_path
17
+ attr_accessor :service_name
16
18
  attr_reader :proxy_host
17
19
  attr_reader :proxy_port
18
20
 
@@ -22,34 +24,37 @@ module Compute
22
24
  #
23
25
  # :username - Your Openstack username *required*
24
26
  # :api_key - Your Openstack API key *required*
25
- # :api_url - The url of the Openstack Compute API server.
27
+ # :auth_url - Configurable auth_url endpoint.
28
+ # :service_name - (Optional for v2.0 auth only). The name of the compute service to use. Defaults to 'nova'.
26
29
  # :retry_auth - Whether to retry if your auth token expires (defaults to true)
27
30
  # :proxy_host - If you need to connect through a proxy, supply the hostname here
28
31
  # :proxy_port - If you need to connect through a proxy, supply the port here
29
32
  #
30
- # cf = OpenStack::Compute::Connection.new(:username => 'USERNAME', :api_key => 'API_KEY', :api_url => 'API_URL')
33
+ # cf = OpenStack::Compute::Connection.new(:username => 'USERNAME', :api_key => 'API_KEY', :auth_url => 'AUTH_URL')
31
34
  def initialize(options = {:retry_auth => true})
32
35
  @authuser = options[:username] || (raise Exception::MissingArgument, "Must supply a :username")
33
36
  @authkey = options[:api_key] || (raise Exception::MissingArgument, "Must supply an :api_key")
34
- @api_url = options[:api_url] || (raise Exception::MissingArgument, "Must supply an :api_url")
37
+ @auth_url = options[:auth_url] || (raise Exception::MissingArgument, "Must supply an :auth_url")
38
+ @service_name = options[:service_name] || "nova"
35
39
 
36
- api_uri=nil
40
+ auth_uri=nil
37
41
  begin
38
- api_uri=URI.parse(@api_url)
42
+ auth_uri=URI.parse(@auth_url)
39
43
  rescue Exception => e
40
- raise Exception::InvalidArgument, "Invalid :api_url parameter: #{e.message}"
44
+ raise Exception::InvalidArgument, "Invalid :auth_url parameter: #{e.message}"
41
45
  end
42
- raise Exception::InvalidArgument, "Invalid :api_url parameter." if api_uri.nil? or api_uri.host.nil?
43
- @api_host = api_uri.host
44
- @api_port = api_uri.port
45
- @api_scheme = api_uri.scheme
46
+ raise Exception::InvalidArgument, "Invalid :auth_url parameter." if auth_uri.nil? or auth_uri.host.nil?
47
+ @auth_host = auth_uri.host
48
+ @auth_port = auth_uri.port
49
+ @auth_scheme = auth_uri.scheme
50
+ @auth_path = auth_uri.path
46
51
 
47
52
  @retry_auth = options[:retry_auth]
48
53
  @proxy_host = options[:proxy_host]
49
54
  @proxy_port = options[:proxy_port]
50
55
  @authok = false
51
56
  @http = {}
52
- OpenStack::Compute::Authentication.new(self)
57
+ OpenStack::Compute::Authentication.init(self)
53
58
  end
54
59
 
55
60
  # Returns true if the authentication was successful and returns false otherwise.
@@ -79,7 +84,7 @@ module Compute
79
84
  retry
80
85
  rescue OpenStack::Compute::Exception::ExpiredAuthToken
81
86
  raise OpenStack::Compute::Exception::Connection, "Authentication token expired and you have requested not to retry" if @retry_auth == false
82
- OpenStack::Compute::Authentication.new(self)
87
+ OpenStack::Compute::Authentication.init(self)
83
88
  retry
84
89
  end
85
90
 
@@ -0,0 +1,36 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class AuthenticationTest < Test::Unit::TestCase
4
+
5
+ def test_good_authentication
6
+ response = {'x-server-management-url' => 'http://server-manage.example.com/path', 'x-auth-token' => 'dummy_token'}
7
+ response.stubs(:code).returns('204')
8
+ server = mock(:use_ssl= => true, :verify_mode= => true, :start => true, :finish => true)
9
+ server.stubs(:get).returns(response)
10
+ Net::HTTP.stubs(:new).returns(server)
11
+ connection = stub(:authuser => 'bad_user', :authkey => 'bad_key', :auth_host => "a.b.c", :auth_port => "443", :auth_scheme => "https", :auth_path => "/v1.0", :authok= => true, :authtoken= => true, :svrmgmthost= => "", :svrmgmtpath= => "", :svrmgmtpath => "", :svrmgmtport= => "", :svrmgmtscheme= => "", :proxy_host => nil, :proxy_port => nil)
12
+ result = OpenStack::Compute::Authentication.init(connection)
13
+ assert_equal result.class, OpenStack::Compute::AuthV10
14
+ end
15
+
16
+ def test_bad_authentication
17
+ response = mock()
18
+ response.stubs(:code).returns('499')
19
+ server = mock(:use_ssl= => true, :verify_mode= => true, :start => true)
20
+ server.stubs(:get).returns(response)
21
+ Net::HTTP.stubs(:new).returns(server)
22
+ connection = stub(:authuser => 'bad_user', :authkey => 'bad_key', :auth_host => "a.b.c", :auth_port => "443", :auth_scheme => "https", :auth_path => "/v1.0", :authok= => true, :authtoken= => true, :proxy_host => nil, :proxy_port => nil)
23
+ assert_raises(OpenStack::Compute::Exception::Authentication) do
24
+ result = OpenStack::Compute::Authentication.init(connection)
25
+ end
26
+ end
27
+
28
+ def test_bad_hostname
29
+ Net::HTTP.stubs(:new).raises(OpenStack::Compute::Exception::Connection)
30
+ connection = stub(:authuser => 'bad_user', :authkey => 'bad_key', :auth_host => "a.b.c", :auth_port => "443", :auth_scheme => "https", :auth_path => "/v1.0", :authok= => true, :authtoken= => true, :proxy_host => nil, :proxy_port => nil)
31
+ assert_raises(OpenStack::Compute::Exception::Connection) do
32
+ result = OpenStack::Compute::Authentication.init(connection)
33
+ end
34
+ end
35
+
36
+ end
@@ -0,0 +1,39 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class ComputeConnectionTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ connection = stub()
7
+ OpenStack::Compute::Authentication.stubs(:init).returns(connection)
8
+ end
9
+
10
+ def test_init_connection_no_credentials
11
+ assert_raises(OpenStack::Compute::Exception::MissingArgument) do
12
+ conn = OpenStack::Compute::Connection.new(:api_key => "AABBCCDD11", :auth_url => "a.b.c")
13
+ end
14
+ end
15
+
16
+ def test_init_connection_no_password
17
+ assert_raises(OpenStack::Compute::Exception::MissingArgument) do
18
+ conn = OpenStack::Compute::Connection.new(:username => "test_account", :auth_url => "a.b.c")
19
+ end
20
+ end
21
+
22
+ def test_init_connection_no_auth_url
23
+ assert_raises(OpenStack::Compute::Exception::MissingArgument) do
24
+ conn = OpenStack::Compute::Connection.new(:username => "test_account", :api_key => "AABBCCDD11")
25
+ end
26
+ end
27
+
28
+ def test_init_connection_bad_auth_url
29
+ assert_raises(OpenStack::Compute::Exception::InvalidArgument) do
30
+ conn = OpenStack::Compute::Connection.new(:username => "test_account", :api_key => "AABBCCDD11", :auth_url => "***")
31
+ end
32
+ end
33
+
34
+ def test_init_connection
35
+ conn = OpenStack::Compute::Connection.new(:username => "test_account", :api_key => "AABBCCDD11", :auth_url => "https://a.b.c")
36
+ assert_not_nil conn, "Connection.new returned nil."
37
+ end
38
+
39
+ end
@@ -0,0 +1,49 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class ExceptionTest < Test::Unit::TestCase
4
+
5
+ def test_400_cloud_servers_fault
6
+ response = mock()
7
+ response.stubs(:code => "400", :body => "{\"ComputeFault\":{\"message\":\"422 Unprocessable Entity: We could not process your request at this time. We have been notified and are looking into the issue. [E03]\",\"details\":\"com.rackspace.cloud.service.servers.OpenStack::ComputeFault: Fault occured\",\"code\":400}}" )
8
+ exception=nil
9
+ begin
10
+ OpenStack::Compute::Exception.raise_exception(response)
11
+ rescue Exception => e
12
+ exception=e
13
+ end
14
+ assert_equal(OpenStack::Compute::Exception::ComputeFault, e.class)
15
+ assert_equal("400", e.response_code)
16
+ assert_not_nil(e.response_body)
17
+ end
18
+
19
+ def test_413_over_limit
20
+ response = mock()
21
+ response.stubs(:code => "413", :body => "{\"overLimit\":{\"message\":\"Too many requests...\",\"code\":413,\"retryAfter\":\"2010-08-25T10:47:57.890-05:00\"}}")
22
+ exception=nil
23
+ begin
24
+ OpenStack::Compute::Exception.raise_exception(response)
25
+ rescue Exception => e
26
+ exception=e
27
+ end
28
+ assert_equal(OpenStack::Compute::Exception::OverLimit, e.class)
29
+ assert_equal("413", e.response_code)
30
+ assert_not_nil(e.response_body)
31
+ end
32
+
33
+ def test_other
34
+ response = mock()
35
+ body="{\"blahblah\":{\"message\":\"Failed...\",\"code\":500}}"
36
+ response.stubs(:code => "500", :body => body)
37
+ exception=nil
38
+ begin
39
+ OpenStack::Compute::Exception.raise_exception(response)
40
+ rescue Exception => e
41
+ exception=e
42
+ end
43
+ assert_equal(OpenStack::Compute::Exception::Other, exception.class)
44
+ assert_equal("500", exception.response_code)
45
+ assert_not_nil(exception.response_body)
46
+ assert_equal(body, exception.response_body)
47
+ end
48
+
49
+ end
@@ -0,0 +1,123 @@
1
+ require File.dirname(__FILE__) + '/test_helper'
2
+
3
+ class ServersTest < Test::Unit::TestCase
4
+
5
+ include TestConnection
6
+
7
+ def setup
8
+ @conn=get_test_connection
9
+ end
10
+
11
+ def test_list_servers
12
+
13
+ json_response = %{{
14
+ "servers" : [
15
+ {
16
+ "id" : 1234,
17
+ "name" : "sample-server",
18
+ "imageId" : 2,
19
+ "flavorId" : 1,
20
+ "hostId" : "e4d909c290d0fb1ca068ffaddf22cbd0",
21
+ "status" : "BUILD",
22
+ "progress" : 60,
23
+ "addresses" : {
24
+ "public" : [
25
+ "67.23.10.132",
26
+ "67.23.10.131"
27
+ ],
28
+ "private" : [
29
+ "10.176.42.16"
30
+ ]
31
+ },
32
+ "metadata" : {
33
+ "Server Label" : "Web Head 1",
34
+ "Image Version" : "2.1"
35
+ }
36
+ },
37
+ {
38
+ "id" : 5678,
39
+ "name" : "sample-server2",
40
+ "imageId" : 2,
41
+ "flavorId" : 1,
42
+ "hostId" : "9e107d9d372bb6826bd81d3542a419d6",
43
+ "status" : "ACTIVE",
44
+ "addresses" : {
45
+ "public" : [
46
+ "67.23.10.133"
47
+ ],
48
+ "private" : [
49
+ "10.176.42.17"
50
+ ]
51
+ },
52
+ "metadata" : {
53
+ "Server Label" : "DB 1"
54
+ }
55
+ }
56
+ ]
57
+ }}
58
+ response = mock()
59
+ response.stubs(:code => "200", :body => json_response)
60
+
61
+ @conn.stubs(:csreq).returns(response)
62
+ servers=@conn.list_servers
63
+
64
+ assert_equal 2, servers.size
65
+ assert_equal 1234, servers[0][:id]
66
+ assert_equal "sample-server", servers[0][:name]
67
+
68
+ end
69
+
70
+ def test_get_server
71
+
72
+ server=get_test_server
73
+ assert "sample-server", server.name
74
+ assert "2", server.imageId
75
+ assert "1", server.flavorId
76
+ assert "e4d909c290d0fb1ca068ffaddf22cbd0", server.hostId
77
+ assert "BUILD", server.status
78
+ assert "60", server.progress
79
+ assert "67.23.10.132", server.addresses[:public][0]
80
+ assert "67.23.10.131", server.addresses[:public][1]
81
+ assert "10.176.42.16", server.addresses[:private][1]
82
+
83
+ end
84
+
85
+ private
86
+ def get_test_server
87
+
88
+ json_response = %{{
89
+ "server" : {
90
+ "id" : 1234,
91
+ "name" : "sample-server",
92
+ "imageId" : 2,
93
+ "flavorId" : 1,
94
+ "hostId" : "e4d909c290d0fb1ca068ffaddf22cbd0",
95
+ "status" : "BUILD",
96
+ "progress" : 60,
97
+ "addresses" : {
98
+ "public" : [
99
+ "67.23.10.132",
100
+ "67.23.10.131"
101
+ ],
102
+ "private" : [
103
+ "10.176.42.16"
104
+ ]
105
+ },
106
+ "metadata" : {
107
+ "Server Label" : "Web Head 1",
108
+ "Image Version" : "2.1"
109
+ }
110
+ }
111
+ }}
112
+
113
+ response = mock()
114
+ response.stubs(:code => "200", :body => json_response)
115
+
116
+ @conn=get_test_connection
117
+
118
+ @conn.stubs(:csreq).returns(response)
119
+ return @conn.server(1234)
120
+
121
+ end
122
+
123
+ end
@@ -0,0 +1,23 @@
1
+ require 'test/unit'
2
+ $:.unshift File.dirname(__FILE__) + '/../lib'
3
+ require 'openstack/compute'
4
+ require 'rubygems'
5
+ require 'mocha'
6
+
7
+ module TestConnection
8
+
9
+ def get_test_connection
10
+
11
+ conn_response = {'x-server-management-url' => 'http://server-manage.example.com/path', 'x-auth-token' => 'dummy_token'}
12
+ conn_response.stubs(:code).returns('204')
13
+ #server = mock(:use_ssl= => true, :verify_mode= => true, :start => true, :finish => true)
14
+ server = mock(:start => true, :finish => true)
15
+ server.stubs(:get => conn_response, :use_ssl= => true, :verify_mode= => true)
16
+ #server.stubs(:get).returns(conn_response)
17
+ Net::HTTP.stubs(:new).returns(server)
18
+
19
+ OpenStack::Compute::Connection.new(:username => "test_account", :api_key => "AABBCCDD11", :auth_url => "http://a.b.c")
20
+
21
+ end
22
+
23
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: openstack-compute
3
3
  version: !ruby/object:Gem::Version
4
- hash: 23
4
+ hash: 21
5
5
  prerelease: false
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
- - 0
10
- version: 1.0.0
9
+ - 1
10
+ version: 1.0.1
11
11
  platform: ruby
12
12
  authors:
13
13
  - Dan Prince
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-08-12 00:00:00 -04:00
18
+ date: 2011-08-29 00:00:00 -04:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency
@@ -51,6 +51,11 @@ files:
51
51
  - lib/openstack/compute/flavor.rb
52
52
  - lib/openstack/compute/image.rb
53
53
  - lib/openstack/compute/server.rb
54
+ - test/authentication_test.rb
55
+ - test/exception_test.rb
56
+ - test/test_helper.rb
57
+ - test/connection_test.rb
58
+ - test/servers_test.rb
54
59
  has_rdoc: true
55
60
  homepage: https://launchpad.net/ruby-openstack-compute
56
61
  licenses: []
@@ -85,5 +90,9 @@ rubygems_version: 1.3.7
85
90
  signing_key:
86
91
  specification_version: 3
87
92
  summary: OpenStack Compute Ruby API
88
- test_files: []
89
-
93
+ test_files:
94
+ - test/authentication_test.rb
95
+ - test/exception_test.rb
96
+ - test/test_helper.rb
97
+ - test/connection_test.rb
98
+ - test/servers_test.rb