fog-openstack 0.1.31 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +1 -0
- data/.rubocop.yml +4 -1
- data/.travis.yml +5 -5
- data/.zuul.yaml +8 -8
- data/Rakefile +14 -4
- data/fog-openstack.gemspec +3 -2
- data/lib/fog/baremetal/openstack.rb +6 -24
- data/lib/fog/compute/openstack.rb +6 -27
- data/lib/fog/compute/openstack/requests/create_security_group.rb +1 -1
- data/lib/fog/compute/openstack/requests/create_server.rb +1 -1
- data/lib/fog/compute/openstack/requests/evacuate_server.rb +1 -5
- data/lib/fog/container_infra/openstack.rb +6 -25
- data/lib/fog/dns/openstack/v1.rb +5 -17
- data/lib/fog/dns/openstack/v2.rb +5 -22
- data/lib/fog/event/openstack.rb +5 -24
- data/lib/fog/identity/openstack.rb +24 -71
- data/lib/fog/identity/openstack/v2.rb +6 -4
- data/lib/fog/identity/openstack/v3.rb +5 -11
- data/lib/fog/image/openstack/v1.rb +8 -21
- data/lib/fog/image/openstack/v2.rb +8 -21
- data/lib/fog/image/openstack/v2/models/image.rb +1 -1
- data/lib/fog/introspection/openstack.rb +4 -19
- data/lib/fog/key_manager/openstack.rb +5 -47
- data/lib/fog/metering/openstack.rb +8 -23
- data/lib/fog/metric/openstack.rb +7 -26
- data/lib/fog/monitoring/openstack.rb +3 -12
- data/lib/fog/network/openstack.rb +5 -26
- data/lib/fog/network/openstack/requests/set_tenant.rb +0 -1
- data/lib/fog/nfv/openstack.rb +4 -24
- data/lib/fog/openstack.rb +17 -431
- data/lib/fog/openstack/auth/catalog.rb +64 -0
- data/lib/fog/openstack/auth/catalog/v2.rb +23 -0
- data/lib/fog/openstack/auth/catalog/v3.rb +23 -0
- data/lib/fog/openstack/auth/name.rb +65 -0
- data/lib/fog/openstack/auth/token.rb +69 -0
- data/lib/fog/openstack/auth/token/v2.rb +70 -0
- data/lib/fog/openstack/auth/token/v3.rb +116 -0
- data/lib/fog/openstack/core.rb +100 -76
- data/lib/fog/openstack/version.rb +1 -1
- data/lib/fog/orchestration/openstack.rb +4 -21
- data/lib/fog/planning/openstack.rb +13 -23
- data/lib/fog/shared_file_system/openstack.rb +10 -27
- data/lib/fog/storage/openstack.rb +6 -11
- data/lib/fog/volume/openstack.rb +1 -1
- data/lib/fog/volume/openstack/models/backup.rb +2 -2
- data/lib/fog/volume/openstack/requests/restore_backup.rb +2 -2
- data/lib/fog/volume/openstack/requests/update_volume.rb +12 -1
- data/lib/fog/volume/openstack/v1.rb +4 -21
- data/lib/fog/volume/openstack/v1/models/volume.rb +1 -2
- data/lib/fog/volume/openstack/v1/requests/update_volume.rb +0 -17
- data/lib/fog/volume/openstack/v2.rb +4 -21
- data/lib/fog/volume/openstack/v2/models/volume.rb +1 -1
- data/lib/fog/volume/openstack/v2/requests/update_volume.rb +0 -18
- data/lib/fog/workflow/openstack/v2.rb +5 -22
- data/playbooks/fog-openstack-unittest-spec/run.yaml +2 -1
- data/playbooks/fog-openstack-unittest-test/run.yaml +2 -1
- data/unit/auth/catalog_test.rb +252 -0
- data/unit/auth/name_test.rb +115 -0
- data/unit/auth/token_test.rb +478 -0
- data/unit/auth_helper.rb +102 -0
- data/unit/test_helper.rb +6 -0
- metadata +41 -16
- data/lib/fog/compute/openstack/requests/list_tenants.rb +0 -43
@@ -0,0 +1,64 @@
|
|
1
|
+
module Fog
|
2
|
+
module OpenStack
|
3
|
+
module Auth
|
4
|
+
module Catalog
|
5
|
+
attr_reader :payload
|
6
|
+
|
7
|
+
class CatalogError < RuntimeError; end
|
8
|
+
class EndpointError < RuntimeError; end
|
9
|
+
class ServiceTypeError < RuntimeError; end
|
10
|
+
|
11
|
+
def initialize(payload)
|
12
|
+
@payload = payload
|
13
|
+
end
|
14
|
+
|
15
|
+
def get_endpoint_url(names, interfaces, region = nil)
|
16
|
+
# TODO: Inject OpenStack Service Types Authority
|
17
|
+
names_list = if names.kind_of?(String)
|
18
|
+
[names]
|
19
|
+
else
|
20
|
+
names
|
21
|
+
end
|
22
|
+
entries = get_by_type(names_list)
|
23
|
+
raise ServiceTypeError, 'No endpoint match' if entries.empty?
|
24
|
+
|
25
|
+
interfaces_list = if interfaces.kind_of?(String)
|
26
|
+
[interfaces]
|
27
|
+
else
|
28
|
+
interfaces
|
29
|
+
end
|
30
|
+
|
31
|
+
list = []
|
32
|
+
interfaces_list.each do |interface|
|
33
|
+
val = get_endpoint(entries, interface, region)
|
34
|
+
list << val if val
|
35
|
+
end
|
36
|
+
|
37
|
+
raise EndpointError, 'No endpoint found' if list.empty?
|
38
|
+
list[0]
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def get_by_type(names)
|
44
|
+
raise CatalogError, 'Empty content' unless @payload
|
45
|
+
@payload.select do |e|
|
46
|
+
names.include?(e['type'])
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def get_endpoint(entries, interface, region)
|
51
|
+
list = []
|
52
|
+
entries.each do |type|
|
53
|
+
next unless type.key?('endpoints')
|
54
|
+
type['endpoints'].each do |endpoint|
|
55
|
+
list << endpoint_url(endpoint, interface) if endpoint_match?(endpoint, interface, region)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
raise EndpointError, 'Multiple endpoints found' if list.size > 1
|
59
|
+
list[0]
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'fog/openstack/auth/catalog'
|
2
|
+
|
3
|
+
module Fog
|
4
|
+
module OpenStack
|
5
|
+
module Auth
|
6
|
+
module Catalog
|
7
|
+
class V2
|
8
|
+
include Fog::OpenStack::Auth::Catalog
|
9
|
+
|
10
|
+
def endpoint_match?(endpoint, interface, region)
|
11
|
+
if endpoint.key?("#{interface}URL")
|
12
|
+
true unless !region.nil? && endpoint['region'] != region
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def endpoint_url(endpoint, interface)
|
17
|
+
endpoint["#{interface}URL"]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'fog/openstack/auth/catalog'
|
2
|
+
|
3
|
+
module Fog
|
4
|
+
module OpenStack
|
5
|
+
module Auth
|
6
|
+
module Catalog
|
7
|
+
class V3
|
8
|
+
include Fog::OpenStack::Auth::Catalog
|
9
|
+
|
10
|
+
def endpoint_match?(endpoint, interface, region)
|
11
|
+
if endpoint['interface'] == interface
|
12
|
+
true unless !region.nil? && endpoint['region'] != region
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def endpoint_url(endpoint, _)
|
17
|
+
endpoint['url']
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Fog
|
2
|
+
module OpenStack
|
3
|
+
module Auth
|
4
|
+
class CredentialsError < RuntimeError; end
|
5
|
+
|
6
|
+
module Domain
|
7
|
+
attr_accessor :domain
|
8
|
+
|
9
|
+
def identity
|
10
|
+
data = {}
|
11
|
+
if !id.nil?
|
12
|
+
data.merge!(to_h(:id))
|
13
|
+
elsif !name.nil? && !domain.nil?
|
14
|
+
data.merge!(to_h(:name))
|
15
|
+
data[:domain] = @domain.identity
|
16
|
+
else
|
17
|
+
raise Fog::OpenStack::Auth::CredentialsError,
|
18
|
+
"#{self.class}: An Id, or a name with its domain, must be provided"
|
19
|
+
end
|
20
|
+
data
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
Name = Struct.new(:id, :name)
|
25
|
+
class Name
|
26
|
+
def identity
|
27
|
+
return to_h(:id) unless id.nil?
|
28
|
+
return to_h(:name) unless name.nil?
|
29
|
+
raise Fog::OpenStack::Auth::CredentialsError, "#{self.class}: No available id or name"
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_h(var)
|
33
|
+
{var => send(var)}
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class DomainScope < Name
|
38
|
+
def identity
|
39
|
+
{:domain => super}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class ProjectScope < Name
|
44
|
+
include Fog::OpenStack::Auth::Domain
|
45
|
+
|
46
|
+
def identity
|
47
|
+
{:project => super}
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class User < Name
|
52
|
+
include Fog::OpenStack::Auth::Domain
|
53
|
+
|
54
|
+
attr_accessor :password
|
55
|
+
|
56
|
+
def identity
|
57
|
+
data = super
|
58
|
+
raise CredentialsError, "#{self.class}: No password available" if password.nil?
|
59
|
+
data.merge!(to_h(:password))
|
60
|
+
{:user => data}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'fog/openstack/auth/token/v2'
|
2
|
+
require 'fog/openstack/auth/token/v3'
|
3
|
+
require 'fog/openstack/auth/catalog/v2'
|
4
|
+
require 'fog/openstack/auth/catalog/v3'
|
5
|
+
|
6
|
+
module Fog
|
7
|
+
module OpenStack
|
8
|
+
module Auth
|
9
|
+
module Token
|
10
|
+
attr_reader :catalog, :expires, :tenant, :token, :user, :data
|
11
|
+
|
12
|
+
class ExpiryError < RuntimeError; end
|
13
|
+
class StandardError < RuntimeError; end
|
14
|
+
class URLError < RuntimeError; end
|
15
|
+
|
16
|
+
def self.build(auth)
|
17
|
+
if auth[:openstack_tenant_id] || auth[:openstack_tenant]
|
18
|
+
Fog::OpenStack::Auth::Token::V2.new(auth)
|
19
|
+
else
|
20
|
+
Fog::OpenStack::Auth::Token::V3.new(auth)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def initialize(auth)
|
25
|
+
raise URLError, 'No URL provided' if auth[:openstack_auth_url].nil? || auth[:openstack_auth_url].empty?
|
26
|
+
@creds = {
|
27
|
+
:data => build_credentials(auth),
|
28
|
+
:uri => URI.parse(auth[:openstack_auth_url])
|
29
|
+
}
|
30
|
+
response = authenticate(@creds)
|
31
|
+
set(response)
|
32
|
+
end
|
33
|
+
|
34
|
+
def get
|
35
|
+
set(authenticate(@creds)) if expired?
|
36
|
+
@token
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
def authenticate(creds)
|
42
|
+
connection_options = {}
|
43
|
+
connection = Fog::Core::Connection.new(creds[:uri].to_s, false, connection_options)
|
44
|
+
|
45
|
+
request = {
|
46
|
+
:expects => [200, 201],
|
47
|
+
:headers => {'Content-Type' => 'application/json'},
|
48
|
+
:body => Fog::JSON.encode(creds[:data]),
|
49
|
+
:method => 'POST',
|
50
|
+
:path => creds[:uri].path + path
|
51
|
+
}
|
52
|
+
|
53
|
+
connection.request(request)
|
54
|
+
end
|
55
|
+
|
56
|
+
def expired?
|
57
|
+
if @expires.nil? || @expires.empty?
|
58
|
+
raise ExpiryError, 'Missing token expiration data'
|
59
|
+
end
|
60
|
+
Time.parse(@expires) < Time.now.utc
|
61
|
+
end
|
62
|
+
|
63
|
+
def refresh
|
64
|
+
raise StandardError, "__method__ not implemented yet!"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'fog/openstack/auth/token'
|
2
|
+
require 'fog/openstack/auth/name'
|
3
|
+
|
4
|
+
module Fog
|
5
|
+
module OpenStack
|
6
|
+
module Auth
|
7
|
+
module Token
|
8
|
+
class CredentialsError < RuntimeError; end
|
9
|
+
|
10
|
+
class V2
|
11
|
+
include Fog::OpenStack::Auth::Token
|
12
|
+
attr_reader :tenant
|
13
|
+
|
14
|
+
def credentials
|
15
|
+
if @token
|
16
|
+
identity = {'token' => {'id' => @token}}
|
17
|
+
else
|
18
|
+
raise CredentialsError, "#{self.class}: User name is required" if @user.name.nil?
|
19
|
+
raise CredentialsError, "#{self.class}: User password is required" if @user.password.nil?
|
20
|
+
identity = {'passwordCredentials' => user_credentials}
|
21
|
+
end
|
22
|
+
|
23
|
+
if @tenant.id
|
24
|
+
identity['tenantId'] = @tenant.id
|
25
|
+
elsif @tenant.name
|
26
|
+
identity['tenantName'] = @tenant.name
|
27
|
+
else
|
28
|
+
raise CredentialsError, "#{self.class}: No tenant available"
|
29
|
+
end
|
30
|
+
|
31
|
+
{'auth' => identity}
|
32
|
+
end
|
33
|
+
|
34
|
+
def path
|
35
|
+
'/v2.0/tokens'
|
36
|
+
end
|
37
|
+
|
38
|
+
def user_credentials
|
39
|
+
{
|
40
|
+
'username' => @user.name,
|
41
|
+
'password' => @user.password
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
def set(response)
|
46
|
+
@data = Fog::JSON.decode(response.body)
|
47
|
+
@token = @data['access']['token']['id']
|
48
|
+
@expires = @data['access']['token']['expires']
|
49
|
+
@tenant = @data['access']['token']['tenant']
|
50
|
+
@user = @data['access']['user']
|
51
|
+
catalog = @data['access']['serviceCatalog']
|
52
|
+
@catalog = Fog::OpenStack::Auth::Catalog::V2.new(catalog) if catalog
|
53
|
+
end
|
54
|
+
|
55
|
+
def build_credentials(auth)
|
56
|
+
if auth[:openstack_auth_token]
|
57
|
+
@token = auth[:openstack_auth_token]
|
58
|
+
else
|
59
|
+
@user = Fog::OpenStack::Auth::User.new(auth[:openstack_userid], auth[:openstack_username])
|
60
|
+
@user.password = auth[:openstack_api_key]
|
61
|
+
end
|
62
|
+
|
63
|
+
@tenant = Fog::OpenStack::Auth::Name.new(auth[:openstack_tenant_id], auth[:openstack_tenant])
|
64
|
+
credentials
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,116 @@
|
|
1
|
+
require 'fog/openstack/auth/token'
|
2
|
+
require 'fog/openstack/auth/name'
|
3
|
+
|
4
|
+
module Fog
|
5
|
+
module OpenStack
|
6
|
+
module Auth
|
7
|
+
module Token
|
8
|
+
class V3
|
9
|
+
include Fog::OpenStack::Auth::Token
|
10
|
+
attr_reader :domain, :project
|
11
|
+
|
12
|
+
# Default Domain ID
|
13
|
+
DOMAIN_ID = 'default'.freeze
|
14
|
+
|
15
|
+
def credentials
|
16
|
+
identity = if @token
|
17
|
+
{
|
18
|
+
'methods' => ['token'],
|
19
|
+
'token' => {'id' => @token}
|
20
|
+
}
|
21
|
+
else
|
22
|
+
{
|
23
|
+
'methods' => ['password'],
|
24
|
+
'password' => @user.identity
|
25
|
+
}
|
26
|
+
end
|
27
|
+
|
28
|
+
if scope
|
29
|
+
{
|
30
|
+
'auth' => {
|
31
|
+
'identity' => identity,
|
32
|
+
'scope' => scope
|
33
|
+
}
|
34
|
+
}
|
35
|
+
else
|
36
|
+
{'auth' => {'identity' => identity}}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def path
|
41
|
+
'/v3/auth/tokens'
|
42
|
+
end
|
43
|
+
|
44
|
+
def scope
|
45
|
+
return @project.identity if @project
|
46
|
+
return @domain.identity if @domain
|
47
|
+
end
|
48
|
+
|
49
|
+
def set(response)
|
50
|
+
@data = Fog::JSON.decode(response.body)
|
51
|
+
@token = response.headers['x-subject-token']
|
52
|
+
@expires = @data['token']['expires_at']
|
53
|
+
@tenant = @data['token']['project']
|
54
|
+
@user = @data['token']['user']
|
55
|
+
catalog = @data['token']['catalog']
|
56
|
+
if catalog
|
57
|
+
@catalog = Fog::OpenStack::Auth::Catalog::V3.new(catalog)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def build_credentials(auth)
|
62
|
+
if auth[:openstack_project_id] || auth[:openstack_project_name]
|
63
|
+
# project scoped
|
64
|
+
@project = Fog::OpenStack::Auth::ProjectScope.new(
|
65
|
+
auth[:openstack_project_id],
|
66
|
+
auth[:openstack_project_name]
|
67
|
+
)
|
68
|
+
@project.domain = if auth[:openstack_project_domain_id] || auth[:openstack_project_domain_name]
|
69
|
+
Fog::OpenStack::Auth::Name.new(
|
70
|
+
auth[:openstack_project_domain_id],
|
71
|
+
auth[:openstack_project_domain_name]
|
72
|
+
)
|
73
|
+
elsif auth[:openstack_domain_id] || auth[:openstack_domain_name]
|
74
|
+
Fog::OpenStack::Auth::Name.new(
|
75
|
+
auth[:openstack_domain_id],
|
76
|
+
auth[:openstack_domain_name]
|
77
|
+
)
|
78
|
+
else
|
79
|
+
Fog::OpenStack::Auth::Name.new(DOMAIN_ID, nil)
|
80
|
+
end
|
81
|
+
elsif auth[:openstack_domain_id] || auth[:openstack_domain_name]
|
82
|
+
# domain scoped
|
83
|
+
@domain = Fog::OpenStack::Auth::DomainScope.new(
|
84
|
+
auth[:openstack_domain_id],
|
85
|
+
auth[:openstack_domain_name]
|
86
|
+
)
|
87
|
+
end
|
88
|
+
|
89
|
+
if auth[:openstack_auth_token]
|
90
|
+
@token = auth[:openstack_auth_token]
|
91
|
+
else
|
92
|
+
@user = Fog::OpenStack::Auth::User.new(auth[:openstack_userid], auth[:openstack_username])
|
93
|
+
@user.password = auth[:openstack_api_key]
|
94
|
+
|
95
|
+
@user.domain = if auth[:openstack_user_domain_id] || auth[:openstack_user_domain_name]
|
96
|
+
Fog::OpenStack::Auth::Name.new(
|
97
|
+
auth[:openstack_user_domain_id],
|
98
|
+
auth[:openstack_user_domain_name]
|
99
|
+
)
|
100
|
+
elsif auth[:openstack_domain_id] || auth[:openstack_domain_name]
|
101
|
+
Fog::OpenStack::Auth::Name.new(
|
102
|
+
auth[:openstack_domain_id],
|
103
|
+
auth[:openstack_domain_name]
|
104
|
+
)
|
105
|
+
else
|
106
|
+
Fog::OpenStack::Auth::Name.new(DOMAIN_ID, nil)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
credentials
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
data/lib/fog/openstack/core.rb
CHANGED
@@ -15,56 +15,22 @@ module Fog
|
|
15
15
|
attr_reader :openstack_user_domain_id
|
16
16
|
attr_reader :openstack_project_id
|
17
17
|
attr_reader :openstack_project_domain_id
|
18
|
-
attr_reader :
|
18
|
+
attr_reader :openstack_identity_api_version
|
19
19
|
|
20
20
|
# fallback
|
21
21
|
def self.not_found_class
|
22
22
|
Fog::Compute::OpenStack::NotFound
|
23
23
|
end
|
24
24
|
|
25
|
-
def initialize_identity(options)
|
26
|
-
# Create @openstack_* instance variables from all :openstack_* options
|
27
|
-
options.select { |x| x.to_s.start_with? 'openstack' }.each do |openstack_param, value|
|
28
|
-
instance_variable_set "@#{openstack_param}".to_sym, value
|
29
|
-
end
|
30
|
-
|
31
|
-
@auth_token ||= options[:openstack_auth_token]
|
32
|
-
@openstack_identity_public_endpoint = options[:openstack_identity_endpoint]
|
33
|
-
|
34
|
-
@openstack_auth_uri = URI.parse(options[:openstack_auth_url])
|
35
|
-
@openstack_must_reauthenticate = false
|
36
|
-
@openstack_endpoint_type = options[:openstack_endpoint_type] || 'publicURL'
|
37
|
-
|
38
|
-
@openstack_cache_ttl = options[:openstack_cache_ttl] || 0
|
39
|
-
|
40
|
-
if @auth_token
|
41
|
-
@openstack_can_reauthenticate = false
|
42
|
-
else
|
43
|
-
missing_credentials = []
|
44
|
-
|
45
|
-
missing_credentials << :openstack_api_key unless @openstack_api_key
|
46
|
-
unless @openstack_username || @openstack_userid
|
47
|
-
missing_credentials << 'openstack_username or openstack_userid'
|
48
|
-
end
|
49
|
-
raise ArgumentError, "Missing required arguments: #{missing_credentials.join(', ')}" unless missing_credentials.empty?
|
50
|
-
@openstack_can_reauthenticate = true
|
51
|
-
end
|
52
|
-
|
53
|
-
@current_user = options[:current_user]
|
54
|
-
@current_user_id = options[:current_user_id]
|
55
|
-
@current_tenant = options[:current_tenant]
|
56
|
-
end
|
57
|
-
|
58
25
|
def credentials
|
59
26
|
options = {
|
60
|
-
:provider
|
61
|
-
:openstack_auth_url
|
62
|
-
:openstack_auth_token
|
63
|
-
:
|
64
|
-
:
|
65
|
-
:
|
66
|
-
:
|
67
|
-
:unscoped_token => @unscoped_token
|
27
|
+
:provider => 'openstack',
|
28
|
+
:openstack_auth_url => @openstack_auth_uri.to_s,
|
29
|
+
:openstack_auth_token => @auth_token,
|
30
|
+
:current_user => @current_user,
|
31
|
+
:current_user_id => @current_user_id,
|
32
|
+
:current_tenant => @current_tenant,
|
33
|
+
:unscoped_token => @unscoped_token
|
68
34
|
}
|
69
35
|
openstack_options.merge options
|
70
36
|
end
|
@@ -73,21 +39,28 @@ module Fog
|
|
73
39
|
@connection.reset
|
74
40
|
end
|
75
41
|
|
42
|
+
def initialize(options = {})
|
43
|
+
setup(options)
|
44
|
+
authenticate
|
45
|
+
@connection = Fog::Core::Connection.new(@openstack_management_url, @persistent, @connection_options)
|
46
|
+
end
|
47
|
+
|
76
48
|
private
|
77
49
|
|
78
50
|
def request(params, parse_json = true)
|
79
51
|
retried = false
|
80
52
|
begin
|
81
|
-
response = @connection.request(
|
82
|
-
|
83
|
-
|
84
|
-
|
53
|
+
response = @connection.request(
|
54
|
+
params.merge(
|
55
|
+
:headers => headers(params.delete(:headers)),
|
56
|
+
:path => "#{@path}/#{params[:path]}"
|
57
|
+
)
|
58
|
+
)
|
85
59
|
rescue Excon::Errors::Unauthorized => error
|
86
60
|
# token expiration and token renewal possible
|
87
61
|
if error.response.body != 'Bad username or password' && @openstack_can_reauthenticate && !retried
|
88
62
|
@openstack_must_reauthenticate = true
|
89
63
|
authenticate
|
90
|
-
set_api_path
|
91
64
|
retried = true
|
92
65
|
retry
|
93
66
|
# bad credentials or token renewal not possible
|
@@ -111,10 +84,6 @@ module Fog
|
|
111
84
|
response
|
112
85
|
end
|
113
86
|
|
114
|
-
def set_api_path
|
115
|
-
# if the service supports multiple versions, do the selection here
|
116
|
-
end
|
117
|
-
|
118
87
|
def set_microversion
|
119
88
|
@microversion_key ||= 'Openstack-API-Version'.freeze
|
120
89
|
@microversion_service_type ||= @openstack_service_type.first
|
@@ -172,44 +141,99 @@ module Fog
|
|
172
141
|
options
|
173
142
|
end
|
174
143
|
|
175
|
-
def
|
176
|
-
|
144
|
+
def api_path_prefix
|
145
|
+
path = ''
|
146
|
+
if @openstack_management_uri && @openstack_management_uri.path != '/'
|
147
|
+
path = @openstack_management_uri.path
|
148
|
+
end
|
149
|
+
unless default_path_prefix.empty?
|
150
|
+
path << '/' + default_path_prefix
|
151
|
+
end
|
152
|
+
path
|
153
|
+
end
|
177
154
|
|
178
|
-
|
155
|
+
def default_endpoint_type
|
156
|
+
'public'
|
157
|
+
end
|
179
158
|
|
180
|
-
|
159
|
+
def default_path_prefix
|
160
|
+
''
|
161
|
+
end
|
181
162
|
|
182
|
-
|
163
|
+
def setup(options)
|
164
|
+
if options.respond_to?(:config_service?) && options.config_service?
|
165
|
+
configure(options)
|
166
|
+
return
|
167
|
+
end
|
183
168
|
|
184
|
-
|
185
|
-
|
186
|
-
|
169
|
+
# Create @openstack_* instance variables from all :openstack_* options
|
170
|
+
options.select { |x| x.to_s.start_with? 'openstack' }.each do |openstack_param, value|
|
171
|
+
instance_variable_set "@#{openstack_param}".to_sym, value
|
172
|
+
end
|
187
173
|
|
174
|
+
@auth_token ||= options[:openstack_auth_token]
|
175
|
+
@openstack_must_reauthenticate = false
|
176
|
+
@openstack_endpoint_type = options[:openstack_endpoint_type] || 'public'
|
177
|
+
@openstack_cache_ttl = options[:openstack_cache_ttl] || 0
|
178
|
+
|
179
|
+
if @auth_token
|
180
|
+
@openstack_can_reauthenticate = false
|
181
|
+
else
|
182
|
+
missing_credentials = []
|
183
|
+
|
184
|
+
missing_credentials << :openstack_api_key unless @openstack_api_key
|
185
|
+
unless @openstack_username || @openstack_userid
|
186
|
+
missing_credentials << 'openstack_username or openstack_userid'
|
187
|
+
end
|
188
|
+
unless missing_credentials.empty?
|
189
|
+
raise ArgumentError, "Missing required arguments: #{missing_credentials.join(', ')}"
|
190
|
+
end
|
191
|
+
@openstack_can_reauthenticate = true
|
192
|
+
end
|
193
|
+
|
194
|
+
@current_user = options[:current_user]
|
195
|
+
@current_user_id = options[:current_user_id]
|
196
|
+
@current_tenant = options[:current_tenant]
|
197
|
+
|
198
|
+
@openstack_service_type = options[:openstack_service_type] || default_service_type
|
199
|
+
@openstack_endpoint_type = options[:openstack_endpoint_type] || default_endpoint_type
|
200
|
+
@openstack_endpoint_type.gsub!(/URL/, '')
|
201
|
+
@connection_options = options[:connection_options] || {}
|
202
|
+
@persistent = options[:persistent] || false
|
203
|
+
end
|
204
|
+
|
205
|
+
def authenticate
|
206
|
+
if !@openstack_management_url || @openstack_must_reauthenticate
|
207
|
+
@openstack_auth_token = nil if @openstack_must_reauthenticate
|
208
|
+
|
209
|
+
token = Fog::OpenStack::Auth::Token.build(openstack_options)
|
210
|
+
|
211
|
+
@openstack_management_url = if token.catalog
|
212
|
+
token.catalog.get_endpoint_url(
|
213
|
+
@openstack_service_type,
|
214
|
+
@openstack_endpoint_type,
|
215
|
+
@openstack_region
|
216
|
+
)
|
217
|
+
else
|
218
|
+
@openstack_auth_url
|
219
|
+
end
|
220
|
+
|
221
|
+
@current_user = token.user['name']
|
222
|
+
@current_user_id = token.user['id']
|
223
|
+
@current_tenant = token.tenant
|
224
|
+
@expires = token.expires
|
225
|
+
@auth_token = token.token
|
226
|
+
@unscoped_token = token.token
|
188
227
|
@openstack_must_reauthenticate = false
|
189
|
-
@auth_token = credentials[:token]
|
190
|
-
@openstack_management_url = credentials[:server_management_url]
|
191
|
-
@unscoped_token = credentials[:unscoped_token]
|
192
228
|
else
|
193
229
|
@auth_token = @openstack_auth_token
|
194
230
|
end
|
195
|
-
@openstack_management_uri = URI.parse(@openstack_management_url)
|
196
231
|
|
197
|
-
@
|
198
|
-
@path = @openstack_management_uri.path
|
199
|
-
@path.sub!(%r{/$}, '')
|
200
|
-
@port = @openstack_management_uri.port
|
201
|
-
@scheme = @openstack_management_uri.scheme
|
202
|
-
|
203
|
-
# Not all implementations have identity service in the catalog
|
204
|
-
if @openstack_identity_public_endpoint || @openstack_management_url
|
205
|
-
@identity_connection = Fog::Core::Connection.new(
|
206
|
-
@openstack_identity_public_endpoint || @openstack_management_url,
|
207
|
-
false, @connection_options
|
208
|
-
)
|
209
|
-
end
|
232
|
+
@openstack_management_uri = URI.parse(@openstack_management_url)
|
210
233
|
|
211
234
|
# both need to be set in service's initialize for microversions to work
|
212
235
|
set_microversion if @supported_microversion && @supported_versions
|
236
|
+
@path = api_path_prefix
|
213
237
|
|
214
238
|
true
|
215
239
|
end
|