cloudservers 0.2.0 → 0.3.0
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/Rakefile +9 -2
- data/TODO +0 -6
- data/VERSION +1 -1
- data/cloudservers.gemspec +12 -6
- data/lib/cloudservers/connection.rb +47 -15
- data/lib/cloudservers/exception.rb +36 -18
- data/lib/cloudservers/server.rb +33 -2
- data/lib/cloudservers.rb +9 -1
- data/test/cloudservers_authentication_test.rb +12 -13
- data/test/cloudservers_connection_test.rb +17 -0
- data/test/cloudservers_exception_test.rb +49 -0
- data/test/cloudservers_servers_test.rb +176 -0
- data/test/test_helper.rb +16 -0
- metadata +19 -5
data/Rakefile
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require './lib/cloudservers.rb'
|
3
|
+
require 'rake/testtask'
|
3
4
|
|
4
5
|
begin
|
5
6
|
require 'jeweler'
|
@@ -7,11 +8,17 @@ begin
|
|
7
8
|
gemspec.name = "cloudservers"
|
8
9
|
gemspec.summary = "Rackspace Cloud Servers Ruby API"
|
9
10
|
gemspec.description = "A Ruby API to version 1.0 of the Rackspace Cloud Servers product."
|
10
|
-
gemspec.email = "
|
11
|
+
gemspec.email = "minter@lunenburg.org"
|
11
12
|
gemspec.homepage = "http://github.com/rackspace/cloudservers"
|
12
|
-
gemspec.authors = ["H. Wade Minter","Mike Mayo"]
|
13
|
+
gemspec.authors = ["H. Wade Minter","Mike Mayo","Dan Prince"]
|
13
14
|
gemspec.add_dependency 'json'
|
14
15
|
end
|
15
16
|
rescue LoadError
|
16
17
|
puts "Jeweler not available. Install it with: sudo gem install jeweler"
|
17
18
|
end
|
19
|
+
|
20
|
+
Rake::TestTask.new(:test) do |t|
|
21
|
+
t.pattern = 'test/*_test.rb'
|
22
|
+
t.verbose = true
|
23
|
+
end
|
24
|
+
Rake::Task['test'].comment = "Unit"
|
data/TODO
CHANGED
@@ -1,9 +1,3 @@
|
|
1
|
-
* There are caching bugs in the API, so that accurate information is not always returned (ie. if you add a server and
|
2
|
-
then list available servers, the new one will not show up.). That needs to be corrected on the API end before
|
3
|
-
data will be accurate.
|
4
|
-
|
5
|
-
* Add pagination in object listing.
|
6
|
-
|
7
1
|
* Allow some sort of flag to get the stack trace when an exception is thrown.
|
8
2
|
|
9
3
|
* Shared IP group modification code.
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/cloudservers.gemspec
CHANGED
@@ -5,13 +5,13 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{cloudservers}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = ["H. Wade Minter", "Mike Mayo"]
|
12
|
-
s.date = %q{2010-
|
11
|
+
s.authors = ["H. Wade Minter", "Mike Mayo", "Dan Prince"]
|
12
|
+
s.date = %q{2010-10-21}
|
13
13
|
s.description = %q{A Ruby API to version 1.0 of the Rackspace Cloud Servers product.}
|
14
|
-
s.email = %q{
|
14
|
+
s.email = %q{minter@lunenburg.org}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"README.rdoc",
|
17
17
|
"TODO"
|
@@ -34,15 +34,21 @@ Gem::Specification.new do |s|
|
|
34
34
|
"lib/cloudservers/server.rb",
|
35
35
|
"lib/cloudservers/shared_ip_group.rb",
|
36
36
|
"test/cloudservers_authentication_test.rb",
|
37
|
+
"test/cloudservers_connection_test.rb",
|
38
|
+
"test/cloudservers_exception_test.rb",
|
39
|
+
"test/cloudservers_servers_test.rb",
|
37
40
|
"test/test_helper.rb"
|
38
41
|
]
|
39
42
|
s.homepage = %q{http://github.com/rackspace/cloudservers}
|
40
43
|
s.rdoc_options = ["--charset=UTF-8"]
|
41
44
|
s.require_paths = ["lib"]
|
42
|
-
s.rubygems_version = %q{1.3.
|
45
|
+
s.rubygems_version = %q{1.3.7}
|
43
46
|
s.summary = %q{Rackspace Cloud Servers Ruby API}
|
44
47
|
s.test_files = [
|
45
48
|
"test/cloudservers_authentication_test.rb",
|
49
|
+
"test/cloudservers_connection_test.rb",
|
50
|
+
"test/cloudservers_exception_test.rb",
|
51
|
+
"test/cloudservers_servers_test.rb",
|
46
52
|
"test/test_helper.rb"
|
47
53
|
]
|
48
54
|
|
@@ -50,7 +56,7 @@ Gem::Specification.new do |s|
|
|
50
56
|
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
51
57
|
s.specification_version = 3
|
52
58
|
|
53
|
-
if Gem::Version.new(Gem::
|
59
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
54
60
|
s.add_runtime_dependency(%q<json>, [">= 0"])
|
55
61
|
else
|
56
62
|
s.add_dependency(%q<json>, [">= 0"])
|
@@ -32,8 +32,8 @@ module CloudServers
|
|
32
32
|
#
|
33
33
|
# cf = CloudServers::Connection.new(:username => 'YOUR_USERNAME', :api_key => 'YOUR_API_KEY')
|
34
34
|
def initialize(options = {:retry_auth => true})
|
35
|
-
@authuser = options[:username] || (raise Authentication, "Must supply a :username")
|
36
|
-
@authkey = options[:api_key] || (raise Authentication, "Must supply an :api_key")
|
35
|
+
@authuser = options[:username] || (raise Exception::Authentication, "Must supply a :username")
|
36
|
+
@authkey = options[:api_key] || (raise Exception::Authentication, "Must supply an :api_key")
|
37
37
|
@retry_auth = options[:retry_auth]
|
38
38
|
@proxy_host = options[:proxy_host]
|
39
39
|
@proxy_port = options[:proxy_port]
|
@@ -62,9 +62,9 @@ module CloudServers
|
|
62
62
|
response
|
63
63
|
rescue Errno::EPIPE, Timeout::Error, Errno::EINVAL, EOFError
|
64
64
|
# Server closed the connection, retry
|
65
|
-
raise CloudServers::Exception::Connection, "Unable to reconnect to #{server} after #{
|
65
|
+
raise CloudServers::Exception::Connection, "Unable to reconnect to #{server} after #{attempts} attempts" if attempts >= 5
|
66
66
|
attempts += 1
|
67
|
-
@http[server].finish
|
67
|
+
@http[server].finish if @http[server].started?
|
68
68
|
start_http(server,path,port,scheme,headers)
|
69
69
|
retry
|
70
70
|
rescue CloudServers::Exception::ExpiredAuthToken
|
@@ -86,11 +86,18 @@ module CloudServers
|
|
86
86
|
|
87
87
|
# Returns an array of hashes, one for each server that exists under this account. The hash keys are :name and :id.
|
88
88
|
#
|
89
|
+
# You can also provide :limit and :offset parameters to handle pagination.
|
90
|
+
#
|
89
91
|
# >> cs.list_servers
|
90
92
|
# => [{:name=>"MyServer", :id=>110917}]
|
93
|
+
#
|
94
|
+
# >> cs.list_servers(:limit => 2, :offset => 3)
|
95
|
+
# => [{:name=>"demo-standingcloud-lts", :id=>168867},
|
96
|
+
# {:name=>"demo-aicache1", :id=>187853}]
|
91
97
|
def list_servers(options = {})
|
92
|
-
|
93
|
-
|
98
|
+
anti_cache_param="cacheid=#{Time.now.to_i}"
|
99
|
+
path = CloudServers.paginate(options).empty? ? "#{svrmgmtpath}/servers?#{anti_cache_param}" : "#{svrmgmtpath}/servers?#{CloudServers.paginate(options)}&#{anti_cache_param}"
|
100
|
+
response = csreq("GET",svrmgmthost,path,svrmgmtport,svrmgmtscheme)
|
94
101
|
CloudServers::Exception.raise_exception(response) unless response.code.match(/^20.$/)
|
95
102
|
CloudServers.symbolize_keys(JSON.parse(response.body)["servers"])
|
96
103
|
end
|
@@ -100,10 +107,16 @@ module CloudServers
|
|
100
107
|
# includes public and private IP addresses, status, hostID, and more. All hash keys are symbols except for the metadata
|
101
108
|
# hash, which are verbatim strings.
|
102
109
|
#
|
110
|
+
# You can also provide :limit and :offset parameters to handle pagination.
|
103
111
|
# >> cs.list_servers_detail
|
104
112
|
# => [{:name=>"MyServer", :addresses=>{:public=>["67.23.42.37"], :private=>["10.176.241.237"]}, :metadata=>{"MyData" => "Valid"}, :imageId=>10, :progress=>100, :hostId=>"36143b12e9e48998c2aef79b50e144d2", :flavorId=>1, :id=>110917, :status=>"ACTIVE"}]
|
105
|
-
|
106
|
-
|
113
|
+
#
|
114
|
+
# >> cs.list_servers_detail(:limit => 2, :offset => 3)
|
115
|
+
# => [{:status=>"ACTIVE", :imageId=>10, :progress=>100, :metadata=>{}, :addresses=>{:public=>["x.x.x.x"], :private=>["x.x.x.x"]}, :name=>"demo-standingcloud-lts", :id=>168867, :flavorId=>1, :hostId=>"xxxxxx"},
|
116
|
+
# {:status=>"ACTIVE", :imageId=>8, :progress=>100, :metadata=>{}, :addresses=>{:public=>["x.x.x.x"], :private=>["x.x.x.x"]}, :name=>"demo-aicache1", :id=>187853, :flavorId=>3, :hostId=>"xxxxxx"}]
|
117
|
+
def list_servers_detail(options = {})
|
118
|
+
path = CloudServers.paginate(options).empty? ? "#{svrmgmtpath}/servers/detail" : "#{svrmgmtpath}/servers/detail?#{CloudServers.paginate(options)}"
|
119
|
+
response = csreq("GET",svrmgmthost,path,svrmgmtport,svrmgmtscheme)
|
107
120
|
CloudServers::Exception.raise_exception(response) unless response.code.match(/^20.$/)
|
108
121
|
CloudServers.symbolize_keys(JSON.parse(response.body)["servers"])
|
109
122
|
end
|
@@ -149,11 +162,19 @@ module CloudServers
|
|
149
162
|
# Returns an array of hashes listing available server images that you have access too, including stock Cloud Servers images and
|
150
163
|
# any that you have created. The "id" key in the hash can be used where imageId is required.
|
151
164
|
#
|
165
|
+
# You can also provide :limit and :offset parameters to handle pagination.
|
166
|
+
#
|
152
167
|
# >> cs.list_images
|
153
168
|
# => [{:name=>"CentOS 5.2", :id=>2, :updated=>"2009-07-20T09:16:57-05:00", :status=>"ACTIVE", :created=>"2009-07-20T09:16:57-05:00"},
|
154
169
|
# {:name=>"Gentoo 2008.0", :id=>3, :updated=>"2009-07-20T09:16:57-05:00", :status=>"ACTIVE", :created=>"2009-07-20T09:16:57-05:00"},...
|
155
|
-
|
156
|
-
|
170
|
+
#
|
171
|
+
# >> cs.list_images(:limit => 3, :offset => 2)
|
172
|
+
# => [{:status=>"ACTIVE", :name=>"Fedora 11 (Leonidas)", :updated=>"2009-12-08T13:50:45-06:00", :id=>13},
|
173
|
+
# {:status=>"ACTIVE", :name=>"CentOS 5.3", :updated=>"2009-08-26T14:59:52-05:00", :id=>7},
|
174
|
+
# {:status=>"ACTIVE", :name=>"CentOS 5.4", :updated=>"2009-12-16T01:02:17-06:00", :id=>187811}]
|
175
|
+
def list_images(options = {})
|
176
|
+
path = CloudServers.paginate(options).empty? ? "#{svrmgmtpath}/images/detail" : "#{svrmgmtpath}/images/detail?#{CloudServers.paginate(options)}"
|
177
|
+
response = csreq("GET",svrmgmthost,path,svrmgmtport,svrmgmtscheme)
|
157
178
|
CloudServers::Exception.raise_exception(response) unless response.code.match(/^20.$/)
|
158
179
|
CloudServers.symbolize_keys(JSON.parse(response.body)['images'])
|
159
180
|
end
|
@@ -170,11 +191,19 @@ module CloudServers
|
|
170
191
|
|
171
192
|
# Returns an array of hashes listing all available server flavors. The :id key in the hash can be used when flavorId is required.
|
172
193
|
#
|
194
|
+
# You can also provide :limit and :offset parameters to handle pagination.
|
195
|
+
#
|
173
196
|
# >> cs.list_flavors
|
174
197
|
# => [{:name=>"256 server", :id=>1, :ram=>256, :disk=>10},
|
175
198
|
# {:name=>"512 server", :id=>2, :ram=>512, :disk=>20},...
|
176
|
-
|
177
|
-
|
199
|
+
#
|
200
|
+
# >> cs.list_flavors(:limit => 3, :offset => 2)
|
201
|
+
# => [{:ram=>1024, :disk=>40, :name=>"1GB server", :id=>3},
|
202
|
+
# {:ram=>2048, :disk=>80, :name=>"2GB server", :id=>4},
|
203
|
+
# {:ram=>4096, :disk=>160, :name=>"4GB server", :id=>5}]
|
204
|
+
def list_flavors(options = {})
|
205
|
+
path = CloudServers.paginate(options).empty? ? "#{svrmgmtpath}/flavors/detail" : "#{svrmgmtpath}/flavors/detail?#{CloudServers.paginate(options)}"
|
206
|
+
response = csreq("GET",svrmgmthost,path,svrmgmtport,svrmgmtscheme)
|
178
207
|
CloudServers::Exception.raise_exception(response) unless response.code.match(/^20.$/)
|
179
208
|
CloudServers.symbolize_keys(JSON.parse(response.body)['flavors'])
|
180
209
|
end
|
@@ -191,10 +220,13 @@ module CloudServers
|
|
191
220
|
|
192
221
|
# Returns an array of hashes for all Shared IP Groups that are available. The :id key can be used to find that specific object.
|
193
222
|
#
|
223
|
+
# You can also provide :limit and :offset parameters to handle pagination.
|
224
|
+
#
|
194
225
|
# >> cs.list_shared_ip_groups
|
195
226
|
# => [{:name=>"New Group", :id=>127}]
|
196
|
-
def list_shared_ip_groups
|
197
|
-
|
227
|
+
def list_shared_ip_groups(options = {})
|
228
|
+
path = CloudServers.paginate(options).empty? ? "#{svrmgmtpath}/shared_ip_groups/detail" : "#{svrmgmtpath}/shared_ip_groups/detail?#{CloudServers.paginate(options)}"
|
229
|
+
response = csreq("GET",svrmgmthost,path,svrmgmtport,svrmgmtscheme)
|
198
230
|
CloudServers::Exception.raise_exception(response) unless response.code.match(/^20.$/)
|
199
231
|
CloudServers.symbolize_keys(JSON.parse(response.body)['sharedIpGroups'])
|
200
232
|
end
|
@@ -303,4 +335,4 @@ module CloudServers
|
|
303
335
|
end
|
304
336
|
|
305
337
|
end
|
306
|
-
end
|
338
|
+
end
|
@@ -1,37 +1,50 @@
|
|
1
1
|
module CloudServers
|
2
2
|
class Exception
|
3
|
+
|
4
|
+
class CloudServersError < StandardError
|
5
|
+
|
6
|
+
attr_reader :response_body
|
7
|
+
attr_reader :response_code
|
8
|
+
|
9
|
+
def initialize(message, code, response_body)
|
10
|
+
@response_code=code
|
11
|
+
@response_body=response_body
|
12
|
+
super(message)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
3
16
|
|
4
|
-
class CloudServersFault <
|
17
|
+
class CloudServersFault < CloudServersError # :nodoc:
|
5
18
|
end
|
6
|
-
class ServiceUnavailable <
|
19
|
+
class ServiceUnavailable < CloudServersError # :nodoc:
|
7
20
|
end
|
8
|
-
class Unauthorized <
|
21
|
+
class Unauthorized < CloudServersError # :nodoc:
|
9
22
|
end
|
10
|
-
class BadRequest <
|
23
|
+
class BadRequest < CloudServersError # :nodoc:
|
11
24
|
end
|
12
|
-
class OverLimit <
|
25
|
+
class OverLimit < CloudServersError # :nodoc:
|
13
26
|
end
|
14
|
-
class BadMediaType <
|
27
|
+
class BadMediaType < CloudServersError # :nodoc:
|
15
28
|
end
|
16
|
-
class BadMethod <
|
29
|
+
class BadMethod < CloudServersError # :nodoc:
|
17
30
|
end
|
18
|
-
class ItemNotFound <
|
31
|
+
class ItemNotFound < CloudServersError # :nodoc:
|
19
32
|
end
|
20
|
-
class BuildInProgress <
|
33
|
+
class BuildInProgress < CloudServersError # :nodoc:
|
21
34
|
end
|
22
|
-
class ServerCapacityUnavailable <
|
35
|
+
class ServerCapacityUnavailable < CloudServersError # :nodoc:
|
23
36
|
end
|
24
|
-
class BackupOrResizeInProgress <
|
37
|
+
class BackupOrResizeInProgress < CloudServersError # :nodoc:
|
25
38
|
end
|
26
|
-
class ResizeNotAllowed <
|
39
|
+
class ResizeNotAllowed < CloudServersError # :nodoc:
|
27
40
|
end
|
28
|
-
class NotImplemented <
|
41
|
+
class NotImplemented < CloudServersError # :nodoc:
|
42
|
+
end
|
43
|
+
class Other < CloudServersError # :nodoc:
|
29
44
|
end
|
30
45
|
|
31
46
|
# Plus some others that we define here
|
32
47
|
|
33
|
-
class Other < StandardError # :nodoc:
|
34
|
-
end
|
35
48
|
class ExpiredAuthToken < StandardError # :nodoc:
|
36
49
|
end
|
37
50
|
class MissingArgument < StandardError # :nodoc:
|
@@ -52,12 +65,17 @@ module CloudServers
|
|
52
65
|
# proper error. Note that all exceptions are scoped in the CloudServers::Exception namespace.
|
53
66
|
def self.raise_exception(response)
|
54
67
|
return if response.code =~ /^20.$/
|
55
|
-
fault,info = JSON.parse(response.body).first
|
56
68
|
begin
|
69
|
+
fault = nil
|
70
|
+
info = nil
|
71
|
+
JSON.parse(response.body).each_pair do |key, val|
|
72
|
+
fault=key
|
73
|
+
info=val
|
74
|
+
end
|
57
75
|
exception_class = self.const_get(fault[0,1].capitalize+fault[1,fault.length])
|
58
|
-
raise exception_class
|
76
|
+
raise exception_class.new(info["message"], response.code, response.body)
|
59
77
|
rescue NameError
|
60
|
-
raise CloudServers::Exception::Other
|
78
|
+
raise CloudServers::Exception::Other.new("The server returned status #{response.code}", response.code, response.body)
|
61
79
|
end
|
62
80
|
end
|
63
81
|
|
data/lib/cloudservers/server.rb
CHANGED
@@ -249,6 +249,37 @@ module CloudServers
|
|
249
249
|
CloudServers::Exception.raise_exception(response) unless response.code.match(/^20.$/)
|
250
250
|
true
|
251
251
|
end
|
252
|
-
|
252
|
+
|
253
|
+
# Share IP between servers in Shared IP group.
|
254
|
+
# Takes a hash of the form: {:sharedIpGroupId => "1234", :ipAddress => "67.23.10.132", :configureServer => false} as an argument.
|
255
|
+
# The :sharedIpGroupId key is required.
|
256
|
+
# The :ipAddress key is required.
|
257
|
+
# The :configureServer key is optional and defaults to false.
|
258
|
+
#
|
259
|
+
# >> server.share_ip(:sharedIpGroupId => 100, :ipAddress => "67.23.10.132")
|
260
|
+
# => true
|
261
|
+
def share_ip(options)
|
262
|
+
raise CloudServers::Exception::MissingArgument, "Shared IP Group ID must be supplied" unless options[:sharedIpGroupId]
|
263
|
+
raise CloudServers::Exception::MissingArgument, "Ip Address must be supplied" unless options[:ipAddress]
|
264
|
+
options[:configureServer] = false if options[:configureServer].nil?
|
265
|
+
data = JSON.generate(:shareIp => {:sharedIpGroupId => options[:sharedIpGroupId], :configureServer => options[:configureServer]})
|
266
|
+
response = @connection.csreq("PUT",@svrmgmthost,"#{@svrmgmtpath}/servers/#{URI.encode(self.id.to_s)}/ips/public/#{options[:ipAddress]}",@svrmgmtport,@svrmgmtscheme,{'content-type' => 'application/json'},data)
|
267
|
+
CloudServers::Exception.raise_exception(response) unless response.code.match(/^20.$/)
|
268
|
+
true
|
269
|
+
end
|
270
|
+
|
271
|
+
# Unshare an IP address.
|
272
|
+
# Takes a hash of the form: {:ipAddress => "67.23.10.132"} as an argument.
|
273
|
+
# The :ipAddress key is required.
|
274
|
+
#
|
275
|
+
# >> server.unshare_ip(:ipAddress => "67.23.10.132")
|
276
|
+
# => true
|
277
|
+
def unshare_ip(options)
|
278
|
+
raise CloudServers::Exception::MissingArgument, "Ip Address must be supplied" unless options[:ipAddress]
|
279
|
+
response = @connection.csreq("DELETE",@svrmgmthost,"#{@svrmgmtpath}/servers/#{URI.encode(self.id.to_s)}/ips/public/#{options[:ipAddress]}",@svrmgmtport,@svrmgmtscheme)
|
280
|
+
CloudServers::Exception.raise_exception(response) unless response.code.match(/^20.$/)
|
281
|
+
true
|
282
|
+
end
|
283
|
+
|
253
284
|
end
|
254
|
-
end
|
285
|
+
end
|
data/lib/cloudservers.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
#
|
3
3
|
# == Cloud Servers API
|
4
4
|
# ==== Connects Ruby Applications to Rackspace's {Cloud Servers service}[http://www.rackspacecloud.com/cloud_hosting_products/servers]
|
5
|
-
# By H. Wade Minter <
|
5
|
+
# By H. Wade Minter <minter@lunenburg.org> and Mike Mayo <mike.mayo@rackspace.com>
|
6
6
|
#
|
7
7
|
# See COPYING for license information.
|
8
8
|
# Copyright (c) 2009, Rackspace US, Inc.
|
@@ -23,6 +23,7 @@ module CloudServers
|
|
23
23
|
require 'uri'
|
24
24
|
require 'rubygems'
|
25
25
|
require 'json'
|
26
|
+
require 'date'
|
26
27
|
|
27
28
|
unless "".respond_to? :each_char
|
28
29
|
require "jcode"
|
@@ -79,5 +80,12 @@ module CloudServers
|
|
79
80
|
end
|
80
81
|
end
|
81
82
|
|
83
|
+
def self.paginate(options = {})
|
84
|
+
path_args = []
|
85
|
+
path_args.push(URI.encode("limit=#{options[:limit]}")) if options[:limit]
|
86
|
+
path_args.push(URI.encode("offset=#{options[:offset]}")) if options[:offset]
|
87
|
+
path_args.join("&")
|
88
|
+
end
|
89
|
+
|
82
90
|
|
83
91
|
end
|
@@ -1,16 +1,15 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/test_helper'
|
2
2
|
|
3
3
|
class CloudserversAuthenticationTest < Test::Unit::TestCase
|
4
|
-
|
5
|
-
|
4
|
+
|
6
5
|
def test_good_authentication
|
7
|
-
response = {'x-
|
6
|
+
response = {'x-server-management-url' => 'http://server-manage.example.com/path', 'x-auth-token' => 'dummy_token'}
|
8
7
|
response.stubs(:code).returns('204')
|
9
8
|
server = mock(:use_ssl= => true, :verify_mode= => true, :start => true, :finish => true)
|
10
9
|
server.stubs(:get).returns(response)
|
11
10
|
Net::HTTP.stubs(:new).returns(server)
|
12
|
-
|
13
|
-
result = CloudServers::Authentication.new(
|
11
|
+
connection = stub(:authuser => 'bad_user', :authkey => 'bad_key', :authok= => true, :authtoken= => true, :svrmgmthost= => "", :svrmgmtpath= => "", :svrmgmtpath => "", :svrmgmtport= => "", :svrmgmtscheme= => "", :proxy_host => nil, :proxy_port => nil)
|
12
|
+
result = CloudServers::Authentication.new(connection)
|
14
13
|
assert_equal result.class, CloudServers::Authentication
|
15
14
|
end
|
16
15
|
|
@@ -20,18 +19,18 @@ class CloudserversAuthenticationTest < Test::Unit::TestCase
|
|
20
19
|
server = mock(:use_ssl= => true, :verify_mode= => true, :start => true)
|
21
20
|
server.stubs(:get).returns(response)
|
22
21
|
Net::HTTP.stubs(:new).returns(server)
|
23
|
-
|
24
|
-
assert_raises(
|
25
|
-
result = CloudServers::Authentication.new(
|
22
|
+
connection = stub(:authuser => 'bad_user', :authkey => 'bad_key', :authok= => true, :authtoken= => true, :proxy_host => nil, :proxy_port => nil)
|
23
|
+
assert_raises(CloudServers::Exception::Authentication) do
|
24
|
+
result = CloudServers::Authentication.new(connection)
|
26
25
|
end
|
27
26
|
end
|
28
27
|
|
29
28
|
def test_bad_hostname
|
30
|
-
Net::HTTP.stubs(:new).raises(
|
31
|
-
|
32
|
-
assert_raises(
|
33
|
-
result = CloudServers::Authentication.new(
|
29
|
+
Net::HTTP.stubs(:new).raises(CloudServers::Exception::Connection)
|
30
|
+
connection = stub(:authuser => 'bad_user', :authkey => 'bad_key', :authok= => true, :authtoken= => true, :proxy_host => nil, :proxy_port => nil)
|
31
|
+
assert_raises(CloudServers::Exception::Connection) do
|
32
|
+
result = CloudServers::Authentication.new(connection)
|
34
33
|
end
|
35
34
|
end
|
36
35
|
|
37
|
-
end
|
36
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class CloudServersConnectionTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_init_connection_no_credentials
|
6
|
+
assert_raises(CloudServers::Exception::Authentication) do
|
7
|
+
conn = CloudServers::Connection.new(:api_key => "AABBCCDD11")
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def test_init_connection_no_password
|
12
|
+
assert_raises(CloudServers::Exception::Authentication) do
|
13
|
+
conn = CloudServers::Connection.new(:username => "test_account")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class CloudServersExceptionTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def test_400_cloud_servers_fault
|
6
|
+
response = mock()
|
7
|
+
response.stubs(:code => "400", :body => "{\"cloudServersFault\":{\"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.CloudServersFault: Fault occured\",\"code\":400}}" )
|
8
|
+
exception=nil
|
9
|
+
begin
|
10
|
+
CloudServers::Exception.raise_exception(response)
|
11
|
+
rescue Exception => e
|
12
|
+
exception=e
|
13
|
+
end
|
14
|
+
assert_equal(CloudServers::Exception::CloudServersFault, 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
|
+
CloudServers::Exception.raise_exception(response)
|
25
|
+
rescue Exception => e
|
26
|
+
exception=e
|
27
|
+
end
|
28
|
+
assert_equal(CloudServers::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
|
+
CloudServers::Exception.raise_exception(response)
|
40
|
+
rescue Exception => e
|
41
|
+
exception=e
|
42
|
+
end
|
43
|
+
assert_equal(CloudServers::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,176 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/test_helper'
|
2
|
+
|
3
|
+
class CloudServersServersTest < 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
|
+
def test_share_ip
|
86
|
+
|
87
|
+
server=get_test_server
|
88
|
+
response = mock()
|
89
|
+
response.stubs(:code => "200")
|
90
|
+
|
91
|
+
@conn.stubs(:csreq).returns(response)
|
92
|
+
|
93
|
+
assert server.share_ip(:sharedIpGroupId => 100, :ipAddress => "67.23.10.132")
|
94
|
+
end
|
95
|
+
|
96
|
+
def test_share_ip_requires_shared_ip_group_id
|
97
|
+
|
98
|
+
server=get_test_server
|
99
|
+
|
100
|
+
assert_raises(CloudServers::Exception::MissingArgument) do
|
101
|
+
assert server.share_ip(:ipAddress => "67.23.10.132")
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
def test_share_ip_requires_ip_address
|
107
|
+
|
108
|
+
server=get_test_server
|
109
|
+
|
110
|
+
assert_raises(CloudServers::Exception::MissingArgument) do
|
111
|
+
assert server.share_ip(:sharedIpGroupId => 100)
|
112
|
+
end
|
113
|
+
|
114
|
+
end
|
115
|
+
|
116
|
+
def test_unshare_ip
|
117
|
+
|
118
|
+
server=get_test_server
|
119
|
+
response = mock()
|
120
|
+
response.stubs(:code => "200")
|
121
|
+
|
122
|
+
@conn.stubs(:csreq).returns(response)
|
123
|
+
|
124
|
+
assert server.unshare_ip(:ipAddress => "67.23.10.132")
|
125
|
+
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_unshare_ip_requires_ip_address
|
129
|
+
|
130
|
+
server=get_test_server
|
131
|
+
|
132
|
+
assert_raises(CloudServers::Exception::MissingArgument) do
|
133
|
+
assert server.share_ip({})
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
137
|
+
|
138
|
+
private
|
139
|
+
def get_test_server
|
140
|
+
|
141
|
+
json_response = %{{
|
142
|
+
"server" : {
|
143
|
+
"id" : 1234,
|
144
|
+
"name" : "sample-server",
|
145
|
+
"imageId" : 2,
|
146
|
+
"flavorId" : 1,
|
147
|
+
"hostId" : "e4d909c290d0fb1ca068ffaddf22cbd0",
|
148
|
+
"status" : "BUILD",
|
149
|
+
"progress" : 60,
|
150
|
+
"addresses" : {
|
151
|
+
"public" : [
|
152
|
+
"67.23.10.132",
|
153
|
+
"67.23.10.131"
|
154
|
+
],
|
155
|
+
"private" : [
|
156
|
+
"10.176.42.16"
|
157
|
+
]
|
158
|
+
},
|
159
|
+
"metadata" : {
|
160
|
+
"Server Label" : "Web Head 1",
|
161
|
+
"Image Version" : "2.1"
|
162
|
+
}
|
163
|
+
}
|
164
|
+
}}
|
165
|
+
|
166
|
+
response = mock()
|
167
|
+
response.stubs(:code => "200", :body => json_response)
|
168
|
+
|
169
|
+
@conn=get_test_connection
|
170
|
+
|
171
|
+
@conn.stubs(:csreq).returns(response)
|
172
|
+
return @conn.server(1234)
|
173
|
+
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -3,3 +3,19 @@ $:.unshift File.dirname(__FILE__) + '/../lib'
|
|
3
3
|
require 'cloudservers'
|
4
4
|
require 'rubygems'
|
5
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.stubs(:get).returns(conn_response)
|
15
|
+
Net::HTTP.stubs(:new).returns(server)
|
16
|
+
|
17
|
+
CloudServers::Connection.new(:username => "test_account", :api_key => "AABBCCDD11")
|
18
|
+
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
metadata
CHANGED
@@ -1,37 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cloudservers
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
+
hash: 19
|
4
5
|
prerelease: false
|
5
6
|
segments:
|
6
7
|
- 0
|
7
|
-
-
|
8
|
+
- 3
|
8
9
|
- 0
|
9
|
-
version: 0.
|
10
|
+
version: 0.3.0
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- H. Wade Minter
|
13
14
|
- Mike Mayo
|
15
|
+
- Dan Prince
|
14
16
|
autorequire:
|
15
17
|
bindir: bin
|
16
18
|
cert_chain: []
|
17
19
|
|
18
|
-
date: 2010-
|
20
|
+
date: 2010-10-21 00:00:00 -04:00
|
19
21
|
default_executable:
|
20
22
|
dependencies:
|
21
23
|
- !ruby/object:Gem::Dependency
|
22
24
|
name: json
|
23
25
|
prerelease: false
|
24
26
|
requirement: &id001 !ruby/object:Gem::Requirement
|
27
|
+
none: false
|
25
28
|
requirements:
|
26
29
|
- - ">="
|
27
30
|
- !ruby/object:Gem::Version
|
31
|
+
hash: 3
|
28
32
|
segments:
|
29
33
|
- 0
|
30
34
|
version: "0"
|
31
35
|
type: :runtime
|
32
36
|
version_requirements: *id001
|
33
37
|
description: A Ruby API to version 1.0 of the Rackspace Cloud Servers product.
|
34
|
-
email:
|
38
|
+
email: minter@lunenburg.org
|
35
39
|
executables: []
|
36
40
|
|
37
41
|
extensions: []
|
@@ -57,6 +61,9 @@ files:
|
|
57
61
|
- lib/cloudservers/server.rb
|
58
62
|
- lib/cloudservers/shared_ip_group.rb
|
59
63
|
- test/cloudservers_authentication_test.rb
|
64
|
+
- test/cloudservers_connection_test.rb
|
65
|
+
- test/cloudservers_exception_test.rb
|
66
|
+
- test/cloudservers_servers_test.rb
|
60
67
|
- test/test_helper.rb
|
61
68
|
has_rdoc: true
|
62
69
|
homepage: http://github.com/rackspace/cloudservers
|
@@ -68,26 +75,33 @@ rdoc_options:
|
|
68
75
|
require_paths:
|
69
76
|
- lib
|
70
77
|
required_ruby_version: !ruby/object:Gem::Requirement
|
78
|
+
none: false
|
71
79
|
requirements:
|
72
80
|
- - ">="
|
73
81
|
- !ruby/object:Gem::Version
|
82
|
+
hash: 3
|
74
83
|
segments:
|
75
84
|
- 0
|
76
85
|
version: "0"
|
77
86
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
78
88
|
requirements:
|
79
89
|
- - ">="
|
80
90
|
- !ruby/object:Gem::Version
|
91
|
+
hash: 3
|
81
92
|
segments:
|
82
93
|
- 0
|
83
94
|
version: "0"
|
84
95
|
requirements: []
|
85
96
|
|
86
97
|
rubyforge_project:
|
87
|
-
rubygems_version: 1.3.
|
98
|
+
rubygems_version: 1.3.7
|
88
99
|
signing_key:
|
89
100
|
specification_version: 3
|
90
101
|
summary: Rackspace Cloud Servers Ruby API
|
91
102
|
test_files:
|
92
103
|
- test/cloudservers_authentication_test.rb
|
104
|
+
- test/cloudservers_connection_test.rb
|
105
|
+
- test/cloudservers_exception_test.rb
|
106
|
+
- test/cloudservers_servers_test.rb
|
93
107
|
- test/test_helper.rb
|