misty 1.3.3 → 1.4.0

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.
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