dropmyemail-openstack 1.0.9
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +7 -0
- data/README.rdoc +371 -0
- data/VERSION +1 -0
- data/lib/openstack.rb +112 -0
- data/lib/openstack/compute/address.rb +68 -0
- data/lib/openstack/compute/connection.rb +412 -0
- data/lib/openstack/compute/flavor.rb +35 -0
- data/lib/openstack/compute/image.rb +73 -0
- data/lib/openstack/compute/metadata.rb +116 -0
- data/lib/openstack/compute/personalities.rb +23 -0
- data/lib/openstack/compute/server.rb +254 -0
- data/lib/openstack/connection.rb +494 -0
- data/lib/openstack/image/connection.rb +16 -0
- data/lib/openstack/swift/connection.rb +185 -0
- data/lib/openstack/swift/container.rb +214 -0
- data/lib/openstack/swift/storage_object.rb +311 -0
- data/lib/openstack/volume/connection.rb +123 -0
- data/lib/openstack/volume/snapshot.rb +25 -0
- data/lib/openstack/volume/volume.rb +31 -0
- data/test/authentication_test.rb +134 -0
- data/test/connection_test.rb +39 -0
- data/test/exception_test.rb +49 -0
- data/test/metadata_test.rb +210 -0
- data/test/servers_test.rb +210 -0
- data/test/test_helper.rb +22 -0
- metadata +123 -0
@@ -0,0 +1,123 @@
|
|
1
|
+
module OpenStack
|
2
|
+
module Volume
|
3
|
+
|
4
|
+
class Connection
|
5
|
+
|
6
|
+
attr_accessor :connection
|
7
|
+
attr_reader :volumes_native
|
8
|
+
|
9
|
+
def initialize(connection)
|
10
|
+
@connection = connection
|
11
|
+
OpenStack::Authentication.init(@connection)
|
12
|
+
@volumes_native, @volume_path = check_if_native("volumes")
|
13
|
+
@snapshots_native, @snapshot_path = check_if_native("snapshots")
|
14
|
+
end
|
15
|
+
|
16
|
+
# Returns true if the authentication was successful and returns false otherwise.
|
17
|
+
#
|
18
|
+
# cs.authok?
|
19
|
+
# => true
|
20
|
+
def authok?
|
21
|
+
@connection.authok
|
22
|
+
end
|
23
|
+
|
24
|
+
#require params: {:display_name, :size}
|
25
|
+
#optional params: {:display_description, :metadata=>{:key=>val, ...}, :availability_zone, :volume_type }
|
26
|
+
#returns OpenStack::Volume::Volume object
|
27
|
+
def create_volume(options)
|
28
|
+
raise OpenStack::Exception::MissingArgument, ":display_name and :size must be specified to create a volume" unless (options[:display_name] && options[:size])
|
29
|
+
data = JSON.generate(:volume => options)
|
30
|
+
response = @connection.csreq("POST",@connection.service_host,"#{@connection.service_path}/#{@volume_path}",@connection.service_port,@connection.service_scheme,{'content-type' => 'application/json'},data)
|
31
|
+
OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
|
32
|
+
volume_info = JSON.parse(response.body)["volume"]
|
33
|
+
volume = OpenStack::Volume::Volume.new(volume_info)
|
34
|
+
end
|
35
|
+
|
36
|
+
#no options documented in API at Nov 2012
|
37
|
+
#(e.g. like limit/marker as used in Nova for servers)
|
38
|
+
def list_volumes
|
39
|
+
response = @connection.req("GET", "/#{@volume_path}")
|
40
|
+
volumes_hash = JSON.parse(response.body)["volumes"]
|
41
|
+
volumes_hash.inject([]){|res, current| res << OpenStack::Volume::Volume.new(current); res}
|
42
|
+
end
|
43
|
+
alias :volumes :list_volumes
|
44
|
+
|
45
|
+
|
46
|
+
def get_volume(vol_id)
|
47
|
+
response = @connection.req("GET", "/#{@volume_path}/#{vol_id}")
|
48
|
+
volume_hash = JSON.parse(response.body)["volume"]
|
49
|
+
OpenStack::Volume::Volume.new(volume_hash)
|
50
|
+
end
|
51
|
+
alias :volume :get_volume
|
52
|
+
|
53
|
+
def delete_volume(vol_id)
|
54
|
+
response = @connection.req("DELETE", "/#{@volume_path}/#{vol_id}")
|
55
|
+
true
|
56
|
+
end
|
57
|
+
|
58
|
+
def list_snapshots
|
59
|
+
response = @connection.req("GET", "/#{@snapshot_path}")
|
60
|
+
snapshot_hash = JSON.parse(response.body)["snapshots"]
|
61
|
+
snapshot_hash.inject([]){|res, current| res << OpenStack::Volume::Snapshot.new(current); res}
|
62
|
+
end
|
63
|
+
alias :snapshots :list_snapshots
|
64
|
+
|
65
|
+
def get_snapshot(snap_id)
|
66
|
+
response = @connection.req("GET", "/#{@snapshot_path}/#{snap_id}")
|
67
|
+
snapshot_hash = JSON.parse(response.body)["snapshot"]
|
68
|
+
OpenStack::Volume::Snapshot.new(snapshot_hash)
|
69
|
+
end
|
70
|
+
alias :snapshot :get_snapshot
|
71
|
+
|
72
|
+
#require params: {:display_name, :volume_id}
|
73
|
+
#optional params: {:display_description, :metadata=>{:key=>val, ...}, :availability_zone, :volume_type }
|
74
|
+
#returns OpenStack::Volume::Snapshot object
|
75
|
+
def create_snapshot(options)
|
76
|
+
raise OpenStack::Exception::MissingArgument, ":volume_id and :display_name must be specified to create a snapshot" unless (options[:display_name] && options[:volume_id])
|
77
|
+
#:force documented in API but not explained... clarify (fails without)
|
78
|
+
options.merge!({:force=>"true"})
|
79
|
+
data = JSON.generate(:snapshot => options)
|
80
|
+
response = @connection.csreq("POST",@connection.service_host,"#{@connection.service_path}/#{@snapshot_path}",@connection.service_port,@connection.service_scheme,{'content-type' => 'application/json'},data)
|
81
|
+
OpenStack::Exception.raise_exception(response) unless response.code.match(/^20.$/)
|
82
|
+
snapshot_info = JSON.parse(response.body)["snapshot"]
|
83
|
+
OpenStack::Volume::Snapshot.new(snapshot_info)
|
84
|
+
end
|
85
|
+
|
86
|
+
def delete_snapshot(snap_id)
|
87
|
+
@connection.req("DELETE", "/#{@snapshot_path}/#{snap_id}")
|
88
|
+
true
|
89
|
+
end
|
90
|
+
|
91
|
+
private
|
92
|
+
|
93
|
+
#fudge... not clear if volumes support is available as 'native' volume API or
|
94
|
+
#as the os-volumes extension. Need to probe to find out (for now)
|
95
|
+
#see https://lists.launchpad.net/openstack/msg16601.html
|
96
|
+
def check_if_native(entity) #volumes or snapshots
|
97
|
+
native = extension = false
|
98
|
+
#check if 'native' volume API present:
|
99
|
+
begin
|
100
|
+
response = @connection.req("GET", "/#{entity}")
|
101
|
+
native = true if response.code.match(/^20.$/)
|
102
|
+
return true, entity
|
103
|
+
rescue OpenStack::Exception::ItemNotFound => not_found
|
104
|
+
native = false
|
105
|
+
end
|
106
|
+
#check if available as extension:
|
107
|
+
begin
|
108
|
+
response = @connection.req("GET", "/os-#{entity}")
|
109
|
+
extension = true if response.code.match(/^20.$/)
|
110
|
+
return false, "os-#{entity}"
|
111
|
+
rescue OpenStack::Exception::ItemNotFound => not_found
|
112
|
+
extension = false
|
113
|
+
end
|
114
|
+
raise OpenStack::Exception::NotImplemented.new("No Volumes support for this provider", 501, "No #{entity} Support") unless (native || extension)
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
|
119
|
+
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module OpenStack
|
2
|
+
module Volume
|
3
|
+
class Snapshot
|
4
|
+
|
5
|
+
attr_reader :id
|
6
|
+
attr_reader :display_name
|
7
|
+
attr_reader :display_description
|
8
|
+
attr_reader :volume_id
|
9
|
+
attr_reader :status
|
10
|
+
attr_reader :size
|
11
|
+
attr_reader :created_at
|
12
|
+
|
13
|
+
def initialize(snap_info)
|
14
|
+
@id = snap_info["id"]
|
15
|
+
@display_name = snap_info["display_name"] || snap_info["displayName"]
|
16
|
+
@display_description = snap_info["display_description"] || snap_info["displayDescription"]
|
17
|
+
@volume_id = snap_info["volume_id"] || snap_info["volumeId"]
|
18
|
+
@status = snap_info["status"]
|
19
|
+
@size = snap_info["size"]
|
20
|
+
@created_at = snap_info["created_at"] || snap_info["createdAt"]
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module OpenStack
|
2
|
+
module Volume
|
3
|
+
class Volume
|
4
|
+
|
5
|
+
attr_reader :id
|
6
|
+
attr_reader :display_name
|
7
|
+
attr_reader :display_description
|
8
|
+
attr_reader :size
|
9
|
+
attr_reader :volume_type
|
10
|
+
attr_reader :metadata
|
11
|
+
attr_reader :availability_zone
|
12
|
+
attr_reader :snapshot_id
|
13
|
+
attr_reader :attachments
|
14
|
+
attr_reader :created_at
|
15
|
+
|
16
|
+
def initialize(volume_info)
|
17
|
+
@id = volume_info["id"]
|
18
|
+
@display_name = volume_info["display_name"] || volume_info["displayName"]
|
19
|
+
@display_description = volume_info["display_description"] || volume_info["displayDescription"]
|
20
|
+
@size = volume_info["size"]
|
21
|
+
@volume_type = volume_info["volume_type"] || volume_info["volumeType"]
|
22
|
+
@metadata = volume_info["metadata"]
|
23
|
+
@availability_zone = volume_info["availability_zone"] || volume_info["availabilityZone"]
|
24
|
+
@snapshot_id = volume_info["snapshot_id"] || volume_info["snapshotId"]
|
25
|
+
@attachments = volume_info["attachments"]
|
26
|
+
@created_at = volume_info["created_at"] || volume_info["createdAt"]
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,134 @@
|
|
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 => 'good_user',:authtenant => {:type=>"tenantName", :value=>'good_tenant'}, :authkey => 'bad_key', :auth_host => "a.b.c", :auth_port => "443", :auth_scheme => "https", :auth_path => "/v1.0", :service_type=>"compute", :authok= => true, :authtoken= => true, :service_host= => "", :service_path= => "", :service_path => "", :service_port= => "", :service_scheme= => "", :proxy_host => nil, :proxy_port => nil, :api_path => '/foo')
|
12
|
+
result = OpenStack::Authentication.init(connection)
|
13
|
+
assert_equal result.class, OpenStack::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', :authtenant => {:type=>"tenantName", :value=>'good_tenant'}, :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, :api_path => '/foo')
|
23
|
+
assert_raises(OpenStack::Exception::Authentication) do
|
24
|
+
result = OpenStack::Authentication.init(connection)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_bad_hostname
|
29
|
+
Net::HTTP.stubs(:new).raises(OpenStack::Exception::Connection)
|
30
|
+
connection = stub(:authuser => 'bad_user', :authtenant => {:type=>"tenantName", :value=>'good_tenant'}, :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, :api_path => '/foo')
|
31
|
+
assert_raises(OpenStack::Exception::Connection) do
|
32
|
+
result = OpenStack::Authentication.init(connection)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_service_region
|
37
|
+
server = get_test_auth_server
|
38
|
+
Net::HTTP.stubs(:new).returns(server)
|
39
|
+
server.stubs(:started?).returns(true)
|
40
|
+
connection = stub(:authuser => 'good_user', :auth_method => "password",:authtenant => {:type=>"tenantName", :value=>'good_tenant'} , :authkey => 'bad_key', :auth_host => "a.b.c", :auth_port => "443", :auth_scheme => "https", :auth_path => "/v2.0", :authok= => true, :authtoken= => true, :service_host= => "", :service_path= => "", :service_path => "", :service_port= => "", :service_scheme= => "", :proxy_host => nil, :proxy_port => nil, :api_path => '/foo', :service_type => "compute", :service_name => "cloudServers", :region => "South")
|
41
|
+
result = OpenStack::Authentication.init(connection)
|
42
|
+
assert_equal("compute.south.host", result.uri.host)
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_service_name
|
46
|
+
server = get_test_auth_server
|
47
|
+
Net::HTTP.stubs(:new).returns(server)
|
48
|
+
server.stubs(:started?).returns(true)
|
49
|
+
connection = stub(:authuser => 'good_user', :auth_method=>"password", :authtenant => {:type=>"tenantName", :value=>'good_tenant'}, :authkey => 'bad_key', :auth_host => "a.b.c", :auth_port => "443", :auth_scheme => "https", :auth_path => "/v2.0", :authok= => true, :authtoken= => true, :service_host= => "", :service_path= => "", :service_path => "", :service_port= => "", :service_scheme= => "", :proxy_host => nil, :proxy_port => nil, :api_path => '/foo', :service_type => "nova", :service_name => "cloudCompute", :region => "South")
|
50
|
+
result = OpenStack::Authentication.init(connection)
|
51
|
+
assert_equal("nova.south.host", result.uri.host)
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_service_type
|
55
|
+
server = get_test_auth_server
|
56
|
+
Net::HTTP.stubs(:new).returns(server)
|
57
|
+
server.stubs(:started?).returns(true)
|
58
|
+
connection = stub(:authuser => 'good_user', :auth_method => "password", :authtenant => {:type=>"tenantName", :value=>'good_tenant'}, :authkey => 'bad_key', :auth_host => "a.b.c", :auth_port => "443", :auth_scheme => "https", :auth_path => "/v2.0", :authok= => true, :authtoken= => true, :service_host= => "", :service_path= => "", :service_path => "", :service_port= => "", :service_scheme= => "", :proxy_host => nil, :proxy_port => nil, :api_path => '/foo', :service_type => "nova", :service_name => nil, :region => "North")
|
59
|
+
result = OpenStack::Authentication.init(connection)
|
60
|
+
assert_equal("nova.north.host", result.uri.host)
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
private
|
65
|
+
def get_test_auth_server
|
66
|
+
json_response = %{{
|
67
|
+
"access":{
|
68
|
+
"token":{
|
69
|
+
"id":"asdasdasd-adsasdads-asdasdasd-adsadsasd",
|
70
|
+
"expires":"2010-11-01T03:32:15-05:00"
|
71
|
+
},
|
72
|
+
"user":{
|
73
|
+
"id":"123",
|
74
|
+
"name":"testName",
|
75
|
+
"roles":[{
|
76
|
+
"id":"234",
|
77
|
+
"name":"compute:admin"
|
78
|
+
},
|
79
|
+
{
|
80
|
+
"id":"235",
|
81
|
+
"name":"object-store:admin",
|
82
|
+
"tenantId":"1"
|
83
|
+
}
|
84
|
+
],
|
85
|
+
"roles_links":[]
|
86
|
+
},
|
87
|
+
"serviceCatalog":[{
|
88
|
+
"name":"cloudServers",
|
89
|
+
"type":"compute",
|
90
|
+
"endpoints":[{
|
91
|
+
"publicURL":"https://compute.north.host/v1.1",
|
92
|
+
"region":"North"
|
93
|
+
},
|
94
|
+
{
|
95
|
+
"publicURL":"https://compute.south.host/v1.1",
|
96
|
+
"region":"South"
|
97
|
+
}
|
98
|
+
],
|
99
|
+
"endpoints_links":[]
|
100
|
+
},
|
101
|
+
{
|
102
|
+
"name":"cloudCompute",
|
103
|
+
"type":"nova",
|
104
|
+
"endpoints":[{
|
105
|
+
"publicURL":"https://nova.north.host/v1.1",
|
106
|
+
"region":"North"
|
107
|
+
},
|
108
|
+
{
|
109
|
+
"publicURL":"https://nova.south.host/v1.1",
|
110
|
+
"region":"South"
|
111
|
+
}
|
112
|
+
],
|
113
|
+
"endpoints_links":[{
|
114
|
+
"rel":"next",
|
115
|
+
"href":"https://identity.north.host/v2.0/endpoints?marker=2"
|
116
|
+
}
|
117
|
+
]
|
118
|
+
}
|
119
|
+
],
|
120
|
+
"serviceCatalog_links":[{
|
121
|
+
"rel":"next",
|
122
|
+
"href":"https://identity.host/v2.0/endpoints?session=2hfh8Ar&marker=2"
|
123
|
+
}
|
124
|
+
]
|
125
|
+
}
|
126
|
+
}}
|
127
|
+
|
128
|
+
response = {'x-server-management-url' => 'http://server-manage.example.com/path', 'x-auth-token' => 'dummy_token'}
|
129
|
+
response.stubs(:code => "200", :body => json_response)
|
130
|
+
server = mock(:use_ssl= => true, :verify_mode= => true, :start => true, :finish => true)
|
131
|
+
server.stubs(:post).returns(response)
|
132
|
+
return server
|
133
|
+
end
|
134
|
+
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::Authentication.stubs(:init).returns(connection)
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_init_connection_no_credentials
|
11
|
+
assert_raises(OpenStack::Exception::MissingArgument) do
|
12
|
+
conn = OpenStack::Connection.create(:api_key => "AABBCCDD11", :auth_url => "a.b.c")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_init_connection_no_password
|
17
|
+
assert_raises(OpenStack::Exception::MissingArgument) do
|
18
|
+
conn = OpenStack::Connection.create(: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::Exception::MissingArgument) do
|
24
|
+
conn = OpenStack::Connection.create(:username => "test_account", :api_key => "AABBCCDD11")
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_init_connection_bad_auth_url
|
29
|
+
assert_raises(OpenStack::Exception::InvalidArgument) do
|
30
|
+
conn = OpenStack::Connection.create(:username => "test_account", :api_key => "AABBCCDD11", :auth_url => "***")
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_init_connection
|
35
|
+
conn = OpenStack::Connection.create(: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::Exception.raise_exception(response)
|
11
|
+
rescue Exception => e
|
12
|
+
exception=e
|
13
|
+
end
|
14
|
+
assert_equal(OpenStack::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::Exception.raise_exception(response)
|
25
|
+
rescue Exception => e
|
26
|
+
exception=e
|
27
|
+
end
|
28
|
+
assert_equal(OpenStack::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::Exception.raise_exception(response)
|
40
|
+
rescue Exception => e
|
41
|
+
exception=e
|
42
|
+
end
|
43
|
+
assert_equal(OpenStack::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,210 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class MetadataTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
include TestConnection
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@compute=get_test_connection
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_metadata_uses_initial_values
|
12
|
+
data = {'key1' => 'value1', 'key2' => 'value2'}
|
13
|
+
metadata = OpenStack::Compute::Metadata.new(@conn, 'blah', data)
|
14
|
+
assert_equal('value1', metadata['key1'])
|
15
|
+
assert_equal('value2', metadata['key2'])
|
16
|
+
assert_equal(nil, metadata['key0'])
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_metadata_presents_saved_values
|
20
|
+
metadata = OpenStack::Compute::Metadata.new(@conn, 'blah')
|
21
|
+
metadata['key3'] = 'value3'
|
22
|
+
assert_equal('value3', metadata['key3'])
|
23
|
+
assert_equal(nil, metadata['key0'])
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_metadata_presents_stored_values
|
27
|
+
metadata = OpenStack::Compute::Metadata.new(@conn, 'blah')
|
28
|
+
metadata.store('key3', 'value3')
|
29
|
+
assert_equal('value3', metadata['key3'])
|
30
|
+
assert_equal(nil, metadata['key0'])
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_metadata_looks_up_values_if_none_provided
|
34
|
+
data = {'metadata' => {'key4' => 'value4'}}
|
35
|
+
json = JSON.generate(data)
|
36
|
+
response = mock()
|
37
|
+
response.stubs(:code => "200", :body => json)
|
38
|
+
conn = mock()
|
39
|
+
@compute.stubs(:connection).returns(conn)
|
40
|
+
conn.stubs(:req).returns(response)
|
41
|
+
metadata = OpenStack::Compute::Metadata.new(@compute, 'blah')
|
42
|
+
assert_equal('value4', metadata['key4'])
|
43
|
+
assert_equal(nil, metadata['key0'])
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_metadata_save_nil
|
47
|
+
conn = mock()
|
48
|
+
metadata = OpenStack::Compute::Metadata.new(conn, 'blah')
|
49
|
+
metadata.save # do nothing or we'd likely be deleting unintentionally
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_metadata_save
|
53
|
+
data = {'key1' => 'value1', 'key3' => 'value3'}
|
54
|
+
json = JSON.generate({'metadata' => data})
|
55
|
+
response = mock()
|
56
|
+
response.stubs(:code => "200", :body => json)
|
57
|
+
compute = mock()
|
58
|
+
conn = mock()
|
59
|
+
compute.stubs(:connection).returns(conn)
|
60
|
+
conn.expects(:req).with('PUT', 'blah/metadata', :data => json).returns(response)
|
61
|
+
metadata = OpenStack::Compute::Metadata.new(compute, 'blah', data)
|
62
|
+
metadata.save
|
63
|
+
end
|
64
|
+
|
65
|
+
def test_metadata_update_all
|
66
|
+
data_in = {'key5' => 'value5', 'key6' => 'value6'}
|
67
|
+
data_out = {'key5' => 'value5', 'key6' => 'value6', 'key7' => 'value7'}
|
68
|
+
json_in = JSON.generate({'metadata' => data_in})
|
69
|
+
json_out = JSON.generate({'metadata' => data_out})
|
70
|
+
response = mock()
|
71
|
+
response.stubs(:code => "200", :body => json_out)
|
72
|
+
compute = mock()
|
73
|
+
conn = mock()
|
74
|
+
compute.stubs(:connection).returns(conn)
|
75
|
+
conn.expects(:req).with('POST', 'blah/metadata', :data => json_in).returns(response)
|
76
|
+
metadata = OpenStack::Compute::Metadata.new(compute, 'blah')
|
77
|
+
metadata['key5'] = 'value5'
|
78
|
+
metadata['key6'] = 'value6'
|
79
|
+
metadata.update
|
80
|
+
assert_equal('value5', metadata['key5'])
|
81
|
+
assert_equal('value6', metadata['key6'])
|
82
|
+
assert_equal('value7', metadata['key7'])
|
83
|
+
end
|
84
|
+
|
85
|
+
def test_metadata_update_some_keys
|
86
|
+
json1 = JSON.generate({'meta' => {'key1' => 'value1'}})
|
87
|
+
response1 = mock()
|
88
|
+
response1.stubs(:code => "200", :body => json1)
|
89
|
+
json2 = JSON.generate({'meta' => {'key2' => 'value2'}})
|
90
|
+
response2 = mock()
|
91
|
+
response2.stubs(:code => "200", :body => json2)
|
92
|
+
conn = mock()
|
93
|
+
compute = mock()
|
94
|
+
compute.stubs(:connection).returns(conn)
|
95
|
+
conn.expects(:req).with('PUT', 'blah/metadata/key1', :data => json1).returns(response1)
|
96
|
+
conn.expects(:req).with('PUT', 'blah/metadata/key2', :data => json2).returns(response2)
|
97
|
+
data = {'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3'}
|
98
|
+
metadata = OpenStack::Compute::Metadata.new(compute, 'blah', data)
|
99
|
+
metadata.update(['key1', 'key2'])
|
100
|
+
end
|
101
|
+
|
102
|
+
def test_metadata_update_one_key
|
103
|
+
json = JSON.generate({'meta' => {'key2' => 'value2'}})
|
104
|
+
response = mock()
|
105
|
+
response.stubs(:code => "200", :body => json)
|
106
|
+
compute = mock()
|
107
|
+
conn = mock()
|
108
|
+
compute.stubs(:connection).returns(conn)
|
109
|
+
conn.expects(:req).with('PUT', 'blah/metadata/key2', :data => json).returns(response)
|
110
|
+
data = {'key1' => 'value1', 'key2' => 'value2'}
|
111
|
+
metadata = OpenStack::Compute::Metadata.new(compute, 'blah', data)
|
112
|
+
metadata.update(['key2'])
|
113
|
+
end
|
114
|
+
|
115
|
+
def test_metadata_update_nonexistent_key
|
116
|
+
data = {'key1' => 'value1', 'key2' => 'value2'}
|
117
|
+
compute = mock()
|
118
|
+
conn = mock()
|
119
|
+
compute.stubs(:connection).returns(conn)
|
120
|
+
metadata = OpenStack::Compute::Metadata.new(compute, 'blah', data)
|
121
|
+
metadata.update(['key3']) # just asserting nothing is called on conn
|
122
|
+
end
|
123
|
+
|
124
|
+
def test_metadata_update_nil
|
125
|
+
compute = mock()
|
126
|
+
conn = mock()
|
127
|
+
compute.stubs(:connection).returns(conn)
|
128
|
+
metadata = OpenStack::Compute::Metadata.new(compute, 'blah')
|
129
|
+
metadata.update # just asserting nothing is called on the connection
|
130
|
+
end
|
131
|
+
|
132
|
+
def test_refresh_one_key
|
133
|
+
json = JSON.generate({'meta' => {'key1' => 'value1'}})
|
134
|
+
response = mock()
|
135
|
+
response.stubs(:code => "200", :body => json)
|
136
|
+
compute = mock()
|
137
|
+
conn = mock()
|
138
|
+
compute.stubs(:connection).returns(conn)
|
139
|
+
conn.expects(:req).with('GET', 'blah/metadata/key1').returns(response)
|
140
|
+
metadata = OpenStack::Compute::Metadata.new(compute, 'blah')
|
141
|
+
metadata.refresh(['key1'])
|
142
|
+
assert_equal('value1', metadata['key1'])
|
143
|
+
end
|
144
|
+
|
145
|
+
def test_refresh_some_keys_with_key_not_found
|
146
|
+
json = JSON.generate({'meta' => {'key1' => 'value1'}})
|
147
|
+
response = mock()
|
148
|
+
response.stubs(:code => "200", :body => json)
|
149
|
+
not_found = mock()
|
150
|
+
not_found.stubs(:code => "404")
|
151
|
+
compute = mock()
|
152
|
+
conn = mock()
|
153
|
+
compute.stubs(:connection).returns(conn)
|
154
|
+
conn.expects(:req).with('GET', 'blah/metadata/key1').returns(response)
|
155
|
+
conn.expects(:req).with('GET', 'blah/metadata/key0').returns(not_found)
|
156
|
+
metadata = OpenStack::Compute::Metadata.new(compute, 'blah')
|
157
|
+
metadata.refresh(['key1', 'key0'])
|
158
|
+
assert_equal('value1', metadata['key1'])
|
159
|
+
assert(metadata['key0'].nil?)
|
160
|
+
end
|
161
|
+
|
162
|
+
def test_delete_a_key
|
163
|
+
response = mock()
|
164
|
+
response.stubs(:code => "204")
|
165
|
+
connection = mock()
|
166
|
+
compute = mock()
|
167
|
+
compute.stubs(:connection).returns(connection)
|
168
|
+
connection.expects(:req).with('DELETE', 'blah/metadata/key1').returns(response)
|
169
|
+
metadata = OpenStack::Compute::Metadata.new(compute, 'blah')
|
170
|
+
metadata.delete!(['key1'])
|
171
|
+
end
|
172
|
+
|
173
|
+
def test_delete_a_key_with_prior_information
|
174
|
+
response = mock()
|
175
|
+
response.stubs(:code => "204")
|
176
|
+
comp = mock()
|
177
|
+
conn = mock()
|
178
|
+
comp.stubs(:connection).returns(conn)
|
179
|
+
conn.expects(:req).with('DELETE', 'blah/metadata/key1').returns(response)
|
180
|
+
data = {'key1' => 'value1', 'key2' => 'value2'}
|
181
|
+
metadata = OpenStack::Compute::Metadata.new(comp, 'blah', data)
|
182
|
+
metadata.delete!(['key1'])
|
183
|
+
assert(metadata['key1'].nil?)
|
184
|
+
assert_equal('value2', metadata['key2'])
|
185
|
+
end
|
186
|
+
##
|
187
|
+
def test_delete_keys_softly
|
188
|
+
comp = mock()
|
189
|
+
conn = mock()
|
190
|
+
comp.stubs(:connection).returns(conn)
|
191
|
+
data = {'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3'}
|
192
|
+
metadata = OpenStack::Compute::Metadata.new(comp, 'blah', data)
|
193
|
+
metadata.delete(['key1', 'key3'])
|
194
|
+
assert(metadata['key1'].nil?)
|
195
|
+
assert_equal('value2', metadata['key2'])
|
196
|
+
assert(metadata['key3'].nil?)
|
197
|
+
end
|
198
|
+
|
199
|
+
def test_each_pair
|
200
|
+
comp = mock()
|
201
|
+
conn = mock()
|
202
|
+
comp.stubs(:connection).returns(conn)
|
203
|
+
data = {'key1' => 'value1', 'key2' => 'value2', 'key3' => 'value3'}
|
204
|
+
metadata = OpenStack::Compute::Metadata.new(comp, 'blah', data)
|
205
|
+
metadata.each_pair do |k,v|
|
206
|
+
assert_equal v, data[k]
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
end
|