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:
Sofer Athlan-Guyot 2015-09-01 16:06:39 +02:00 committed by Athlan-Guyot sofer
parent 759c626987
commit 07f19bd38a
13 changed files with 817 additions and 48 deletions

View 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';
}

View 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

View File

@ -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

View 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

View 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

View File

@ -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]
}

View File

@ -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

View File

@ -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

View File

@ -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

View 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

View File

@ -1,5 +1,6 @@
require 'beaker-rspec'
require 'beaker/puppet_install_helper'
require 'shared_examples_acceptance'
run_puppet_install_helper

View 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

View 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