misty 0.5.1 → 0.6.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: '0108d5bb9451b9500d689c21f6cf43b4ae90186c'
4
- data.tar.gz: a6d0744f4806007d55044ad7fe3f96e4be645ec0
3
+ metadata.gz: 8f77fca7e84ccf06eb7cf92b3c2ee1a9233d0427
4
+ data.tar.gz: d8d73c45718a708d0da3f5bf076aa0cc802c0f4c
5
5
  SHA512:
6
- metadata.gz: b73c8d875c03a7495c5e84be31ca00e9b6b13667d0a576334e710f76a6586ec47a7400022ef29f6e896cea866793ac2d41f174cbfb9b81b6b016137875957335
7
- data.tar.gz: 8df0ce513d52b08551537a0fe6dc702ce1d6f7e9f06ac43082c1f14a7c27d33952d136273592a8eb8ba6a936077c9eca8450bc49a897ef3dfcc85caae4d5a943
6
+ metadata.gz: 5a98bcc69158a796d55ee9ce9ba7ccb5cc6d6f99bc0fc9217137e00905a243cc1608aea11dd9dc996423dcfdc9c2ad25a1435bc17cbbe66cfc03c1c9e491ed78
7
+ data.tar.gz: 72475d27ad43c025522654ce010b520a837cfd70c403ae8ac70b632300ab7c900e03eda7f860d2fe53b095ce6324e3438304143e9957ff4866ee8c7849b68b84
data/README.md CHANGED
@@ -152,6 +152,10 @@ The following parameters can be used:
152
152
  User domain id
153
153
  * `:user_domain`
154
154
  User domain name
155
+ * `:password`
156
+ Password for user. Cannot be used together with `:token`.
157
+ * `:token`
158
+ Previous Keystone v3 token for user. Can only be used with Keystone v3. Overrides all user and password parameters.
155
159
 
156
160
  #### Keystone v3
157
161
  Keystone v3 is default recommended version:
@@ -212,10 +216,6 @@ The following options are applied to each service unless specifically provided f
212
216
  Type: String
213
217
  Allowed values: "public", "internal", "admin"
214
218
  Default: "public"
215
- * :http_proxy
216
- For example: `"http://userid:password@somewhere.com:8080/"` or `ENV["http_proxy"]`
217
- Type: String
218
- Default: `""`
219
219
  * :ssl_verify_mode
220
220
  When using SSL mode (defined by URI scheme => "https://")
221
221
  Type: Boolean
@@ -276,8 +276,12 @@ openstack.network.post("/v2.0/qos/policies/48985e6b8da145699d411f12a3459fca/dscp
276
276
  # Requirements
277
277
 
278
278
  ## Ruby versions tested
279
+ * Ruby 2.4.1
279
280
  * Ruby 2.4.0
281
+ * Ruby 2.3.4
280
282
  * Ruby 2.3.3
283
+ * Ruby 2.3.2
284
+ * Ruby 2.3.1
281
285
  * Ruby 2.3.0
282
286
 
283
287
  # Contributing
@@ -14,31 +14,27 @@ module Misty
14
14
 
15
15
  include Misty::HTTP::NetHTTP
16
16
 
17
- def self.factory(options, *args)
18
- if options[:tenant_id] || options[:tenant]
19
- return Misty::AuthV2.new(options, *args)
17
+ attr_reader :catalog
18
+
19
+ def self.factory(auth, config)
20
+ if auth[:tenant_id] || auth[:tenant]
21
+ return Misty::AuthV2.new(auth, config)
20
22
  else
21
- return Misty::AuthV3.new(options, *args)
23
+ return Misty::AuthV3.new(auth, config)
22
24
  end
23
25
  end
24
26
 
25
- attr_reader :catalog
26
-
27
- def initialize(options, proxy, ssl_verify_mode, log)
28
- @ssl_verify_mode, @log = ssl_verify_mode, log
29
- @credentials = scoped_authentication
30
-
31
- raise URLError, "No URL provided" unless options[:url] && !options[:url].empty?
32
- @uri = URI.parse(options[:url])
33
- @proxy = proxy
27
+ def initialize(auth, config)
28
+ raise URLError, "No URL provided" unless auth[:url] && !auth[:url].empty?
29
+ @credentials = set_credentials(auth)
30
+ @http = net_http(URI.parse(auth[:url]), config.ssl_verify_mode, config.log)
34
31
  @token = nil
35
- setup(authenticate)
32
+ @token, @catalog, @expires = set(authenticate)
36
33
  raise CatalogError, "No catalog provided during authentication" if @catalog.empty?
37
34
  end
38
35
 
39
36
  def authenticate
40
- http = net_http(@uri, @proxy, @ssl_verify_mode, @log)
41
- response = http.post(self.class.path, @credentials.to_json, Misty::HEADER_JSON)
37
+ response = @http.post(self.class.path, @credentials.to_json, Misty::HEADER_JSON)
42
38
  raise AuthenticationError, "Response code=#{response.code}, Msg=#{response.msg}" unless response.code =~ /200|201/
43
39
  response
44
40
  end
@@ -58,7 +54,7 @@ module Misty
58
54
  end
59
55
 
60
56
  def get_token
61
- authenticate if expired?
57
+ @token, @catalog, @expires = set(authenticate) if expired?
62
58
  @token
63
59
  end
64
60
  end
@@ -6,13 +6,6 @@ module Misty
6
6
  "/v2.0/tokens"
7
7
  end
8
8
 
9
- def initialize(options, *args)
10
- @user = Misty::Auth::User.new(options[:user_id], options[:user])
11
- @user.password = options[:password]
12
- @tenant = Misty::Auth::Name.new(options[:tenant_id], options[:tenant])
13
- super(options, *args)
14
- end
15
-
16
9
  def catalog_endpoints(endpoints, region, interface)
17
10
  endpoints.each do |endpoint|
18
11
  if endpoint["region"] == region && endpoint["#{interface}URL"]
@@ -21,50 +14,58 @@ module Misty
21
14
  end
22
15
  end
23
16
 
24
- def get_endpoint_url(endpoints, region, interface)
25
- endpoint = endpoints.select { |ep| !ep[interface].empty? }
26
- raise CatalogError, "No endpoint available for region '#{region}' and interface '#{interface}'" unless endpoint
27
- endpoint[0][interface]
28
- end
29
-
30
- def setup(response)
31
- payload = JSON.load(response.body)
32
- @token = payload["access"]["token"]["id"]
33
- @catalog = payload["access"]["serviceCatalog"]
34
- @expires = payload["access"]["token"]["expires"]
35
- end
36
-
37
- def scoped_authentication
17
+ def credentials
38
18
  raise Misty::Auth::CredentialsError, "#{self.class}: User name is required" if @user.name.nil?
39
19
  raise Misty::Auth::CredentialsError, "#{self.class}: User password is required" if @user.password.nil?
40
- return auth_by_id if @tenant.id
41
- return auth_by_name if @tenant.name
20
+ return creds_by_id if @tenant.id
21
+ return creds_by_name if @tenant.name
42
22
  raise Misty::Auth::CredentialsError, "#{self.class}: No tenant available"
43
23
  end
44
24
 
45
- def auth_by_name
25
+ def credentials_data
26
+ {
27
+ "username": @user.name,
28
+ "password": @user.password
29
+ }
30
+ end
31
+
32
+ def creds_by_name
46
33
  {
47
34
  "auth": {
48
- "passwordCredentials": credentials,
35
+ "passwordCredentials": credentials_data,
49
36
  "tenantName": @tenant.name
50
37
  }
51
38
  }
52
39
  end
53
40
 
54
- def auth_by_id
41
+ def creds_by_id
55
42
  {
56
43
  "auth": {
57
- "passwordCredentials": credentials,
44
+ "passwordCredentials": credentials_data,
58
45
  "tenantId": @tenant.id
59
46
  }
60
47
  }
61
48
  end
62
49
 
63
- def credentials
64
- {
65
- "username": @user.name,
66
- "password": @user.password
67
- }
50
+ def get_endpoint_url(endpoints, region, interface)
51
+ endpoint = endpoints.select { |ep| !ep[interface].empty? }
52
+ raise CatalogError, "No endpoint available for region '#{region}' and interface '#{interface}'" unless endpoint
53
+ endpoint[0][interface]
54
+ end
55
+
56
+ def set(response)
57
+ payload = JSON.load(response.body)
58
+ token = payload["access"]["token"]["id"]
59
+ catalog = payload["access"]["serviceCatalog"]
60
+ expires = payload["access"]["token"]["expires"]
61
+ [token, catalog, expires]
62
+ end
63
+
64
+ def set_credentials(auth)
65
+ @user = Misty::Auth::User.new(auth[:user_id], auth[:user])
66
+ @user.password = auth[:password]
67
+ @tenant = Misty::Auth::Name.new(auth[:tenant_id], auth[:tenant])
68
+ credentials
68
69
  end
69
70
  end
70
71
  end
@@ -2,26 +2,6 @@ require 'misty/auth'
2
2
 
3
3
  module Misty
4
4
  class AuthV3 < Misty::Auth
5
- def initialize(options, *args)
6
- if options[:project_id] || options[:project]
7
- # scope: project
8
- project_domain_id = options[:project_domain_id] ? options[:project_domain_id] : Misty::DOMAIN_ID
9
- @project = Misty::Auth::ProjectScope.new(options[:project_id], options[:project])
10
- @project.domain = Misty::Auth::Name.new(project_domain_id, options[:user_domain])
11
- else
12
- # scope: domain
13
- domain_id = options[:domain_id] ? options[:domain_id] : Misty::DOMAIN_ID
14
- @domain = Misty::Auth::DomainScope.new(domain_id, options[:domain]) if domain_id || options[:domain]
15
- end
16
-
17
- user_domain_id = options[:user_domain_id] ? options[:user_domain_id] : Misty::DOMAIN_ID
18
- @user = Misty::Auth::User.new(options[:user_id], options[:user])
19
- @user.password = options[:password]
20
- @user.domain = Misty::Auth::Name.new(user_domain_id, options[:user_domain])
21
-
22
- super(options, *args)
23
- end
24
-
25
5
  def self.path
26
6
  "/v3/auth/tokens"
27
7
  end
@@ -34,35 +14,68 @@ module Misty
34
14
  end
35
15
  end
36
16
 
37
- def get_endpoint_url(endpoints, region, interface)
38
- endpoint = endpoints.select { |ep| ep["region_id"] == region && ep["interface"] == interface }
39
- raise CatalogError, "No endpoint available for region '#{region}' and interface '#{interface}'" unless endpoint
40
- endpoint[0]["url"]
41
- end
42
-
43
- def scoped_authentication
17
+ def credentials
18
+ if @token
19
+ identity = {
20
+ "methods": ["token"],
21
+ "token": { "id": @token }
22
+ }
23
+ else
24
+ identity = {
25
+ "methods": ["password"],
26
+ "password": @user.identity
27
+ }
28
+ end
44
29
  {
45
30
  "auth": {
46
- "identity": {
47
- "methods": ["password"],
48
- "password": @user.identity
49
- },
31
+ "identity": identity,
50
32
  "scope": scope
51
33
  }
52
34
  }
53
35
  end
54
36
 
37
+ def get_endpoint_url(endpoints, region, interface)
38
+ endpoint = endpoints.select { |ep| ep["region_id"] == region && ep["interface"] == interface }
39
+ raise CatalogError, "No endpoint available for region '#{region}' and interface '#{interface}'" unless endpoint
40
+ endpoint[0]["url"]
41
+ end
42
+
55
43
  def scope
56
44
  return @project.identity if @project
57
45
  return @domain.identity if @domain
58
46
  raise Misty::Auth::CredentialsError, "#{self.class}: No scope available"
59
47
  end
60
48
 
61
- def setup(response)
49
+ def set(response)
62
50
  payload = JSON.load(response.body)
63
- @token = response["x-subject-token"]
64
- @catalog = payload["token"]["catalog"]
65
- @expires = payload["token"]["expires_at"]
51
+ token = response["x-subject-token"]
52
+ catalog = payload["token"]["catalog"]
53
+ expires = payload["token"]["expires_at"]
54
+ [token, catalog, expires]
55
+ end
56
+
57
+ def set_credentials(auth)
58
+ if auth[:project_id] || auth[:project]
59
+ # scope: project
60
+ project_domain_id = auth[:project_domain_id] ? auth[:project_domain_id] : Misty::DOMAIN_ID
61
+ @project = Misty::Auth::ProjectScope.new(auth[:project_id], auth[:project])
62
+ @project.domain = Misty::Auth::Name.new(project_domain_id, auth[:user_domain])
63
+ else
64
+ # scope: domain
65
+ domain_id = auth[:domain_id] ? auth[:domain_id] : Misty::DOMAIN_ID
66
+ @domain = Misty::Auth::DomainScope.new(domain_id, auth[:domain]) if domain_id || auth[:domain]
67
+ end
68
+
69
+ if auth[:token]
70
+ @token = auth[:token]
71
+ else
72
+ user_domain_id = auth[:user_domain_id] ? auth[:user_domain_id] : Misty::DOMAIN_ID
73
+ @user = Misty::Auth::User.new(auth[:user_id], auth[:user])
74
+ @user.password = auth[:password]
75
+ @user.domain = Misty::Auth::Name.new(user_domain_id, auth[:user_domain])
76
+ end
77
+
78
+ credentials
66
79
  end
67
80
  end
68
81
  end
@@ -3,62 +3,39 @@ require 'misty/auth/auth_v3'
3
3
 
4
4
  module Misty
5
5
  class Cloud
6
- class Setup
7
- attr_accessor :auth, :content_type, :log, :interface, :proxy, :region_id, :ssl_verify_mode
6
+ class Config
7
+ attr_accessor :auth, :content_type, :interface, :log, :region_id, :ssl_verify_mode
8
8
  end
9
9
 
10
- Options = Struct.new(:alarming, :baremetal, :block_storage, :clustering, :compute, :container, :data_processing,
11
- :database, :data_protection, :dns, :identity, :image, :messaging, :metering, :network, :object_storage,
12
- :orchestration, :search, :shared_file_systems)
13
-
14
- attr_reader :services
15
-
16
- def initialize(params = {:auth => {}})
17
- @setup = self.class.setup(params)
18
- @options = Options.new
19
- @services = setup_services(params)
10
+ def self.dot_to_underscore(val)
11
+ val.gsub(/\./,'_')
20
12
  end
21
13
 
22
- def self.setup(params)
23
- setup = Setup.new
24
- setup.content_type = params[:content_type] ? params[:content_type] : Misty::CONTENT_TYPE
25
- setup.interface = params[:interface] ? params[:interface] : Misty::INTERFACE
26
- setup.log = Logger.new(params[:log_file] ? params[:log_file] : Misty::LOG_FILE)
27
- setup.log.level = params[:log_level] ? params[:log_level] : Misty::LOG_LEVEL
28
- setup.region_id = params[:region_id] ? params[:region_id] : Misty::REGION_ID
29
- setup.ssl_verify_mode = params.key?(:ssl_verify_mode) ? params[:ssl_verify_mode] : Misty::SSL_VERIFY_MODE
30
- http_proxy = params[:http_proxy] ? params[:http_proxy] : ""
31
- setup.proxy = URI.parse(http_proxy)
32
- setup.auth = Misty::Auth.factory(params[:auth], setup.proxy, setup.ssl_verify_mode, setup.log)
33
- setup
14
+ def initialize(params)# = {:auth => {}})
15
+ @params = params
16
+ @config = self.class.set_configuration(params)
17
+ @services = Misty.services
18
+ @auth = Misty::Auth.factory(params[:auth], @config)
34
19
  end
35
20
 
36
- def setup_services(params)
37
- services = {}
38
- Misty.services.each do |service|
39
- @options.send("#{service.name}=".to_sym, params[service.name] ? params[service.name] : {})
40
-
41
- if params[service.name] && params[service.name][:api_version] \
42
- && service.versions.include?(params[service.name][:api_version])
43
- services.merge!(service.name => {service.project => params[service.name][:api_version]})
44
- else
45
- # Highest version is used by default!
46
- services.merge!(service.name => {service.project => service.versions.sort[-1]})
47
- end
48
- end
49
- services
21
+ def self.set_configuration(params)
22
+ config = Config.new
23
+ config.content_type = params[:content_type] ? params[:content_type] : Misty::CONTENT_TYPE
24
+ config.interface = params[:interface] ? params[:interface] : Misty::INTERFACE
25
+ config.log = Logger.new(params[:log_file] ? params[:log_file] : Misty::LOG_FILE)
26
+ config.log.level = params[:log_level] ? params[:log_level] : Misty::LOG_LEVEL
27
+ config.region_id = params[:region_id] ? params[:region_id] : Misty::REGION_ID
28
+ config.ssl_verify_mode = params.key?(:ssl_verify_mode) ? params[:ssl_verify_mode] : Misty::SSL_VERIFY_MODE
29
+ config
50
30
  end
51
31
 
52
32
  def build_service(service_name)
53
- project = @services[service_name].keys[0]
54
- version = @services[service_name].fetch(project)
55
- version = self.class.dot_to_underscore(version)
56
- klass = Object.const_get("Misty::Openstack::#{project.capitalize}::#{version.capitalize}")
57
- klass.new(@setup, @options[service_name])
58
- end
59
-
60
- def self.dot_to_underscore(val)
61
- val.gsub(/\./,'_')
33
+ service = @services.find {|service| service.name == service_name}
34
+ service.options = @params[service.name] if @params[service.name]
35
+ service.version = service.options[:api_version]
36
+ version = self.class.dot_to_underscore(service.version)
37
+ klass = Object.const_get("Misty::Openstack::#{service.project.capitalize}::#{version.capitalize}")
38
+ klass.new(@auth, @config, service.options)
62
39
  end
63
40
 
64
41
  def alarming
@@ -6,6 +6,10 @@ require 'misty/http/direct'
6
6
  module Misty
7
7
  module HTTP
8
8
  class Client
9
+ class Options
10
+ attr_accessor :base_path, :base_url, :interface, :region_id, :service_names, :ssl_verify_mode, :version
11
+ end
12
+
9
13
  class InvalidDataError < StandardError; end
10
14
 
11
15
  include Misty::HTTP::NetHTTP
@@ -17,8 +21,6 @@ module Misty
17
21
 
18
22
  attr_reader :microversion
19
23
 
20
- Options = Struct.new(:base_path, :base_url, :interface, :region_id, :service_names, :ssl_verify_mode, :version)
21
-
22
24
  def requests
23
25
  list = []
24
26
  self.class.api.each do |_path, verbs|
@@ -45,13 +47,14 @@ module Misty
45
47
  # :ssl_verify_mode => true
46
48
  # (micro)version: Can be numbered (3.1) or by state (CURRENT, LATEST or SUPPORTED)
47
49
  # :version => "CURRENT"
48
- def initialize(setup, options)
49
- @setup = setup
50
+ def initialize(auth, config, options)
51
+ @auth = auth
52
+ @config = config
50
53
  @options = setup(options)
51
- @uri = URI.parse(@setup.auth.get_endpoint(@options.service_names, @options.region_id, @options.interface))
54
+ @uri = URI.parse(@auth.get_endpoint(@options.service_names, @options.region_id, @options.interface))
52
55
  @base_path = @options.base_path ? @options.base_path : @uri.path
53
56
  @base_path = @base_path.chomp("/")
54
- @http = net_http(@uri, @setup.proxy, @options[:ssl_verify_mode], @setup.log)
57
+ @http = net_http(@uri, @options.ssl_verify_mode, @config.log)
55
58
  @version = nil
56
59
  @microversion = false
57
60
  end
@@ -72,7 +75,7 @@ module Misty
72
75
  end
73
76
 
74
77
  def headers
75
- h = headers_default.merge("X-Auth-Token" => "#{@setup.auth.get_token}")
78
+ h = headers_default.merge("X-Auth-Token" => "#{@auth.get_token}")
76
79
  h.merge!(microversion_header) if microversion
77
80
  h
78
81
  end
@@ -87,10 +90,10 @@ module Misty
87
90
  options = Options.new()
88
91
  options.base_path = params[:base_path] ? params[:base_path] : nil
89
92
  options.base_url = params[:base_url] ? params[:base_url] : nil
90
- options.interface = params[:interface] ? params[:interface] : @setup.interface
91
- options.region_id = params[:region_id] ? params[:region_id] : @setup.region_id
93
+ options.interface = params[:interface] ? params[:interface] : @config.interface
94
+ options.region_id = params[:region_id] ? params[:region_id] : @config.region_id
92
95
  options.service_names = params[:service_name] ? self.class.service_names << params[:service_name] : self.class.service_names
93
- options.ssl_verify_mode = params[:ssl_verify_mode] ? params[:ssl_verify_mode] : @setup.ssl_verify_mode
96
+ options.ssl_verify_mode = params[:ssl_verify_mode] ? params[:ssl_verify_mode] : @config.ssl_verify_mode
94
97
  options.version = params[:version] ? params[:version] : "CURRENT"
95
98
 
96
99
  unless INTERFACES.include?(options.interface)
@@ -85,11 +85,18 @@ module Misty
85
85
  end
86
86
 
87
87
  def query_param(data)
88
+ result = nil
88
89
  if data.is_a? String
89
- str = '?'
90
- str.force_encoding('ASCII-8BIT')
91
- str << data unless data.empty?
90
+ result = ''
91
+ if data != ''
92
+ result = '?'
93
+ result.force_encoding('ASCII-8BIT')
94
+ result << data
95
+ end
96
+ elsif data.is_a? Hash
97
+ result = data.empty? ? '' : '?' + URI.encode_www_form(data)
92
98
  end
99
+ return result
93
100
  end
94
101
  end
95
102
  end
@@ -1,8 +1,8 @@
1
1
  module Misty
2
2
  module HTTP
3
3
  module NetHTTP
4
- def net_http(endpoint, proxy, ssl_verify_mode, log)
5
- http = Net::HTTP.new(endpoint.host, endpoint.port, proxy.host, proxy.port, proxy.user, proxy.password)
4
+ def net_http(endpoint, ssl_verify_mode, log)
5
+ http = Net::HTTP.new(endpoint.host, endpoint.port)
6
6
  http.set_debug_output(log) if log.level == Logger::DEBUG
7
7
  if endpoint.scheme == "https"
8
8
  http.use_ssl = true
@@ -2,7 +2,7 @@ module Misty
2
2
  module HTTP
3
3
  module Request
4
4
  def decode?(response)
5
- if @setup.content_type != :json && response.code =~ /2??/ && !response.is_a?(Net::HTTPNoContent) \
5
+ if @config.content_type != :json && response.code =~ /2??/ && !response.is_a?(Net::HTTPNoContent) \
6
6
  && !response.is_a?(Net::HTTPResetContent) && response.header["content-type"] \
7
7
  && response.header["content-type"].include?("application/json")
8
8
  true
@@ -16,51 +16,51 @@ module Misty
16
16
  end
17
17
 
18
18
  def http_delete(path, headers)
19
- @setup.log.info(http_to_s(path, headers))
19
+ @config.log.info(http_to_s(path, headers))
20
20
  request = Net::HTTP::Delete.new(path, headers)
21
21
  http(request)
22
22
  end
23
23
 
24
24
  def http_copy(path, headers)
25
- @setup.log.info(http_to_s(path, headers))
25
+ @config.log.info(http_to_s(path, headers))
26
26
  request = Net::HTTP::Copy.new(path, headers)
27
27
  http(request)
28
28
  end
29
29
 
30
30
  def http_get(path, headers)
31
- @setup.log.info(http_to_s(path, headers))
31
+ @config.log.info(http_to_s(path, headers))
32
32
  request = Net::HTTP::Get.new(path, headers)
33
33
  http(request)
34
34
  end
35
35
 
36
36
  def http_head(path, headers)
37
- @setup.log.info(http_to_s(path, headers))
37
+ @config.log.info(http_to_s(path, headers))
38
38
  request = Net::HTTP::Head.new(path, headers)
39
39
  http(request)
40
40
  end
41
41
 
42
42
  def http_options(path, headers)
43
- @setup.log.info(http_to_s(path, headers))
43
+ @config.log.info(http_to_s(path, headers))
44
44
  request = Net::HTTP::Options.new(path, headers)
45
45
  http(request)
46
46
  end
47
47
 
48
48
  def http_patch(path, headers, data)
49
- @setup.log.info(http_to_s(path, headers, data))
49
+ @config.log.info(http_to_s(path, headers, data))
50
50
  request = Net::HTTP::Patch.new(path, headers)
51
51
  request.body = Misty.to_json(data)
52
52
  http(request)
53
53
  end
54
54
 
55
55
  def http_post(path, headers, data)
56
- @setup.log.info(http_to_s(path, headers, data))
56
+ @config.log.info(http_to_s(path, headers, data))
57
57
  request = Net::HTTP::Post.new(path, headers)
58
58
  request.body = Misty.to_json(data)
59
59
  http(request)
60
60
  end
61
61
 
62
62
  def http_put(path, headers, data)
63
- @setup.log.info(http_to_s(path, headers, data))
63
+ @config.log.info(http_to_s(path, headers, data))
64
64
  request = Net::HTTP::Put.new(path, headers)
65
65
  request.body = Misty.to_json(data)
66
66
  http(request)
@@ -1,3 +1,5 @@
1
+ require 'misty/services'
2
+
1
3
  module Misty
2
4
  HEADER_JSON = {
3
5
  "Content-Type" => "application/json",
@@ -26,36 +28,28 @@ module Misty
26
28
  # Default mode when SSL is used (uri.scheme == "https")
27
29
  SSL_VERIFY_MODE = true
28
30
 
29
- Service = Struct.new(:name, :project, :versions) do
30
- def to_s
31
- "#{name}: #{project} => #{versions}"
32
- end
33
- end
34
-
35
- SERVICES = []
36
- SERVICES << Service.new(:alarming, :aodh, ["v2"])
37
- SERVICES << Service.new(:baremetal, :ironic, ["v1"])
38
- SERVICES << Service.new(:block_storage, :cinder, ["v3", "v1"])
39
- SERVICES << Service.new(:clustering, :senlin, ["v1"])
40
- SERVICES << Service.new(:compute, :nova, ["v2.1"])
41
- SERVICES << Service.new(:container, :magnum, ["v1"])
42
- SERVICES << Service.new(:data_processing, :sahara, ["v1.1"])
43
- SERVICES << Service.new(:data_protection, :karbor, ["v1"])
44
- SERVICES << Service.new(:database, :trove, ["v1.0"])
45
- SERVICES << Service.new(:dns, :designate, ["v2"])
46
- SERVICES << Service.new(:identity, :keystone, ["v3", "v2.0"])
47
- SERVICES << Service.new(:image, :glance, ["v2", "v1"])
48
- SERVICES << Service.new(:messaging, :zaqar, ["v2"])
49
- SERVICES << Service.new(:metering, :ceilometer, ["v2"])
50
- SERVICES << Service.new(:network, :neutron, ["v2.0"])
51
- SERVICES << Service.new(:object_storage, :swift, ["v1"])
52
- SERVICES << Service.new(:orchestration, :heat, ["v1"])
53
- SERVICES << Service.new(:search, :searchlight, ["v1"])
54
- SERVICES << Service.new(:shared_file_systems, :manila, ["v2"])
55
- SERVICES.freeze
56
-
57
31
  def self.services
58
- SERVICES
32
+ services = Misty::Services.new
33
+ services.add(:alarming, :aodh, ["v2"])
34
+ services.add(:baremetal, :ironic, ["v1"])
35
+ services.add(:block_storage, :cinder, ["v3", "v1"])
36
+ services.add(:clustering, :senlin, ["v1"])
37
+ services.add(:compute, :nova, ["v2.1"])
38
+ services.add(:container, :magnum, ["v1"])
39
+ services.add(:data_processing, :sahara, ["v1.1"])
40
+ services.add(:data_protection, :karbor, ["v1"])
41
+ services.add(:database, :trove, ["v1.0"])
42
+ services.add(:dns, :designate, ["v2"])
43
+ services.add(:identity, :keystone, ["v3", "v2.0"])
44
+ services.add(:image, :glance, ["v2", "v1"])
45
+ services.add(:messaging, :zaqar, ["v2"])
46
+ services.add(:metering, :ceilometer, ["v2"])
47
+ services.add(:network, :neutron, ["v2.0"])
48
+ services.add(:object_storage, :swift, ["v1"])
49
+ services.add(:orchestration, :heat, ["v1"])
50
+ services.add(:search, :searchlight, ["v1"])
51
+ services.add(:shared_file_systems, :manila, ["v2"])
52
+ services
59
53
  end
60
54
 
61
55
  def self.to_json(data)
@@ -6,7 +6,7 @@ module Misty
6
6
 
7
7
  VERSION_STATES = %w{CURRENT LATEST SUPPORTED}
8
8
 
9
- def initialize(cloud, options)
9
+ def initialize(auth, cloud, options)
10
10
  super
11
11
  @microversion = true
12
12
  @version = version_get(@options.version)
@@ -0,0 +1,49 @@
1
+ module Misty
2
+ class Services
3
+ class Service
4
+ attr_reader :name, :options, :project, :versions, :version
5
+
6
+ def initialize(name, project, versions)
7
+ @name = name
8
+ @project = project
9
+ @versions = versions
10
+ @options = {}
11
+ end
12
+
13
+ def options=(val)
14
+ @options = val
15
+ end
16
+
17
+ def version=(val)
18
+ if @versions.include?(val)
19
+ @version = val
20
+ else
21
+ # Use highest version
22
+ @version = versions.sort[-1]
23
+ end
24
+ end
25
+
26
+ def to_s
27
+ "#{name}: #{project} => #{versions}"
28
+ end
29
+ end
30
+
31
+ include Enumerable
32
+
33
+ attr_reader :services
34
+
35
+ def initialize
36
+ @services = []
37
+ end
38
+
39
+ def add(*args)
40
+ @services << Service.new(*args)
41
+ end
42
+
43
+ def each
44
+ @services.each do |service|
45
+ yield service
46
+ end
47
+ end
48
+ end
49
+ end
@@ -1,3 +1,3 @@
1
1
  module Misty
2
- VERSION = "0.5.1"
2
+ VERSION = "0.6.0"
3
3
  end
@@ -2,11 +2,16 @@ require 'test_helper'
2
2
  require 'auth_helper'
3
3
 
4
4
  describe Misty::Auth do
5
- let(:log) { Logger.new('/dev/null') }
5
+ let(:config) do
6
+ config = Misty::Cloud::Config.new
7
+ config.log = Logger.new('/dev/null')
8
+ config.ssl_verify_mode = false
9
+ config
10
+ end
6
11
 
7
12
  describe Misty::AuthV3 do
8
13
  describe "#new" do
9
- it "authenticates using project scoped authorization" do
14
+ it "authenticates with password using project scoped authorization" do
10
15
  auth = {
11
16
  :url => "http://localhost:5000",
12
17
  :user_id => "user_id",
@@ -19,10 +24,10 @@ describe Misty::Auth do
19
24
  :headers => {'Accept'=>'application/json', 'Content-Type'=>'application/json'}).
20
25
  to_return(:status => 200, :body => JSON.dump(auth_response_v3("identity", "keystone")), :headers => {"x-subject-token"=>"token_data"})
21
26
 
22
- Misty::AuthV3.new(auth, URI.parse(""), false, log)
27
+ Misty::AuthV3.new(auth, config)
23
28
  end
24
29
 
25
- it "authenticates using domain scoped authorization" do
30
+ it "authenticates with password using domain scoped authorization" do
26
31
  auth = {
27
32
  :url => "http://localhost:5000",
28
33
  :user_id => "user_id",
@@ -34,7 +39,36 @@ describe Misty::Auth do
34
39
  :headers => {'Accept'=>'application/json', 'Content-Type'=>'application/json'}).
35
40
  to_return(:status => 200, :body => JSON.dump(auth_response_v3("identity", "keystone")), :headers => {"x-subject-token"=>"token_data"})
36
41
 
37
- Misty::AuthV3.new(auth, URI.parse(""), false, log)
42
+ Misty::AuthV3.new(auth, config)
43
+ end
44
+
45
+ it "authenticates with token using project scoped authorization" do
46
+ auth = {
47
+ :url => "http://localhost:5000",
48
+ :token => "exampletoken",
49
+ :project_id => "project_id"
50
+ }
51
+
52
+ stub_request(:post, "http://localhost:5000/v3/auth/tokens").
53
+ with(:body => "{\"auth\":{\"identity\":{\"methods\":[\"token\"],\"token\":{\"id\":\"exampletoken\"}},\"scope\":{\"project\":{\"id\":\"project_id\"}}}}",
54
+ :headers => {'Accept'=>'application/json', 'Content-Type'=>'application/json'}).
55
+ to_return(:status => 200, :body => JSON.dump(auth_response_v3("identity", "keystone")), :headers => {"x-subject-token"=>"token_data"})
56
+
57
+ Misty::AuthV3.new(auth, config)
58
+ end
59
+
60
+ it "authenticates with token using domain scoped authorization" do
61
+ auth = {
62
+ :url => "http://localhost:5000",
63
+ :token => "exampletoken",
64
+ }
65
+
66
+ stub_request(:post, "http://localhost:5000/v3/auth/tokens").
67
+ with(:body => "{\"auth\":{\"identity\":{\"methods\":[\"token\"],\"token\":{\"id\":\"exampletoken\"}},\"scope\":{\"domain\":{\"id\":\"default\"}}}}",
68
+ :headers => {'Accept'=>'application/json', 'Content-Type'=>'application/json'}).
69
+ to_return(:status => 200, :body => JSON.dump(auth_response_v3("identity", "keystone")), :headers => {"x-subject-token"=>"token_data"})
70
+
71
+ Misty::AuthV3.new(auth, config)
38
72
  end
39
73
  end
40
74
 
@@ -53,15 +87,15 @@ describe Misty::Auth do
53
87
  to_return(:status => 200, :body => "{\"token\":{\"catalog\":[]}}", :headers => {"x-subject-token"=>"token_data"})
54
88
 
55
89
  proc do
56
- Misty::AuthV3.new({}, URI.parse(""), false, log)
57
- end.must_raise Misty::Auth::CredentialsError
90
+ Misty::AuthV3.new({}, config)
91
+ end.must_raise Misty::Auth::URLError
58
92
  end
59
93
 
60
94
  it "#get_token" do
61
95
  stub_request(:post, "http://localhost:5000/v3/auth/tokens").
62
96
  to_return(:status => 200, :body => "{\"token\":{\"catalog\":[\"catalog_data\"]}}", :headers => {"x-subject-token"=>"token_data"})
63
97
 
64
- auth = Misty::AuthV3.new(authv3_creds, URI.parse(""), false, log)
98
+ auth = Misty::AuthV3.new(authv3_creds, config)
65
99
  auth.stub :expired?, false do
66
100
  auth.get_token.must_equal "token_data"
67
101
  end
@@ -71,7 +105,7 @@ describe Misty::Auth do
71
105
  stub_request(:post, "http://localhost:5000/v3/auth/tokens").
72
106
  to_return(:status => 200, :body => "{\"token\":{\"catalog\":[\"catalog_data\"]}}", :headers => {"x-subject-token"=>"token_data"})
73
107
 
74
- auth = Misty::AuthV3.new(authv3_creds, URI.parse(""), false, log)
108
+ auth = Misty::AuthV3.new(authv3_creds, config)
75
109
  auth.catalog.must_equal ["catalog_data"]
76
110
  end
77
111
 
@@ -79,7 +113,7 @@ describe Misty::Auth do
79
113
  stub_request(:post, "http://localhost:5000/v3/auth/tokens").
80
114
  to_return(:status => 200, :body => JSON.dump(auth_response_v3("identity", "keystone")), :headers => {"x-subject-token"=>"token_data"})
81
115
 
82
- auth = Misty::AuthV3.new(authv3_creds, URI.parse(""), false, log)
116
+ auth = Misty::AuthV3.new(authv3_creds, config)
83
117
  auth.get_endpoint(%w{identity}, "regionOne", "public").must_equal "http://localhost"
84
118
  end
85
119
  end
@@ -92,8 +126,8 @@ describe Misty::Auth do
92
126
  to_return(:status => 200, :body => "{\"access\":{\"token\":{\"id\":\"token_data\"}}}", :headers => {})
93
127
 
94
128
  proc do
95
- Misty::AuthV2.new({}, URI.parse(""), false, log)
96
- end.must_raise Misty::Auth::CredentialsError
129
+ Misty::AuthV2.new({}, config)
130
+ end.must_raise Misty::Auth::URLError
97
131
  end
98
132
  end
99
133
 
@@ -111,7 +145,7 @@ describe Misty::Auth do
111
145
  stub_request(:post, "http://localhost:5000/v2.0/tokens").
112
146
  to_return(:status => 200, :body => "{\"access\":{\"token\":{\"id\":\"token_data\"},\"serviceCatalog\":[\"catalog_data\"]}}", :headers => {})
113
147
 
114
- auth = Misty::AuthV2.new(authv2_creds, URI.parse(""), false, log)
148
+ auth = Misty::AuthV2.new(authv2_creds, config)
115
149
  auth.stub :expired?, false do
116
150
  auth.get_token.must_equal "token_data"
117
151
  end
@@ -121,7 +155,7 @@ describe Misty::Auth do
121
155
  stub_request(:post, "http://localhost:5000/v2.0/tokens").
122
156
  to_return(:status => 200, :body => "{\"access\":{\"token\":{\"id\":\"token_data\"},\"serviceCatalog\":[\"catalog_data\"]}}", :headers => {})
123
157
 
124
- auth = Misty::AuthV2.new(authv2_creds, URI.parse(""), false, log)
158
+ auth = Misty::AuthV2.new(authv2_creds, config)
125
159
  auth.catalog.must_equal ["catalog_data"]
126
160
  end
127
161
 
@@ -129,7 +163,7 @@ describe Misty::Auth do
129
163
  stub_request(:post, "http://localhost:5000/v2.0/tokens").
130
164
  to_return(:status => 200, :body => JSON.dump(auth_response_v2("identity", "keystone")), :headers => {"x-subject-token"=>"token_data"})
131
165
 
132
- auth = Misty::AuthV2.new(authv2_creds, URI.parse(""), false, log)
166
+ auth = Misty::AuthV2.new(authv2_creds, config)
133
167
  auth.get_endpoint(%w{identity}, "regionOne", "public").must_equal "http://localhost"
134
168
  end
135
169
  end
@@ -27,57 +27,55 @@ describe Misty::Cloud do
27
27
 
28
28
  it "uses default version" do
29
29
  cloud = Misty::Cloud.new(:auth => auth)
30
- cloud.services[:identity].must_equal ({:keystone => "v3"})
31
- end
32
-
33
- it "uses provided version" do
34
- cloud = Misty::Cloud.new(:auth => auth, :identity => {:api_version => "v2.0"})
35
- cloud.services[:identity].must_equal ({:keystone => "v2.0"})
30
+ cloud.identity.must_be_kind_of Misty::Openstack::Keystone::V3
36
31
  end
37
32
 
38
33
  it "uses default version when provided version is out of range" do
39
34
  cloud = Misty::Cloud.new(:auth => auth, :identity => {:api_version => "v1"})
40
- cloud.services[:identity].must_equal ({:keystone => "v3"})
35
+ cloud.identity.must_be_kind_of Misty::Openstack::Keystone::V3
36
+ end
37
+
38
+ it "uses provided version" do
39
+ cloud = Misty::Cloud.new(:auth => auth, :identity => {:api_version => "v2.0"})
40
+ cloud.identity.must_be_kind_of Misty::Openstack::Keystone::V2_0
41
41
  end
42
42
  end
43
43
 
44
- describe "All SERVICES" do
45
- it "have a method defined" do
46
- Misty::SERVICES.each do |service|
44
+ describe "Each service" do
45
+ it "has a method defined" do
46
+ Misty::services.each do |service|
47
47
  method = Misty::Cloud.method_defined?(service.name)
48
48
  method.must_equal true
49
49
  end
50
50
  end
51
51
  end
52
52
 
53
- describe "#setup" do
53
+ describe "#config" do
54
54
  it "sets up default values" do
55
55
  Misty::Auth.stub :factory, nil do
56
- setup = Misty::Cloud.setup({})
57
- setup.must_be_kind_of Misty::Cloud::Setup
58
- setup.content_type.must_equal Misty::CONTENT_TYPE
59
- setup.log.must_be_kind_of Logger
60
- setup.interface.must_equal Misty::INTERFACE
61
- setup.proxy.must_be_kind_of URI
62
- setup.proxy.host.must_be_nil
63
- setup.region_id.must_equal Misty::REGION_ID
64
- setup.ssl_verify_mode.must_equal Misty::SSL_VERIFY_MODE
56
+ config = Misty::Cloud.set_configuration({})
57
+ config.must_be_kind_of Misty::Cloud::Config
58
+ config.content_type.must_equal Misty::CONTENT_TYPE
59
+ config.log.must_be_kind_of Logger
60
+ config.interface.must_equal Misty::INTERFACE
61
+ config.region_id.must_equal Misty::REGION_ID
62
+ config.ssl_verify_mode.must_equal Misty::SSL_VERIFY_MODE
65
63
  end
66
64
  end
67
65
  end
68
66
 
69
67
  describe "#new" do
70
68
  describe "fails" do
71
- it "when no credentials" do
69
+ it "when no parameters" do
72
70
  proc do
73
71
  Misty::Cloud.new
74
- end.must_raise Misty::Auth::CredentialsError
72
+ end.must_raise ArgumentError
75
73
  end
76
74
 
77
75
  it "with empty credentials" do
78
76
  proc do
79
77
  Misty::Cloud.new(:auth => {})
80
- end.must_raise Misty::Auth::CredentialsError
78
+ end.must_raise Misty::Auth::URLError
81
79
  end
82
80
 
83
81
  it "with incomplete credentials" do
@@ -42,8 +42,7 @@ describe Misty::HTTP::Client do
42
42
  describe "#net_http" do
43
43
  it "returns a Net/http instance" do
44
44
  endpoint = URI.parse("http://localhost")
45
- proxy = URI.parse("")
46
- service.send(:net_http, endpoint, proxy, false, Logger.new("/dev/null")).must_be_instance_of Net::HTTP
45
+ service.send(:net_http, endpoint, false, Logger.new("/dev/null")).must_be_instance_of Net::HTTP
47
46
  end
48
47
  end
49
48
 
@@ -122,12 +122,23 @@ describe Misty::HTTP::MethodBuilder do
122
122
  service.send(:query_param, "name=foobar").must_equal "?name=foobar"
123
123
  end
124
124
 
125
- it "returns nil when passing an empty String" do
126
- service.send(:query_param, "").must_be_nil
125
+ it "returns empty string when passing an empty String" do
126
+ service.send(:query_param, "").must_equal ""
127
127
  end
128
128
 
129
- it "returns nil unless passing a String" do
130
- service.send(:query_param, "name" => "foobar").must_be_nil
129
+ it "returns a query string when passing in a Hash" do
130
+ service.send(:query_param, {}).must_equal ''
131
+
132
+ service.send(:query_param, {:foo => 'bar'}).must_equal '?foo=bar'
133
+ service.send(:query_param, {'foo' => 'bar'}).must_equal '?foo=bar'
134
+
135
+ service.send(:query_param, {:foo => ['bar', 'baz'], :value => 42, :flag => nil }).must_equal '?foo=bar&foo=baz&value=42&flag'
136
+
137
+ service.send(:query_param, {'===' => 'Ëncøding is hárd!'}).must_equal '?%3D%3D%3D=%C3%8Bnc%C3%B8ding+is+h%C3%A1rd%21'
138
+ end
139
+
140
+ it "returns nil unless passing a String or Hash" do
141
+ service.send(:query_param, 42).must_be_nil
131
142
  end
132
143
  end
133
144
  end
@@ -1,15 +1,116 @@
1
1
  require 'test_helper'
2
2
 
3
+ def validate(service)
4
+ service.must_be_kind_of Misty::Services::Service
5
+ service.name.must_be_kind_of Symbol
6
+ service.project.must_be_kind_of Symbol
7
+ service.versions.must_be_kind_of Array
8
+ service.versions.each do |version|
9
+ version.must_be_kind_of String
10
+ end
11
+ end
12
+
3
13
  describe Misty do
4
- describe "SERVICES" do
5
- it "has expected structure" do
6
- Misty::SERVICES.each do |service|
7
- service.name.must_be_kind_of Symbol
8
- service.project.must_be_kind_of Symbol
9
- service.versions.must_be_kind_of Array
10
- service.versions.each do |version|
11
- version.must_be_kind_of String
12
- end
14
+ describe "#set_services" do
15
+ it "has alarming service" do
16
+ service = Misty::services.find { |s| s.name == :alarming}
17
+ validate(service)
18
+ end
19
+
20
+ it "has baremetal service" do
21
+ service = Misty::services.find { |s| s.name == :baremetal}
22
+ validate(service)
23
+ end
24
+
25
+ it "has block_storage service" do
26
+ service = Misty::services.find { |s| s.name == :block_storage}
27
+ validate(service)
28
+ end
29
+
30
+ it "has clustering service" do
31
+ service = Misty::services.find { |s| s.name == :clustering}
32
+ validate(service)
33
+ end
34
+
35
+ it "has compute service" do
36
+ service = Misty::services.find { |s| s.name == :compute}
37
+ validate(service)
38
+ end
39
+
40
+ it "has container service" do
41
+ service = Misty::services.find { |s| s.name == :container}
42
+ validate(service)
43
+ end
44
+
45
+ it "has data_processing service" do
46
+ service = Misty::services.find { |s| s.name == :data_processing}
47
+ validate(service)
48
+ end
49
+
50
+ it "has data_protection service" do
51
+ service = Misty::services.find { |s| s.name == :data_protection}
52
+ validate(service)
53
+ end
54
+
55
+ it "has database service" do
56
+ service = Misty::services.find { |s| s.name == :database}
57
+ validate(service)
58
+ end
59
+
60
+ it "has dns service" do
61
+ service = Misty::services.find { |s| s.name == :dns}
62
+ validate(service)
63
+ end
64
+
65
+ it "has identity service" do
66
+ service = Misty::services.find { |s| s.name == :identity}
67
+ validate(service)
68
+ end
69
+
70
+ it "has image service" do
71
+ service = Misty::services.find { |s| s.name == :image}
72
+ validate(service)
73
+ end
74
+
75
+ it "has messaging service" do
76
+ service = Misty::services.find { |s| s.name == :messaging}
77
+ validate(service)
78
+ end
79
+
80
+ it "has metering service" do
81
+ service = Misty::services.find { |s| s.name == :metering}
82
+ validate(service)
83
+ end
84
+
85
+ it "has network service" do
86
+ service = Misty::services.find { |s| s.name == :network}
87
+ validate(service)
88
+ end
89
+
90
+ it "has object_storage service" do
91
+ service = Misty::services.find { |s| s.name == :object_storage}
92
+ validate(service)
93
+ end
94
+
95
+ it "has orchestration service" do
96
+ service = Misty::services.find { |s| s.name == :orchestration}
97
+ validate(service)
98
+ end
99
+
100
+ it "has search service" do
101
+ service = Misty::services.find { |s| s.name == :search}
102
+ validate(service)
103
+ end
104
+
105
+ it "has shared_file_systems service" do
106
+ service = Misty::services.find { |s| s.name == :shared_file_systems}
107
+ validate(service)
108
+ end
109
+
110
+ describe "#services" do
111
+ it "returns Services" do
112
+ services = Misty::services
113
+ services.must_be_kind_of Misty::Services
13
114
  end
14
115
  end
15
116
  end
@@ -31,12 +31,10 @@ describe Misty::HTTP::Microversion do
31
31
  "token_id"
32
32
  end
33
33
 
34
- setup = Misty::Cloud::Setup.new
35
- setup.auth = auth
34
+ setup = Misty::Cloud::Config.new
36
35
  setup.content_type = :ruby
37
36
  setup.log = Logger.new('/dev/null')
38
37
  setup.interface = Misty::INTERFACE
39
- setup.proxy = URI.parse('')
40
38
  setup.region_id = Misty::REGION_ID
41
39
  setup.ssl_verify_mode = Misty::SSL_VERIFY_MODE
42
40
 
@@ -44,7 +42,7 @@ describe Misty::HTTP::Microversion do
44
42
  with(:headers => {'Accept'=>'application/json', 'Content-Type'=>'application/json'}).
45
43
  to_return(:status => 200, :body => JSON.dump(versions_data), :headers => {})
46
44
 
47
- Misty::Openstack::Nova::V2_1.new(setup, {})
45
+ Misty::Openstack::Nova::V2_1.new(auth, setup, {})
48
46
  end
49
47
 
50
48
  describe "#version_get" do
@@ -15,12 +15,10 @@ def service(content_type = :ruby)
15
15
  "token_id"
16
16
  end
17
17
 
18
- setup = Misty::Cloud::Setup.new
19
- setup.auth = auth
18
+ setup = Misty::Cloud::Config.new
20
19
  setup.content_type = content_type
21
20
  setup.log = Logger.new('/dev/null')
22
21
  setup.interface = Misty::INTERFACE
23
- setup.proxy = URI.parse("")
24
22
  setup.region_id = Misty::REGION_ID
25
23
  setup.ssl_verify_mode = Misty::SSL_VERIFY_MODE
26
24
 
@@ -28,5 +26,5 @@ def service(content_type = :ruby)
28
26
  with(:headers => request_header).
29
27
  to_return(:status => 200, :body => "", :headers => {})
30
28
 
31
- Misty::Openstack::Neutron::V2_0.new(setup, {})
29
+ Misty::Openstack::Neutron::V2_0.new(auth, setup, {})
32
30
  end
@@ -0,0 +1,16 @@
1
+ require 'test_helper'
2
+
3
+ describe "Services" do
4
+ describe "#add" do
5
+ it "Adds a service" do
6
+ services = Misty::Services.new
7
+ services.add(:name, :project, ["v1", "v2.0"])
8
+ services.services.size.must_equal 1
9
+ service = services.services[0]
10
+ service.must_be_kind_of Misty::Services::Service
11
+ service.name.must_equal :name
12
+ service.project.must_equal :project
13
+ service.versions.must_include "v1"
14
+ end
15
+ end
16
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: misty
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gilles Dubreuil
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-04-18 00:00:00.000000000 Z
11
+ date: 2017-05-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -186,6 +186,7 @@ files:
186
186
  - lib/misty/openstack/trove/v1_0.rb
187
187
  - lib/misty/openstack/zaqar/v2.rb
188
188
  - lib/misty/openstack/zaqar/zaqar_v2.rb
189
+ - lib/misty/services.rb
189
190
  - lib/misty/version.rb
190
191
  - test/integration/compute_test.rb
191
192
  - test/integration/network_test.rb
@@ -208,6 +209,7 @@ files:
208
209
  - test/unit/openstack/APIs_test.rb
209
210
  - test/unit/openstack/microversion_test.rb
210
211
  - test/unit/service_helper.rb
212
+ - test/unit/services_test.rb
211
213
  - test/unit/test_helper.rb
212
214
  homepage: https://github.com/flystack/misty
213
215
  licenses: