yao 0.0.2.rc3 → 0.0.2

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: 04c45b85c7164bc9cd7bac93189eec8c2aff4712
4
- data.tar.gz: cb05d894031f89862beba5e27c372ba7ec09d8e3
3
+ metadata.gz: 4efa85ede55eb2f96de87fba1af6fcbcb3ec3228
4
+ data.tar.gz: 860deb926f0bd3dd5fe4addca1ff152ee7902e18
5
5
  SHA512:
6
- metadata.gz: a4745f172f77fd7fa273f2253ab94394b6223d5d26fd0d10c42cd809bea46b05b3059cf9cb260acb8fdc7eb6cad0303aff87c68321ebbb15dda2a86b615a47ec
7
- data.tar.gz: 415e8fcd67ca260f14ec1105d83197680c0c999a7d1c5f07ee2ea00263a0c99d9c5401aaddde7b7d77b7d99153d2c858914481f885d9ed98fb3ab0fa83b6b258
6
+ metadata.gz: a3db94bfb4a5c854c186a63521371a7ef00be604080a2ebf932dd54af4cec5ef6e0eee1cce840c98453a3e055b051921eb5e33ae9cf587db7dc5aa29314dd0a2
7
+ data.tar.gz: a661e89dec7b324abe55fd5c7c74affe9406767a32fb2a1b92a0e64d9d7bc9f6fa48c78ab701c3bfbbd79298db0178c162997b43a45e7f46998f2849123e236a
@@ -0,0 +1,16 @@
1
+ language: ruby
2
+
3
+ rvm:
4
+ - 2.1.7
5
+ - 2.2.3
6
+
7
+ install: bundle install --path vendor/bundle
8
+
9
+ cache:
10
+ directories: vendor/bundle
11
+
12
+ script: bundle exec rake test
13
+
14
+ notifications:
15
+ slack:
16
+ secure: XhJ3SUF4I7a+MleHLEokgNrqROeCiTfVGzVOwFCTqVETurarb0s4FA5MGWgu7C9MCkIAVFLATwgIZQ9lo9MWFujVTh4Qj+rOdjI08c2ehVxwPyGMXbvkvqMRzvBbJuswnrXuJGUzxdCCjea64cdiZxguDiODp+cfjtKGSB59aNZoMsgwqVTppGDyXAThqZx/l2UKYjzONbnuCI9T9wt+UWW8nAMDn5zSTLVqVyK4GXs2ofGXswQlHvc7VlPLkmHVGm0ywazCyct+lo/Y9x1ofOeHZJllLRc5wccLxciCJBLJDrm/28LHy1PoidR5TXNRjp5ioJGVMwqvsBY8z3OwD8XVv6CPPGRYnEsJVT90R9HJoQ5YFHX5sDeGVbHSaX63eK4W7bn8MxqvEuQF5XU86B2xpLFOTKMK7HRKYjbToRKGMolj+1zv65orHM2Ts0ZtCuwa41oiYkRLWzSc9UDODn67OF+pJlEEYouljsGfcRYcv7JJ2rhFnFXi/9uISxzQMsP4L8dwEEJHxSkaSwJBMJf/it5hD4m5oO0oBQ1DRd3qg2ljpLPuzuY+pW1/R1JY1Z/DA4Kw7dvr8R0DJmXdDiWI9EYilYcP8Wk5qYlJdDGLEUfL8I+tz+e67wAzpqm9okE4gNiJ4HsS2MtztXCJgoSkBJVvhoEE9SXsYNICAno=
data/Gemfile CHANGED
@@ -2,3 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in yao.gemspec
4
4
  gemspec
5
+
6
+ gem 'travis'
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Yao
2
2
 
3
- YAO is a Yet Another OpenStack API Wrapper that rocks!!
3
+ YAO is a Yet Another OpenStack API Wrapper that rocks!! [![Build Status](https://travis-ci.org/udzura/yao.svg)](https://travis-ci.org/udzura/yao)
4
4
 
5
5
  ## Installation
6
6
 
data/Rakefile CHANGED
@@ -1,2 +1,12 @@
1
1
  require "bundler/gem_tasks"
2
+ require "rake/testtask"
2
3
 
4
+ desc 'Run yao\'s test suite'
5
+ Rake::TestTask.new do |t|
6
+ # To run test for only one file (or file path pattern)
7
+ # $ bundle exec rake test TEST=test/test_specified_path.rb
8
+ t.libs.concat ["test"]
9
+ t.test_files = Dir["test/**/test_*.rb"]
10
+ t.verbose = true
11
+ t.ruby_opts = ["-r config"]
12
+ end
@@ -2,73 +2,37 @@ require 'yao'
2
2
  require 'json'
3
3
  require 'time'
4
4
 
5
- module Yao::Auth
5
+ require 'yao/token'
6
+
7
+ module Yao
6
8
  %i(tenant_name username password).each do |name|
7
- Yao.config.param name, nil do |_|
8
- Yao::Auth.try_new
9
- end
9
+ Yao.config.param name, nil
10
10
  end
11
11
 
12
- class << self
13
- def try_new
14
- if Yao.config.tenant_name && Yao.config.username && Yao.config.password && Yao.default_client
15
- Yao::Auth.new
12
+ module Auth
13
+ class << self
14
+ def try_new
15
+ if Yao.config.tenant_name && Yao.config.username && Yao.config.password && Yao.default_client
16
+ Yao::Auth.new
17
+ end
16
18
  end
17
- end
18
19
 
19
- def new(
20
- tenant_name: Yao.config.tenant_name,
21
- username: Yao.config.username,
22
- password: Yao.config.password
23
- )
24
- authinfo = {
25
- auth: {
26
- passwordCredentials: {
27
- username: username, password: password
20
+ def new(
21
+ tenant_name: Yao.config.tenant_name,
22
+ username: Yao.config.username,
23
+ password: Yao.config.password
24
+ )
25
+ auth_info = {
26
+ auth: {
27
+ passwordCredentials: {
28
+ username: username, password: password
29
+ }
28
30
  }
29
31
  }
30
- }
31
- authinfo[:auth][:tenantName] = tenant_name if tenant_name
32
+ auth_info[:auth][:tenantName] = tenant_name if tenant_name
32
33
 
33
- reply = Yao.default_client.default.post('/v2.0/tokens') do |req|
34
- req.body = authinfo.to_json
35
- req.headers['Content-Type'] = 'application/json'
36
- end
37
-
38
- body = reply.body["access"]
39
-
40
- token = Token.new(body["token"])
41
- token.register_endpoints(body["serviceCatalog"])
42
- return token
43
- end
44
- end
45
-
46
- class Token
47
- def initialize(token_data)
48
- @token = token_data["id"]
49
- @issued_at = Time.parse token_data["issued_at"]
50
- @expire_at = Time.parse token_data["expires"]
51
-
52
- @endpoints = {}
53
- end
54
- attr_accessor :token, :issued_at, :expire_at, :endpoints
55
- alias expires expire_at
56
-
57
- def register_endpoints(_endpoints)
58
- return unless _endpoints
59
-
60
- _endpoints.each do |endpoint_data|
61
- key = endpoint_data["type"]
62
- value = if d = endpoint_data["endpoints"].first
63
- d["publicURL"]
64
- else
65
- nil
66
- end
67
- if value
68
- @endpoints[key] = value
69
- end
34
+ return Token.issue(Yao.default_client.default, auth_info)
70
35
  end
71
- Yao.default_client.register_endpoints(@endpoints, token: @token)
72
36
  end
73
37
  end
74
38
  end
@@ -33,8 +33,8 @@ module Yao
33
33
  class << self
34
34
  attr_accessor :default_client
35
35
 
36
- def gen_client(endpoint, token: nil)
37
- Faraday.new( endpoint ) do |f|
36
+ def client_generator_hook
37
+ lambda do |f, token|
38
38
  f.request :url_encoded
39
39
  f.request :json
40
40
 
@@ -42,13 +42,28 @@ module Yao
42
42
  f.request :os_token, token
43
43
  end
44
44
 
45
+ f.response :os_error_detector
45
46
  f.response :json, :content_type => /\bjson$/
46
- f.response :logger
47
+
48
+ if Yao.config.debug
49
+ f.response :logger
50
+ f.response :os_dumper
51
+ end
52
+
53
+ if Yao.config.debug_record_response
54
+ f.response :os_response_recorder
55
+ end
47
56
 
48
57
  f.adapter Faraday.default_adapter
49
58
  end
50
59
  end
51
60
 
61
+ def gen_client(endpoint, token: nil)
62
+ Faraday.new( endpoint ) do |f|
63
+ client_generator_hook.call(f, token)
64
+ end
65
+ end
66
+
52
67
  def reset_client(new_endpoint=nil)
53
68
  set = ClientSet.new
54
69
  set.register_endpoints("default" => (new_endpoint || Yao.config.endpoint))
@@ -59,7 +74,6 @@ module Yao
59
74
  Yao.config.param :auth_url, nil do |endpoint|
60
75
  if endpoint
61
76
  Yao::Client.reset_client(endpoint)
62
- Yao::Auth.try_new
63
77
  end
64
78
  end
65
79
  end
@@ -67,4 +81,7 @@ module Yao
67
81
  def self.default_client
68
82
  Yao::Client.default_client
69
83
  end
84
+
85
+ Yao.config.param :debug, false
86
+ Yao.config.param :debug_record_response, false
70
87
  end
@@ -10,10 +10,35 @@ module Yao
10
10
  @_configuration_hooks ||= {}
11
11
  end
12
12
 
13
+ def _configuration_hooks_queue
14
+ @_configuration_hooks_queue ||= []
15
+ end
16
+
13
17
  def configuration
14
18
  @configuration ||= {}
15
19
  end
16
20
 
21
+ HOOK_RENEW_CLIENT_KEYS = %i(tenant_name username password auth_url debug debug_record_response)
22
+ def delay_hook=(v)
23
+ @delay_hook = v
24
+ if !v and !_configuration_hooks_queue.empty?
25
+ _configuration_hooks_queue.each do |n, val|
26
+ _configuration_hooks[n].call(val) if _configuration_hooks[n]
27
+ end
28
+ # Authorization process should have special hook
29
+ # and should run last
30
+ unless (_configuration_hooks_queue.map(&:first) & HOOK_RENEW_CLIENT_KEYS).empty?
31
+ Yao::Auth.try_new
32
+ end
33
+
34
+ _configuration_hooks_queue.clear
35
+ end
36
+ end
37
+
38
+ def delay_hook?
39
+ @delay_hook
40
+ end
41
+
17
42
  def param(name, default, &hook)
18
43
  raise("Duplicate definition of #{name}") if self.respond_to?(name)
19
44
 
@@ -35,14 +60,22 @@ module Yao
35
60
  def set(name, value)
36
61
  raise("Undefined config key #{name}") unless self.respond_to?(name)
37
62
  configuration[name.to_sym] = value
38
- _configuration_hooks[name].call(value) if _configuration_hooks[name]
63
+ if delay_hook?
64
+ _configuration_hooks_queue.push([name, value])
65
+ else
66
+ _configuration_hooks[name].call(value) if _configuration_hooks[name]
67
+ end
39
68
  value
40
69
  end
41
70
  end
42
71
 
43
72
  def self.config(&blk)
44
73
  @__config ||= Config.new
45
- @__config.instance_eval(&blk) if blk
74
+ if blk
75
+ @__config.delay_hook = true
76
+ @__config.instance_eval(&blk)
77
+ @__config.delay_hook = false
78
+ end
46
79
  @__config
47
80
  end
48
81
 
@@ -7,8 +7,70 @@ class Faraday::Request::OSToken
7
7
  end
8
8
 
9
9
  def call(env)
10
- env[:request_headers]['X-Auth-Token'] = @token
10
+ if @token.expired?
11
+ @token.reflesh(Yao.default_client.default)
12
+ end
13
+
14
+ env[:request_headers]['X-Auth-Token'] = @token.to_s
11
15
  @app.call(env)
12
16
  end
13
17
  end
14
18
  Faraday::Request.register_middleware os_token: -> { Faraday::Request::OSToken }
19
+
20
+ class Faraday::Response::OSDumper < Faraday::Response::Middleware
21
+ def on_complete(env)
22
+ require 'pp'
23
+ params = [
24
+ env.url.to_s,
25
+ JSON.parse(env.body),
26
+ env.request_headers,
27
+ env.response_headers,
28
+ env.method,
29
+ env.status
30
+ ].map(&:pretty_inspect)
31
+ $stdout.puts(<<-FMT % params)
32
+ ================================
33
+ OpenStack response inspection:
34
+ ================================
35
+ Requested To: %s
36
+
37
+ Body:
38
+ %s
39
+ Request Headers:
40
+ %s
41
+ Response Headers:
42
+ %s
43
+
44
+ Method: %s
45
+ Status Code: %s
46
+ ================================
47
+
48
+ FMT
49
+ end
50
+ end
51
+ Faraday::Response.register_middleware os_dumper: -> { Faraday::Response::OSDumper }
52
+
53
+ class Faraday::Response::OSResponseRecorder < Faraday::Response::Middleware
54
+ def on_complete(env)
55
+ require 'pathname'
56
+ root = Pathname.new(File.expand_path('../../../tmp', __FILE__))
57
+ path = [env.method.to_s.upcase, env.url.path.gsub('/', '-')].join("-") + ".json"
58
+
59
+ puts root.join(path)
60
+ File.open(root.join(path), 'w') do |f|
61
+ f.write env.body
62
+ end
63
+ end
64
+ end
65
+ Faraday::Response.register_middleware os_response_recorder: -> { Faraday::Response::OSResponseRecorder }
66
+
67
+ require 'yao/server_error'
68
+ class Faraday::Response::OSErrorDetector < Faraday::Response::Middleware
69
+ # TODO: Better handling, respecting official doc
70
+ def on_complete(env)
71
+ return if env.success?
72
+
73
+ raise Yao::ServerError.detect(env)
74
+ end
75
+ end
76
+ Faraday::Response.register_middleware os_error_detector: -> { Faraday::Response::OSErrorDetector }
@@ -13,6 +13,7 @@ module Yao
13
13
  autoload :Network, "yao/resources/network"
14
14
  autoload :Subnet, "yao/resources/subnet"
15
15
  autoload :Port, "yao/resources/port"
16
+ autoload :Tenant, "yao/resources/tenant"
16
17
 
17
18
  end
18
19
 
@@ -5,7 +5,6 @@ module Yao::Resources
5
5
  def self.extended(base)
6
6
  base.class_eval do
7
7
  class << self
8
- attr_reader :client
9
8
  attr_accessor :resource_name, :resources_name
10
9
 
11
10
  extend Forwardable
@@ -18,13 +17,16 @@ module Yao::Resources
18
17
 
19
18
  def service=(name)
20
19
  @service = name
21
- @client = Yao.default_client.pool[name]
22
20
  end
23
21
 
24
22
  def service
25
23
  @service
26
24
  end
27
25
 
26
+ def client
27
+ Yao.default_client.pool[service]
28
+ end
29
+
28
30
  # restful methods
29
31
  def list
30
32
  return_resources(GET(resources_name).body[resources_name_in_json])
@@ -8,6 +8,15 @@ module Yao::Resources
8
8
  map_attribute_to_resource :image => Image
9
9
  map_attribute_to_resources :security_groups => SecurityGroup
10
10
 
11
+ map_attribute_to_attribute 'OS-EXT-AZ:availability_zone' => :availability_zone
12
+ map_attribute_to_attribute 'OS-DCF:diskConfig' => :dcf_disk_config
13
+ map_attribute_to_attribute 'OS-EXT-SRV-ATTR:host' => :ext_srv_attr_host
14
+ map_attribute_to_attribute 'OS-EXT-SRV-ATTR:hypervisor_hostname' => :ext_srv_attr_hypervisor_hostname
15
+ map_attribute_to_attribute 'OS-EXT-SRV-ATTR:instance_name' => :ext_srv_attr_instance_name
16
+ map_attribute_to_attribute 'OS-EXT-STS:power_state' => :ext_sts_power_state
17
+ map_attribute_to_attribute 'OS-EXT-STS:task_state' => :ext_sts_task_state
18
+ map_attribute_to_attribute 'OS-EXT-STS:vm_state' => :ext_sts_vm_state
19
+
11
20
  self.service = "compute"
12
21
  self.resource_name = "server"
13
22
  self.resources_name = "servers"
@@ -0,0 +1,9 @@
1
+ module Yao::Resources
2
+ class Tenant < Base
3
+ friendly_attributes :id, :name, :description, :enabled
4
+
5
+ self.service = "identity"
6
+ self.resource_name = "tenant"
7
+ self.resources_name = "tenants"
8
+ end
9
+ end
@@ -0,0 +1,81 @@
1
+ module Yao
2
+ class ServerError < ::StandardError
3
+ def initialize(message, requested_env)
4
+ @status = requested_env.status
5
+ @env = requested_env
6
+ super(message)
7
+ end
8
+ attr_reader :status, :env
9
+
10
+ def self.detect(env)
11
+ case env.status
12
+ when 400
13
+ if env.body && env.body["computeFault"]
14
+ ComputeFault.new(extract_message(env.body), env)
15
+ elsif env.body && env.body.to_a.join.include?('NetworkNotFound')
16
+ NetworkNotFound.new(extract_message(env.body), env)
17
+ else
18
+ BadRequest.new(extract_message(env.body), env)
19
+ end
20
+ when 401
21
+ Unauthorized.new(extract_message(env.body), env)
22
+ when 404
23
+ if env.body && env.body["itemNotFound"]
24
+ ItemNotFound.new(extract_message(env.body), env)
25
+ else
26
+ NotFound.new("The resource could not be found.", env)
27
+ end
28
+ when 405
29
+ BadMethod.new(extract_message(env.body), env)
30
+ when 409
31
+ if env.body && env.body["buildInProgress"]
32
+ BuildInProgress.new(extract_message(env.body), env)
33
+ else
34
+ Conflict.new(extract_message(env.body), env)
35
+ end
36
+ when 413
37
+ OverLimit.new(extract_message(env.body), env)
38
+ when 415
39
+ BadMediaType.new(extract_message(env.body), env)
40
+ when 422
41
+ UnprocessableEntity.new(extract_message(env.body), env)
42
+ when 500
43
+ ComputeFault.new(extract_message(env.body), env)
44
+ when 503
45
+ if env.body && env.body[" serverCapacityUnavailable"]
46
+ ServerCapacityUnavailable.new(extract_message(env.body), env)
47
+ else
48
+ ServiceUnavailable.new(extract_message(env.body), env)
49
+ end
50
+ else
51
+ new(extract_message(env.body), env)
52
+ end
53
+ rescue => e
54
+ new("Detection failed - %s" % e.message, env)
55
+ end
56
+
57
+ def self.extract_message(body)
58
+ body.values.first["message"] or raise
59
+ rescue
60
+ "Something is wrong. - %s" % body.inspect
61
+ end
62
+ end
63
+
64
+ # Errors as OpenStack error type
65
+ class ComputeFault < ServerError; end
66
+ class UnprocessableEntity < ServerError; end
67
+ class ItemNotFound < ServerError; end
68
+ class ServiceUnavailable < ServerError; end
69
+ class NotFound < ServerError; end
70
+ class BadRequest < ServerError; end
71
+ class Unauthorized < ServerError; end
72
+ class Forbidden < ServerError; end
73
+ class BadMethod < ServerError; end
74
+ class OverLimit < ServerError; end
75
+ class BadMediaType < ServerError; end
76
+ class NetworkNotFound < ServerError; end
77
+ class BuildInProgress < ServerError; end
78
+ class Conflict < ServerError; end
79
+ class ServerCapacityUnavailable < ServerError; end
80
+
81
+ end
@@ -0,0 +1,63 @@
1
+ require 'yao/client'
2
+
3
+ module Yao
4
+ class Token
5
+ def self.issue(cli, auth_info)
6
+ t = new(auth_info)
7
+ t.reflesh(cli)
8
+ t
9
+ end
10
+
11
+ def initialize(auth_info, token_data=nil)
12
+ @auth_info = auth_info
13
+
14
+ @endpoints = {}
15
+ end
16
+ attr_accessor :auth_info, :token, :issued_at, :expire_at, :endpoints
17
+ alias expires expire_at
18
+ alias to_s token
19
+
20
+ def register(token_data)
21
+ @token = token_data["id"]
22
+ @issued_at = Time.parse(token_data["issued_at"]).localtime
23
+ @expire_at = Time.parse(token_data["expires"]).localtime
24
+ end
25
+
26
+ def expired?
27
+ return true unless self.expire_at
28
+ Time.now >= self.expire_at
29
+ end
30
+
31
+ def reflesh(cli)
32
+ @endpoints.clear
33
+
34
+ res = cli.post('/v2.0/tokens') do |req|
35
+ req.body = auth_info.to_json
36
+ req.headers['Content-Type'] = 'application/json'
37
+ end
38
+
39
+ body = res.body["access"]
40
+
41
+ register(body["token"])
42
+ register_endpoints(body["serviceCatalog"])
43
+ self
44
+ end
45
+
46
+ def register_endpoints(_endpoints)
47
+ return unless _endpoints
48
+
49
+ _endpoints.each do |endpoint_data|
50
+ key = endpoint_data["type"]
51
+ value = if d = endpoint_data["endpoints"].first
52
+ d["publicURL"]
53
+ else
54
+ nil
55
+ end
56
+ if value
57
+ @endpoints[key] = value
58
+ end
59
+ end
60
+ Yao.default_client.register_endpoints(@endpoints, token: self)
61
+ end
62
+ end
63
+ end
@@ -1,3 +1,3 @@
1
1
  module Yao
2
- VERSION = "0.0.2.rc3"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,9 @@
1
+ require 'test/unit'
2
+ require 'test/unit/rr'
3
+ require 'power_assert'
4
+ require 'yao'
5
+
6
+ require 'webmock/test_unit'
7
+
8
+ WebMock.disable_net_connect!
9
+ #WebMock.allow_net_connect!
@@ -0,0 +1,152 @@
1
+ class TestAuth < Test::Unit::TestCase
2
+
3
+ AUTH_JSON = \
4
+ "{\"auth\":{\"passwordCredentials\":{\"username\":\"udzura\",\"password\":\"XXXXXXXX\"},\"tenantName\":\"example\"}}"
5
+
6
+ RESPONSE_JSON = <<-JSON
7
+ {
8
+ "access": {
9
+ "token": {
10
+ "issued_at": "2015-08-31T03:58:36.073232",
11
+ "expires": "2015-09-01T03:58:36Z",
12
+ "id": "aaaa166533fd49f3b11b1cdce2430000",
13
+ "tenant": {
14
+ "description": "Testing",
15
+ "enabled": true,
16
+ "id": "aaaa166533fd49f3b11b1cdce2430000",
17
+ "name": "example"
18
+ }
19
+ },
20
+ "serviceCatalog": [
21
+ {
22
+ "endpoints": [
23
+ {
24
+ "adminURL": "http://nova-endpoint.example.com:8774/v2/b598bf98671c47e1b955f8c9660e3c44",
25
+ "region": "RegionOne",
26
+ "internalURL": "http://nova-endpoint.example.com:8774/v2/b598bf98671c47e1b955f8c9660e3c44",
27
+ "id": "1a66e6af97c440b2a7bbc4f9735923d9",
28
+ "publicURL": "http://nova-endpoint.example.com:8774/v2/b598bf98671c47e1b955f8c9660e3c44"
29
+ }
30
+ ],
31
+ "endpoints_links": [],
32
+ "type": "compute",
33
+ "name": "nova"
34
+ },
35
+ {
36
+ "endpoints": [
37
+ {
38
+ "adminURL": "http://neutron-endpoint.example.com:9696/",
39
+ "region": "RegionOne",
40
+ "internalURL": "http://neutron-endpoint.example.com:9696/",
41
+ "id": "0418104da877468ca65d739142fa3454",
42
+ "publicURL": "http://neutron-endpoint.example.com:9696/"
43
+ }
44
+ ],
45
+ "endpoints_links": [],
46
+ "type": "network",
47
+ "name": "neutron"
48
+ },
49
+ {
50
+ "endpoints": [
51
+ {
52
+ "adminURL": "http://glance-endpoint.example.com:9292",
53
+ "region": "RegionOne",
54
+ "internalURL": "http://glance-endpoint.example.com:9292",
55
+ "id": "246f33509ff64802b86eb081307ecec0",
56
+ "publicURL": "http://glance-endpoint.example.com:9292"
57
+ }
58
+ ],
59
+ "endpoints_links": [],
60
+ "type": "image",
61
+ "name": "glance"
62
+ },
63
+ {
64
+ "endpoints": [
65
+ {
66
+ "adminURL": "http://endpoint.example.com:12345/v2.0",
67
+ "region": "RegionOne",
68
+ "internalURL": "http://endpoint.example.com:5000/v2.0",
69
+ "id": "2b982236cc084128bf42b647c1b7fb49",
70
+ "publicURL": "http://endpoint.example.com:5000/v2.0"
71
+ }
72
+ ],
73
+ "endpoints_links": [],
74
+ "type": "identity",
75
+ "name": "keystone"
76
+ }
77
+ ],
78
+ "user": {
79
+ "username": "udzura",
80
+ "roles_links": [],
81
+ "id": "a9994b2dee82423da7da572397d3157a",
82
+ "roles": [
83
+ {
84
+ "name": "admin"
85
+ }
86
+ ],
87
+ "name": "udzura"
88
+ },
89
+ "metadata": {
90
+ "is_admin": 0,
91
+ "roles": [
92
+ "ce5330c512cc4bd289b3a725ad1106b7"
93
+ ]
94
+ }
95
+ }
96
+ }
97
+ JSON
98
+
99
+ def setup
100
+ stub_request(:post, "http://endpoint.example.com:12345/v2.0/tokens").with(body: AUTH_JSON)
101
+ .to_return(:status => 200, :body => RESPONSE_JSON, :headers => {'Content-Type' => 'application/json'})
102
+
103
+ Yao.config.set :auth_url, "http://endpoint.example.com:12345"
104
+ @token = Yao::Auth.new(tenant_name: "example", username: "udzura", password: "XXXXXXXX")
105
+ end
106
+
107
+ def teardown
108
+ end
109
+
110
+ def test_auth_successful
111
+ cli = Yao.default_client.pool["default"]
112
+ assert { cli.url_prefix.to_s == "http://endpoint.example.com:12345/" }
113
+ end
114
+
115
+ def test_service_sclients_initialized
116
+ %w(compute network image identity).each do |service|
117
+ cli = Yao.default_client.pool[service]
118
+ assert { !cli.nil? }
119
+ end
120
+ end
121
+
122
+ def test_nova_tenant_logged_in
123
+ tenant_id = "b598bf98671c47e1b955f8c9660e3c44"
124
+ cli = Yao.default_client.compute
125
+ assert { cli.url_prefix.to_s == "http://nova-endpoint.example.com:8774/v2/#{tenant_id}" }
126
+ end
127
+
128
+ def test_neutron_prefix_added
129
+ cli = Yao.default_client.network
130
+ assert { cli.url_prefix.to_s == "http://neutron-endpoint.example.com:9696/v2.0" }
131
+ end
132
+
133
+ def test_token_is_valid
134
+ assert { @token.token == "aaaa166533fd49f3b11b1cdce2430000" }
135
+ assert { @token.issued_at == Time.parse("2015-08-31T03:58:36.073232") }
136
+ assert { @token.expire_at == Time.parse("2015-09-01T03:58:36Z") }
137
+ assert { @token.endpoints.size == 4 }
138
+ end
139
+
140
+ def test_hooked_by_configure_block
141
+ auth = Yao::Auth
142
+ stub(auth).new
143
+
144
+ Yao.configure do
145
+ auth_url "http://endpoint.example.com:12345"
146
+ tenant_name "example"
147
+ username "udzura"
148
+ password "XXXXXXXX"
149
+ end
150
+ assert_received(auth) {|a| a.new }
151
+ end
152
+ end
@@ -0,0 +1,49 @@
1
+ class TestClient < Test::Unit::TestCase
2
+ def setup
3
+ stub(Yao.config).debug { false }
4
+ stub(Yao.config).debug_record_response { false }
5
+ end
6
+
7
+ def test_gen_client
8
+ cli = Yao::Client.gen_client("http://cool-api.example.com:12345/v3.0")
9
+ assert { cli.url_prefix.to_s == "http://cool-api.example.com:12345/v3.0" }
10
+
11
+ handlers = [
12
+ Faraday::Request::UrlEncoded,
13
+ FaradayMiddleware::EncodeJson,
14
+ Faraday::Response::OSErrorDetector,
15
+ FaradayMiddleware::ParseJson,
16
+ Faraday::Adapter::NetHttp
17
+ ]
18
+ assert { cli.builder.handlers == handlers }
19
+ end
20
+
21
+ def test_gen_with_token
22
+ cli = Yao::Client.gen_client("http://cool-api.example.com:12345/v3.0", token: "deadbeaf")
23
+ handlers = [
24
+ Faraday::Request::UrlEncoded,
25
+ FaradayMiddleware::EncodeJson,
26
+ Faraday::Request::OSToken,
27
+ Faraday::Response::OSErrorDetector,
28
+ FaradayMiddleware::ParseJson,
29
+ Faraday::Adapter::NetHttp
30
+ ]
31
+ assert { cli.builder.handlers == handlers }
32
+ end
33
+
34
+ def test_debug_mode
35
+ stub(Yao.config).debug { true }
36
+
37
+ cli = Yao::Client.gen_client("http://cool-api.example.com:12345/v3.0")
38
+ handlers = [
39
+ Faraday::Request::UrlEncoded,
40
+ FaradayMiddleware::EncodeJson,
41
+ Faraday::Response::OSErrorDetector,
42
+ FaradayMiddleware::ParseJson,
43
+ Faraday::Response::Logger,
44
+ Faraday::Response::OSDumper,
45
+ Faraday::Adapter::NetHttp
46
+ ]
47
+ assert { cli.builder.handlers == handlers }
48
+ end
49
+ end
@@ -0,0 +1,65 @@
1
+ class TestConfig < Test::Unit::TestCase
2
+ def test_define_param
3
+ assert { !Yao.config.respond_to?(:foobar) }
4
+
5
+ Yao.config.param :foobar, nil
6
+ assert { Yao.config.respond_to?(:foobar) }
7
+ end
8
+
9
+ def test_raise_undefined_key
10
+ e = nil
11
+ begin
12
+ Yao.config.set :some_imaginary_key, 123
13
+ rescue => e
14
+ end
15
+ assert { e.message == "Undefined config key some_imaginary_key" }
16
+ end
17
+
18
+ def test_define_hook
19
+ hooked_value = nil
20
+
21
+ Yao.config.param :do_hook, "sample" do |v|
22
+ hooked_value = v
23
+ end
24
+ assert("param definition should not hook callbacks") do
25
+ hooked_value.nil?
26
+ end
27
+
28
+ Yao.config.set :do_hook, "true value"
29
+ assert { hooked_value = "true value" }
30
+
31
+ Yao.config.do_hook("next value")
32
+ assert { Yao.config.do_hook == "next value" }
33
+ assert { hooked_value == "next value" }
34
+ end
35
+
36
+ def test_delayed_hook
37
+ hooked_value = nil
38
+ Yao.config.param :def_hook1, "test" do |v|
39
+ if Yao.config.def_hook2
40
+ hooked_value = v
41
+ end
42
+ end
43
+ Yao.config.param :def_hook2, false
44
+
45
+ Yao.configure do
46
+ def_hook1 "test 2"
47
+ def_hook2 true
48
+ end
49
+
50
+ assert { hooked_value == "test 2" }
51
+ end
52
+
53
+ def test_auth_is_hooked
54
+ auth = Yao::Auth
55
+ count = Yao::Config::HOOK_RENEW_CLIENT_KEYS.size
56
+ mock(auth).try_new.times(count)
57
+ Yao::Config::HOOK_RENEW_CLIENT_KEYS.each do |key|
58
+ Yao.configure do
59
+ set key, "dummy"
60
+ end
61
+ end
62
+
63
+ assert_received(auth) {|a| a.try_new.times(count) }
64
+ end
65
+ end
@@ -0,0 +1,25 @@
1
+ class TestServerError < Test::Unit::TestCase
2
+ def test_detects_error_with_env
3
+ env = Faraday::Env.new
4
+ env.body = {"itemNotFound"=>{"message"=>"Image not found.", "code"=>404}}
5
+ env.status = 404
6
+
7
+ error = Yao::ServerError.detect(env)
8
+ assert { error.is_a? Yao::ItemNotFound }
9
+ assert { error.env.is_a? Faraday::Env }
10
+ assert { error.status == 404 }
11
+ assert { error.env.body["itemNotFound"]["message"] == "Image not found." }
12
+ end
13
+
14
+ def test_anyway_returns_error
15
+ env = Faraday::Env.new
16
+ env.body = "<html>Not found.</html>"
17
+ env.status = 599
18
+
19
+ error = Yao::ServerError.detect(env)
20
+ assert { error.is_a? Yao::ServerError }
21
+ assert { error.env.is_a? Faraday::Env }
22
+ assert { error.status == 599 }
23
+ assert { error.message == "Something is wrong. - \"<html>Not found.</html>\"" }
24
+ end
25
+ end
@@ -0,0 +1,74 @@
1
+ class TestToken < Test::Unit::TestCase
2
+ def setup
3
+ stub(Yao.config).debug { false }
4
+ stub(Yao.config).debug_record_response { false }
5
+ end
6
+
7
+ def test_expired
8
+ t = Yao::Token.new({})
9
+ t.register({
10
+ "id" => "aaaa166533fd49f3b11b1cdce2430000",
11
+ "issued_at" => Time.now.iso8601,
12
+ "expires" => (Time.now - 3600).utc.iso8601
13
+ })
14
+
15
+ assert { t.expired? }
16
+
17
+ t.register({
18
+ "id" => "aaaa166533fd49f3b11b1cdce2430000",
19
+ "issued_at" => Time.now.iso8601,
20
+ "expires" => (Time.now + 3600).utc.iso8601
21
+ })
22
+ assert { ! t.expired? }
23
+ end
24
+
25
+ AUTH_JSON = \
26
+ "{\"auth\":{\"passwordCredentials\":{\"username\":\"udzura\",\"password\":\"XXXXXXXX\"},\"tenantName\":\"example\"}}"
27
+
28
+ def gen_response_json
29
+ <<-JSON
30
+ {
31
+ "access": {
32
+ "token": {
33
+ "issued_at": "#{Time.now.iso8601}",
34
+ "expires": "#{(Time.now + 3600).utc.iso8601}",
35
+ "id": "aaaa166533fd49f3b11b1cdce2430000",
36
+ "tenant": {
37
+ "description": "Testing",
38
+ "enabled": true,
39
+ "id": "aaaa166533fd49f3b11b1cdce2430000",
40
+ "name": "example"
41
+ }
42
+ },
43
+ "serviceCatalog": []
44
+ }
45
+ }
46
+ JSON
47
+ end
48
+
49
+ def test_reflesh
50
+ auth_info = {
51
+ auth: {
52
+ passwordCredentials: {
53
+ username: "udzura", password: "XXXXXXXX"
54
+ },
55
+ tenantName: "example"
56
+ }
57
+ }
58
+ t = Yao::Token.new(auth_info)
59
+ t.register({
60
+ "id" => "old_token",
61
+ "issued_at" => Time.now.iso8601,
62
+ "expires" => (Time.now - 3600).utc.iso8601
63
+ })
64
+ assert { t.token == "old_token" }
65
+
66
+ stub_request(:post, "http://endpoint.example.com:12345/v2.0/tokens").with(body: AUTH_JSON)
67
+ .to_return(:status => 200, :body => gen_response_json, :headers => {'Content-Type' => 'application/json'})
68
+
69
+ Yao.config.auth_url "http://endpoint.example.com:12345"
70
+ t.reflesh(Yao.default_client.default)
71
+
72
+ assert { t.token == "aaaa166533fd49f3b11b1cdce2430000" }
73
+ end
74
+ end
@@ -28,4 +28,5 @@ Gem::Specification.new do |spec|
28
28
  spec.add_development_dependency "test-unit-rr"
29
29
  spec.add_development_dependency "power_assert"
30
30
  spec.add_development_dependency "pry"
31
+ spec.add_development_dependency "webmock"
31
32
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: yao
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2.rc3
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Uchio, KONDO
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-08-26 00:00:00.000000000 Z
11
+ date: 2015-09-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -136,6 +136,20 @@ dependencies:
136
136
  - - ">="
137
137
  - !ruby/object:Gem::Version
138
138
  version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: webmock
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
139
153
  description: YAO is a Yet Another OpenStack API Wrapper that rocks!!
140
154
  email:
141
155
  - udzura@udzura.jp
@@ -144,6 +158,7 @@ extensions: []
144
158
  extra_rdoc_files: []
145
159
  files:
146
160
  - ".gitignore"
161
+ - ".travis.yml"
147
162
  - Gemfile
148
163
  - LICENSE.txt
149
164
  - README.md
@@ -169,7 +184,16 @@ files:
169
184
  - lib/yao/resources/security_group_rule.rb
170
185
  - lib/yao/resources/server.rb
171
186
  - lib/yao/resources/subnet.rb
187
+ - lib/yao/resources/tenant.rb
188
+ - lib/yao/server_error.rb
189
+ - lib/yao/token.rb
172
190
  - lib/yao/version.rb
191
+ - test/config.rb
192
+ - test/yao/test_auth.rb
193
+ - test/yao/test_client.rb
194
+ - test/yao/test_config.rb
195
+ - test/yao/test_server_error.rb
196
+ - test/yao/test_token.rb
173
197
  - yao.gemspec
174
198
  homepage: https://github.com/udzura/yao
175
199
  licenses:
@@ -186,13 +210,19 @@ required_ruby_version: !ruby/object:Gem::Requirement
186
210
  version: '0'
187
211
  required_rubygems_version: !ruby/object:Gem::Requirement
188
212
  requirements:
189
- - - ">"
213
+ - - ">="
190
214
  - !ruby/object:Gem::Version
191
- version: 1.3.1
215
+ version: '0'
192
216
  requirements: []
193
217
  rubyforge_project:
194
218
  rubygems_version: 2.2.3
195
219
  signing_key:
196
220
  specification_version: 4
197
221
  summary: Yet Another OpenStack API Wrapper that rocks!!
198
- test_files: []
222
+ test_files:
223
+ - test/config.rb
224
+ - test/yao/test_auth.rb
225
+ - test/yao/test_client.rb
226
+ - test/yao/test_config.rb
227
+ - test/yao/test_server_error.rb
228
+ - test/yao/test_token.rb