]> git.donarmstrong.com Git - dsa-puppet.git/blob - 3rdparty/modules/openstacklib/lib/puppet/provider/aviator.rb
8de1bf201261ea30b6516f35650df71821e4440f
[dsa-puppet.git] / 3rdparty / modules / openstacklib / lib / puppet / provider / aviator.rb
1 require 'puppet'
2 require 'puppet/feature/aviator'
3 require 'puppet/util/inifile'
4
5 class Puppet::Provider::Aviator < Puppet::Provider
6
7   def session
8     @session ||= authenticate(resource[:auth], resource[:log_file])
9   end
10
11   def self.session
12     @session ||= authenticate(nil, nil)
13   end
14
15   def request(service, request, &block)
16     self.class.make_request(service, request, session_data, &block)
17   end
18
19   def self.request(service, request, &block)
20     self.make_request(service, request, session_data, &block)
21   end
22
23   # needed for tests
24   def session_data
25     @session_data
26   end
27
28   def self.session_data
29     @session_data
30   end
31
32   def session_data=(data)
33     @session_data=data
34   end
35
36   def self.session_data=(data)
37     @session_data=data
38   end
39
40   private
41
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)
49     auth_params ||= {}
50     if password_credentials_set?(auth_params)
51       @session = get_authenticated_session(auth_params, log_file)
52
53     elsif openrc_set?(auth_params)
54       credentials = get_credentials_from_openrc(auth_params['openrc'])
55       @session = get_authenticated_session(credentials, log_file)
56
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]
61
62     elsif env_vars_set?
63       credentials = get_credentials_from_env
64       @session = get_authenticated_session(credentials, log_file)
65
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]
70     end
71   end
72
73   def self.authenticate(auth_params, log_file)
74     auth_params = {} unless auth_params
75     if env_vars_set?
76       credentials = get_credentials_from_env
77       @session = get_authenticated_session(credentials, log_file)
78
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]
83     end
84   end
85
86
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)
90     session_hash = {}
91     if service_token
92       credentials = {
93         'service_token' => service_token,
94         'host_uri'      => auth_url,
95       }
96       session_hash = get_unauthenticated_session(credentials, log_file)
97     else  # All authentication efforts failed
98       raise(Puppet::Error, 'No credentials provided.')
99     end
100   end
101
102
103   def self.make_request(service, request, session_data, &block)
104     response = nil
105     if service && service.default_session_data
106       response = service.request(request, :endpoint_type => 'admin') do |params|
107         yield(params) if block
108       end
109     elsif session_data
110       response = service.request(request, :endpoint_type => 'admin',
111                                  :session_data => session_data) do |params|
112         yield(params) if block
113       end
114     else
115       raise(Puppet::Error, 'Cannot make a request with no session data.')
116     end
117     if response.body.hash['error']
118       raise(Puppet::Error, "Error making request: #{response.body.hash['error']['code']} #{response.body.hash['error']['title']}")
119     end
120     response
121   end
122
123
124   def password_credentials_set?(auth_params)
125     auth_params['username'] && auth_params['password'] && auth_params['tenant_name'] && auth_params['host_uri']
126   end
127
128
129   def openrc_set?(auth_params)
130     auth_params['openrc']
131   end
132
133
134   def service_credentials_set?(auth_params)
135     auth_params['service_token'] && auth_params['host_uri']
136   end
137
138
139   def self.env_vars_set?
140     ENV['OS_USERNAME'] && ENV['OS_PASSWORD'] && ENV['OS_TENANT_NAME'] && ENV['OS_AUTH_URL']
141   end
142
143
144   def env_vars_set?
145     self.class.env_vars_set?
146   end
147
148
149   def get_credentials_from_openrc(file)
150     creds = {}
151     begin
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(/'/, '')
156         creds[key] = value
157       end
158       return creds
159     rescue Exception => error
160       return {}
161     end
162   end
163
164
165   def self.get_credentials_from_env
166     ENV.to_hash.dup.delete_if { |key, _| ! (key =~ /^OS/) } # Ruby 1.8.7
167   end
168
169   def get_credentials_from_env
170     self.class.get_credentials_from_env
171   end
172
173
174   def self.keystone_file
175     keystone_file = Puppet::Util::IniConfig::File.new
176     keystone_file.read('/etc/keystone/keystone.conf')
177     keystone_file
178   end
179
180   def keystone_file
181     return @keystone_file if @keystone_file
182     @keystone_file = Puppet::Util::IniConfig::File.new
183     @keystone_file.read('/etc/keystone/keystone.conf')
184     @keystone_file
185   end
186
187
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}"
191     else
192       return nil
193     end
194   end
195
196   def get_admin_token_from_keystone_file
197     conf_file = keystone_file
198     self.class.get_admin_token_from_keystone_file(conf_file)
199   end
200
201
202   def self.get_auth_url_from_keystone_file(conf_file)
203     if 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)
208         end
209
210         if conf_file['DEFAULT']['admin_port']
211           admin_port = conf_file['DEFAULT']['admin_port'].strip
212         else
213           admin_port = '35357'
214         end
215
216         if conf_file['DEFAULT']['admin_bind_host']
217           host = conf_file['DEFAULT']['admin_bind_host'].strip
218           if host == "0.0.0.0"
219             host = "127.0.0.1"
220           end
221         else
222           host = "127.0.0.1"
223         end
224       end
225
226       if conf_file['ssl'] && conf_file['ssl']['enable'] && conf_file['ssl']['enable'].strip.downcase == 'true'
227         protocol = 'https'
228       else
229         protocol = 'http'
230       end
231     end
232
233     "#{protocol}://#{host}:#{admin_port}/v2.0/"
234   end
235
236   def get_auth_url_from_keystone_file
237     self.class.get_auth_url_from_keystone_file(keystone_file)
238   end
239
240
241   def self.make_configuration(credentials)
242     host_uri = versioned_endpoint(credentials['host_uri'] || credentials['OS_AUTH_URL'], credentials['api_version'])
243     {
244       :provider => 'openstack',
245       :auth_service => {
246         :name        => 'identity',
247         :host_uri    => host_uri,
248         :request     => 'create_token',
249         :validator   => 'list_tenants',
250       },
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']
255       }
256     }
257   end
258
259
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)
263     session.authenticate
264     session
265   end
266
267   def get_authenticated_session(credentials, log_file)
268     self.class.get_authenticated_session(credentials, log_file)
269   end
270
271
272   def self.get_unauthenticated_session(credentials, log_file)
273     configuration = {
274       :provider => 'openstack',
275     }
276     session_data = {
277       :base_url      => credentials['host_uri'],
278       :service_token => credentials['service_token']
279     }
280     session = ::Aviator::Session.new(:config => configuration, :log_file => log_file)
281     { :session => session, :data => session_data }
282   end
283
284   def get_unauthenticated_session(credentials, log_file)
285     self.class.get_unauthenticated_session(credentials, log_file)
286   end
287
288
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\/?$/
292       endpoint
293     else
294       "#{endpoint.chomp('/')}/#{version}"
295     end
296   end
297 end