fog-openstack 0.1.31 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|