openstack-compute 1.0.0 → 1.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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