dropmyemail-openstack 1.0.9
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/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
|