misty 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. checksums.yaml +4 -4
  2. data/lib/misty/auth.rb +5 -13
  3. data/lib/misty/auth/auth_v2.rb +13 -11
  4. data/lib/misty/auth/auth_v3.rb +11 -9
  5. data/lib/misty/auth/errors.rb +12 -0
  6. data/lib/misty/auth/name.rb +4 -4
  7. data/lib/misty/client.rb +105 -0
  8. data/lib/misty/client_pack.rb +16 -0
  9. data/lib/misty/http/method_builder.rb +36 -20
  10. data/lib/misty/misty.rb +14 -0
  11. data/lib/misty/openstack/aodh/aodh_v2.rb +1 -1
  12. data/lib/misty/openstack/aodh/v2.rb +5 -8
  13. data/lib/misty/openstack/ceilometer/ceilometer_v2.rb +1 -1
  14. data/lib/misty/openstack/ceilometer/v2.rb +5 -8
  15. data/lib/misty/openstack/cinder/cinder_v1.rb +1 -1
  16. data/lib/misty/openstack/cinder/cinder_v2.rb +1 -1
  17. data/lib/misty/openstack/cinder/cinder_v3.rb +1 -1
  18. data/lib/misty/openstack/cinder/v1.rb +6 -9
  19. data/lib/misty/openstack/cinder/v2.rb +6 -9
  20. data/lib/misty/openstack/cinder/v3.rb +7 -10
  21. data/lib/misty/openstack/designate/designate_v2.rb +1 -1
  22. data/lib/misty/openstack/designate/v2.rb +5 -8
  23. data/lib/misty/openstack/extension.rb +33 -0
  24. data/lib/misty/openstack/freezer/freezer_v1.rb +1 -1
  25. data/lib/misty/openstack/freezer/v1.rb +5 -8
  26. data/lib/misty/openstack/glance/glance_v1.rb +1 -1
  27. data/lib/misty/openstack/glance/glance_v2.rb +1 -1
  28. data/lib/misty/openstack/glance/v1.rb +5 -8
  29. data/lib/misty/openstack/glance/v2.rb +5 -8
  30. data/lib/misty/openstack/heat/heat_v1.rb +1 -1
  31. data/lib/misty/openstack/heat/v1.rb +6 -9
  32. data/lib/misty/openstack/ironic/ironic_v1.rb +1 -1
  33. data/lib/misty/openstack/ironic/v1.rb +6 -9
  34. data/lib/misty/openstack/karbor/karbor_v1.rb +1 -1
  35. data/lib/misty/openstack/karbor/v1.rb +5 -8
  36. data/lib/misty/openstack/keystone/keystone_v2_0.rb +1 -1
  37. data/lib/misty/openstack/keystone/keystone_v2_0_ext.rb +2 -2
  38. data/lib/misty/openstack/keystone/keystone_v3.rb +1 -1
  39. data/lib/misty/openstack/keystone/keystone_v3_ext.rb +2 -2
  40. data/lib/misty/openstack/keystone/v2_0.rb +8 -10
  41. data/lib/misty/openstack/keystone/v3.rb +8 -10
  42. data/lib/misty/openstack/magnum/magnum_v1.rb +1 -1
  43. data/lib/misty/openstack/magnum/v1.rb +6 -9
  44. data/lib/misty/openstack/manila/manila_v2.rb +1 -1
  45. data/lib/misty/openstack/manila/v2.rb +6 -9
  46. data/lib/misty/openstack/murano/murano_v1.rb +1 -1
  47. data/lib/misty/openstack/murano/v1.rb +5 -8
  48. data/lib/misty/openstack/neutron/neutron_v2_0.rb +1 -1
  49. data/lib/misty/openstack/neutron/v2_0.rb +5 -8
  50. data/lib/misty/openstack/nova/nova_v2_1.rb +1 -1
  51. data/lib/misty/openstack/nova/v2_1.rb +7 -9
  52. data/lib/misty/openstack/octavia/octavia_v2_0.rb +1 -1
  53. data/lib/misty/openstack/octavia/v2_0.rb +5 -8
  54. data/lib/misty/openstack/sahara/sahara_v1_1.rb +1 -1
  55. data/lib/misty/openstack/sahara/v1_1.rb +5 -8
  56. data/lib/misty/openstack/searchlight/searchlight_v1.rb +1 -1
  57. data/lib/misty/openstack/searchlight/v1.rb +5 -8
  58. data/lib/misty/openstack/senlin/senlin_v1.rb +1 -1
  59. data/lib/misty/openstack/senlin/v1.rb +5 -8
  60. data/lib/misty/openstack/swift/swift_v1.rb +1 -1
  61. data/lib/misty/openstack/swift/v1.rb +17 -9
  62. data/lib/misty/openstack/tacker/tacker_v1_0.rb +1 -1
  63. data/lib/misty/openstack/tacker/v1_0.rb +5 -8
  64. data/lib/misty/openstack/trove/trove_v1_0.rb +1 -1
  65. data/lib/misty/openstack/trove/v1_0.rb +5 -8
  66. data/lib/misty/openstack/zaqar/v2.rb +5 -8
  67. data/lib/misty/openstack/zaqar/zaqar_v2.rb +1 -1
  68. data/lib/misty/version.rb +1 -1
  69. data/test/unit/{http/client_test.rb → client_test.rb} +20 -8
  70. data/test/unit/cloud/requests_test.rb +77 -5
  71. data/test/unit/cloud/services_test.rb +20 -5
  72. data/test/unit/http/header_test.rb +0 -1
  73. data/test/unit/http/method_builder_test.rb +4 -4
  74. data/test/unit/http/request_test.rb +29 -20
  75. data/test/unit/microversion_test.rb +1 -1
  76. data/test/unit/misty_test.rb +18 -0
  77. data/test/unit/openstack/APIs_test.rb +18 -13
  78. data/test/unit/openstack/extension_test.rb +68 -0
  79. data/test/unit/service_helper.rb +1 -1
  80. metadata +8 -4
  81. data/lib/misty/http/client.rb +0 -108
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 5dc7dd3f594f1b57498eb00f5ec84950d93f1a7f
4
- data.tar.gz: 55db4993251e461c1a0ff34c71b88b4cbc84d475
3
+ metadata.gz: ffe75b3968e66e94826272e86f37008a8f8588c5
4
+ data.tar.gz: 1d22179b70ec1d3f0defcad2eccd8f375ccd27bc
5
5
  SHA512:
6
- metadata.gz: 25e78f721473b692864310a5adb8a0b59a46a92e704414532647495372711487397f75cedfa0020943624d185dad98985bb25a9be47aeb55e197ebbba1f758ba
7
- data.tar.gz: a387e6ba5f95e5c284a1bf9f1b6259d8703ae2e6d019ed2643bf95a5746d9594d70ee6047964e0b279a12ac1c4a2e8465fa67680f0cef182595044a7764566ad
6
+ metadata.gz: 1a35311aff1b3149a027ecc54843791b350d0c67da4551e0f589c601c5d186721e02754a3b1bcf690964d546c57212f7c9e8cdd30548c142cad7ccd39c5e4274
7
+ data.tar.gz: d5f88faf9a3076df2ddd3f2569b01d9885425d866e2c572069497de6167d782d54af995256b221235eb87c8fdf439060cd02cbdc0d2b053fc0a05cd7d9682040
@@ -1,17 +1,9 @@
1
- require 'misty/http/net_http'
1
+ require 'misty/auth/errors'
2
2
  require 'misty/auth/name'
3
+ require 'misty/http/net_http'
3
4
 
4
5
  module Misty
5
- class Auth
6
- class AuthenticationError < StandardError; end
7
- class CatalogError < StandardError; end
8
- class TokenError < StandardError; end
9
-
10
- class ExpiryError < RuntimeError; end
11
- class CredentialsError < RuntimeError; end
12
- class InitError < RuntimeError; end
13
- class URLError < RuntimeError; end
14
-
6
+ module Auth
15
7
  include Misty::HTTP::NetHTTP
16
8
 
17
9
  attr_reader :catalog, :token
@@ -41,7 +33,7 @@ module Misty
41
33
  Misty::HTTP::NetHTTP.http_request(
42
34
  @uri, ssl_verify_mode: @config.ssl_verify_mode, log: @config.log
43
35
  ) do |connection|
44
- response = connection.post(self.class.path, @credentials.to_json,
36
+ response = connection.post(path, @credentials.to_json,
45
37
  { 'Content-Type' => 'application/json', 'Accept' => 'application/json' })
46
38
  unless response.code =~ /200|201/
47
39
  raise AuthenticationError, "Response code=#{response.code}, Msg=#{response.msg}"
@@ -76,7 +68,7 @@ module Misty
76
68
  def find_url(service, region_id, interface)
77
69
  if service['endpoints']
78
70
  service['endpoints'].each do |endpoint|
79
- if (url = self.class.get_url(endpoint, region_id, interface))
71
+ if (url = endpoint_url(endpoint, region_id, interface))
80
72
  return url
81
73
  end
82
74
  end
@@ -1,21 +1,15 @@
1
1
  require 'misty/auth'
2
2
 
3
3
  module Misty
4
- class AuthV2 < Misty::Auth
5
- def self.path
6
- '/v2.0/tokens'
7
- end
8
-
9
- def self.get_url(endpoint, region_id, interface)
10
- return endpoint["#{interface}URL"] if endpoint['region'] == region_id && endpoint["#{interface}URL"]
11
- end
4
+ class AuthV2
5
+ include Misty::Auth
12
6
 
13
7
  def credentials
14
8
  if @token
15
9
  identity = { 'token': { 'id': @token } }
16
10
  else
17
- raise Misty::Auth::CredentialsError, "#{self.class}: User name is required" if @user.name.nil?
18
- raise Misty::Auth::CredentialsError, "#{self.class}: User password is required" if @user.password.nil?
11
+ raise CredentialsError, "#{self.class}: User name is required" if @user.name.nil?
12
+ raise CredentialsError, "#{self.class}: User password is required" if @user.password.nil?
19
13
  identity = { 'passwordCredentials': user_credentials }
20
14
  end
21
15
 
@@ -24,12 +18,20 @@ module Misty
24
18
  elsif @tenant.name
25
19
  identity.merge!('tenantName': @tenant.name)
26
20
  else
27
- raise Misty::Auth::CredentialsError, "#{self.class}: No tenant available"
21
+ raise CredentialsError, "#{self.class}: No tenant available"
28
22
  end
29
23
 
30
24
  { 'auth': identity }
31
25
  end
32
26
 
27
+ def endpoint_url(endpoint, region_id, interface)
28
+ return endpoint["#{interface}URL"] if endpoint['region'] == region_id && endpoint["#{interface}URL"]
29
+ end
30
+
31
+ def path
32
+ '/v2.0/tokens'
33
+ end
34
+
33
35
  def user_credentials
34
36
  {
35
37
  'username': @user.name,
@@ -1,14 +1,8 @@
1
1
  require 'misty/auth'
2
2
 
3
3
  module Misty
4
- class AuthV3 < Misty::Auth
5
- def self.path
6
- '/v3/auth/tokens'
7
- end
8
-
9
- def self.get_url(endpoint, region_id, interface)
10
- return endpoint['url'] if endpoint['region_id'] == region_id && endpoint['interface'] == interface
11
- end
4
+ class AuthV3
5
+ include Misty::Auth
12
6
 
13
7
  def credentials
14
8
  if @token
@@ -30,10 +24,18 @@ module Misty
30
24
  }
31
25
  end
32
26
 
27
+ def endpoint_url(endpoint, region_id, interface)
28
+ return endpoint['url'] if endpoint['region_id'] == region_id && endpoint['interface'] == interface
29
+ end
30
+
31
+ def path
32
+ '/v3/auth/tokens'
33
+ end
34
+
33
35
  def scope
34
36
  return @project.identity if @project
35
37
  return @domain.identity if @domain
36
- raise Misty::Auth::CredentialsError, "#{self.class}: No scope available"
38
+ raise CredentialsError, "#{self.class}: No scope available"
37
39
  end
38
40
 
39
41
  def set(response)
@@ -0,0 +1,12 @@
1
+ module Misty
2
+ module Auth
3
+ class AuthenticationError < StandardError; end
4
+ class CatalogError < StandardError; end
5
+ class TokenError < StandardError; end
6
+
7
+ class ExpiryError < RuntimeError; end
8
+ class CredentialsError < RuntimeError; end
9
+ class InitError < RuntimeError; end
10
+ class URLError < RuntimeError; end
11
+ end
12
+ end
@@ -1,5 +1,5 @@
1
1
  module Misty
2
- class Auth
2
+ module Auth
3
3
  module Domain
4
4
  attr_accessor :domain
5
5
 
@@ -11,7 +11,7 @@ module Misty
11
11
  data.merge!(to_h(:name))
12
12
  data.merge!({ :domain => @domain.identity })
13
13
  else
14
- raise Misty::Auth::CredentialsError, "#{self.class}: An Id, or a name with its domain, must be provided"
14
+ raise CredentialsError, "#{self.class}: An Id, or a name with its domain, must be provided"
15
15
  end
16
16
  data
17
17
  end
@@ -21,7 +21,7 @@ module Misty
21
21
  def identity
22
22
  return to_h(:id) unless id.nil?
23
23
  return to_h(:name) unless name.nil?
24
- raise Misty::Auth::CredentialsError, "#{self.class}: No available id or name"
24
+ raise CredentialsError, "#{self.class}: No available id or name"
25
25
  end
26
26
 
27
27
  def to_h(var)
@@ -50,7 +50,7 @@ module Misty
50
50
 
51
51
  def identity
52
52
  data = super
53
- raise Misty::Auth::CredentialsError, "#{self.class}: No password available" if password.nil?
53
+ raise CredentialsError, "#{self.class}: No password available" if password.nil?
54
54
  data.merge!(to_h(:password))
55
55
  { :user => data }
56
56
  end
@@ -0,0 +1,105 @@
1
+ module Misty
2
+ module Client
3
+ class Options
4
+ attr_accessor :base_path, :base_url, :headers, :interface, :region_id,
5
+ :service_names, :ssl_verify_mode, :version
6
+ end
7
+
8
+ class InvalidDataError < StandardError; end
9
+
10
+ INTERFACES = %w{admin public internal}
11
+
12
+ attr_reader :headers, :microversion
13
+
14
+ # Options - Values shown are the default
15
+ # Base path can be forced (Not recommended, mainly used for test purposes)
16
+ # :base_path => nil
17
+ # URL can be forced (Helps when setup is broken)
18
+ # :base_url => nil
19
+ # Optional headers
20
+ # :headers => {}
21
+ # Endpoint type (admin, public or internal)
22
+ # :interface => "public"
23
+ # Region ID
24
+ # :region_id => "regionOne"
25
+ # Service name
26
+ # The Service names are pre defined but more can be added using this option.
27
+ # :service_name
28
+ # SSL Verify Mode
29
+ # :ssl_verify_mode => true
30
+ # (micro)version: Can be numbered (3.1) or by state (CURRENT, LATEST or SUPPORTED)
31
+ # :version => "CURRENT"
32
+ def initialize(auth, config, options = {})
33
+ @auth = auth
34
+ @config = config
35
+ @options = setup(options)
36
+ @uri = URI.parse(@auth.get_url(@options.service_names, @options.region_id, @options.interface))
37
+ @base_path = @options.base_path ? @options.base_path : @uri.path
38
+ @base_path = @base_path.chomp('/')
39
+ @version = nil
40
+ @microversion = false
41
+ @headers = Misty::HTTP::Header.new(@config.headers.get.clone)
42
+ @headers.add('X-Auth-Token' => @auth.get_token.to_s)
43
+ @headers.add(microversion_header) if microversion
44
+ @headers.add(@options.headers) unless @options.headers.empty?
45
+ end
46
+
47
+ # Mixing classes to override
48
+ # When a catalog provides a base path and the Service API definition containts the generic equivalent as prefix
49
+ # then the preifx is redundant and must be removed from the path.
50
+ # For example:
51
+ # Catalog provides 'http://192.0.2.21:8004/v1/48985e6b8da145699d411f12a3459fca'
52
+ # and Service API has '/v1/{tenant_id}/stacks'
53
+ # then the path prefix is ignored and path is only '/stacks'
54
+ def prefix_path_to_ignore
55
+ ''
56
+ end
57
+
58
+ def requests
59
+ requests_api + requests_custom
60
+ end
61
+
62
+ private
63
+
64
+ def baseclass
65
+ self.class.to_s.split('::')[-1]
66
+ end
67
+
68
+ def requests_api
69
+ @requests_api_list ||= begin
70
+ list = []
71
+ api.each do |_path, verbs|
72
+ verbs.each do |_verb, requests|
73
+ list << requests
74
+ end
75
+ end
76
+ list.flatten!
77
+ end
78
+ end
79
+
80
+ def requests_custom
81
+ []
82
+ end
83
+
84
+ def setup(params)
85
+ options = Options.new()
86
+ options.base_path = params[:base_path] ? params[:base_path] : nil
87
+ options.base_url = params[:base_url] ? params[:base_url] : nil
88
+ options.headers = params[:headers] ? params[:headers] : {}
89
+ options.interface = params[:interface] ? params[:interface] : @config.interface
90
+ options.region_id = params[:region_id] ? params[:region_id] : @config.region_id
91
+ options.service_names = params[:service_name] ? service_names << params[:service_name] : service_names
92
+ options.ssl_verify_mode = params[:ssl_verify_mode].nil? ? @config.ssl_verify_mode : params[:ssl_verify_mode]
93
+ options.version = params[:version] ? params[:version] : 'CURRENT'
94
+
95
+ unless INTERFACES.include?(options.interface)
96
+ raise InvalidDataError, "Options ':interface' must be one of #{INTERFACES}"
97
+ end
98
+
99
+ unless options.ssl_verify_mode == !!options.ssl_verify_mode
100
+ raise InvalidDataError, "Options ':ssl_verify_mode' must be a boolean"
101
+ end
102
+ options
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,16 @@
1
+ require 'misty/client'
2
+ require 'misty/http/net_http'
3
+ require 'misty/http/method_builder'
4
+ require 'misty/http/request'
5
+ require 'misty/http/direct'
6
+ require 'misty/http/header'
7
+
8
+ module Misty
9
+ module ClientPack
10
+ include Misty::Client
11
+ include Misty::HTTP::NetHTTP
12
+ include Misty::HTTP::MethodBuilder
13
+ include Misty::HTTP::Request
14
+ include Misty::HTTP::Direct
15
+ end
16
+ end
@@ -11,9 +11,22 @@ module Misty
11
11
 
12
12
  private
13
13
 
14
+ def process_data(header, args)
15
+ if args.size == 1 && Misty.json_encode?(args[0])
16
+ header.add('Content-Type' => 'application/json')
17
+ return Misty.to_json(args[0])
18
+ elsif args.size == 1
19
+ return args[0]
20
+ end
21
+ end
22
+
14
23
  def method_call(method, *args)
15
- header = @headers.get.clone
16
- header.merge!(args.pop.get) if args[-1].class == Misty::HTTP::Header
24
+ if args[-1].class == Misty::HTTP::Header
25
+ header = Misty::HTTP::Header.new(@headers.get.clone)
26
+ header.add(args.pop.get)
27
+ else
28
+ header = @headers
29
+ end
17
30
 
18
31
  base, path = prefixed_path(method[:path])
19
32
  size_path_parameters = count_path_params(path)
@@ -24,23 +37,26 @@ module Misty
24
37
 
25
38
  case method[:request]
26
39
  when :COPY
27
- http_copy(final_path, header)
40
+ http_copy(final_path, header.get)
28
41
  when :DELETE
29
- http_delete(final_path, header)
42
+ http_delete(final_path, header.get)
30
43
  when :GET
31
- final_path << query_param(args_left[0]) if args_left && args_left.size == 1
32
- http_get(final_path, header)
44
+ final_path << query_param(args_left.shift) if args_left && args_left.size == 1
45
+ http_get(final_path, header.get)
33
46
  when :HEAD
34
- http_head(final_path, header)
47
+ http_head(final_path, header.get)
35
48
  when :POST
36
- data = args_left[0] if args_left && args_left.size == 1
37
- http_post(final_path, header, data)
49
+ final_path << query_param(args_left.shift) if args_left && args_left.size == 2
50
+ data = process_data(header, args_left)
51
+ http_post(final_path, header.get, data)
38
52
  when :PUT
39
- data = args_left[0] if args_left && args_left.size == 1
40
- http_put(final_path, header, data)
53
+ final_path << query_param(args_left.shift) if args_left && args_left.size == 2
54
+ data = process_data(header, args_left)
55
+ http_put(final_path, header.get, data)
41
56
  when :PATCH
42
- data = args_left[0] if args_left && args_left.size == 1
43
- http_patch(final_path, header, data)
57
+ final_path << query_param(args_left.shift) if args_left && args_left.size == 2
58
+ data = process_data(header, args_left)
59
+ http_patch(final_path, header.get, data)
44
60
  else
45
61
  raise SyntaxError, "Invalid HTTP request: #{method[:request]}"
46
62
  end
@@ -58,10 +74,10 @@ module Misty
58
74
  end
59
75
 
60
76
  def get_method(name)
61
- self.class.api.each do |path, requests|
62
- requests.each do |request, methods_list|
63
- if methods_list.include?(name)
64
- return {:path => path, :request => request, :name => name}
77
+ api.each do |path, verbs_list|
78
+ verbs_list.each do |verb, methods|
79
+ if methods.include?(name)
80
+ return {:path => path, :request => verb, :name => name}
65
81
  end
66
82
  end
67
83
  end
@@ -77,9 +93,9 @@ module Misty
77
93
  end
78
94
 
79
95
  def prefixed_path(path)
80
- unless self.class.prefix_path_to_ignore.empty?
81
- if path =~ %r{#{self.class.prefix_path_to_ignore}}
82
- return true, path.gsub(self.class.prefix_path_to_ignore, '')
96
+ unless prefix_path_to_ignore.empty?
97
+ if path =~ %r{#{prefix_path_to_ignore}}
98
+ return true, path.gsub(prefix_path_to_ignore, '')
83
99
  else
84
100
  return false, path
85
101
  end
@@ -48,6 +48,20 @@ module Misty
48
48
  # Default when uri.scheme is https
49
49
  SSL_VERIFY_MODE = true
50
50
 
51
+ def self.json_encode?(data)
52
+ return true if data.is_a?(Array) || data.is_a?(Hash)
53
+ if data.is_a?(String)
54
+ begin
55
+ JSON.parse(data)
56
+ rescue JSON::ParserError
57
+ return false
58
+ else
59
+ return true
60
+ end
61
+ end
62
+ return false
63
+ end
64
+
51
65
  def self.services
52
66
  services = Misty::Services.new
53
67
  SERVICES.each do |service|
@@ -1,5 +1,5 @@
1
1
  module Misty::Openstack::AodhV2
2
- def v2
2
+ def api
3
3
  {"/v2/capabilities"=>{:GET=>[:list_capabilities]},
4
4
  "/v2/alarms"=>{:GET=>[:list_alarms], :POST=>[:create_alarm]},
5
5
  "/v2/alarms/{alarm_id}"=>
@@ -1,17 +1,14 @@
1
- require 'misty/http/client'
2
1
  require 'misty/openstack/aodh/aodh_v2'
2
+ require 'misty/client_pack'
3
3
 
4
4
  module Misty
5
5
  module Openstack
6
6
  module Aodh
7
- class V2 < Misty::HTTP::Client
8
- extend Misty::Openstack::AodhV2
7
+ class V2
8
+ include Misty::Openstack::AodhV2
9
+ include Misty::ClientPack
9
10
 
10
- def self.api
11
- v2
12
- end
13
-
14
- def self.service_names
11
+ def service_names
15
12
  %w{alarming}
16
13
  end
17
14
  end