misty 1.3.3 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +332 -267
  3. data/lib/misty.rb +1 -1
  4. data/lib/misty/auth.rb +17 -6
  5. data/lib/misty/auth/auth_v2.rb +3 -0
  6. data/lib/misty/auth/auth_v3.rb +13 -5
  7. data/lib/misty/auth/name.rb +3 -3
  8. data/lib/misty/client_pack.rb +2 -2
  9. data/lib/misty/cloud.rb +111 -76
  10. data/lib/misty/config.rb +138 -0
  11. data/lib/misty/{auth/errors.rb → errors.rb} +9 -1
  12. data/lib/misty/http/direct.rb +18 -1
  13. data/lib/misty/http/method_builder.rb +10 -17
  14. data/lib/misty/http/net_http.rb +1 -1
  15. data/lib/misty/http/request.rb +26 -14
  16. data/lib/misty/microversion.rb +22 -41
  17. data/lib/misty/misty.rb +14 -24
  18. data/lib/misty/openstack/cinder/v3.rb +8 -0
  19. data/lib/misty/openstack/ironic/v1.rb +8 -0
  20. data/lib/misty/openstack/magnum/v1.rb +5 -1
  21. data/lib/misty/openstack/manila/v2.rb +8 -0
  22. data/lib/misty/openstack/nova/v2_1.rb +13 -8
  23. data/lib/misty/openstack/service.rb +88 -0
  24. data/lib/misty/openstack/swift/v1.rb +2 -2
  25. data/lib/misty/service.rb +9 -12
  26. data/lib/misty/version.rb +1 -1
  27. data/test/integration/{network_test.rb → networking_test.rb} +8 -8
  28. data/test/integration/test_helper.rb +1 -0
  29. data/test/integration/vcr/{network_using_neutron_v2_0.yml → networking_using_neutron_v2_0.yml} +0 -0
  30. data/test/unit/auth/name_test.rb +31 -27
  31. data/test/unit/auth_helper.rb +4 -4
  32. data/test/unit/auth_test.rb +44 -30
  33. data/test/unit/cloud/config_test.rb +165 -0
  34. data/test/unit/cloud/requests_test.rb +0 -12
  35. data/test/unit/cloud/services_test.rb +41 -12
  36. data/test/unit/cloud_test.rb +35 -44
  37. data/test/unit/http/request_test.rb +1 -1
  38. data/test/unit/microversion_test.rb +59 -35
  39. data/test/unit/misty_test.rb +1 -1
  40. data/test/unit/openstack/service_test.rb +52 -0
  41. data/test/unit/service_helper.rb +23 -20
  42. data/test/unit/services_test.rb +1 -1
  43. data/test/unit/test_helper.rb +0 -4
  44. metadata +37 -22
  45. data/lib/misty/client.rb +0 -104
  46. data/test/unit/client_test.rb +0 -97
@@ -5,8 +5,16 @@ module Misty
5
5
  class TokenError < StandardError; end
6
6
 
7
7
  class ExpiryError < RuntimeError; end
8
- class CredentialsError < RuntimeError; end
9
8
  class InitError < RuntimeError; end
10
9
  class URLError < RuntimeError; end
11
10
  end
11
+
12
+ class Config
13
+ class CredentialsError < RuntimeError; end
14
+ class InvalidDataError < StandardError; end
15
+ end
16
+
17
+ module Microversion
18
+ class VersionError < RuntimeError; end
19
+ end
12
20
  end
@@ -1,7 +1,24 @@
1
1
  module Misty
2
2
  module HTTP
3
- # Provides methods to submit the current service with a path and override @base_path if needed
3
+ # Allows to submit http request wwith provided path and override base_path if needed
4
4
  module Direct
5
+
6
+ # ==== Examples
7
+ # auth = { ... }
8
+ # cloud = Misty::Cloud.new(:auth => auth)
9
+ #
10
+ # net = cloud.network.get('/v2.0/networks')
11
+ # pp net.body
12
+ #
13
+ # id = cloud.identity.get('/')
14
+ # pp id.body
15
+ #
16
+ # servers = cloud.compute.get('/servers')
17
+ # pp servers.body
18
+ #
19
+ # img = cloud.image.get('/v1')
20
+ # pp img.body
21
+
5
22
  def base_set(base_path)
6
23
  base = base_path ? base_path : @base_path
7
24
  end
@@ -21,13 +21,6 @@ module Misty
21
21
  end
22
22
 
23
23
  def method_call(method, *args)
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
30
-
31
24
  base, path = prefixed_path(method[:path])
32
25
  size_path_parameters = count_path_params(path)
33
26
  path_params = args[0, size_path_parameters]
@@ -37,26 +30,26 @@ module Misty
37
30
 
38
31
  case method[:request]
39
32
  when :COPY
40
- http_copy(final_path, header.get)
33
+ http_copy(final_path, @request_headers.get)
41
34
  when :DELETE
42
- http_delete(final_path, header.get)
35
+ http_delete(final_path, @request_headers.get)
43
36
  when :GET
44
37
  final_path << query_param(args_left.shift) if args_left && args_left.size == 1
45
- http_get(final_path, header.get)
38
+ http_get(final_path, @request_headers.get)
46
39
  when :HEAD
47
- http_head(final_path, header.get)
40
+ http_head(final_path, @request_headers.get)
48
41
  when :POST
49
42
  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)
43
+ data = process_data(@request_headers, args_left)
44
+ http_post(final_path, @request_headers.get, data)
52
45
  when :PUT
53
46
  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)
47
+ data = process_data(@request_headers, args_left)
48
+ http_put(final_path, @request_headers.get, data)
56
49
  when :PATCH
57
50
  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)
51
+ data = process_data(@request_headers, args_left)
52
+ http_patch(final_path, @request_headers.get, data)
60
53
  else
61
54
  raise SyntaxError, "Invalid HTTP request: #{method[:request]}"
62
55
  end
@@ -1,6 +1,6 @@
1
1
  module Misty
2
2
  module HTTP
3
- # This class implements the http request routine.
3
+ # This class wraps net/http request routine.
4
4
  module NetHTTP
5
5
  def self.http_request(uri, options = {})
6
6
  http_options = {}
@@ -1,21 +1,32 @@
1
1
  module Misty
2
2
  module HTTP
3
3
  module Request
4
+
5
+ DECODE_TO_JSON = ["application/json", "application/octet-stream"].freeze
6
+
4
7
  def decode?(response)
5
8
  return false if response.body.nil? || response.body.empty?
6
- if @config.content_type != :json && response.code =~ /2??/ && !response.is_a?(Net::HTTPNoContent) \
7
- && !response.is_a?(Net::HTTPResetContent) && response.header['content-type'] \
8
- && response.header['content-type'].include?('application/json')
9
+ if @request_content_type != :json && response.code =~ /2??/ \
10
+ && !response.is_a?(Net::HTTPNoContent) \
11
+ && !response.is_a?(Net::HTTPResetContent) \
12
+ && response.header['content-type'] && decode_to_json?(response.header['content-type'])
9
13
  return true
10
14
  end
11
15
  false
12
16
  end
13
17
 
18
+ def decode_to_json?(content_type)
19
+ DECODE_TO_JSON.each do |type|
20
+ return true if content_type.include?(type)
21
+ end
22
+ false
23
+ end
24
+
14
25
  def http(request)
15
26
  request['X-Auth-Token'] = @auth.get_token
16
27
 
17
28
  Misty::HTTP::NetHTTP.http_request(
18
- @uri, ssl_verify_mode: @options.ssl_verify_mode, log: @config.log
29
+ @uri, ssl_verify_mode: @ssl_verify_mode, log: @log
19
30
  ) do |connection|
20
31
  response = connection.request(request)
21
32
  response.body = JSON.parse(response.body) if decode?(response)
@@ -24,59 +35,60 @@ module Misty
24
35
  end
25
36
 
26
37
  def http_delete(path, headers)
27
- @config.log.info(http_to_s(path, headers))
38
+ @log.info(http_to_s('DELETE', path, headers))
28
39
  request = Net::HTTP::Delete.new(path, headers)
29
40
  http(request)
30
41
  end
31
42
 
32
43
  def http_copy(path, headers)
33
- @config.log.info(http_to_s(path, headers))
44
+ @log.info(http_to_s('COPY', path, headers))
34
45
  request = Net::HTTP::Copy.new(path, headers)
35
46
  http(request)
36
47
  end
37
48
 
38
49
  def http_get(path, headers)
39
- @config.log.info(http_to_s(path, headers))
50
+ @log.info(http_to_s('GET', path, headers))
40
51
  request = Net::HTTP::Get.new(path, headers)
41
52
  http(request)
42
53
  end
43
54
 
44
55
  def http_head(path, headers)
45
- @config.log.info(http_to_s(path, headers))
56
+ @log.info(http_to_s('HEAD', path, headers))
46
57
  request = Net::HTTP::Head.new(path, headers)
47
58
  http(request)
48
59
  end
49
60
 
50
61
  def http_options(path, headers)
51
- @config.log.info(http_to_s(path, headers))
62
+ @log.info(http_to_s('OPTIONS', path, headers))
52
63
  request = Net::HTTP::Options.new(path, headers)
53
64
  http(request)
54
65
  end
55
66
 
56
67
  def http_patch(path, headers, data)
57
- @config.log.info(http_to_s(path, headers, data))
68
+ @log.info(http_to_s('PATCH', path, headers, data))
58
69
  request = Net::HTTP::Patch.new(path, headers)
59
70
  request.body = data
60
71
  http(request)
61
72
  end
62
73
 
63
74
  def http_post(path, headers, data)
64
- @config.log.info(http_to_s(path, headers, data))
75
+ @log.info(http_to_s('POST', path, headers, data))
65
76
  request = Net::HTTP::Post.new(path, headers)
66
77
  request.body = data
67
78
  http(request)
68
79
  end
69
80
 
70
81
  def http_put(path, headers, data)
71
- @config.log.info(http_to_s(path, headers, data))
82
+ @log.info(http_to_s('PUT', path, headers, data))
72
83
  request = Net::HTTP::Put.new(path, headers)
73
84
  request.body = data
74
85
  http(request)
75
86
  end
76
87
 
77
- def http_to_s(path, headers, data = nil)
78
- log = "base_url='#{@uri.host}:#{@uri.port}', path='#{path}', header=#{headers}"
88
+ def http_to_s(verb, path, headers, data = nil)
89
+ log = "HTTP #{verb} base_url='#{@uri.host}:#{@uri.port}', path='#{path}', header=#{headers}"
79
90
  log << ", data='#{data}'" if data
91
+ log
80
92
  end
81
93
  end
82
94
  end
@@ -1,54 +1,28 @@
1
1
  module Misty
2
+ # Handles OpenStack Services supporting Microversion feature
2
3
  module Microversion
3
- class VersionError < RuntimeError; end
4
-
5
- VERSION_STATES = %w{CURRENT LATEST SUPPORTED}
6
-
7
- def initialize(auth, cloud, options)
8
- super
9
- @microversion = true
10
- @version = version_get(@options.version)
11
- end
12
-
13
- def microversion_header
14
- {'X-Openstack-API-Version' => "#{baseclass.downcase} #{@version}" }
15
- end
16
-
17
- def version_get(version_option)
18
- if VERSION_STATES.include?(version_option)
19
- return version_by_state(version_option)
4
+ def set_version(version)
5
+ case version
6
+ when nil || ''
7
+ # TODO:
8
+ # version_discovery
9
+ when 'latest'
10
+ 'latest'
11
+ when /^([1-9]+\d*)\.([1-9]+\d*)$/
12
+ version if version_match(version)
20
13
  else
21
- return version_by_number(version_option)
14
+ raise VersionError, ":version must be '<number.number>' or 'latest'"
22
15
  end
23
16
  end
24
17
 
25
- def versions
26
- @versions ||= versions_fetch
18
+ def microversion_header(version)
19
+ {'X-Openstack-API-Version' => "#{service_names[0]} #{version}" }
27
20
  end
28
21
 
29
22
  private
30
23
 
31
- def version_by_number(number)
32
- versions.each do |version|
33
- return number if version['min_version'] <= number && version['version'] >= number
34
- end
35
- raise VersionError, "Version #{number} is out of range of available versions #{versions}"
36
- end
37
-
38
- def version_by_state(state)
39
- version_details = nil
40
- versions.each do |version|
41
- if version['status'] == state
42
- version_details = version
43
- break
44
- end
45
- end
46
- raise VersionError, "Version #{state} is not available among #{versions}" if version_details.nil?
47
- if version_details['version'].empty?
48
- @microversion = false
49
- return ''
50
- end
51
- version_details['version']
24
+ def versions
25
+ @versions ||= versions_fetch
52
26
  end
53
27
 
54
28
  def versions_fetch
@@ -59,5 +33,12 @@ module Misty
59
33
  raise VersionError, 'Missing version data' unless list
60
34
  list
61
35
  end
36
+
37
+ def version_match(number)
38
+ versions.each do |version|
39
+ return number if version['min_version'] <= number && version['version'] >= number
40
+ end
41
+ raise VersionError, "Version #{number} is out of range of available versions: #{versions}"
42
+ end
62
43
  end
63
44
  end
@@ -1,19 +1,23 @@
1
1
  require 'misty/services'
2
+ require 'logger'
3
+
4
+ # Misty is a HTTP client for OpenStack APIs, aiming to be fast, flexible and exhaustive.
5
+ # Misty acts as a conduit to OpenStack APIs by handling requests as transparently as possible.
2
6
 
3
7
  module Misty
4
8
  SERVICES = [
5
9
  { name: :application_catalog, project: :murano, versions: ['v1']},
6
10
  { name: :alarming, project: :aodh, versions: ['v2']},
7
11
  { name: :backup, project: :freezer, versions: ['v1']},
8
- { name: :baremetal, project: :ironic, microversion: 'v1'},
9
- { name: :block_storage, project: :cinder, microversion: 'v3', versions: ['v2', 'v1']},
12
+ { name: :baremetal, project: :ironic, versions: ['v1'], microversion: 'v1'},
13
+ { name: :block_storage, project: :cinder, versions: ['v3', 'v2', 'v1'], microversion: 'v3'},
10
14
  { name: :clustering, project: :senlin, versions: ['v1']},
11
- { name: :compute, project: :nova, microversion: 'v2.1'},
12
- { name: :container_infrastructure_management, project: :magnum, microversion: 'v1'},
15
+ { name: :compute, project: :nova, versions: ['v2.1'], microversion: 'v2.1'},
16
+ { name: :container_infrastructure_management, project: :magnum, versions: ['v1'], microversion: 'v1'},
13
17
  { name: :data_processing, project: :sahara, versions: ['v1.1']},
14
18
  { name: :data_protection_orchestration, project: :karbor, versions: ['v1']},
15
19
  { name: :database, project: :trove, versions: ['v1.0']},
16
- { name: :domain_name_server, project: :designate, versions: ['v2']},
20
+ { name: :dns , project: :designate, versions: ['v2']},
17
21
  { name: :identity, project: :keystone, versions: ['v3', 'v2.0']},
18
22
  { name: :image, project: :glance, versions: ['v2', 'v1']},
19
23
  { name: :load_balancer, project: :octavia, versions: ['v2.0']},
@@ -24,30 +28,12 @@ module Misty
24
28
  { name: :object_storage, project: :swift, versions: ['v1']},
25
29
  { name: :orchestration, project: :heat, versions: ['v1']},
26
30
  { name: :search, project: :searchlight, versions: ['v1']},
27
- { name: :shared_file_systems, project: :manila, microversion: 'v2'}
31
+ { name: :shared_file_systems, project: :manila, versions: ['v2'], microversion: 'v2'}
28
32
  ]
29
33
 
30
- # Default REST content type. Use :json or :ruby
31
- CONTENT_TYPE = :ruby
32
-
33
34
  # Default Domain ID
34
35
  DOMAIN_ID = 'default'
35
36
 
36
- # Default Interface
37
- INTERFACE = 'public'
38
-
39
- # Default log file. Use :log_file option to override
40
- LOG_FILE = 'misty.log'
41
-
42
- # Default log level. Use :log_level option to override
43
- LOG_LEVEL = Logger::INFO
44
-
45
- # Default Region ID
46
- REGION_ID = 'regionOne'
47
-
48
- # Default when uri.scheme is https
49
- SSL_VERIFY_MODE = true
50
-
51
37
  def self.json_encode?(data)
52
38
  return true if data.is_a?(Array) || data.is_a?(Hash)
53
39
  if data.is_a?(String)
@@ -62,6 +48,10 @@ module Misty
62
48
  return false
63
49
  end
64
50
 
51
+ # Provides list of supported services
52
+ # ==== Example
53
+ # pp Misty.services
54
+
65
55
  def self.services
66
56
  services = Misty::Services.new
67
57
  SERVICES.each do |service|
@@ -10,6 +10,14 @@ module Misty
10
10
  include Misty::ClientPack
11
11
  include Misty::Microversion
12
12
 
13
+ def microversion
14
+ '3.44'
15
+ end
16
+
17
+ def microversion_header(version)
18
+ {'X-Openstack-Cinder-API-Version' => "#{version}"}
19
+ end
20
+
13
21
  def prefix_path_to_ignore
14
22
  '/v3/{tenant_id}'
15
23
  end
@@ -10,6 +10,14 @@ module Misty
10
10
  include Misty::ClientPack
11
11
  include Misty::Microversion
12
12
 
13
+ def microversion
14
+ '1.32'
15
+ end
16
+
17
+ def microversion_header(version)
18
+ {'X-Openstack-Ironic-API-Version' => "#{version}"}
19
+ end
20
+
13
21
  def service_names
14
22
  %w{baremetal}
15
23
  end
@@ -10,8 +10,12 @@ module Misty
10
10
  include Misty::ClientPack
11
11
  include Misty::HTTP::Microversion
12
12
 
13
+ def microversion
14
+ '1.4'
15
+ end
16
+
13
17
  def service_names
14
- %w{container}
18
+ %w{container-infrastructure-management container-infrastructure}
15
19
  end
16
20
  end
17
21
  end
@@ -10,6 +10,14 @@ module Misty
10
10
  include Misty::ClientPack
11
11
  include Misty::Microversion
12
12
 
13
+ def microversion
14
+ '2.40'
15
+ end
16
+
17
+ def microversion_header(version)
18
+ {'X-Openstack-Manila-API-Version' => "#{version}"}
19
+ end
20
+
13
21
  def service_names
14
22
  %w{shared-file-systems shared}
15
23
  end
@@ -20,16 +20,21 @@ module Misty
20
20
  http_get("/#{version}", headers)
21
21
  end
22
22
 
23
- def service_names
24
- %w{compute}
23
+ def microversion
24
+ '2.60'
25
+ end
26
+
27
+ def microversion_header(version)
28
+ # Use default 'OpenStack-API-Version' or older 'X-Openstack-Nova-API-Version'
29
+ if @version >= '2.27'
30
+ super
31
+ else
32
+ {'X-Openstack-Nova-API-Version' => "#{version}"}
33
+ end
25
34
  end
26
35
 
27
- def microversion_header
28
- # Versions 2.27+ use default OpenStack-API-Version
29
- header = super
30
- # For prior vesions then remove once depcrecated
31
- header.merge!('X-Openstack-Nova-API-Version' => "#{@version}",)
32
- header
36
+ def service_names
37
+ %w{compute}
33
38
  end
34
39
  end
35
40
  end