Add keystone domain specific configuration.
Implements blueprint keystone-domain-configuration Adds a provider able to configure multiple domains and two parameters in keystone class to setup a working multi-domains configuration. The keystone_config type has been refactored into a mixin to be shared by keystone_config and keystone_domain_config. The provider, even though it is inheriting from openstack_config (and not keystone_config because it hard code the path), has required more new code. The problem is that we have several configuration files to work with (one per domain) which is unusual. The self.prefetch method is required to check the current catalog. If it's changing the Keystone_config[identity/domain_config_dir] we take it directly into account without the need for another run. Keystone_config[identity/domain_config_dir] configuration and the associated directory are autorequired. Change-Id: I5e4b298460ee592640af59ac9dcbefa3daf98098
This commit is contained in:
parent
759c626987
commit
07f19bd38a
40
examples/v3_domain_configuration.pp
Normal file
40
examples/v3_domain_configuration.pp
Normal file
@ -0,0 +1,40 @@
|
||||
# Example using v3 domain configuration. This setup a directory where
|
||||
# the domain configurations will be and adjust the keystone.
|
||||
# For the rest of the configuration check v3_basic.pp.
|
||||
#
|
||||
|
||||
Exec { logoutput => 'on_failure' }
|
||||
|
||||
class { '::mysql::server': }
|
||||
class { '::keystone::db::mysql':
|
||||
password => 'keystone',
|
||||
}
|
||||
class { '::keystone':
|
||||
verbose => true,
|
||||
debug => true,
|
||||
database_connection => 'mysql://keystone:keystone@192.168.1.1/keystone',
|
||||
admin_token => 'admin_token',
|
||||
enabled => true,
|
||||
# The domain configuration setup at keystone level
|
||||
using_domain_config => true,
|
||||
}
|
||||
class { '::keystone::roles::admin':
|
||||
email => 'test@example.tld',
|
||||
password => 'a_big_secret',
|
||||
}
|
||||
class { '::keystone::endpoint':
|
||||
public_url => 'http://192.168.1.1:5000/',
|
||||
admin_url => 'http://192.168.1.1:35357/',
|
||||
}
|
||||
|
||||
# Creates the /etc/keystone/domains/keystone.my_domain.conf file and
|
||||
# notifies keystone service
|
||||
keystone_domain_config {
|
||||
'my_domain::ldap/url': value => 'ldap://ldapservice.my_org.com';
|
||||
'my_domain::ldap/user': value => 'cn=Manager,dc=openstack,dc=org';
|
||||
'my_domain::ldap/password': value => 'mysecret';
|
||||
'my_domain::ldap/suffix': value => 'dc=openstack,dc=org';
|
||||
'my_domain::ldap/group_tree_dn': value => 'ou=UserGroups,dc=openstack,dc=org';
|
||||
'my_domain::ldap/user_tree_dn': value => 'ou=Users,dc=openstack,dc=org';
|
||||
'my_domain::ldap/user_mail_attribute': value => 'mail';
|
||||
}
|
108
lib/puppet/provider/keystone_domain_config/openstack.rb
Normal file
108
lib/puppet/provider/keystone_domain_config/openstack.rb
Normal file
@ -0,0 +1,108 @@
|
||||
Puppet::Type.type(:keystone_domain_config).provide(
|
||||
:openstack,
|
||||
:parent => Puppet::Type.type(:openstack_config).provider(:ini_setting)
|
||||
) do
|
||||
|
||||
class Puppet::Error::OpenstackMissingDomainName < Puppet::Error; end
|
||||
class Puppet::Error::OpenstackMissingDomainDir < Puppet::Error; end
|
||||
|
||||
# return the first which is defined:
|
||||
# 1. the value defined in the catalog (@base_dir)
|
||||
# 2. the value defined in the keystone.conf file
|
||||
# 3. the default value '/etc/keystone/domains'
|
||||
def self.base_dir
|
||||
return @base_dir if @base_dir
|
||||
base_dir = Puppet::Resource.indirection
|
||||
.find('Keystone_config/identity/domain_config_dir')[:value]
|
||||
if base_dir == :absent
|
||||
'/etc/keystone/domains'
|
||||
else
|
||||
base_dir
|
||||
end
|
||||
end
|
||||
|
||||
def self.find_domain_conf(catalog)
|
||||
catalog.resources.find do |r|
|
||||
# better than is_a? here because symbol
|
||||
# Puppet::Type::Keystone_config may not be defined.
|
||||
r.class.to_s == 'Puppet::Type::Keystone_config' &&
|
||||
r.name == 'identity/domain_config_dir'
|
||||
end
|
||||
end
|
||||
|
||||
# Use the prefetch hook to check if the keystone_config
|
||||
# identity/domain_config_dir is changed in the same catalog. This
|
||||
# avoid to have to run puppet twice to get the right domain config
|
||||
# file changed. Note, prefetch is the only time we can have acces
|
||||
# to the catalog from the provider.
|
||||
def self.prefetch(resources)
|
||||
catalog = resources.values.first.catalog
|
||||
resource_dir = find_domain_conf(catalog)
|
||||
@base_dir = resource_dir.nil? ? nil : resource_dir[:value]
|
||||
end
|
||||
|
||||
def self.base_dir_exists?
|
||||
base_dir_resource = Puppet::Resource.indirection
|
||||
.find("file/#{base_dir}")[:ensure]
|
||||
base_dir_resource == :directory ? true : false
|
||||
end
|
||||
|
||||
def create
|
||||
unless self.class.base_dir_exists?
|
||||
raise(Puppet::Error::OpenstackMissingDomainDir,
|
||||
"You must create the #{self.class.base_dir} directory " \
|
||||
'for keystone domain configuration.')
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
# Do not provide self.file_path method. We need to create instance
|
||||
# with different file paths, so we cannot have the same path for all
|
||||
# the instances. This force us to redefine the instances class
|
||||
# method.
|
||||
def self.instances
|
||||
resources = []
|
||||
Dir.glob(File.join(base_dir,'keystone.*.conf')).each do |domain_conf_file|
|
||||
domain = domain_conf_file.gsub(/^.*\/keystone\.(.*)\.conf$/, '\1')
|
||||
ini_file = Puppet::Util::IniFile.new(domain_conf_file, '=')
|
||||
ini_file.section_names.each do |section_name|
|
||||
ini_file.get_settings(section_name).each do |setting, value|
|
||||
resources.push(
|
||||
new(
|
||||
:name => "#{domain}::#{section_name}/#{setting}",
|
||||
:value => value,
|
||||
:ensure => :present
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
resources
|
||||
end
|
||||
|
||||
def path
|
||||
File.join(self.class.base_dir, 'keystone.' + domain + '.conf')
|
||||
end
|
||||
|
||||
# This avoid to have only one file for all the instances.
|
||||
alias_method :file_path, :path
|
||||
|
||||
def domain
|
||||
if !@domain.nil?
|
||||
@domain
|
||||
else
|
||||
result = name.partition('::')
|
||||
if (result[1] == '' && result[2] == '') || result[0] == ''
|
||||
raise(Puppet::Error::OpenstackMissingDomainName,
|
||||
'You must provide a domain name in the name of the resource ' \
|
||||
'<domain_name>::<section>/<key>. It cannot be empty.')
|
||||
else
|
||||
@domain = result[0]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def section
|
||||
@section ||= super.sub(domain + '::', '')
|
||||
end
|
||||
end
|
@ -1,53 +1,12 @@
|
||||
Puppet::Type.newtype(:keystone_config) do
|
||||
|
||||
ensurable
|
||||
require File.expand_path(File.join(
|
||||
File.dirname(__FILE__), '..', '..',
|
||||
'puppet_x', 'keystone_config', 'ini_setting'))
|
||||
# mixin, shared with keystone_domain_config until this one moves on
|
||||
# to openstack cli
|
||||
extend PuppetX::KeystoneConfig::IniSetting
|
||||
|
||||
newparam(:name, :namevar => true) do
|
||||
desc 'Section/setting name to manage from keystone.conf'
|
||||
newvalues(/\S+\/\S+/)
|
||||
end
|
||||
|
||||
newproperty(:value) do
|
||||
desc 'The value of the setting to be defined.'
|
||||
munge do |value|
|
||||
value = value.to_s.strip
|
||||
value.capitalize! if value =~ /^(true|false)$/i
|
||||
value
|
||||
end
|
||||
newvalues(/^[\S ]*$/)
|
||||
|
||||
def is_to_s( currentvalue )
|
||||
if resource.secret?
|
||||
return '[old secret redacted]'
|
||||
else
|
||||
return currentvalue
|
||||
end
|
||||
end
|
||||
|
||||
def should_to_s( newvalue )
|
||||
if resource.secret?
|
||||
return '[new secret redacted]'
|
||||
else
|
||||
return newvalue
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
newparam(:secret, :boolean => true) do
|
||||
desc 'Whether to hide the value from Puppet logs. Defaults to `false`.'
|
||||
|
||||
newvalues(:true, :false)
|
||||
|
||||
defaultto false
|
||||
end
|
||||
|
||||
newparam(:ensure_absent_val) do
|
||||
desc 'A value that is specified as the value property will behave as if ensure => absent was specified'
|
||||
defaultto('<SERVICE DEFAULT>')
|
||||
end
|
||||
|
||||
autorequire(:package) do
|
||||
'keystone'
|
||||
end
|
||||
create_parameters
|
||||
|
||||
end
|
||||
|
36
lib/puppet/type/keystone_domain_config.rb
Normal file
36
lib/puppet/type/keystone_domain_config.rb
Normal file
@ -0,0 +1,36 @@
|
||||
Puppet::Type.newtype(:keystone_domain_config) do
|
||||
|
||||
require File.expand_path(File.join(
|
||||
File.dirname(__FILE__), '..', '..',
|
||||
'puppet_x', 'keystone_config', 'ini_setting'))
|
||||
# mixin, shared with keystone_domain_config until this one moves on
|
||||
# to openstack cli
|
||||
extend PuppetX::KeystoneConfig::IniSetting
|
||||
|
||||
def initialize(*args)
|
||||
super
|
||||
# latest version of puppet got autonotify, but 3.8.2 doesn't so
|
||||
# use this.
|
||||
keystone_service = 'Service[keystone]'
|
||||
self[:notify] = [keystone_service] if !catalog.nil? &&
|
||||
catalog.resource(keystone_service)
|
||||
end
|
||||
|
||||
create_parameters
|
||||
|
||||
# if one declare the domain directory as a resource, this will
|
||||
# create a soft dependancy with it.
|
||||
autorequire(:file) do
|
||||
currently_defined = provider.class.find_domain_conf(catalog)
|
||||
# we use the catalog and fall back to provider.self.base_dir (see
|
||||
# its comment). Note at this time the @base_dir in
|
||||
# provider.class.base_dir will always be false as self.prefetch
|
||||
# hasn't run yet.
|
||||
currently_defined.nil? ? [provider.class.base_dir] : [currently_defined[:value]]
|
||||
end
|
||||
|
||||
# if the keystone configuration is changed we require it
|
||||
autorequire(:keystone_config) do
|
||||
['identity/domain_config_dir']
|
||||
end
|
||||
end
|
61
lib/puppet_x/keystone_config/ini_setting.rb
Normal file
61
lib/puppet_x/keystone_config/ini_setting.rb
Normal file
@ -0,0 +1,61 @@
|
||||
module PuppetX
|
||||
module KeystoneConfig
|
||||
# Mixin for shared code between keystone_config and
|
||||
# keystone_domain_config. This can be reincluded directly to
|
||||
# keystone_config when openstackcli supports domain configuration and
|
||||
# keystone_domain_config is refactored.
|
||||
module IniSetting
|
||||
def create_parameters
|
||||
ensurable
|
||||
|
||||
newparam(:name, :namevar => true) do
|
||||
desc 'Section/setting name to manage from keystone.conf'
|
||||
newvalues(/\S+\/\S+/)
|
||||
end
|
||||
|
||||
newproperty(:value) do
|
||||
desc 'The value of the setting to be defined.'
|
||||
munge do |value|
|
||||
value = value.to_s.strip
|
||||
value.capitalize! if value =~ /^(true|false)$/i
|
||||
value
|
||||
end
|
||||
newvalues(/^[\S ]*$/)
|
||||
|
||||
def is_to_s( currentvalue )
|
||||
if resource.secret?
|
||||
return '[old secret redacted]'
|
||||
else
|
||||
return currentvalue
|
||||
end
|
||||
end
|
||||
|
||||
def should_to_s( newvalue )
|
||||
if resource.secret?
|
||||
return '[new secret redacted]'
|
||||
else
|
||||
return newvalue
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
newparam(:secret, :boolean => true) do
|
||||
desc 'Whether to hide the value from Puppet logs. Defaults to `false`.'
|
||||
|
||||
newvalues(:true, :false)
|
||||
|
||||
defaultto false
|
||||
end
|
||||
|
||||
newparam(:ensure_absent_val) do
|
||||
desc 'A value that is specified as the value property will behave as if ensure => absent was specified'
|
||||
defaultto('<SERVICE DEFAULT>')
|
||||
end
|
||||
|
||||
autorequire(:package) do
|
||||
'keystone'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -462,6 +462,18 @@
|
||||
# Policy backend driver. (string value)
|
||||
# Defaults to $::os_service_default.
|
||||
#
|
||||
# [*using_domain_config*]
|
||||
# (optional) Eases the use of the keystone_domain_config resource type.
|
||||
# It ensures that a directory for holding the domain configuration is present
|
||||
# and the associated configuration in keystone.conf is set up right.
|
||||
# Defaults to false
|
||||
#
|
||||
# [*domain_config_directory*]
|
||||
# (optional) Specify a domain configuration directory.
|
||||
# For this to work the using_domain_config must be set to true. Raise an
|
||||
# error if it's not the case.
|
||||
# Defaults to '/etc/keystone/domains'
|
||||
#
|
||||
# == Dependencies
|
||||
# None
|
||||
#
|
||||
@ -581,6 +593,8 @@ class keystone(
|
||||
$memcache_pool_maxsize = $::os_service_default,
|
||||
$memcache_pool_unused_timeout = $::os_service_default,
|
||||
$policy_driver = $::os_service_default,
|
||||
$using_domain_config = false,
|
||||
$domain_config_directory = '/etc/keystone/domains',
|
||||
# DEPRECATED PARAMETERS
|
||||
$admin_workers = max($::processorcount, 2),
|
||||
$public_workers = max($::processorcount, 2),
|
||||
@ -971,6 +985,39 @@ class keystone(
|
||||
}
|
||||
}
|
||||
}
|
||||
if $domain_config_directory != '/etc/keystone/domains' and !$using_domain_config {
|
||||
fail('You must activate domain configuration using "using_domain_config" parameter to keystone class.')
|
||||
}
|
||||
|
||||
if $using_domain_config {
|
||||
validate_absolute_path($domain_config_directory)
|
||||
# Better than ensure resource. We don't want to conflict with any
|
||||
# user definition even if they don't match exactly our parameters.
|
||||
# The error catching mechanism in the provider will remind them if
|
||||
# they did something silly, like defining a file rather than a
|
||||
# directory. For the permission it's their choice.
|
||||
if (!defined(File[$domain_config_directory])) {
|
||||
file { $domain_config_directory:
|
||||
ensure => directory,
|
||||
owner => 'keystone',
|
||||
group => 'keystone',
|
||||
mode => '0750',
|
||||
} -> File['/etc/keystone/keystone.conf']
|
||||
}
|
||||
# Here we want the creation to fail if the user has created those
|
||||
# resources with different values. That means that the user
|
||||
# wrongly uses using_domain_config parameter.
|
||||
ensure_resource(
|
||||
'keystone_config',
|
||||
'identity/domain_specific_drivers_enabled',
|
||||
{'value' => true}
|
||||
)
|
||||
ensure_resource(
|
||||
'keystone_config',
|
||||
'identity/domain_config_dir',
|
||||
{'value' => $domain_config_directory}
|
||||
)
|
||||
}
|
||||
anchor { 'keystone_started':
|
||||
require => Service[$service_name]
|
||||
}
|
||||
|
@ -279,4 +279,127 @@ describe 'basic keystone server with resources' do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#keystone_domain_config' do
|
||||
# make sure everything is clean before playing the manifest
|
||||
shared_examples 'clean_domain_configuration', :clean_domain_cfg => true do
|
||||
before(:context) do
|
||||
hosts.each do |host|
|
||||
on host, 'rm -rf /etc/keystone/domains >/dev/null 2>&1'
|
||||
on host, 'rm -rf /tmp/keystone.*.conf >/dev/null 2>&1'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'one domain configuration', :clean_domain_cfg => true do
|
||||
context 'simple use case' do
|
||||
it_behaves_like 'puppet_apply_success', <<-EOM
|
||||
file { '/etc/keystone/domains': ensure => directory }
|
||||
keystone_domain_config { 'services::ldap/url':
|
||||
value => 'http://auth.com/1',
|
||||
}
|
||||
EOM
|
||||
|
||||
context '/etc/keystone/domains/keystone.services.conf' do
|
||||
# the idiom
|
||||
|
||||
# note: cannot use neither instance variable nor let on
|
||||
# parameter for shared_example
|
||||
it_behaves_like 'a_valid_configuration', <<-EOC
|
||||
|
||||
[ldap]
|
||||
url=http://auth.com/1
|
||||
EOC
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a non default identity/domain_config_dir' do
|
||||
it_behaves_like 'puppet_apply_success', <<-EOM
|
||||
keystone_config { 'identity/domain_config_dir': value => '/tmp' }
|
||||
keystone_domain_config { 'services::ldap/url':
|
||||
value => 'http://auth.com/1',
|
||||
}
|
||||
EOM
|
||||
|
||||
context '/tmp/keystone.services.conf' do
|
||||
it_behaves_like 'a_valid_configuration', <<-EOC
|
||||
|
||||
[ldap]
|
||||
url=http://auth.com/1
|
||||
EOC
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a multiple configurations', :clean_domain_cfg => true do
|
||||
it_behaves_like 'puppet_apply_success', <<-EOM
|
||||
file { '/etc/keystone/domains': ensure => directory }
|
||||
keystone_config { 'identity/domain_config_dir': value => '/etc/keystone/domains' }
|
||||
keystone_domain_config { 'services::ldap/url':
|
||||
value => 'http://auth.com/1',
|
||||
}
|
||||
keystone_domain_config { 'services::http/url':
|
||||
value => 'http://auth.com/2',
|
||||
}
|
||||
keystone_domain_config { 'external::ldap/url':
|
||||
value => 'http://ext-auth.com/1',
|
||||
}
|
||||
EOM
|
||||
|
||||
describe command('puppet resource keystone_domain_config') do
|
||||
its(:exit_status) { is_expected.to eq(0) }
|
||||
its(:stdout) { is_expected.to eq(<<EOO) }
|
||||
keystone_domain_config { 'external::ldap/url':
|
||||
ensure => 'present',
|
||||
value => 'http://ext-auth.com/1',
|
||||
}
|
||||
keystone_domain_config { 'services::http/url':
|
||||
ensure => 'present',
|
||||
value => 'http://auth.com/2',
|
||||
}
|
||||
keystone_domain_config { 'services::ldap/url':
|
||||
ensure => 'present',
|
||||
value => 'http://auth.com/1',
|
||||
}
|
||||
EOO
|
||||
end
|
||||
|
||||
describe '/etc/keystone/domains/keystone.services.conf' do
|
||||
it_behaves_like 'a_valid_configuration', <<EOC
|
||||
|
||||
[http]
|
||||
url=http://auth.com/2
|
||||
|
||||
[ldap]
|
||||
url=http://auth.com/1
|
||||
EOC
|
||||
end
|
||||
describe '/etc/keystone/domains/keystone.external.conf' do
|
||||
it_behaves_like 'a_valid_configuration', <<EOC
|
||||
|
||||
[ldap]
|
||||
url=http://ext-auth.com/1
|
||||
EOC
|
||||
end
|
||||
end
|
||||
|
||||
context 'checking that the purge is working' do
|
||||
it_behaves_like 'puppet_apply_success', <<-EOM
|
||||
resources { 'keystone_domain_config': purge => true }
|
||||
keystone_domain_config { 'services::ldap/url':
|
||||
value => 'http://auth.com/1',
|
||||
}
|
||||
EOM
|
||||
|
||||
context '/etc/keystone/domains/keystone.services.conf' do
|
||||
it_behaves_like 'a_valid_configuration', <<-EOC
|
||||
|
||||
[http]
|
||||
|
||||
[ldap]
|
||||
url=http://auth.com/1
|
||||
EOC
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -215,6 +215,7 @@ describe 'keystone server running with Apache/WSGI with resources' do
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'composite namevar for keystone_service and keystone_endpoint' do
|
||||
let(:pp) do
|
||||
<<-EOM
|
||||
@ -259,4 +260,127 @@ describe 'keystone server running with Apache/WSGI with resources' do
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context '#keystone_domain_config' do
|
||||
# make sure everything is clean before playing the manifest
|
||||
shared_examples 'clean_domain_configuration', :clean_domain_cfg => true do
|
||||
before(:context) do
|
||||
hosts.each do |host|
|
||||
on host, 'rm -rf /etc/keystone/domains >/dev/null 2>&1'
|
||||
on host, 'rm -rf /tmp/keystone.*.conf >/dev/null 2>&1'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'one domain configuration', :clean_domain_cfg => true do
|
||||
context 'simple use case' do
|
||||
it_behaves_like 'puppet_apply_success', <<-EOM
|
||||
file { '/etc/keystone/domains': ensure => directory }
|
||||
keystone_domain_config { 'services::ldap/url':
|
||||
value => 'http://auth.com/1',
|
||||
}
|
||||
EOM
|
||||
|
||||
context '/etc/keystone/domains/keystone.services.conf' do
|
||||
# the idiom
|
||||
|
||||
# note: cannot use neither instance variable nor let on
|
||||
# parameter for shared_example
|
||||
it_behaves_like 'a_valid_configuration', <<-EOC
|
||||
|
||||
[ldap]
|
||||
url=http://auth.com/1
|
||||
EOC
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a non default identity/domain_config_dir' do
|
||||
it_behaves_like 'puppet_apply_success', <<-EOM
|
||||
keystone_config { 'identity/domain_config_dir': value => '/tmp' }
|
||||
keystone_domain_config { 'services::ldap/url':
|
||||
value => 'http://auth.com/1',
|
||||
}
|
||||
EOM
|
||||
|
||||
context '/tmp/keystone.services.conf' do
|
||||
it_behaves_like 'a_valid_configuration', <<-EOC
|
||||
|
||||
[ldap]
|
||||
url=http://auth.com/1
|
||||
EOC
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'with a multiple configurations', :clean_domain_cfg => true do
|
||||
it_behaves_like 'puppet_apply_success', <<-EOM
|
||||
file { '/etc/keystone/domains': ensure => directory }
|
||||
keystone_config { 'identity/domain_config_dir': value => '/etc/keystone/domains' }
|
||||
keystone_domain_config { 'services::ldap/url':
|
||||
value => 'http://auth.com/1',
|
||||
}
|
||||
keystone_domain_config { 'services::http/url':
|
||||
value => 'http://auth.com/2',
|
||||
}
|
||||
keystone_domain_config { 'external::ldap/url':
|
||||
value => 'http://ext-auth.com/1',
|
||||
}
|
||||
EOM
|
||||
|
||||
describe command('puppet resource keystone_domain_config') do
|
||||
its(:exit_status) { is_expected.to eq(0) }
|
||||
its(:stdout) { is_expected.to eq(<<EOO) }
|
||||
keystone_domain_config { 'external::ldap/url':
|
||||
ensure => 'present',
|
||||
value => 'http://ext-auth.com/1',
|
||||
}
|
||||
keystone_domain_config { 'services::http/url':
|
||||
ensure => 'present',
|
||||
value => 'http://auth.com/2',
|
||||
}
|
||||
keystone_domain_config { 'services::ldap/url':
|
||||
ensure => 'present',
|
||||
value => 'http://auth.com/1',
|
||||
}
|
||||
EOO
|
||||
end
|
||||
|
||||
describe '/etc/keystone/domains/keystone.services.conf' do
|
||||
it_behaves_like 'a_valid_configuration', <<EOC
|
||||
|
||||
[http]
|
||||
url=http://auth.com/2
|
||||
|
||||
[ldap]
|
||||
url=http://auth.com/1
|
||||
EOC
|
||||
end
|
||||
describe '/etc/keystone/domains/keystone.external.conf' do
|
||||
it_behaves_like 'a_valid_configuration', <<EOC
|
||||
|
||||
[ldap]
|
||||
url=http://ext-auth.com/1
|
||||
EOC
|
||||
end
|
||||
end
|
||||
|
||||
context 'checking that the purge is working' do
|
||||
it_behaves_like 'puppet_apply_success', <<-EOM
|
||||
resources { 'keystone_domain_config': purge => true }
|
||||
keystone_domain_config { 'services::ldap/url':
|
||||
value => 'http://auth.com/1',
|
||||
}
|
||||
EOM
|
||||
|
||||
context '/etc/keystone/domains/keystone.services.conf' do
|
||||
it_behaves_like 'a_valid_configuration', <<-EOC
|
||||
|
||||
[http]
|
||||
|
||||
[ldap]
|
||||
url=http://auth.com/1
|
||||
EOC
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -106,6 +106,7 @@ describe 'keystone' do
|
||||
'rabbit_heartbeat_timeout_threshold' => '60',
|
||||
'rabbit_heartbeat_rate' => '10',
|
||||
'default_domain' => 'other_domain',
|
||||
'using_domain_config' => false
|
||||
}
|
||||
|
||||
httpd_params = {'service_name' => 'httpd'}.merge(default_params)
|
||||
@ -1007,4 +1008,65 @@ describe 'keystone' do
|
||||
it_configures 'when configuring default domain'
|
||||
end
|
||||
|
||||
describe "when configuring using_domain_config" do
|
||||
describe 'with default config' do
|
||||
let :params do
|
||||
default_params
|
||||
end
|
||||
it { is_expected.to_not contain_file('/etc/keystone/domains') }
|
||||
end
|
||||
describe 'when using domain config' do
|
||||
let :params do
|
||||
default_params.merge({
|
||||
'using_domain_config'=> true,
|
||||
})
|
||||
end
|
||||
it { is_expected.to contain_file('/etc/keystone/domains').with(
|
||||
'ensure' => "directory",
|
||||
) }
|
||||
it { is_expected
|
||||
.to contain_keystone_config('identity/domain_specific_drivers_enabled')
|
||||
.with('value' => true,
|
||||
) }
|
||||
it { is_expected
|
||||
.to contain_keystone_config('identity/domain_config_dir')
|
||||
.with('value' => '/etc/keystone/domains',
|
||||
) }
|
||||
end
|
||||
describe 'when using domain config and a wrong directory' do
|
||||
let :params do
|
||||
default_params.merge({
|
||||
'using_domain_config'=> true,
|
||||
'domain_config_directory' => 'this/is/not/an/absolute/path'
|
||||
})
|
||||
end
|
||||
it 'should raise an error' do
|
||||
expect { should contain_file('/etc/keystone/domains') }
|
||||
.to raise_error(Puppet::Error, %r(this/is/not/an/absolute/path" is not))
|
||||
end
|
||||
end
|
||||
describe 'when setting domain directory and not using domain config' do
|
||||
let :params do
|
||||
default_params.merge({
|
||||
'using_domain_config'=> false,
|
||||
'domain_config_directory' => '/this/is/an/absolute/path'
|
||||
})
|
||||
end
|
||||
it 'should raise an error' do
|
||||
expect { should contain_file('/etc/keystone/domains') }
|
||||
.to raise_error(Puppet::Error, %r(You must activate domain))
|
||||
end
|
||||
end
|
||||
describe 'when setting domain directory and using domain config' do
|
||||
let :params do
|
||||
default_params.merge({
|
||||
'using_domain_config'=> true,
|
||||
'domain_config_directory' => '/this/is/an/absolute/path'
|
||||
})
|
||||
end
|
||||
it { is_expected.to contain_file('/this/is/an/absolute/path').with(
|
||||
'ensure' => "directory",
|
||||
) }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
34
spec/shared_examples_acceptance.rb
Normal file
34
spec/shared_examples_acceptance.rb
Normal file
@ -0,0 +1,34 @@
|
||||
# Test a normal puppet run with idempotency.
|
||||
shared_examples_for 'puppet_apply_success' do |manifest|
|
||||
it 'should apply the manifest without error' do
|
||||
apply_manifest(manifest, :catch_failures => true)
|
||||
end
|
||||
it 'should be idempotent' do
|
||||
apply_manifest(manifest, :catch_changes => true)
|
||||
end
|
||||
end
|
||||
|
||||
# Check that a file exists and its content match the one given as
|
||||
# argument. The argument can be a multiline string or an array of
|
||||
# regexp.
|
||||
#
|
||||
# To use it encapsulate it in a context whose name is the file to
|
||||
# test.
|
||||
shared_examples 'a_valid_configuration' do |config_content|
|
||||
let(:configuration_file) do |example|
|
||||
# see the idiom it leads to later in this file
|
||||
example.metadata[:example_group][:parent_example_group][:description]
|
||||
end
|
||||
subject { file(configuration_file) }
|
||||
it { is_expected.to be_file }
|
||||
it { is_expected.to exist }
|
||||
content = nil
|
||||
if config_content.is_a?(Array)
|
||||
content = config_content
|
||||
else
|
||||
content = config_content.split("\n").map { |l| Regexp.quote(l) }
|
||||
end
|
||||
it 'content should be valid' do
|
||||
expect(subject.content).to include_regexp(content)
|
||||
end
|
||||
end
|
@ -1,5 +1,6 @@
|
||||
require 'beaker-rspec'
|
||||
require 'beaker/puppet_install_helper'
|
||||
require 'shared_examples_acceptance'
|
||||
|
||||
run_puppet_install_helper
|
||||
|
||||
|
139
spec/unit/provider/keystone_domain_config/openstack_spec.rb
Normal file
139
spec/unit/provider/keystone_domain_config/openstack_spec.rb
Normal file
@ -0,0 +1,139 @@
|
||||
#
|
||||
# these tests are a little concerning b/c they are hacking around the
|
||||
# modulepath, so these tests will not catch issues that may eventually arise
|
||||
# related to loading these plugins.
|
||||
# I could not, for the life of me, figure out how to programatcally set the modulepath
|
||||
$LOAD_PATH.push(
|
||||
File.join(
|
||||
File.dirname(__FILE__),
|
||||
'..',
|
||||
'..',
|
||||
'..',
|
||||
'fixtures',
|
||||
'modules',
|
||||
'inifile',
|
||||
'lib')
|
||||
)
|
||||
require 'spec_helper'
|
||||
provider_class = Puppet::Type.type(:keystone_domain_config).provider(:openstack)
|
||||
|
||||
describe provider_class do
|
||||
|
||||
include PuppetlabsSpec::Files
|
||||
let(:tmpfile) { tmpfilename('keystone.conf') }
|
||||
|
||||
context '#interface' do
|
||||
it 'should configure a domain file if the name has :: delimiter' do
|
||||
resource = Puppet::Type::Keystone_domain_config.new(
|
||||
{ :name => 'bar::dude/foo', :value => 'blahh' }
|
||||
)
|
||||
provider = provider_class.new(resource)
|
||||
expect(provider.path).to eq('/etc/keystone/domains/keystone.bar.conf')
|
||||
expect(provider.section).to eq('dude')
|
||||
expect(provider.setting).to eq('foo')
|
||||
end
|
||||
|
||||
it "should raise an error if the configuration directory doesn't exist" do
|
||||
resource = Puppet::Type::Keystone_domain_config.new(
|
||||
{ :name => 'bar::dude/foo', :value => 'blahh' }
|
||||
)
|
||||
expect { provider_class.new(resource).create }
|
||||
.to raise_error(Puppet::Error::OpenstackMissingDomainDir)
|
||||
end
|
||||
end
|
||||
|
||||
context '#create' do
|
||||
before(:example) do
|
||||
# This is created just to get access to the ini_file.
|
||||
config = Puppet::Type::Keystone_config.new({
|
||||
:name => 'identity/domain_config_dir',
|
||||
:value => '/tmp'
|
||||
})
|
||||
config_provider = Puppet::Type.type(:keystone_config)
|
||||
.provider(:ini_setting)
|
||||
keystone_config = config_provider.new(config)
|
||||
keystone_config.class.expects(:file_path).at_least_once.returns(tmpfile)
|
||||
keystone_config.create
|
||||
|
||||
@domain = Puppet::Type::Keystone_domain_config.new(
|
||||
{ :name => 'bar::dude/foo', :value => 'blahh' }
|
||||
)
|
||||
@domain_provider = provider_class.new(@domain)
|
||||
end
|
||||
|
||||
after(:example) do
|
||||
Dir.glob('/tmp/keystone.*.conf').each do |tmp_conf|
|
||||
File.delete(tmp_conf)
|
||||
end
|
||||
end
|
||||
|
||||
context 'correct name definition' do
|
||||
it 'should adjust the domain path if it is modified with Keystone_config' do
|
||||
expect(@domain_provider.file_path)
|
||||
.to eq('/tmp/keystone.bar.conf')
|
||||
end
|
||||
|
||||
it 'should fill a domain configuration correctly' do
|
||||
expect { @domain_provider.create }.not_to raise_error
|
||||
expect(File).to exist('/tmp/keystone.bar.conf')
|
||||
expect(File.read('/tmp/keystone.bar.conf'))
|
||||
.to eq('
|
||||
[dude]
|
||||
foo=blahh
|
||||
')
|
||||
end
|
||||
|
||||
it 'should fill multiple domain configurations correctly' do
|
||||
baz_domain = Puppet::Type::Keystone_domain_config.new(
|
||||
{ :name => 'baz::duck/go', :value => 'where' }
|
||||
)
|
||||
baz_domain_provider = provider_class.new(baz_domain)
|
||||
|
||||
expect { @domain_provider.create }.not_to raise_error
|
||||
expect { baz_domain_provider.create }.not_to raise_error
|
||||
|
||||
expect(File).to exist('/tmp/keystone.bar.conf')
|
||||
expect(File).to exist('/tmp/keystone.baz.conf')
|
||||
|
||||
expect(File.read('/tmp/keystone.bar.conf'))
|
||||
.to eq('
|
||||
[dude]
|
||||
foo=blahh
|
||||
')
|
||||
|
||||
expect(File.read('/tmp/keystone.baz.conf'))
|
||||
.to eq('
|
||||
[duck]
|
||||
go=where
|
||||
')
|
||||
end
|
||||
|
||||
it 'should find the instance' do
|
||||
@domain_provider.create
|
||||
instances = @domain_provider.class.instances
|
||||
expect(instances.count).to eq(1)
|
||||
expect(
|
||||
instances[0].instance_variable_get('@property_hash')[:name]
|
||||
).to eq('bar::dude/foo')
|
||||
end
|
||||
end
|
||||
|
||||
context 'invalid name definition' do
|
||||
it 'should raise an error if no domain is given' do
|
||||
resource = Puppet::Type::Keystone_domain_config.new(
|
||||
{ :name => 'dude/foo', :value => 'blahh' }
|
||||
)
|
||||
expect { provider_class.new(resource).create }
|
||||
.to raise_error(Puppet::Error::OpenstackMissingDomainName)
|
||||
end
|
||||
|
||||
it 'should raise an error if an empty domain is given' do
|
||||
resource = Puppet::Type::Keystone_domain_config.new(
|
||||
{ :name => '::dude/foo', :value => 'blahh' }
|
||||
)
|
||||
expect { provider_class.new(resource).create }
|
||||
.to raise_error(Puppet::Error::OpenstackMissingDomainName)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
35
spec/unit/type/keystone_domain_config_spec.rb
Normal file
35
spec/unit/type/keystone_domain_config_spec.rb
Normal file
@ -0,0 +1,35 @@
|
||||
require 'puppet'
|
||||
require 'puppet/type/keystone_domain_config'
|
||||
|
||||
describe 'Puppet::Type.type(:keystone_domain_config)' do
|
||||
let(:keystone_domain_config) do
|
||||
Puppet::Type.type(:keystone_domain_config)
|
||||
.new(:name => 'service::DEFAULT/foo', :value => 'bar')
|
||||
end
|
||||
|
||||
let(:catalog) { Puppet::Resource::Catalog.new }
|
||||
|
||||
it 'should autorequire the directory holding the configurations' do
|
||||
directory = Puppet::Type.type(:file).new(
|
||||
:name => '/etc/keystone/domains',
|
||||
:ensure => 'directory'
|
||||
)
|
||||
catalog.add_resource directory, keystone_domain_config
|
||||
dependency = keystone_domain_config.autorequire
|
||||
expect(dependency.size).to eq(1)
|
||||
expect(dependency[0].target).to eq(keystone_domain_config)
|
||||
expect(dependency[0].source).to eq(directory)
|
||||
end
|
||||
|
||||
it 'should autorequire the keystone_config identity/domain_config_dir' do
|
||||
keystone_config = Puppet::Type.type(:keystone_config).new(
|
||||
:name => 'identity/domain_config_dir',
|
||||
:value => '/tmp'
|
||||
)
|
||||
catalog.add_resource keystone_config, keystone_domain_config
|
||||
dependency = keystone_domain_config.autorequire
|
||||
expect(dependency.size).to eq(1)
|
||||
expect(dependency[0].target).to eq(keystone_domain_config)
|
||||
expect(dependency[0].source).to eq(keystone_config)
|
||||
end
|
||||
end
|
Loading…
x
Reference in New Issue
Block a user