openstack 2.2.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 884339fc18898d36fca662e853c156bb029b193f
4
- data.tar.gz: f85e37571dc9182651aec8019cec200b023d3de7
3
+ metadata.gz: 019f3ab58603e2185aa4558273454869205efb90
4
+ data.tar.gz: d6a1995446cc59cf255d03354552738e81d3efeb
5
5
  SHA512:
6
- metadata.gz: c237b9cf749c80d7147c954fb2239032dd5dffed0eeca36f87874bb549147c36713c7b851673a38c2c01e2ebbd6c4791f76553075c3d1c367672261bd5bc4515
7
- data.tar.gz: a18111ee6f10c9137e983f1afa4a0ae3d32504b80704f005bd037115283ba8a64f869935e30274db322bdd7ae87361d0a74cadec143cb7f7502ab1c760983580
6
+ metadata.gz: cde951d618983f94dc1e808d60240647ef5ead95d6d345fbd9e5b25929a0ad89742f279e5d2d9e00082ec6c71bce816ba4573fb1b5b8d9f9c24d9d6d94c519e0
7
+ data.tar.gz: 2eab3097fbd3de0458141ecbd06a4d55cb949369ef46df26220c9e3e07eac1c82b7dafca2cd04a9ee9779b983c07d1cb019ad34b4be4a918e38d5bcd0debce1c
data/README.md CHANGED
@@ -1,18 +1,33 @@
1
1
  # Ruby OpenStack
2
2
 
3
- Ruby OpenStack Compute, Object-Store, Block Storage and Network bindings for the OpenStack API. It supports Keystone Authentication (v1.0 and v2.0), Nova and Swift. See the [getting started](https://github.com/ruby-openstack/ruby-openstack/wiki) for documentation.
3
+ Ruby OpenStack Compute, Object-Store, Block Storage and Network bindings for the OpenStack API. It supports Keystone Authentication (v1.0, v2.0 and v3.0), Nova and Swift. See the [getting started](https://github.com/ruby-openstack/ruby-openstack/wiki) for documentation.
4
4
 
5
- [![Build Status](https://travis-ci.org/ruby-openstack/ruby-openstack.svg?branch=next)](https://travis-ci.org/ruby-openstack/ruby-openstack)
5
+ [![Build Status](https://travis-ci.org/ruby-openstack/ruby-openstack.svg?branch=master)](https://travis-ci.org/ruby-openstack/ruby-openstack)
6
+
7
+ ## Installation
8
+
9
+ Add the Ruby OpenStack as dependency to your project Gemfile:
10
+
11
+ ```
12
+ source 'https://rubygems.org'
13
+ gem 'openstack'
14
+ ```
15
+
16
+ ## Maintainer
17
+
18
+ The library is currently maintained by [Nitrado](http://nitrado.net/).
19
+ The people behind the OpenStack Team from Nitrado are Alexander Birkner and Aaron Fischer.
6
20
 
7
21
  ## Authors
8
22
 
23
+ * Alexander Birkner (alexander.birkner@marbis.net)
24
+ * Aaron Fischer (aaron.fischer@marbis.net)
9
25
  * Marios Andreou (marios@redhat.com)
10
26
  * Dan Prince (dprince@redhat.com)
11
27
  * Naveed Massjouni (naveedm9@gmail.com)
12
- * Aaron Fischer (aaron.fischer@marbis.net)
13
- * Alexander Birkner (alexander.birkner@marbis.net)
14
28
 
15
- Initial code checkin on May 23rd 2012 - code refactored from and based on the Rackspace [Cloud Servers gem](https://github.com/rackspace/ruby-openstack-compute) and [Rackspace Cloud Files gem](https://github.com/rackspace/ruby-cloudfiles). Since Nov 2015 maintained by [Marbis GmbH](http://nitrado.net/).
29
+ Initial code checkin on May 23rd 2012 - code refactored from and based on the Rackspace [Cloud Servers gem](https://github.com/rackspace/ruby-openstack-compute) and [Rackspace Cloud Files gem](https://github.com/rackspace/ruby-cloudfiles).
30
+ Since Nov 2015 the library is maintained by [Nitrado](http://nitrado.net/).
16
31
 
17
32
  ## License
18
33
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.2.0
1
+ 3.0.0
@@ -117,7 +117,9 @@ module Compute
117
117
  # => "NewServerSHMGpvI"
118
118
  def create_server(options)
119
119
  raise OpenStack::Exception::MissingArgument, "Server name, flavorRef, and imageRef, must be supplied" unless (options[:name] && options[:flavorRef] && options[:imageRef])
120
- options[:personality] = Personalities.get_personality(options[:personality])
120
+ if options[:personality]
121
+ options[:personality] = Personalities.get_personality(options[:personality])
122
+ end
121
123
  options[:security_groups] = (options[:security_groups] || []).inject([]){|res, c| res << {"name"=>c} ;res}
122
124
  data = JSON.generate(:server => options)
123
125
  response = @connection.csreq("POST",@connection.service_host,"#{@connection.service_path}/servers",@connection.service_port,@connection.service_scheme,{'content-type' => 'application/json'},data)
@@ -125,7 +127,7 @@ module Compute
125
127
  server_info = JSON.parse(response.body)['server']
126
128
  server = OpenStack::Compute::Server.new(self,server_info['id'])
127
129
  server.adminPass = server_info['adminPass']
128
- return server
130
+ server
129
131
  end
130
132
 
131
133
  # Returns an array of hashes listing available server images that you have access too,
@@ -508,12 +510,18 @@ module Compute
508
510
  true
509
511
  end
510
512
 
511
- def get_floating_ip_polls
513
+ def get_floating_ip_pools
512
514
  check_extension 'os-floating-ip-pools'
513
515
  response = @connection.req('GET', '/os-floating-ip-pools')
514
516
  JSON.parse(response.body)['floating_ip_pools']
515
517
  end
516
518
 
519
+ #deprecated - please do not use this typo method :)
520
+ def get_floating_ip_polls
521
+ puts "get_floating_ip_polls() is DEPRECATED: Please use get_floating_ip_pools() without typo!"
522
+ self.get_floating_ip_pools
523
+ end
524
+
517
525
  def get_floating_ips_bulk
518
526
  check_extension 'os-floating-ips-bulk'
519
527
  response = @connection.req('GET', '/os-floating-ips-bulk')
@@ -22,6 +22,14 @@ class Connection
22
22
  attr_reader :auth_path
23
23
  attr_reader :service_name
24
24
  attr_reader :service_type
25
+ attr_reader :user_domain
26
+ attr_reader :user_domain_id
27
+ attr_reader :project_id
28
+ attr_reader :project_name
29
+ attr_reader :project_domain_name
30
+ attr_reader :project_domain_id
31
+ attr_reader :domain_name
32
+ attr_reader :domain_id
25
33
  attr_reader :proxy_host
26
34
  attr_reader :proxy_port
27
35
  attr_reader :ca_cert
@@ -45,14 +53,23 @@ class Connection
45
53
  #
46
54
  # options hash:
47
55
  #
48
- # :auth_method - Type of authentication - 'password', 'key', 'rax-kskey' - defaults to 'password'
49
56
  # :username - Your OpenStack username or public key, depending on auth_method. *required*
57
+ # :auth_method - Type of authentication - 'password', 'key', 'rax-kskey', 'token' - defaults to 'password'.
58
+ # For auth v3.0 valid options are 'password', 'token', 'password_user_id'
50
59
  # :authtenant_name OR :authtenant_id - Your OpenStack tenant name or id *required*. Defaults to username.
51
60
  # passing :authtenant will default to using that parameter as tenant name.
52
61
  # :api_key - Your OpenStack API key *required* (either private key or password, depending on auth_method)
53
62
  # :auth_url - Configurable auth_url endpoint.
54
63
  # :service_name - (Optional for v2.0 auth only). The optional name of the compute service to use.
55
64
  # :service_type - (Optional for v2.0 auth only). Defaults to "compute"
65
+ # :user_domain - (Optional for v3.0 auth only). The optional name of the user domain.
66
+ # :user_domain_id - (Optional for v3.0 auth only). Defaults to "default"
67
+ # :project_id - (Optional for v3.0 auth only). For authorization scoping
68
+ # :project_name - (Optional for v3.0 auth only). For authorization scoping
69
+ # :project_domain_name - (Optional for v3.0 auth only). For authorization scoping
70
+ # :project_domain_id - (Optional for v3.0 auth only). For authorization scoping
71
+ # :domain_name - (Optional for v3.0 auth only). For authorization scoping
72
+ # :domain_id - (Optional for v3.0 auth only). For authorization scoping
56
73
  # :region - (Optional for v2.0 auth only). The specific service region to use. Defaults to first returned region.
57
74
  # :retry_auth - Whether to retry if your auth token expires (defaults to true)
58
75
  # :proxy_host - If you need to connect through a proxy, supply the hostname here
@@ -60,6 +77,7 @@ class Connection
60
77
  # :ca_cert - path to a CA chain in PEM format
61
78
  # :ssl_version - explicitly set an version (:SSLv3 etc, see OpenSSL::SSL::SSLContext::METHODS)
62
79
  # :is_debug - Only for development purpose for debug output
80
+ # :endpoint_type - Type of endpoint. Optional. 'publicURL', 'internalURL', 'adminURL'
63
81
  #
64
82
  # The options hash is used to create a new OpenStack::Connection object
65
83
  # (private constructor) and this is passed to the constructor of OpenStack::Compute::Connection
@@ -98,6 +116,14 @@ class Connection
98
116
  @auth_method = options[:auth_method] || "password"
99
117
  @service_name = options[:service_name] || nil
100
118
  @service_type = options[:service_type] || "compute"
119
+ @user_domain_id = options[:user_domain_id] || "default"
120
+ @user_domain = options[:user_domain] || nil
121
+ @project_id = options[:project_id] || nil
122
+ @project_name = options[:project_name] || nil
123
+ @project_domain_name = options[:project_domain_name] || nil
124
+ @project_domain_id = options[:project_domain_id] || nil
125
+ @domain_name = options[:domain_name] || nil
126
+ @domain_id = options[:domain_id] || nil
101
127
  @region = options[:region] || @region = nil
102
128
  @regions_list = {} # this is populated during authentication - from the returned service catalogue
103
129
  @is_debug = options[:is_debug]
@@ -144,10 +170,10 @@ class Connection
144
170
  start_http(server,path,port,scheme,hdrhash)
145
171
  response = @http[server].request(request)
146
172
  if @is_debug
147
- puts "REQUEST: PUT => #{path}"
148
- puts data if data
149
- puts "RESPONSE: #{response.body}"
150
- puts '----------------------------------------'
173
+ puts "REQUEST: PUT => #{path}"
174
+ puts data if data
175
+ puts "RESPONSE: #{response.body}"
176
+ puts '----------------------------------------'
151
177
  end
152
178
  raise OpenStack::Exception::ExpiredAuthToken if response.code == "401"
153
179
  response
@@ -185,10 +211,10 @@ class Connection
185
211
  response = @http[server].request(request)
186
212
  end
187
213
  if @is_debug
188
- puts "REQUEST: #{auth_method} => #{path}"
189
- puts data if data
190
- puts "RESPONSE: #{response.body}"
191
- puts '----------------------------------------'
214
+ puts "REQUEST: #{method.to_s} => #{path}"
215
+ puts data if data
216
+ puts "RESPONSE: #{response.body}"
217
+ puts '----------------------------------------'
192
218
  end
193
219
  raise OpenStack::Exception::ExpiredAuthToken if response.code == "401"
194
220
  response
@@ -264,64 +290,119 @@ class Connection
264
290
  end
265
291
  end
266
292
 
267
- end #end class Connection
293
+ end #end class Connection
268
294
 
269
- #============================
270
- # OpenStack::Authentication
271
- #============================
295
+ #============================
296
+ # OpenStack::Authentication
297
+ #============================
272
298
 
273
- class Authentication
299
+ class Authentication
274
300
 
275
- # Performs an authentication to the OpenStack auth server.
276
- # If it succeeds, it sets the service_host, service_path, service_port,
277
- # service_scheme, authtoken, and authok variables on the connection.
278
- # If it fails, it raises an exception.
301
+ # Performs an authentication to the OpenStack auth server.
302
+ # If it succeeds, it sets the service_host, service_path, service_port,
303
+ # service_scheme, authtoken, and authok variables on the connection.
304
+ # If it fails, it raises an exception.
279
305
 
280
- def self.init(conn)
281
- if conn.auth_path =~ /.*v2.0\/?$/
282
- AuthV20.new(conn)
283
- else
284
- AuthV10.new(conn)
306
+ def self.init(conn)
307
+ if conn.auth_path =~ /.*v3\/?$/
308
+ AuthV30.new(conn)
309
+ elsif conn.auth_path =~ /.*v2.0\/?$/
310
+ AuthV20.new(conn)
311
+ else
312
+ AuthV10.new(conn)
313
+ end
285
314
  end
286
315
  end
287
316
 
288
- end
317
+ private
318
+
319
+ class AuthV10
320
+ def initialize(connection)
321
+ tries = connection.retries
322
+ time = 3
289
323
 
290
- private
291
- class AuthV20
292
- attr_reader :uri
293
- attr_reader :version
294
- def initialize(connection)
295
-
296
- tries = connection.retries
297
- time = 3
298
-
299
- begin
300
- server = Net::HTTP::Proxy(connection.proxy_host, connection.proxy_port).new(connection.auth_host, connection.auth_port)
301
- if connection.auth_scheme == "https"
302
- server.use_ssl = true
303
- server.verify_mode = OpenSSL::SSL::VERIFY_NONE
304
-
305
- # use the ca_cert if were given one, and make sure we verify!
306
- if !connection.ca_cert.nil?
307
- server.ca_file = connection.ca_cert
308
- server.verify_mode = OpenSSL::SSL::VERIFY_PEER
324
+ hdrhash = { "X-Auth-User" => connection.authuser, "X-Auth-Key" => connection.authkey }
325
+ begin
326
+ server = Net::HTTP::Proxy(connection.proxy_host, connection.proxy_port).new(connection.auth_host, connection.auth_port)
327
+ if connection.auth_scheme == "https"
328
+ server.use_ssl = true
329
+ server.verify_mode = OpenSSL::SSL::VERIFY_NONE
330
+
331
+ # use the ca_cert if were given one, and make sure to verify!
332
+ if !connection.ca_cert.nil?
333
+ server.ca_file = connection.ca_cert
334
+ server.verify_mode = OpenSSL::SSL::VERIFY_PEER
335
+ end
336
+
337
+ # explicitly set the SSL version to use
338
+ server.ssl_version = connection.ssl_version if !connection.ssl_version.nil?
309
339
  end
340
+ server.start
341
+ rescue
342
+ puts "Can't connect to the server: #{tries} tries to reconnect" if connection.is_debug
343
+ sleep time += 1
344
+ retry unless (tries -= 1) <= 0
345
+ raise OpenStack::Exception::Connection, "Unable to connect to #{server}"
346
+ end
310
347
 
311
- # explicitly set the SSL version to use
312
- server.ssl_version = connection.ssl_version if !connection.ssl_version.nil?
348
+ response = server.get(connection.auth_path, hdrhash)
349
+
350
+ if (response.code =~ /^20./)
351
+ connection.authtoken = response["x-auth-token"]
352
+ case connection.service_type
353
+ when "compute"
354
+ uri = URI.parse(response["x-server-management-url"])
355
+ when "object-store"
356
+ uri = URI.parse(response["x-storage-url"])
357
+ end
358
+ raise OpenStack::Exception::Authentication, "Unexpected Response from #{connection.auth_host} - couldn't get service URLs: \"x-server-management-url\" is: #{response["x-server-management-url"]} and \"x-storage-url\" is: #{response["x-storage-url"]}" if (uri.host.nil? || uri.host=="")
359
+ connection.service_host = uri.host
360
+ connection.service_path = uri.path
361
+ connection.service_port = uri.port
362
+ connection.service_scheme = uri.scheme
363
+ connection.authok = true
364
+ else
365
+ connection.authok = false
366
+ raise OpenStack::Exception::Authentication, "Authentication failed with response code #{response.code}"
313
367
  end
314
- server.start
315
- rescue
316
- puts "Can't connect to the server: #{tries} tries to reconnect" if connection.is_debug
317
- sleep time += 1
318
- retry unless (tries -= 1) <= 0
319
- raise OpenStack::Exception::Connection, "Unable to connect to #{server}"
368
+ server.finish
320
369
  end
370
+ end
371
+
372
+ class AuthV20
373
+ attr_reader :uri
374
+ attr_reader :version
375
+ def initialize(connection)
376
+
377
+ tries = connection.retries
378
+ time = 3
379
+
380
+ begin
381
+ server = Net::HTTP::Proxy(connection.proxy_host, connection.proxy_port).new(connection.auth_host, connection.auth_port)
382
+ if connection.auth_scheme == "https"
383
+ server.use_ssl = true
384
+ server.verify_mode = OpenSSL::SSL::VERIFY_NONE
385
+
386
+ # use the ca_cert if were given one, and make sure we verify!
387
+ if !connection.ca_cert.nil?
388
+ server.ca_file = connection.ca_cert
389
+ server.verify_mode = OpenSSL::SSL::VERIFY_PEER
390
+ end
391
+
392
+ # explicitly set the SSL version to use
393
+ server.ssl_version = connection.ssl_version if !connection.ssl_version.nil?
394
+ end
395
+ server.start
396
+ rescue
397
+ puts "Can't connect to the server: #{tries} tries to reconnect" if connection.is_debug
398
+ sleep time += 1
399
+ retry unless (tries -= 1) <= 0
400
+ raise OpenStack::Exception::Connection, "Unable to connect to #{server}"
401
+ end
321
402
 
322
- @uri = String.new
403
+ @uri = String.new
323
404
 
324
- case connection.auth_method
405
+ case connection.auth_method
325
406
  when "password"
326
407
  auth_data = JSON.generate({ "auth" => { "passwordCredentials" => { "username" => connection.authuser, "password" => connection.authkey }, connection.authtenant[:type] => connection.authtenant[:value]}})
327
408
  when "rax-kskey"
@@ -330,248 +411,330 @@ class AuthV20
330
411
  auth_data = JSON.generate({"auth" => { "apiAccessKeyCredentials" => {"accessKey" => connection.authuser, "secretKey" => connection.authkey}, connection.authtenant[:type] => connection.authtenant[:value]}})
331
412
  else
332
413
  raise Exception::InvalidArgument, "Unrecognized auth method #{connection.auth_method}"
333
- end
414
+ end
334
415
 
335
- response = server.post(connection.auth_path.chomp("/")+"/tokens", auth_data, {'Content-Type' => 'application/json'})
336
- if (response.code =~ /^20./)
337
- resp_data=JSON.parse(response.body)
338
- connection.authtoken = resp_data['access']['token']['id']
339
- implemented_services = resp_data["access"]["serviceCatalog"].inject([]){|res, current| res << current["type"] ;res}
340
- raise OpenStack::Exception::NotImplemented.new("The requested service: \"#{connection.service_type}\" is not present " +
341
- "in the returned service catalogue.", 501, "#{resp_data["access"]["serviceCatalog"]}") unless implemented_services.include?(connection.service_type)
342
- resp_data['access']['serviceCatalog'].each do |service|
343
- service["endpoints"].each do |endpoint|
344
- connection.regions_list[endpoint["region"]] ||= []
345
- connection.regions_list[endpoint["region"]] << {:service=>service["type"], :versionId => endpoint["versionId"]}
346
- end
347
- if connection.service_name
348
- check_service_name = connection.service_name
349
- else
350
- check_service_name = service['name']
351
- end
352
- if service['type'] == connection.service_type and service['name'] == check_service_name
353
- endpoints = service["endpoints"]
354
- if connection.region
355
- endpoints.each do |ep|
356
- if ep["region"] and ep["region"].upcase == connection.region.upcase
357
- @uri = URI.parse(ep[connection.endpoint_type])
358
- end
359
- end
360
- else
361
- @uri = URI.parse(endpoints[0][connection.endpoint_type])
416
+ response = server.post(connection.auth_path.chomp("/")+"/tokens", auth_data, {'Content-Type' => 'application/json'})
417
+ if (response.code =~ /^20./)
418
+ resp_data=JSON.parse(response.body)
419
+ connection.authtoken = resp_data['access']['token']['id']
420
+ implemented_services = resp_data["access"]["serviceCatalog"].inject([]){|res, current| res << current["type"] ;res}
421
+ raise OpenStack::Exception::NotImplemented.new("The requested service: \"#{connection.service_type}\" is not present " +
422
+ "in the returned service catalogue.", 501, "#{resp_data["access"]["serviceCatalog"]}") unless implemented_services.include?(connection.service_type)
423
+ resp_data['access']['serviceCatalog'].each do |service|
424
+ service["endpoints"].each do |endpoint|
425
+ connection.regions_list[endpoint["region"]] ||= []
426
+ connection.regions_list[endpoint["region"]] << {:service=>service["type"], :versionId => endpoint["versionId"]}
362
427
  end
363
- if @uri == ""
364
- raise OpenStack::Exception::Authentication, "No API endpoint for region #{connection.region}"
428
+ if connection.service_name
429
+ check_service_name = connection.service_name
365
430
  else
366
- if @version #already got one version of endpoints
367
- current_version = get_version_from_response(service,connection.endpoint_type)
368
- if @version.to_f > current_version.to_f
369
- next
431
+ check_service_name = service['name']
432
+ end
433
+ if service['type'] == connection.service_type and service['name'] == check_service_name
434
+ endpoints = service["endpoints"]
435
+ if connection.region
436
+ endpoints.each do |ep|
437
+ if ep["region"] and ep["region"].upcase == connection.region.upcase
438
+ @uri = URI.parse(ep[connection.endpoint_type])
439
+ end
440
+ end
441
+ else
442
+ @uri = URI.parse(endpoints[0][connection.endpoint_type])
443
+ end
444
+ if @uri == ""
445
+ raise OpenStack::Exception::Authentication, "No API endpoint for region #{connection.region}"
446
+ else
447
+ if @version #already got one version of endpoints
448
+ current_version = get_version_from_response(service,connection.endpoint_type)
449
+ if @version.to_f > current_version.to_f
450
+ next
451
+ end
370
452
  end
453
+ #grab version to check next time round for multi-version deployments
454
+ @version = get_version_from_response(service,connection.endpoint_type)
455
+ connection.service_host = @uri.host
456
+ connection.service_path = @uri.path
457
+ connection.service_port = @uri.port
458
+ connection.service_scheme = @uri.scheme
459
+ connection.authok = true
371
460
  end
372
- #grab version to check next time round for multi-version deployments
373
- @version = get_version_from_response(service,connection.endpoint_type)
374
- connection.service_host = @uri.host
375
- connection.service_path = @uri.path
376
- connection.service_port = @uri.port
377
- connection.service_scheme = @uri.scheme
378
- connection.authok = true
379
461
  end
380
462
  end
463
+ else
464
+ connection.authtoken = false
465
+ raise OpenStack::Exception::Authentication, "Authentication failed with response code #{response.code}"
381
466
  end
382
- else
383
- connection.authtoken = false
384
- raise OpenStack::Exception::Authentication, "Authentication failed with response code #{response.code}"
467
+ server.finish if server.started?
385
468
  end
386
- server.finish if server.started?
387
- end
388
469
 
389
- def get_version_from_response(service,endpoint_type)
390
- service["endpoints"].first["versionId"] || parse_version_from_endpoint(service["endpoints"].first[endpoint_type])
391
- end
470
+ def get_version_from_response(service,endpoint_type)
471
+ service["endpoints"].first["versionId"] || parse_version_from_endpoint(service["endpoints"].first[endpoint_type])
472
+ end
392
473
 
393
- #IN --> https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v1.1/46871569847393
394
- #OUT --> "1.1"
395
- def parse_version_from_endpoint(endpoint)
396
- endpoint.match(/\/v(\d).(\d)/).to_s.sub("/v", "")
474
+ #IN --> https://az-2.region-a.geo-1.compute.hpcloudsvc.com/v1.1/46871569847393
475
+ #OUT --> "1.1"
476
+ def parse_version_from_endpoint(endpoint)
477
+ endpoint.match(/\/v(\d).(\d)/).to_s.sub("/v", "")
478
+ end
397
479
  end
398
480
 
399
- end
481
+ # Implement the Identity Version 3.x API
482
+ # http://developer.openstack.org/api-ref-identity-v3.html
483
+ # This is still experimental, so don't use in production.
484
+ class AuthV30
485
+ attr_reader :uri, :version
486
+ # TODO: Parse the version for an endpoint
400
487
 
401
- class AuthV10
488
+ def initialize(connection)
489
+ tries = connection.retries
490
+ time = 3
402
491
 
403
- def initialize(connection)
492
+ begin
493
+ server = Net::HTTP::Proxy(connection.proxy_host, connection.proxy_port).new(connection.auth_host, connection.auth_port)
494
+ if connection.auth_scheme == "https"
495
+ server.use_ssl = true
496
+ server.verify_mode = OpenSSL::SSL::VERIFY_NONE
497
+
498
+ # use the ca_cert if were given one, and make sure we verify!
499
+ unless connection.ca_cert.nil?
500
+ server.ca_file = connection.ca_cert
501
+ server.verify_mode = OpenSSL::SSL::VERIFY_PEER
502
+ end
404
503
 
405
- tries = connection.retries
406
- time = 3
504
+ # explicitly set the SSL version to use
505
+ server.ssl_version = connection.ssl_version unless connection.ssl_version.nil?
506
+ end
507
+ server.start
508
+ rescue
509
+ puts "Can't connect to the server: #{tries} tries to reconnect" if connection.is_debug
510
+ sleep time += 1
511
+ retry unless (tries -= 1) <= 0
512
+ raise OpenStack::Exception::Connection, "Unable to connect to #{server}"
513
+ end
407
514
 
408
- hdrhash = { "X-Auth-User" => connection.authuser, "X-Auth-Key" => connection.authkey }
409
- begin
410
- server = Net::HTTP::Proxy(connection.proxy_host, connection.proxy_port).new(connection.auth_host, connection.auth_port)
411
- if connection.auth_scheme == "https"
412
- server.use_ssl = true
413
- server.verify_mode = OpenSSL::SSL::VERIFY_NONE
515
+ # Build Auth JSON
516
+ auth = { "auth" => { "identity" => {} } }
517
+
518
+ case connection.auth_method.to_sym
519
+ when :password
520
+ auth["auth"]["identity"]["methods"] = ["password"]
521
+ auth["auth"]["identity"]["password"] = { "user" => { "name" => connection.authuser, "password" => connection.authkey } }
522
+ auth["auth"]["identity"]["password"]["user"]["domain"] = connection.user_domain ? { "name" => connection.user_domain } : { "id" => connection.user_domain_id }
523
+ when :password_user_id
524
+ auth["auth"]["identity"]["methods"] = ["password"]
525
+ auth["auth"]["identity"]["password"] = { "user" => { "id" => connection.authuser, "password" => connection.authkey } }
526
+ when :token
527
+ auth["auth"]["identity"]["methods"] = ["token"]
528
+ auth["auth"]["identity"]["token"] = { "id" => connection.authkey }
529
+ else
530
+ raise Exception::InvalidArgument, "Unrecognized auth method #{connection.auth_method}."
531
+ end
414
532
 
415
- # use the ca_cert if were given one, and make sure to verify!
416
- if !connection.ca_cert.nil?
417
- server.ca_file = connection.ca_cert
418
- server.verify_mode = OpenSSL::SSL::VERIFY_PEER
419
- end
533
+ # handle project authentication scope
534
+ if (connection.project_id || connection.project_name) && (connection.project_domain_name || connection.project_domain_id)
535
+ auth["auth"]["scope"] = { "project" => { "domain" => {} } }
536
+ auth["auth"]["scope"]["project"]["name"] = connection.project_name if connection.project_name
537
+ auth["auth"]["scope"]["project"]["id"] = connection.project_id if connection.project_id
538
+ auth["auth"]["scope"]["project"]["domain"]["name"] = connection.project_domain_name if connection.project_domain_name
539
+ auth["auth"]["scope"]["project"]["domain"]["id"] = connection.project_domain_id if connection.project_domain_id
540
+ end
420
541
 
421
- # explicitly set the SSL version to use
422
- server.ssl_version = connection.ssl_version if !connection.ssl_version.nil?
542
+ # handle domain authentication scope
543
+ if connection.domain_name || connection.domain_id
544
+ auth["auth"]["scope"] = { "domain" => {} }
545
+ auth["auth"]["scope"]["domain"]["name"] = connection.domain_name if connection.domain_name
546
+ auth["auth"]["scope"]["domain"]["id"] = connection.domain_id if connection.domain_id
423
547
  end
424
- server.start
425
- rescue
426
- puts "Can't connect to the server: #{tries} tries to reconnect" if connection.is_debug
427
- sleep time += 1
428
- retry unless (tries -= 1) <= 0
429
- raise OpenStack::Exception::Connection, "Unable to connect to #{server}"
430
- end
431
548
 
432
- response = server.get(connection.auth_path, hdrhash)
549
+ response = server.post(connection.auth_path.chomp('/') + '/auth/tokens',
550
+ JSON.generate(auth),
551
+ {'Content-Type' => 'application/json'})
433
552
 
434
- if (response.code =~ /^20./)
435
- connection.authtoken = response["x-auth-token"]
436
- case connection.service_type
437
- when "compute"
438
- uri = URI.parse(response["x-server-management-url"])
439
- when "object-store"
440
- uri = URI.parse(response["x-storage-url"])
553
+ # debugging
554
+ if connection.is_debug
555
+ puts "REQUEST: POST => #{connection.auth_path.chomp('/') + '/auth/tokens'}"
556
+ puts "RESPONSE: #{response.body}"
557
+ puts '----------------------------------------'
441
558
  end
442
- raise OpenStack::Exception::Authentication, "Unexpected Response from #{connection.auth_host} - couldn't get service URLs: \"x-server-management-url\" is: #{response["x-server-management-url"]} and \"x-storage-url\" is: #{response["x-storage-url"]}" if (uri.host.nil? || uri.host=="")
443
- connection.service_host = uri.host
444
- connection.service_path = uri.path
445
- connection.service_port = uri.port
446
- connection.service_scheme = uri.scheme
447
- connection.authok = true
448
- else
449
- connection.authok = false
450
- raise OpenStack::Exception::Authentication, "Authentication failed with response code #{response.code}"
451
- end
452
- server.finish
453
- end
454
559
 
455
- end
560
+ if response.code =~ /^20./
561
+ connection.authtoken = response['X-Subject-Token']
456
562
 
563
+ resp_data=JSON.parse(response.body)
457
564
 
458
- #============================
459
- # OpenStack::Exception
460
- #============================
565
+ catalog = resp_data["token"]["catalog"]
566
+ unless catalog
567
+ raise OpenStack::Exception::Authentication, "No service catalog returned. Maybe your auth request is unscoped. Please check if your selected user has a default project."
568
+ end
461
569
 
462
- class Exception
570
+ # Check if the used service is available
571
+ implemented_services = resp_data["token"]["catalog"].map {|service| service['type']}
572
+ raise OpenStack::Exception::NotImplemented.new("The requested service: \"#{connection.service_type}\" is not present " +
573
+ "in the returned service catalogue.", 501, "#{resp_data["access"]["serviceCatalog"]}") unless implemented_services.include?(connection.service_type)
574
+ catalog.each do |service|
575
+ service["endpoints"].each do |endpoint|
576
+ connection.regions_list[endpoint["region"]] ||= []
577
+ connection.regions_list[endpoint["region"]] << {:service=>service["type"], :versionId => endpoint["versionId"]}
578
+ end
463
579
 
464
- class ComputeError < StandardError
580
+ # set use preset service name if set, otherwise ignore.
581
+ if connection.service_name
582
+ check_service_name = connection.service_name
583
+ else
584
+ check_service_name = service['name']
585
+ end
465
586
 
466
- attr_reader :response_body
467
- attr_reader :response_code
587
+ if service['type'] == connection.service_type and service['name'] == check_service_name
588
+ endpoints = service["endpoints"]
468
589
 
469
- def initialize(message, code, response_body)
470
- @response_code=code
471
- @response_body=response_body
472
- super(message)
473
- end
590
+ # filter endpoints by interfacetype
591
+ interface_type = connection.endpoint_type.gsub('URL','')
592
+ endpoints = endpoints.select {|ep| ep['interface'] == interface_type}
474
593
 
475
- end
594
+ # Select endpoint based on region
595
+ if connection.region
596
+ endpoints.each do |ep|
597
+ if ep["region"] and ep["region"].upcase == connection.region.upcase
598
+ @uri = URI.parse(ep['url'])
599
+ end
600
+ end
601
+ else
602
+ @uri = URI.parse(endpoints[0]['url'])
603
+ end
476
604
 
477
- class ComputeFault < ComputeError # :nodoc:
478
- end
479
- class ServiceUnavailable < ComputeError # :nodoc:
480
- end
481
- class Unauthorized < ComputeError # :nodoc:
482
- end
483
- class BadRequest < ComputeError # :nodoc:
484
- end
485
- class OverLimit < ComputeError # :nodoc:
486
- end
487
- class BadMediaType < ComputeError # :nodoc:
488
- end
489
- class BadMethod < ComputeError # :nodoc:
490
- end
491
- class ItemNotFound < ComputeError # :nodoc:
492
- end
493
- class BuildInProgress < ComputeError # :nodoc:
494
- end
495
- class ServerCapacityUnavailable < ComputeError # :nodoc:
496
- end
497
- class BackupOrResizeInProgress < ComputeError # :nodoc:
498
- end
499
- class ResizeNotAllowed < ComputeError # :nodoc:
500
- end
501
- class NotImplemented < ComputeError # :nodoc:
502
- end
503
- class Other < ComputeError # :nodoc:
504
- end
505
- class ResourceStateConflict < ComputeError # :nodoc:
506
- end
507
- class QuantumError < ComputeError # :nodoc:
605
+ if @uri == ""
606
+ raise OpenStack::Exception::Authentication, "No API endpoint for region #{connection.region}"
607
+ else
608
+ connection.service_host = @uri.host
609
+ connection.service_path = @uri.path
610
+ connection.service_port = @uri.port
611
+ connection.service_scheme = @uri.scheme
612
+ connection.authok = true
613
+ end
614
+ end
615
+ end
616
+ else
617
+ connection.authtoken = false
618
+ raise OpenStack::Exception::Authentication, "Authentication failed with response code #{response.code}"
619
+ end
620
+ server.finish if server.started?
621
+ end
508
622
  end
509
623
 
510
- # Plus some others that we define here
511
624
 
512
- class ExpiredAuthToken < StandardError # :nodoc:
513
- end
514
- class MissingArgument < StandardError # :nodoc:
515
- end
516
- class InvalidArgument < StandardError # :nodoc:
517
- end
518
- class TooManyPersonalityItems < StandardError # :nodoc:
519
- end
520
- class PersonalityFilePathTooLong < StandardError # :nodoc:
521
- end
522
- class PersonalityFileTooLarge < StandardError # :nodoc:
523
- end
524
- class Authentication < StandardError # :nodoc:
525
- end
526
- class Connection < StandardError # :nodoc:
527
- end
625
+ #============================
626
+ # OpenStack::Exception
627
+ #============================
528
628
 
529
- # In the event of a non-200 HTTP status code, this method takes the HTTP response, parses
530
- # the JSON from the body to get more information about the exception, then raises the
531
- # proper error. Note that all exceptions are scoped in the OpenStack::Compute::Exception namespace.
532
- def self.raise_exception(response)
533
- return if response.code =~ /^20.$/
534
- begin
535
- fault = nil
536
- info = nil
537
- if response.body.nil? && response.code == "404" #HEAD ops no body returned
538
- exception_class = self.const_get("ItemNotFound")
539
- raise exception_class.new("The resource could not be found", "404", "")
540
- else
541
- JSON.parse(response.body).each_pair do |key, val|
542
- fault=key
543
- info=val
544
- end
545
- exception_class = self.const_get(fault[0,1].capitalize+fault[1,fault.length])
546
- raise exception_class.new((info["message"] || info), response.code, response.body)
629
+ class Exception
630
+ class ComputeError < StandardError
631
+ attr_reader :response_body
632
+ attr_reader :response_code
633
+
634
+ def initialize(message, code, response_body)
635
+ @response_code=code
636
+ @response_body=response_body
637
+ super(message)
547
638
  end
548
- rescue JSON::ParserError => parse_error
639
+ end
640
+
641
+ class ComputeFault < ComputeError # :nodoc:
642
+ end
643
+ class ServiceUnavailable < ComputeError # :nodoc:
644
+ end
645
+ class Unauthorized < ComputeError # :nodoc:
646
+ end
647
+ class BadRequest < ComputeError # :nodoc:
648
+ end
649
+ class OverLimit < ComputeError # :nodoc:
650
+ end
651
+ class BadMediaType < ComputeError # :nodoc:
652
+ end
653
+ class BadMethod < ComputeError # :nodoc:
654
+ end
655
+ class ItemNotFound < ComputeError # :nodoc:
656
+ end
657
+ class BuildInProgress < ComputeError # :nodoc:
658
+ end
659
+ class ServerCapacityUnavailable < ComputeError # :nodoc:
660
+ end
661
+ class BackupOrResizeInProgress < ComputeError # :nodoc:
662
+ end
663
+ class ResizeNotAllowed < ComputeError # :nodoc:
664
+ end
665
+ class NotImplemented < ComputeError # :nodoc:
666
+ end
667
+ class Other < ComputeError # :nodoc:
668
+ end
669
+ class ResourceStateConflict < ComputeError # :nodoc:
670
+ end
671
+ class QuantumError < ComputeError # :nodoc:
672
+ end
673
+
674
+ # Plus some others that we define here
675
+
676
+ class ExpiredAuthToken < StandardError # :nodoc:
677
+ end
678
+ class MissingArgument < StandardError # :nodoc:
679
+ end
680
+ class InvalidArgument < StandardError # :nodoc:
681
+ end
682
+ class TooManyPersonalityItems < StandardError # :nodoc:
683
+ end
684
+ class PersonalityFilePathTooLong < StandardError # :nodoc:
685
+ end
686
+ class PersonalityFileTooLarge < StandardError # :nodoc:
687
+ end
688
+ class Authentication < StandardError # :nodoc:
689
+ end
690
+ class Connection < StandardError # :nodoc:
691
+ end
692
+
693
+ # In the event of a non-200 HTTP status code, this method takes the HTTP response, parses
694
+ # the JSON from the body to get more information about the exception, then raises the
695
+ # proper error. Note that all exceptions are scoped in the OpenStack::Compute::Exception namespace.
696
+ def self.raise_exception(response)
697
+ return if response.code =~ /^20.$/
698
+ begin
699
+ fault = nil
700
+ info = nil
701
+ if response.body.nil? && response.code == "404" #HEAD ops no body returned
702
+ exception_class = self.const_get("ItemNotFound")
703
+ raise exception_class.new("The resource could not be found", "404", "")
704
+ else
705
+ JSON.parse(response.body).each_pair do |key, val|
706
+ fault=key
707
+ info=val
708
+ end
709
+ exception_class = self.const_get(fault[0,1].capitalize+fault[1,fault.length])
710
+ raise exception_class.new((info["message"] || info), response.code, response.body)
711
+ end
712
+ rescue JSON::ParserError => parse_error
549
713
  deal_with_faulty_error(response, parse_error)
550
- rescue NameError
551
- raise OpenStack::Exception::Other.new("The server returned status #{response.code}", response.code, response.body)
714
+ rescue NameError
715
+ raise OpenStack::Exception::Other.new("The server returned status #{response.code}", response.code, response.body)
716
+ end
552
717
  end
553
- end
554
718
 
555
- private
719
+ private
556
720
 
557
- #e.g. os.delete("non-existant") ==> response.body is:
558
- # "404 Not Found\n\nThe resource could not be found.\n\n "
559
- # which doesn't parse. Deal with such cases here if possible (JSON::ParserError)
560
- def self.deal_with_faulty_error(response, parse_error)
561
- case response.code
562
- when "404"
563
- klass = self.const_get("ItemNotFound")
564
- msg = "The resource could not be found"
565
- when "409"
566
- klass = self.const_get("ResourceStateConflict")
567
- msg = "There was a conflict with the state of the resource"
568
- else
569
- klass = self.const_get("Other")
570
- msg = "Oops - not sure what happened: #{parse_error}"
571
- end
572
- raise klass.new(msg, response.code.to_s, response.body)
721
+ #e.g. os.delete("non-existant") ==> response.body is:
722
+ # "404 Not Found\n\nThe resource could not be found.\n\n "
723
+ # which doesn't parse. Deal with such cases here if possible (JSON::ParserError)
724
+ def self.deal_with_faulty_error(response, parse_error)
725
+ case response.code
726
+ when "404"
727
+ klass = self.const_get("ItemNotFound")
728
+ msg = "The resource could not be found"
729
+ when "409"
730
+ klass = self.const_get("ResourceStateConflict")
731
+ msg = "There was a conflict with the state of the resource"
732
+ else
733
+ klass = self.const_get("Other")
734
+ msg = "Oops - not sure what happened: #{parse_error}"
735
+ end
736
+ raise klass.new(msg, response.code.to_s, response.body)
737
+ end
573
738
  end
574
739
  end
575
740
 
576
- end
577
-
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: 2.2.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Prince