Files
puppet-keystone/lib/puppet/provider/keystone.rb
Denis Egorenko 367f812476 Hash domains by name
Currently every project and user resource generates a call to
fetch_domain, which is an unhashed query to the openstack domain show
command. This is very wasteful and does not scale well. This patch takes
the code that hashes domains by id and generates an inverse, a hash of
domains by name. This code is used in place of fetch_domain, which is
removed. Since the only thing used in this hash is the id, which should
be immutable, we should not have issues with the other fields changing
(like description and enabled).

This should provide a performance boost to users who have a lot of users
and projects, especially if everything is in the default domain.

Co-Authored-By: Denis Egorenko <degorenko@mirantis.com>

Change-Id: I99d8fe272aedc0cbc6ad48561ea50a7b7d6cdb1e
2016-01-18 16:56:53 +03:00

251 lines
6.5 KiB
Ruby

require 'puppet/util/inifile'
require 'puppet/provider/openstack'
require 'puppet/provider/openstack/auth'
require 'puppet/provider/openstack/credentials'
require 'puppet/provider/keystone/util'
class Puppet::Provider::Keystone < Puppet::Provider::Openstack
extend Puppet::Provider::Openstack::Auth
INI_FILENAME = '/etc/keystone/keystone.conf'
DEFAULT_DOMAIN = 'Default'
@@default_domain_id = nil
def self.admin_endpoint
@admin_endpoint ||= get_admin_endpoint
end
def self.admin_token
@admin_token ||= get_admin_token
end
def self.clean_host(host)
host ||= '127.0.0.1'
case host
when '0.0.0.0'
return '127.0.0.1'
when '::0'
return '[::1]'
else
return host
end
end
def self.default_domain_from_ini_file
default_domain_from_conf = Puppet::Resource.indirection
.find('Keystone_config/identity/default_domain_id')
if default_domain_from_conf[:ensure] == :present
# get from ini file
default_domain_from_conf[:value]
else
nil
end
rescue
nil
end
def self.default_domain_id
if @@default_domain_id
# cached
@@default_domain_id
else
@@default_domain_id = default_domain_from_ini_file
end
@@default_domain_id = @@default_domain_id.nil? ? 'default' : @@default_domain_id
end
def self.default_domain_changed
default_domain_id != 'default'
end
def self.default_domain_deprecation_message
'Support for a resource without the domain ' \
'set is deprecated in Liberty cycle. ' \
'It will be dropped in the M-cycle. ' \
"Currently using '#{default_domain}' as default domain name " \
"while the default domain id is '#{default_domain_id}'."
end
def self.default_domain
DEFAULT_DOMAIN
end
def self.resource_to_name(domain, name, check_for_default = true)
raise Puppet::Error, "Domain cannot be nil for project '#{name}'. " \
'Please report a bug.' if domain.nil?
join_str = '::'
name_display = [name]
unless check_for_default && domain == default_domain
name_display << domain
end
name_display.join(join_str)
end
def self.name_to_resource(name)
uniq = name.split('::')
if uniq.count == 1
uniq.insert(0, default_domain)
else
uniq.reverse!
end
uniq
end
# Prefix with default domain if missing from the name.
def self.make_full_name(name)
resource_to_name(*name_to_resource(name), false)
end
def self.domain_name_from_id(id)
unless @domain_hash
list = request('domain', 'list')
@domain_hash = Hash[list.collect{|domain| [domain[:id], domain[:name]]}]
end
unless @domain_hash.include?(id)
name = request('domain', 'show', id)[:name]
err("Could not find domain with id [#{id}]") unless name
@domain_hash[id] = name
end
@domain_hash[id]
end
def self.domain_id_from_name(name)
unless @domain_hash_name
list = request('domain', 'list')
@domain_hash_name = Hash[list.collect{|domain| [domain[:name], domain[:id]]}]
end
unless @domain_hash_name.include?(name)
id = request('domain', 'show', name)[:id]
err("Could not find domain with name [#{name}]") unless id
@domain_hash_name[name] = id
end
@domain_hash_name[name]
end
def self.fetch_project(name, domain)
domain ||= default_domain
request('project', 'show', [name, '--domain', domain])
rescue Puppet::ExecutionFailure => e
raise e unless e.message =~ /No project with a name or ID/
end
def self.fetch_user(name, domain)
domain ||= default_domain
request('user', 'show', [name, '--domain', domain])
rescue Puppet::ExecutionFailure => e
raise e unless e.message =~ /No user with a name or ID/
end
def self.get_admin_endpoint
endpoint = nil
if keystone_file
if url = get_section('DEFAULT', 'admin_endpoint')
endpoint = url.chomp('/')
else
admin_port = get_section('DEFAULT', 'admin_port') || '35357'
host = clean_host(get_section('DEFAULT', 'admin_bind_host'))
protocol = ssl? ? 'https' : 'http'
endpoint = "#{protocol}://#{host}:#{admin_port}"
end
end
return endpoint
end
def self.get_admin_token
get_section('DEFAULT', 'admin_token')
end
def self.get_auth_url
auth_url = nil
if ENV['OS_AUTH_URL']
auth_url = ENV['OS_AUTH_URL'].dup
elsif auth_url = get_os_vars_from_rcfile(rc_filename)['OS_AUTH_URL']
else
auth_url = admin_endpoint
end
return auth_url
end
def self.get_section(group, name)
if keystone_file && keystone_file[group] && keystone_file[group][name]
return keystone_file[group][name].strip
end
return nil
end
def self.get_service_url
service_url = nil
if ENV['OS_URL']
service_url = ENV['OS_URL'].dup
elsif admin_endpoint
service_url = admin_endpoint
service_url << "/v#{@credentials.version}"
end
return service_url
end
def self.ini_filename
INI_FILENAME
end
def self.keystone_file
return @keystone_file if @keystone_file
if File.exists?(ini_filename)
@keystone_file = Puppet::Util::IniConfig::File.new
@keystone_file.read(ini_filename)
@keystone_file
end
end
def self.request(service, action, properties=nil)
super
rescue Puppet::Error::OpenstackAuthInputError, Puppet::Error::OpenstackUnauthorizedError => error
request_by_service_token(service, action, error, properties)
end
def self.request_by_service_token(service, action, error, properties=nil)
properties ||= []
@credentials.token = admin_token
@credentials.url = service_url
raise error unless @credentials.service_token_set?
Puppet::Provider::Openstack.request(service, action, properties, @credentials)
end
def self.service_url
@service_url ||= get_service_url
end
def self.set_domain_for_name(name, domain_name)
if domain_name.nil? || domain_name.empty?
raise(Puppet::Error, "Missing domain name for resource #{name}")
end
domain_id = self.domain_id_from_name(domain_name)
case domain_id
when default_domain_id
name
when nil
name
else
name << "::#{domain_name}"
end
end
def self.ssl?
if keystone_file && keystone_file['ssl'] && keystone_file['ssl']['enable'] && keystone_file['ssl']['enable'].strip.downcase == 'true'
return true
end
return false
end
# Helper functions to use on the pre-validated enabled field
def bool_to_sym(bool)
bool == true ? :true : :false
end
def sym_to_bool(sym)
sym == :true ? true : false
end
end