2 require 'puppet/feature/aviator'
3 require 'puppet/util/inifile'
5 class Puppet::Provider::Aviator < Puppet::Provider
8 @session ||= authenticate(resource[:auth], resource[:log_file])
12 @session ||= authenticate(nil, nil)
15 def request(service, request, &block)
16 self.class.make_request(service, request, session_data, &block)
19 def self.request(service, request, &block)
20 self.make_request(service, request, session_data, &block)
32 def session_data=(data)
36 def self.session_data=(data)
42 # Attempt to find credentials in this order:
43 # 1. username,password,tenant,host set in type parameters
44 # 2. openrc file path set in type parameters
45 # 3. service token and host set in type parameters
46 # 4. username,password,tenant,host set in environment variables
47 # 5. service token and host set in keystone.conf (backwards compatible version)
48 def authenticate(auth_params, log_file)
50 if password_credentials_set?(auth_params)
51 @session = get_authenticated_session(auth_params, log_file)
53 elsif openrc_set?(auth_params)
54 credentials = get_credentials_from_openrc(auth_params['openrc'])
55 @session = get_authenticated_session(credentials, log_file)
57 elsif service_credentials_set?(auth_params)
58 session_hash = get_unauthenticated_session(auth_params, log_file)
59 @session_data = session_hash[:data]
60 @session = session_hash[:session]
63 credentials = get_credentials_from_env
64 @session = get_authenticated_session(credentials, log_file)
66 else # Last effort: try to get the token from keystone.conf
67 session_hash = self.class.try_auth_with_token(keystone_file, log_file)
68 @session_data = session_hash[:data]
69 @session = session_hash[:session]
73 def self.authenticate(auth_params, log_file)
74 auth_params = {} unless auth_params
76 credentials = get_credentials_from_env
77 @session = get_authenticated_session(credentials, log_file)
79 else # Last effort: try to get the token from keystone.conf
80 session_hash = try_auth_with_token(keystone_file, log_file)
81 @session_data = session_hash[:data]
82 @session = session_hash[:session]
87 def self.try_auth_with_token(conf_file, log_file)
88 service_token = get_admin_token_from_keystone_file(conf_file)
89 auth_url = get_auth_url_from_keystone_file(conf_file)
93 'service_token' => service_token,
94 'host_uri' => auth_url,
96 session_hash = get_unauthenticated_session(credentials, log_file)
97 else # All authentication efforts failed
98 raise(Puppet::Error, 'No credentials provided.')
103 def self.make_request(service, request, session_data, &block)
105 if service && service.default_session_data
106 response = service.request(request, :endpoint_type => 'admin') do |params|
107 yield(params) if block
110 response = service.request(request, :endpoint_type => 'admin',
111 :session_data => session_data) do |params|
112 yield(params) if block
115 raise(Puppet::Error, 'Cannot make a request with no session data.')
117 if response.body.hash['error']
118 raise(Puppet::Error, "Error making request: #{response.body.hash['error']['code']} #{response.body.hash['error']['title']}")
124 def password_credentials_set?(auth_params)
125 auth_params['username'] && auth_params['password'] && auth_params['tenant_name'] && auth_params['host_uri']
129 def openrc_set?(auth_params)
130 auth_params['openrc']
134 def service_credentials_set?(auth_params)
135 auth_params['service_token'] && auth_params['host_uri']
139 def self.env_vars_set?
140 ENV['OS_USERNAME'] && ENV['OS_PASSWORD'] && ENV['OS_TENANT_NAME'] && ENV['OS_AUTH_URL']
145 self.class.env_vars_set?
149 def get_credentials_from_openrc(file)
152 File.open(file).readlines.delete_if{|l| l=~ /^#/}.each do |line|
153 key, value = line.split('=')
154 key = key.split(' ').last
155 value = value.chomp.gsub(/'/, '')
159 rescue Exception => error
165 def self.get_credentials_from_env
166 ENV.to_hash.dup.delete_if { |key, _| ! (key =~ /^OS/) } # Ruby 1.8.7
169 def get_credentials_from_env
170 self.class.get_credentials_from_env
174 def self.keystone_file
175 keystone_file = Puppet::Util::IniConfig::File.new
176 keystone_file.read('/etc/keystone/keystone.conf')
181 return @keystone_file if @keystone_file
182 @keystone_file = Puppet::Util::IniConfig::File.new
183 @keystone_file.read('/etc/keystone/keystone.conf')
188 def self.get_admin_token_from_keystone_file(conf_file)
189 if conf_file and conf_file['DEFAULT'] and conf_file['DEFAULT']['admin_token']
190 return "#{conf_file['DEFAULT']['admin_token'].strip}"
196 def get_admin_token_from_keystone_file
197 conf_file = keystone_file
198 self.class.get_admin_token_from_keystone_file(conf_file)
202 def self.get_auth_url_from_keystone_file(conf_file)
204 if conf_file['DEFAULT']
205 if conf_file['DEFAULT']['admin_endpoint']
206 auth_url = conf_file['DEFAULT']['admin_endpoint'].strip
207 return versioned_endpoint(auth_url)
210 if conf_file['DEFAULT']['admin_port']
211 admin_port = conf_file['DEFAULT']['admin_port'].strip
216 if conf_file['DEFAULT']['admin_bind_host']
217 host = conf_file['DEFAULT']['admin_bind_host'].strip
226 if conf_file['ssl'] && conf_file['ssl']['enable'] && conf_file['ssl']['enable'].strip.downcase == 'true'
233 "#{protocol}://#{host}:#{admin_port}/v2.0/"
236 def get_auth_url_from_keystone_file
237 self.class.get_auth_url_from_keystone_file(keystone_file)
241 def self.make_configuration(credentials)
242 host_uri = versioned_endpoint(credentials['host_uri'] || credentials['OS_AUTH_URL'], credentials['api_version'])
244 :provider => 'openstack',
247 :host_uri => host_uri,
248 :request => 'create_token',
249 :validator => 'list_tenants',
251 :auth_credentials => {
252 :username => credentials['username'] || credentials['OS_USERNAME'],
253 :password => credentials['password'] || credentials['OS_PASSWORD'],
254 :tenant_name => credentials['tenant_name'] || credentials['OS_TENANT_NAME']
260 def self.get_authenticated_session(credentials, log_file)
261 configuration = make_configuration(credentials)
262 session = ::Aviator::Session.new(:config => configuration, :log_file => log_file)
267 def get_authenticated_session(credentials, log_file)
268 self.class.get_authenticated_session(credentials, log_file)
272 def self.get_unauthenticated_session(credentials, log_file)
274 :provider => 'openstack',
277 :base_url => credentials['host_uri'],
278 :service_token => credentials['service_token']
280 session = ::Aviator::Session.new(:config => configuration, :log_file => log_file)
281 { :session => session, :data => session_data }
284 def get_unauthenticated_session(credentials, log_file)
285 self.class.get_unauthenticated_session(credentials, log_file)
289 def self.versioned_endpoint(endpoint, version = 'v2.0')
290 version = 'v2.0' if version.nil?
291 if endpoint =~ /\/#{version}\/?$/ || endpoint =~ /\/v2.0\/?$/ || endpoint =~ /\/v3\/?$/
294 "#{endpoint.chomp('/')}/#{version}"