openstack 1.0.6 → 1.0.7

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