openstack 1.0.6 → 1.0.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.rdoc +51 -2
- data/VERSION +1 -1
- data/lib/openstack.rb +4 -0
- data/lib/openstack/compute/connection.rb +20 -0
- data/lib/openstack/connection.rb +22 -1
- data/lib/openstack/volume/connection.rb +90 -0
- data/lib/openstack/volume/snapshot.rb +0 -0
- data/lib/openstack/volume/volume.rb +31 -0
- metadata +5 -2
data/README.rdoc
CHANGED
@@ -2,13 +2,15 @@
|
|
2
2
|
|
3
3
|
== Description
|
4
4
|
|
5
|
-
Ruby Openstack Compute
|
5
|
+
Ruby Openstack Compute, Object-Store and Block Storage bindings for the OpenStack API.
|
6
|
+
|
7
|
+
http://api.openstack.org/api-reference.html
|
6
8
|
|
7
9
|
Currently supports both v1.0 and v2.0 (keystone) auth.
|
8
10
|
|
9
11
|
Use OpenStack::Connection.create to get a handle to an OpenStack service - set the :service_type parameter to either 'compute' or 'object-store' (defaults to 'compute'). If the requested service is not deployed the gem will throw a OpenStack::Exception::NotImplemented (501) - e.g. :service_type is 'object-store' but swift service isn't deployed.
|
10
12
|
|
11
|
-
The OpenStack::Connection.create class method is a factory constructor which will return the appropriate Connection object, depending on the ':service_type' parameter passed with the options hash: set to either 'compute' or
|
13
|
+
The OpenStack::Connection.create class method is a factory constructor which will return the appropriate Connection object, depending on the ':service_type' parameter passed with the options hash: set to either 'compute', 'volume', or 'object-store' (defaults to 'compute') - see below for examples.
|
12
14
|
|
13
15
|
Other parameters for the create method:
|
14
16
|
|
@@ -179,6 +181,53 @@ See the class definitions for documentation on specific methods and operations.
|
|
179
181
|
>> os.delete_security_group(9571)
|
180
182
|
=> true
|
181
183
|
|
184
|
+
#Attach a volume to a server - params in order are: server_id, volume_id, attachment_point
|
185
|
+
|
186
|
+
>> os.attach_volume(704289, 90805, "/dev/sde")
|
187
|
+
=> true
|
188
|
+
|
189
|
+
#List attachments for a server:
|
190
|
+
|
191
|
+
>> os.list_attachments 704289
|
192
|
+
=> {:volumeAttachments=>[{:device=>"/dev/sde", :serverId=>704289, :id=>90805, :volumeId=>90805}]}
|
193
|
+
|
194
|
+
#Detach volume from server - params in order are server_id and attachment_id
|
195
|
+
>> os.detach_volume(704289, 90805)
|
196
|
+
=> true
|
197
|
+
|
198
|
+
== Examples for Volumes:
|
199
|
+
|
200
|
+
#NOTE - attach/detach operations are implemented for the compute service as the OS API defines these operations as extensions to Openstack Compute.
|
201
|
+
|
202
|
+
vs = OpenStack::Connection.create({:username => "username", :api_key=>"pass", :auth_url => "https://region-a.geo-1.identity.hpcloudsvc.com:35357/v2.0/", :authtenant=>"username-default-tenant", :service_type=>"volume"})
|
203
|
+
|
204
|
+
# Create a volume: - MUST specify display_name and size parameters... optional params are {:display_description, :metadata=>{:key=>val, ...}, :availability_zone, :volume_type }
|
205
|
+
|
206
|
+
>> volume = vs.create_volume({:display_name=>"marios volume", :size=>1, :display_description=>"some new volume bla"})
|
207
|
+
=> #<OpenStack::Volume::Volume:0x8a3c534 @id=90805, @display_name="marios volume", @display_description="some new volume bla", @size=1, @volume_type=nil, @metadata={}, @availability_zone="nova", @snapshot_id="", @attachments=[{}], @created_at="2012-11-15 13:51:23">
|
208
|
+
|
209
|
+
>> volume.size
|
210
|
+
=> 1
|
211
|
+
|
212
|
+
>> volume.attachments
|
213
|
+
=> [{}]
|
214
|
+
|
215
|
+
# List volumes:
|
216
|
+
|
217
|
+
>> vs.list_volumes #aliased as just 'volumes' ... vs.volumes
|
218
|
+
=> [#<OpenStack::Volume::Volume:0x8aad2e8 @id=90625, @display_name="marios volume", @display_description="attach test volume", @size=1, @volume_type=nil, @metadata={}, @availability_zone="nova", @snapshot_id="", @attachments=[{}], @created_at="2012-11-15 09:54:58">, #<OpenStack::Volume::Volume:0x8aad144 @id=90805, @display_name="marios volume", @display_description="some new volume bla", @size=1, @volume_type=nil, @metadata={}, @availability_zone="nova", @snapshot_id="", @attachments=[{}], @created_at="2012-11-15 13:51:23">]
|
219
|
+
|
220
|
+
# Get a particular volume - must specify ID:
|
221
|
+
|
222
|
+
>> vs.get_volume(90625) #aliased as 'volume'
|
223
|
+
=> #<OpenStack::Volume::Volume:0x8abd4a4 @id=90625, @display_name="marios volume", @display_description="attach test volume", @size=1, @volume_type=nil, @metadata={}, @availability_zone="nova", @snapshot_id="", @attachments=[{}], @created_at="2012-11-15 09:54:58">
|
224
|
+
|
225
|
+
# Delete a volume:
|
226
|
+
|
227
|
+
>> vs.delete_volume(90805)
|
228
|
+
=> true
|
229
|
+
|
230
|
+
|
182
231
|
== Examples for Object-Store:
|
183
232
|
|
184
233
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.0.
|
1
|
+
1.0.7
|
data/lib/openstack.rb
CHANGED
@@ -42,6 +42,10 @@ module OpenStack
|
|
42
42
|
require 'openstack/swift/connection'
|
43
43
|
require 'openstack/swift/container'
|
44
44
|
require 'openstack/swift/storage_object'
|
45
|
+
require 'openstack/volume/connection'
|
46
|
+
require 'openstack/volume/volume'
|
47
|
+
require 'openstack/volume/snapshot'
|
48
|
+
|
45
49
|
|
46
50
|
# Constants that set limits on server creation
|
47
51
|
MAX_PERSONALITY_ITEMS = 5
|
@@ -387,6 +387,26 @@ module Compute
|
|
387
387
|
response = @connection.req("DELETE", "/os-security-group-rules/#{id}")
|
388
388
|
true
|
389
389
|
end
|
390
|
+
|
391
|
+
#VOLUMES - attach detach
|
392
|
+
def attach_volume(server_id, volume_id, device_id)
|
393
|
+
raise OpenStack::Exception::NotImplemented.new("os-volumes not implemented by #{@connection.http.keys.first}", 501, "NOT IMPLEMENTED") unless api_extensions[:"os-volumes"]
|
394
|
+
data = JSON.generate(:volumeAttachment => {"volumeId" => volume_id, "device"=> device_id})
|
395
|
+
response = @connection.req("POST", "/servers/#{server_id}/os-volume_attachments", {:data=>data})
|
396
|
+
true
|
397
|
+
end
|
398
|
+
|
399
|
+
def list_attachments(server_id)
|
400
|
+
raise OpenStack::Exception::NotImplemented.new("os-volumes not implemented by #{@connection.http.keys.first}", 501, "NOT IMPLEMENTED") unless api_extensions[:"os-volumes"]
|
401
|
+
response = @connection.req("GET", "/servers/#{server_id}/os-volume_attachments")
|
402
|
+
OpenStack.symbolize_keys(JSON.parse(response.body))
|
403
|
+
end
|
404
|
+
|
405
|
+
def detach_volume(server_id, attachment_id)
|
406
|
+
raise OpenStack::Exception::NotImplemented.new("os-volumes not implemented by #{@connection.http.keys.first}", 501, "NOT IMPLEMENTED") unless api_extensions[:"os-volumes"]
|
407
|
+
response = @connection.req("DELETE", "/servers/#{server_id}/os-volume_attachments/#{attachment_id}")
|
408
|
+
true
|
409
|
+
end
|
390
410
|
end
|
391
411
|
end
|
392
412
|
end
|
data/lib/openstack/connection.rb
CHANGED
@@ -63,6 +63,8 @@ class Connection
|
|
63
63
|
OpenStack::Compute::Connection.new(connection)
|
64
64
|
when "object-store"
|
65
65
|
OpenStack::Swift::Connection.new(connection)
|
66
|
+
when "volume"
|
67
|
+
OpenStack::Volume::Connection.new(connection)
|
66
68
|
else
|
67
69
|
raise Exception::InvalidArgument, "Invalid :service_type parameter: #{@service_type}"
|
68
70
|
end
|
@@ -242,9 +244,9 @@ class Authentication
|
|
242
244
|
end
|
243
245
|
|
244
246
|
private
|
245
|
-
|
246
247
|
class AuthV20
|
247
248
|
attr_reader :uri
|
249
|
+
attr_reader :version
|
248
250
|
def initialize(connection)
|
249
251
|
begin
|
250
252
|
server = Net::HTTP::Proxy(connection.proxy_host, connection.proxy_port).new(connection.auth_host, connection.auth_port)
|
@@ -292,6 +294,14 @@ class AuthV20
|
|
292
294
|
if @uri == ""
|
293
295
|
raise OpenStack::Exception::Authentication, "No API endpoint for region #{connection.region}"
|
294
296
|
else
|
297
|
+
if @version #already got one version of endpoints
|
298
|
+
current_version = get_version_from_response(service)
|
299
|
+
if @version.to_f > current_version.to_f
|
300
|
+
next
|
301
|
+
end
|
302
|
+
end
|
303
|
+
#grab version to check next time round for multi-version deployments
|
304
|
+
@version = get_version_from_response(service)
|
295
305
|
connection.service_host = @uri.host
|
296
306
|
connection.service_path = @uri.path
|
297
307
|
connection.service_port = @uri.port
|
@@ -306,6 +316,17 @@ class AuthV20
|
|
306
316
|
end
|
307
317
|
server.finish if server.started?
|
308
318
|
end
|
319
|
+
|
320
|
+
def get_version_from_response(service)
|
321
|
+
service["endpoints"].first["versionId"] || parse_version_from_endpoint(service["endpoints"].first["publicURL"])
|
322
|
+
end
|
323
|
+
|
324
|
+
#IN --> https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v1.1/46871569847393
|
325
|
+
#OUT --> "1.1"
|
326
|
+
def parse_version_from_endpoint(endpoint)
|
327
|
+
endpoint.match(/\/v(\d).(\d)/).to_s.sub("/v", "")
|
328
|
+
end
|
329
|
+
|
309
330
|
end
|
310
331
|
|
311
332
|
class AuthV10
|
@@ -0,0 +1,90 @@
|
|
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
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns true if the authentication was successful and returns false otherwise.
|
16
|
+
#
|
17
|
+
# cs.authok?
|
18
|
+
# => true
|
19
|
+
def authok?
|
20
|
+
@connection.authok
|
21
|
+
end
|
22
|
+
|
23
|
+
#require params: {:display_name, :size}
|
24
|
+
#optional params: {:display_description, :metadata=>{:key=>val, ...}, :availability_zone, :volume_type }
|
25
|
+
#returns OpenStack::Volume::Volume object
|
26
|
+
def create_volume(options)
|
27
|
+
raise OpenStack::Exception::MissingArgument, ":display_name and :size must be specified to create a volume" unless (options[:display_name] && options[:size])
|
28
|
+
data = JSON.generate(:volume => options)
|
29
|
+
response = @connection.csreq("POST",@connection.service_host,"#{@connection.service_path}/#{@volume_path}",@connection.service_port,@connection.service_scheme,{'content-type' => 'application/json'},data)
|
30
|
+
volume_info = JSON.parse(response.body)["volume"]
|
31
|
+
volume = OpenStack::Volume::Volume.new(volume_info)
|
32
|
+
end
|
33
|
+
|
34
|
+
#no options documented in API at Nov 2012
|
35
|
+
#(e.g. like limit/marker as used in Nova for servers)
|
36
|
+
def list_volumes
|
37
|
+
response = @connection.req("GET", "/#{@volume_path}")
|
38
|
+
volumes_hash = JSON.parse(response.body)["volumes"]
|
39
|
+
volumes_hash.inject([]){|res, current| res << OpenStack::Volume::Volume.new(current); res}
|
40
|
+
end
|
41
|
+
alias :volumes :list_volumes
|
42
|
+
|
43
|
+
|
44
|
+
def get_volume(vol_id)
|
45
|
+
response = @connection.req("GET", "/#{@volume_path}/#{vol_id}")
|
46
|
+
volume_hash = JSON.parse(response.body)["volume"]
|
47
|
+
OpenStack::Volume::Volume.new(volume_hash)
|
48
|
+
end
|
49
|
+
alias :volume :get_volume
|
50
|
+
|
51
|
+
def delete_volume(vol_id)
|
52
|
+
response = @connection.req("DELETE", "/#{@volume_path}/#{vol_id}")
|
53
|
+
true
|
54
|
+
end
|
55
|
+
|
56
|
+
#TODO SNAPSHOTS
|
57
|
+
|
58
|
+
private
|
59
|
+
|
60
|
+
#fudge... not clear if volumes support is available as 'native' volume API or
|
61
|
+
#as the os-volumes extension. Need to probe to find out (for now)
|
62
|
+
#see https://lists.launchpad.net/openstack/msg16601.html
|
63
|
+
def check_if_native
|
64
|
+
native = extension = false
|
65
|
+
#check if 'native' volume API present:
|
66
|
+
begin
|
67
|
+
response = @connection.req("GET", "/volumes")
|
68
|
+
native = true if response.code.match(/^20.$/)
|
69
|
+
return true, "volumes"
|
70
|
+
rescue OpenStack::Exception::ItemNotFound => not_found
|
71
|
+
native = false
|
72
|
+
end
|
73
|
+
#check if available as extension:
|
74
|
+
begin
|
75
|
+
response = @connection.req("GET", "/os-volumes")
|
76
|
+
extension = true if response.code.match(/^20.$/)
|
77
|
+
return false, "os-volumes"
|
78
|
+
rescue OpenStack::Exception::ItemNotFound => not_found
|
79
|
+
extension = false
|
80
|
+
end
|
81
|
+
raise OpenStack::Exception::NotImplemented.new("No Volumes support for this provider", 501, "No Volumes Support") unless (native || extension)
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
File without changes
|
@@ -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
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openstack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.7
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: bin
|
12
12
|
cert_chain: []
|
13
|
-
date: 2012-
|
13
|
+
date: 2012-11-19 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: mocha
|
@@ -84,6 +84,9 @@ files:
|
|
84
84
|
- lib/openstack/swift/connection.rb
|
85
85
|
- lib/openstack/swift/container.rb
|
86
86
|
- lib/openstack/swift/storage_object.rb
|
87
|
+
- lib/openstack/volume/connection.rb
|
88
|
+
- lib/openstack/volume/snapshot.rb
|
89
|
+
- lib/openstack/volume/volume.rb
|
87
90
|
- test/authentication_test.rb
|
88
91
|
- test/connection_test.rb
|
89
92
|
- test/exception_test.rb
|