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.
@@ -2,13 +2,15 @@
2
2
 
3
3
  == Description
4
4
 
5
- Ruby Openstack Compute and Object-Store bindings for the v1.0 OSAPI.
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 'object-store' (defaults to 'compute') - see below for examples.
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.6
1
+ 1.0.7
@@ -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
@@ -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.6
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-09-13 00:00:00.000000000 Z
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