cloudservers 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|