Add keystone::bootstrap class

This class combines the keystone-manage bootstrap command
from init, the keystone::endpoint functionality that manages
the keystone endpoints and the keystone::roles::admin class
that manages users and projects.

This is one of the steps to make sure we only have a single
point of entry for bootstrapping (keystone-manage bootstrap)
and then only managing resources after that.

This is especially required since we are getting rid of the
admin token and cannot manage resources before keystone-manage
bootstrap has created the user, project, service and endpoints
for us.

These resources should always be in the default domain and
deployments should manage domain specific configuration themselves
using the provider resources.

This class uses the default values from the keystone-manage
bootstrap command.

In the past puppet-keystone has always created a openstack project
that is assumed as a admin project even though the bootstrap command
creates the admin project. Since this uses the default values from
the bootstrap command we should move away from having an openstack
project, if we need that in testing it should be created there and
not in the default deployment.

Depends-On: https://review.opendev.org/#/c/698528/
Change-Id: I683fcdd743bddf6d4e989dd7e7c553db745934db
This commit is contained in:
Tobias Urdin 2019-11-02 12:32:24 +01:00 committed by Alex Schultz
parent 48ef9708cc
commit bc1ff1d7cb
27 changed files with 878 additions and 831 deletions

View File

@ -53,21 +53,14 @@ To utilize the keystone module's functionality you will need to declare multiple
```puppet
class { 'keystone':
catalog_type => 'sql',
admin_token => 'random_uuid',
database_connection => 'mysql://keystone_admin:super_secret_db_password@openstack-controller.example.com/keystone',
}
# Adds the admin credential to keystone.
class { 'keystone::roles::admin':
email => 'admin@example.com',
class { 'keystone::bootstrap':
password => 'super_secret',
}
# Installs the service user endpoint.
class { 'keystone::endpoint':
public_url => 'http://10.16.0.101:5000/v2.0',
admin_url => 'http://10.16.1.101:5000/v2.0',
internal_url => 'http://10.16.2.101:5000/v2.0',
public_url => 'http://10.16.0.101:5000',
admin_url => 'http://10.16.1.101:5000',
internal_url => 'http://10.16.2.101:5000',
region => 'example-1',
}
```

View File

@ -28,16 +28,12 @@ class { 'keystone':
debug => true,
database_connection => 'mysql://keystone:keystone@127.0.0.1/keystone',
catalog_type => 'sql',
admin_token => 'admin_token',
enabled => false,
}
class { 'keystone::roles::admin':
email => 'test@puppetlabs.com',
password => 'ChangeMe',
}
class { 'keystone::endpoint':
public_url => "https://${::fqdn}:5000/",
admin_url => "https://${::fqdn}:5000/",
class { 'keystone::bootstrap':
password => 'ChangeMe',
public_url => "https://${::fqdn}:5000",
admin_url => "https://${::fqdn}:5000",
}
keystone_config { 'ssl/enable': value => true }

View File

@ -28,17 +28,13 @@ class { 'keystone':
debug => true,
database_connection => 'mysql://keystone_admin:keystone@127.0.0.1/keystone',
catalog_type => 'sql',
admin_token => 'admin_token',
enabled => true,
}
class { 'keystone::cron::token_flush': }
class { 'keystone::roles::admin':
email => 'test@puppetlabs.com',
password => 'ChangeMe',
}
class { 'keystone::endpoint':
public_url => "https://${::fqdn}:443/main/",
admin_url => "https://${::fqdn}:443/admin/",
class { 'keystone::bootstrap':
password => 'ChangeMe',
public_url => "https://${::fqdn}:443/main",
admin_url => "https://${::fqdn}:443/admin",
}
keystone_config { 'ssl/enable': ensure => absent }

View File

@ -45,18 +45,13 @@ class { 'keystone':
debug => true,
database_connection => 'mysql://keystone:keystone@127.0.0.1/keystone',
catalog_type => 'sql',
admin_token => 'admin_token',
enabled => false,
}
class { 'keystone::roles::admin':
email => 'test@puppetlabs.com',
password => 'ChangeMe',
}
class { 'keystone::endpoint':
public_url => "https://${::fqdn}:5000/",
admin_url => "https://${::fqdn}:5000/",
class { 'keystone::bootstrap':
password => 'ChangeMe',
public_url => "https://${::fqdn}:5000",
admin_url => "https://${::fqdn}:5000",
}
keystone_config { 'ssl/enable': value => true }

View File

@ -1,7 +1,6 @@
class { 'keystone':
debug => true,
database_connection => 'mysql://keystone:keystone@127.0.0.1/keystone',
admin_token => 'admin_token',
enabled => true,
# helper for using domains
using_domain_config => true
@ -9,19 +8,13 @@ class { 'keystone':
# Ensure this matches what is in LDAP or keystone will try to recreate
# the admin user
class { 'keystone::roles::admin':
email => 'test@example.com',
password => 'ChangeMe',
admin_user_domain => 'domain_1',
admin_project_domain => 'domain_1',
service_project_domain => 'domain_1',
class { 'keystone::bootstrap':
password => 'ChangeMe',
}
# Waiting to have keystone::roles::admin being a define instead of a
# class to make the admin for domain_2.
keystone_domain { 'domain_2': ensure => present }
keystone::ldap_backend { 'domain_1':
keystone::ldap_backend { 'Default':
url => 'ldap://ldap.example.com:389',
user => 'uid=bind,cn=users,cn=accounts,dc=example,dc=com',
password => 'SecretPass',

View File

@ -3,8 +3,7 @@
# Ensure this matches what is in LDAP or keystone will try to recreate
# the admin user
class { 'keystone::roles::admin':
email => 'test@example.com',
class { 'keystone::bootstrap':
password => 'ChangeMe',
}

View File

@ -3,8 +3,7 @@
# Ensure this matches what is in LDAP or keystone will try to recreate
# the admin user
class { 'keystone::roles::admin':
email => 'test@example.com',
class { 'keystone::bootstrap':
password => 'ChangeMe',
}

View File

@ -1,24 +1,3 @@
# Example using v3 domains. The admin user is created in the domain
# named 'admin_domain', and assigned the role 'admin' in the 'admin'
# project in the domain 'admin_domain'. The keystone service account is
# created in default domain, and assigned the
# role 'admin' in the project 'services' in the default domain.
# NOTE: Until all of the other services support using Keystone v3
# with keystone_authtoken middleware that supports v3, they cannot
# specify a domain for authentication, and so have to be in the
# default domain.
#
# To be sure everything is working, run:
# $ export OS_IDENTITY_API_VERSION=3
# $ export OS_USERNAME=admin
# $ export OS_USER_DOMAIN_NAME=admin_domain
# $ export OS_PASSWORD=ChangeMe
# $ export OS_PROJECT_NAME=admin
# $ export OS_PROJECT_DOMAIN_NAME=admin_domain
# $ export OS_AUTH_URL=http://keystone.local:5000/v3
# $ openstack user list
#
Exec { logoutput => 'on_failure' }
@ -29,18 +8,8 @@ class { 'keystone::db::mysql':
class { 'keystone':
debug => true,
database_connection => 'mysql://keystone:keystone@127.0.0.1/keystone',
admin_token => 'admin_token',
enabled => true,
}
class { 'keystone::roles::admin':
email => 'test@example.tld',
password => 'a_big_secret',
admin => 'admin', # username
admin_tenant => 'admin', # project name
admin_user_domain => 'admin', # domain for user
admin_tenant_domain => 'admin', # domain for project
}
class { 'keystone::endpoint':
public_url => 'http://127.0.0.1:5000/',
admin_url => 'http://127.0.0.1:5000/',
class { 'keystone::bootstrap':
password => 'a_big_secret',
}

View File

@ -1,8 +1,3 @@
# 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': }
@ -12,18 +7,14 @@ class { 'keystone::db::mysql':
class { 'keystone':
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:5000/',
class { 'keystone::bootstrap':
password => 'a_big_secret',
public_url => 'http://192.168.1.1:5000',
admin_url => 'http://192.168.1.1:5000',
}
# Creates the /etc/keystone/domains/keystone.my_domain.conf file and

View File

@ -13,12 +13,60 @@ class Puppet::Provider::Keystone < Puppet::Provider::Openstack
@@default_domain_id = nil
def self.public_endpoint
@public_endpoint ||= get_public_endpoint
def self.conf_filename
'/etc/keystone/puppet.conf'
end
def self.admin_token
@admin_token ||= get_admin_token
def self.keystone_puppet_conf
return @keystone_puppet_conf if @keystone_puppet_conf
@keystone_puppet_conf = Puppet::Util::IniConfig::File.new
@keystone_puppet_conf.read(conf_filename)
@keystone_puppet_conf
end
def self.get_keystone_puppet_credentials
auth_keys = ['auth_url', 'project_name', 'username',
'password']
conf = keystone_puppet_conf
if conf and conf['keystone_authtoken'] and
auth_keys.all?{|k| !conf['keystone_authtoken'][k].nil?}
creds = Hash[ auth_keys.map \
{ |k| [k, conf['keystone_authtoken'][k].strip] } ]
if conf['project_domain_name']
creds['project_domain_name'] = conf['project_domain_name']
else
creds['project_domain_name'] = 'Default'
end
if conf['user_domain_name']
creds['user_domain_name'] = conf['user_domain_name']
else
creds['user_domain_name'] = 'Default'
end
if conf['keystone_authtoken']['region_name']
creds['region_name'] = conf['keystone_authtoken']['region_name']
end
return creds
else
raise(Puppet::Error, "File: #{conf_filename} does not contain all " +
"required configuration keys. Cannot authenticate to Keystone.")
end
end
def self.keystone_puppet_credentials
@keystone_puppet_credentials ||= get_keystone_puppet_credentials
end
def keystone_puppet_credentials
self.class.keystone_puppet_credentials
end
def self.get_auth_endpoint
q = keystone_puppet_credentials
"#{q['auth_url']}"
end
def self.auth_endpoint
@auth_endpoint ||= get_auth_endpoint
end
def self.default_domain_from_ini_file
@ -152,50 +200,17 @@ class Puppet::Provider::Keystone < Puppet::Provider::Openstack
raise e unless e.message =~ /No user with a name or ID/
end
def self.get_public_endpoint
endpoint = nil
if url = get_section('DEFAULT', 'public_endpoint')
endpoint = url.chomp('/')
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 = public_endpoint
auth_url = auth_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_ENDPOINT']
service_url = ENV['OS_ENDPOINT'].dup
# Compatibility with pre-4.0.0 openstackclient
elsif ENV['OS_URL']
service_url = ENV['OS_URL'].dup
elsif public_endpoint
service_url = public_endpoint
service_url << "/v#{@credentials.version}"
end
return service_url
end
def self.ini_filename
INI_FILENAME
end
@ -212,27 +227,32 @@ class Puppet::Provider::Keystone < Puppet::Provider::Openstack
def self.request(service, action, properties=nil, options={})
super
rescue Puppet::Error::OpenstackAuthInputError, Puppet::Error::OpenstackUnauthorizedError => error
request_by_service_token(service, action, error, properties, options=options)
keystone_request(service, action, error, properties)
end
def self.request_by_service_token(service, action, error, properties=nil, options={})
def self.keystone_request(service, action, error, properties=nil)
properties ||= []
@credentials.token = admin_token
@credentials.endpoint = service_url
raise error unless @credentials.service_token_set?
@credentials.username = keystone_puppet_credentials['username']
@credentials.password = keystone_puppet_credentials['password']
@credentials.project_name = keystone_puppet_credentials['project_name']
@credentials.auth_url = auth_endpoint
if keystone_puppet_credentials['region_name']
@credentials.region_name = keystone_puppet_credentials['region_name']
end
if @credentials.version == '3'
@credentials.user_domain_name = keystone_puppet_credentials['user_domain_name']
@credentials.project_domain_name = keystone_puppet_credentials['project_domain_name']
end
raise error unless @credentials.set?
begin
Puppet::Provider::Openstack.request(service, action, properties, @credentials, options)
Puppet::Provider::Openstack.request(service, action, properties, @credentials)
rescue Puppet::ExecutionFailure, Puppet::Error::OpenstackUnauthorizedError
# openstackclient < 4.0.0 does not support --os-endpoint and requires --os-url
@credentials.url = service_url
Puppet::Provider::Openstack.request(service, action, properties, @credentials, options)
@credentials.url = auth_endpoint
Puppet::Provider::Openstack.request(service, action, properties, @credentials)
end
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}")

View File

@ -0,0 +1,8 @@
Puppet::Type.type(:keystone_puppet_config).provide(
:ini_setting,
:parent => Puppet::Type.type(:openstack_config).provider(:ini_setting)
) do
def self.file_path
'/etc/keystone/puppet.conf'
end
end

View File

@ -0,0 +1,12 @@
Puppet::Type.newtype(:keystone_puppet_config) do
require File.expand_path(File.join(
File.dirname(__FILE__), '..', '..',
'puppet_x', 'keystone_config', 'ini_setting'))
extend PuppetX::KeystoneConfig::IniSetting
create_parameters
autorequire(:file) do
['/etc/keystone/puppet.conf']
end
end

307
manifests/bootstrap.pp Normal file
View File

@ -0,0 +1,307 @@
# == Class: keystone::bootstrap
#
# Bootstrap keystone with keystone-manage bootstrap.
#
# === Parameters
#
# [*password*]
# (Optional) The password for the user.
# WARNING: This parameter will be required in a future release.
# Defaults to undef
#
# [*username*]
# (Optional) The username.
# Defaults to 'admin'
#
# [*email*]
# (Optional) The email for the user.
# Defaults to 'admin@localhost'
#
# [*project_name*]
# (Optional) The project name.
# Defaults to 'admin'
#
# [*service_project_name*]
# (Optional) The service project name.
# Defaults to 'services'
#
# [*role_name*]
# (Optional) The role name.
# Defaults to 'admin'
#
# [*service_name*]
# (Optional) The service name.
# Defaults to 'keystone'
#
# [*admin_url*]
# (Optional) Admin URL for Keystone endpoint.
# This url should *not* contain any version or trailing '/'.
# Defaults to 'http://127.0.0.1:5000'
#
# [*public_url*]
# (Optional) Public URL for Keystone endpoint.
# This URL should *not* contain any version or trailing '/'.
# Defaults to 'http://127.0.0.1:5000'
#
# [*internal_url*]
# (Optional) Internal URL for Keystone endpoint.
# This URL should *not* contain any version or trailing '/'.
# Defaults to $public_url
#
# [*region*]
# (Optional) Region for endpoint.
# Defaults to 'RegionOne'
#
# [*interface*]
# (Optional) Which interface endpoint should be used.
# Defaults to 'public'
#
class keystone::bootstrap (
# TODO(tobias-urdin): Make the password required when compat is removed.
$password = undef,
$username = 'admin',
$email = 'admin@localhost',
$project_name = 'admin',
$service_project_name = 'services',
$role_name = 'admin',
$service_name = 'keystone',
$admin_url = 'http://127.0.0.1:5000',
$public_url = 'http://127.0.0.1:5000',
$internal_url = undef,
$region = 'RegionOne',
$interface = 'public',
) inherits keystone::params {
include ::keystone::deps
# TODO(tobias-urdin): Remove compat layer.
if $password == undef {
if defined('$::keystone::admin_password') and $::keystone::admin_password != undef {
$password_real = $::keystone::admin_password
warning('Using deprecated keystone::admin_password as admin password')
# Check if we differ from the roles admin pw
if defined('$::keystone::roles::admin::password') and $::keystone::roles::admin::password != $password_real {
warning('The keystone::admin_password and keystone::roles::admin::password differs and will cause a flip-flopping\
behaviour and authentication issues for the admin user.')
}
} elsif defined('$::keystone::admin_token') and $::keystone::admin_token != undef {
$password_real = $::keystone::admin_token
warning('Using deprecated keystone::admin_token as admin password')
# Check if we differ from the roles admin pw
if defined('$::keystone::roles::admin::password') and $::keystone::roles::admin::password != $password_real {
warning('The keystone::admin_token and keystone::roles::admin::password differs and will cause a flip-flopping\
behaviour and authentication issues for the admin user.')
}
} else {
# Check the keystone::roles::admin class as well.
if defined('$::keystone::roles::admin::password') and $::keystone::roles::admin::password != undef {
$password_real = $::keystone::roles::admin::password
warning('Using deprecated keystone::roles::admin::password as admin password')
} else {
fail('keystone::bootstrap::password is undef, could not resolve a password')
}
}
} else {
$password_real = $password
}
if defined('$::keystone::endpoint::public_url') and $::keystone::endpoint::public_url != undef {
$public_url_real = $::keystone::endpoint::public_url
$using_deprecated_public_url = true
warning('Using deprecated keystone::endpoint::public_url, please update to using keystone::bootstrap')
} else {
$public_url_real = $public_url
$using_deprecated_public_url = false
}
if defined('$::keystone::endpoint::internal_url') and $::keystone::endpoint::internal_url != undef {
$internal_url_final = $::keystone::endpoint::internal_url
$using_deprecated_internal_url = true
warning('Using deprecated keystone::endpoint::internal_url, please update to using keystone::bootstrap')
} else {
$internal_url_final = $internal_url
$using_deprecated_internal_url = false
}
if defined('$::keystone::endpoint::admin_url') and $::keystone::endpoint::admin_url != undef {
$admin_url_real = $::keystone::endpoint::admin_url
warning('Using deprecated keystone::endpoint::admin_url, please update to using keystone::bootstrap')
} else {
$admin_url_real = $admin_url
}
if defined('$::keystone::endpoint::region') and $::keystone::endpoint::region != undef {
$region_real = $::keystone::endpoint::region
warning('Using deprecated keystone::endpoint::region, please update to using keystone::bootstrap')
} else {
$region_real = $region
}
if !$using_deprecated_internal_url and $internal_url == undef and $using_deprecated_public_url {
warning('Using deprecated keystone::endpoint::public_url for keystone::bootstrap::internal_url')
}
if defined('$::keystone::roles::admin::admin') and $::keystone::roles::admin::admin != undef {
$username_real = $::keystone::roles::admin::admin
if $username_real != $username and $username == 'admin' {
warning('Using keystone::roles::admin::admin as username, the keystone::bootstrap::username default is different\
dont forget to set that later')
}
} else {
$username_real = $username
}
if defined('$::keystone::roles::admin::email') and $::keystone::roles::admin::email != undef {
$email_real = $::keystone::roles::admin::email
if $email_real != $email and $email == 'admin@localhost' {
warning('Using keystone::roles::admin::email as email, the keystone::bootstrap::email default is different\
dont forget to set that later')
}
} else {
$email_real = $email
}
if defined('$::keystone::roles::admin::admin_roles') and $::keystone::roles::admin::admin_roles != undef {
$role_name_real = $::keystone::roles::admin::admin_roles
warning("Using keystone::roles::admin::admin_roles with value ${role_name_real} note that the\
keystone::bootstrap when used will only set a single role, by default the 'admin' role.")
warning('Will use the first value in admin_roles for bootstrap and all (if multiple) for all other resources!')
if is_array($role_name_real) {
$bootstrap_role_name = $role_name_real[0]
} else {
$bootstrap_role_name = $role_name_real
}
} else {
$role_name_real = [$role_name]
$bootstrap_role_name = $role_name
}
if defined('$::keystone::roles::admin::admin_tenant') {
$admin_tenant = $::keystone::roles::admin::admin_tenant
if ($admin_tenant == undef or $admin_tenant == 'openstack') {
# Try to keep the backward compatible creation of the openstack project.
# We still create the 'admin' project with the bootstrap process below.
# This is a best effort, we still ignore the description and default domain.
ensure_resource('keystone_tenant', 'openstack', {
'ensure' => 'present',
'enabled' => true,
})
ensure_resource('keystone_user_role', "${username_real}@openstack", {
'ensure' => 'present',
'roles' => $role_name_real,
})
# Use the default value so we create the "admin" project
$project_name_real = $project_name
} else {
warning('Using keystone::roles::admin::admin_tenant as project name for admin')
$project_name_real = $admin_tenant
}
} else {
$project_name_real = $project_name
}
if defined('$::keystone::roles::admin::service_tenant') and $::keystone::roles::admin::service_tenant != undef {
warning('Using keystone::roles::admin::service_tenant as service project name')
$service_project_name_real = $::keystone::roles::admin::service_tenant
} else {
$service_project_name_real = $service_project_name
}
# Compat code ends here.
$internal_url_real = $internal_url_final ? {
undef => $public_url_real,
default => $internal_url_final
}
if defined('$::keystone::keystone_user') {
$keystone_user = $::keystone::keystone_user
} else {
$keystone_user = $::keystone::params::keystone_user
}
# The initial bootstrap that creates all resources required but
# only subscribes to notifies from the keystone::dbsync::end anchor
# which means this is not guaranteed to execute on each run.
exec { 'keystone bootstrap':
command => 'keystone-manage bootstrap',
environment => [
"OS_BOOTSTRAP_USERNAME=${username_real}",
"OS_BOOTSTRAP_PASSWORD=${password_real}",
"OS_BOOTSTRAP_PROJECT_NAME=${project_name_real}",
"OS_BOOTSTRAP_ROLE_NAME=${bootstrap_role_name}",
"OS_BOOTSTRAP_SERVICE_NAME=${service_name}",
"OS_BOOTSTRAP_ADMIN_URL=${admin_url_real}",
"OS_BOOTSTRAP_PUBLIC_URL=${public_url_real}",
"OS_BOOTSTRAP_INTERNAL_URL=${internal_url_real}",
"OS_BOOTSTRAP_REGION_ID=${region_real}",
],
user => $keystone_user,
path => '/usr/bin',
refreshonly => true,
subscribe => Anchor['keystone::dbsync::end'],
notify => Anchor['keystone::service::begin'],
tag => 'keystone-bootstrap',
}
# Since the bootstrap is not guaranteed to execute on each run we
# use the below resources to make sure the current resources are
# correct so if some value was updated we set that.
ensure_resource('keystone_role', $role_name_real, {
'ensure' => 'present',
})
ensure_resource('keystone_user', $username_real, {
'ensure' => 'present',
'enabled' => true,
'email' => $email_real,
'password' => $password_real,
})
ensure_resource('keystone_tenant', $service_project_name_real, {
'ensure' => 'present',
'enabled' => true,
})
ensure_resource('keystone_tenant', $project_name_real, {
'ensure' => 'present',
'enabled' => true,
})
ensure_resource('keystone_user_role', "${username_real}@${project_name_real}", {
'ensure' => 'present',
'roles' => $role_name_real,
})
ensure_resource('keystone_service', "${service_name}::identity", {
'ensure' => 'present',
})
ensure_resource('keystone_endpoint', "${region_real}/${service_name}::identity", {
'ensure' => 'present',
'public_url' => $public_url_real,
'admin_url' => $admin_url_real,
'internal_url' => $internal_url_real,
})
# The below creates and populates the /etc/keystone/puppet.conf file that contains
# the credentials that can be loaded by providers. Ensure it has the proper owner,
# group and mode so that it cannot be read by anything other than root.
file { '/etc/keystone/puppet.conf':
ensure => 'present',
replace => false,
content => '',
owner => 'root',
group => 'root',
mode => '0600',
require => Anchor['keystone::install::end'],
}
if $interface == 'admin' {
$auth_url_real = $admin_url_real
} elsif $interface == 'internal' {
$auth_url_real = $internal_url_real
} else {
$auth_url_real = $public_url_real
}
keystone::resource::authtoken { 'keystone_puppet_config':
username => $username_real,
password => $password_real,
auth_url => $auth_url_real,
project_name => $project_name_real,
region_name => $region_real,
interface => $interface,
}
}

View File

@ -1,26 +1,29 @@
# == Class: keystone::endpoint
#
# DEPRECATED!
#
# Creates the auth endpoints for keystone
#
# === Parameters
#
# [*public_url*]
# (optional) Public url for keystone endpoint.
# Defaults to 'http://127.0.0.1:5000'
# Defaults to undef
# This url should *not* contain any version or trailing '/'.
#
# [*internal_url*]
# (optional) Internal url for keystone endpoint.
# Defaults to $public_url
# Defaults to undef
# This url should *not* contain any version or trailing '/'.
#
# [*admin_url*]
# (optional) Admin url for keystone endpoint.
# Defaults to 'http://127.0.0.1:5000'
# Defaults to undef
# This url should *not* contain any version or trailing '/'.
#
# [*region*]
# (optional) Region for endpoint. (Defaults to 'RegionOne')
# (optional) Region for endpoint.
# Defaults to undef
#
# [*user_domain*]
# (Optional) Domain for $auth_name
@ -38,10 +41,7 @@
#
# [*version*]
# (optional) API version for endpoint.
# Defaults to ''. Valid values are 'v2.0', 'v3', or the empty string ''.
# If the version is set to the empty string (''), then it won't be
# used. This is the expected behaviour since Keystone V3 handles API versions
# from the context.
# Defaults to undef.
#
# === Examples
#
@ -52,59 +52,23 @@
# }
#
class keystone::endpoint (
$public_url = 'http://127.0.0.1:5000',
$public_url = undef,
$internal_url = undef,
$admin_url = 'http://127.0.0.1:5000',
$region = 'RegionOne',
$admin_url = undef,
$region = undef,
$user_domain = undef,
$project_domain = undef,
$default_domain = undef,
$version = '',
$version = undef,
) {
include keystone::deps
warning('The keystone::endpoint class has been replaced with keystone::bootstrap class\
will try to use the backward compatible approach')
if $version == 'unset' {
warning('keystone::endpoint::version parameter is deprecated and will be removed in a future release.')
$_version = 'v2.0'
} else {
$_version = $version
}
if empty($_version) {
$admin_url_real = $admin_url
$public_url_real = $public_url
if $internal_url {
$internal_url_real = $internal_url
}
else {
$internal_url_real = $public_url
}
}
else {
$public_url_real = "${public_url}/${_version}"
$admin_url_real = "${admin_url}/${_version}"
if $internal_url {
$internal_url_real = "${internal_url}/${_version}"
}
else {
$internal_url_real = "${public_url}/${_version}"
}
if !defined('$::keystone::roles::admin::admin_tenant') {
fail('You are using the backward compatible approach instead of keystone::bootstrap\
you need to ensure that keystone::roles::admin is defined BEFORE keystone::endpoint in your manifest')
}
keystone::resource::service_identity { 'keystone':
configure_user => false,
configure_user_role => false,
service_type => 'identity',
service_description => 'OpenStack Identity Service',
public_url => $public_url_real,
admin_url => $admin_url_real,
internal_url => $internal_url_real,
region => $region,
user_domain => $user_domain,
project_domain => $project_domain,
default_domain => $default_domain,
}
Keystone::Resource::Service_identity['keystone'] -> File<| tag == 'openrc' |>
include keystone::bootstrap
}

View File

@ -13,18 +13,6 @@
# accepts latest or specific versions.
# Defaults to present.
#
# [*admin_token*]
# Admin token that can be used to authenticate as a keystone
# admin. This is not the password for the admin user
# in the Keystone database. This is a token that bypasses authentication.
# The admin_token has been deprecated by the Keystone service and this
# will be deprecated in a future changeset. Required.
#
# [*admin_password*]
# Keystone password for the admin user. This is not the admin_token.
# This is the password that the admin user signs into keystone with.
# Required.
#
# [*catalog_type*]
# (Optional) Type of catalog that keystone uses to store endpoints,services.
# Defaults to sql. (Also accepts template)
@ -403,12 +391,6 @@
# Otherwise Puppet will manage keys with File resource.
# Defaults to false
#
# [*enable_bootstrap*]
# (Optional) Enable keystone bootstrapping.
# This option to true will automatically bootstrap the default domain
# user by running 'keystone-manage bootstrap'.
# Defaults to true
#
# [*default_domain*]
# (Optional) When Keystone v3 support is enabled, v2 clients will need
# to have a domain assigned for certain operations. For example,
@ -565,25 +547,22 @@
# (Optional) The url to validate keystone against
# Defaults to undef
#
# == Dependencies
# None
# [*admin_token*]
# Admin token that can be used to authenticate as a keystone
# admin. This is not the password for the admin user
# in the Keystone database. This is a token that bypasses authentication.
# Defaults to undef
#
# == Examples
# [*admin_password*]
# Keystone password for the admin user. This is not the admin_token.
# This is the password that the admin user signs into keystone with.
# Defaults to undef
#
# class { 'keystone':
# admin_token => 'my_special_token',
# }
#
# OR
#
# class { 'keystone':
# ...
# service_name => 'httpd',
# ...
# }
# class { 'keystone::wsgi::apache':
# ...
# }
# [*enable_bootstrap*]
# (Optional) Enable keystone bootstrapping.
# This option to true will automatically bootstrap the default domain
# user by running 'keystone-manage bootstrap'.
# Defaults to undef
#
# == Authors
#
@ -594,8 +573,6 @@
# Copyright 2012 Puppetlabs Inc, unless otherwise noted.
#
class keystone(
$admin_token,
$admin_password = undef,
$package_ensure = 'present',
$client_package_ensure = 'present',
$log_dir = undef,
@ -668,7 +645,6 @@ class keystone(
$default_domain = undef,
$member_role_id = $::os_service_default,
$member_role_name = $::os_service_default,
$enable_bootstrap = true,
$memcache_dead_retry = $::os_service_default,
$memcache_socket_timeout = $::os_service_default,
$memcache_pool_maxsize = $::os_service_default,
@ -698,6 +674,9 @@ class keystone(
$validate_insecure = undef,
$validate_auth_url = undef,
$validate_cacert = undef,
$admin_token = undef,
$admin_password = undef,
$enable_bootstrap = undef,
) inherits keystone::params {
include keystone::deps
@ -772,14 +751,6 @@ class keystone(
$public_endpoint_real = $public_endpoint
}
if $admin_password == undef {
warning("admin_password is required, please set admin_password to a value != admin_token. \
admin_token will be removed in a later release")
$admin_password_real = $admin_token
} else {
$admin_password_real = $admin_password
}
if $manage_policyrcd {
# openstacklib policy_rcd only affects debian based systems.
Policy_rcd <| title == 'keystone' |> -> Package['keystone']
@ -813,8 +784,12 @@ admin_token will be removed in a later release")
purge => $purge_config,
}
# TODO(tobias-urdin): Remove this when admin_token is removed.
keystone_config {
'DEFAULT/admin_token': ensure => 'absent', secret => true;
}
keystone_config {
'DEFAULT/admin_token': value => $admin_token, secret => true;
'DEFAULT/member_role_id': value => $member_role_id;
'DEFAULT/member_role_name': value => $member_role_name;
}
@ -1105,21 +1080,6 @@ running as a standalone service, or httpd for being run by a httpd server")
fail('You must activate domain configuration using "using_domain_config" parameter to keystone class.')
}
if $enable_bootstrap {
# this requires the database to be up and running and configured
# and is only run once, so we don't need to notify the service
exec { 'keystone-manage bootstrap':
command => 'keystone-manage bootstrap',
environment => "OS_BOOTSTRAP_PASSWORD=${admin_password_real}",
user => $keystone_user,
path => '/usr/bin',
refreshonly => true,
notify => Anchor['keystone::service::begin'],
subscribe => Anchor['keystone::dbsync::end'],
tag => 'keystone-exec',
}
}
if $using_domain_config {
validate_legacy(Stdlib::Absolutepath, 'validate_absolute_path', $domain_config_directory)

View File

@ -1,5 +1,7 @@
# == Class: keystone::roles::admin
#
# DEPRECATED!
#
# This class implements some reasonable admin defaults for keystone.
#
# It creates the following keystone objects:
@ -14,14 +16,15 @@
# [*password*]
# The admin password. Required. In a later release
# this will default to $keystone::admin_password.
# Defaults to undef
#
# [*email*]
# The email address for the admin. Optional.
# Defaults to 'admin@localhost'.
# Defaults to undef
#
# [*admin_roles*]
# The list of the roles with admin privileges. Optional.
# Defaults to ['admin'].
# Defaults to undef
#
# [*admin_tenant*]
# The name of the tenant to be used for admin privileges. Optional.
@ -29,27 +32,27 @@
#
# [*service_tenant*]
# The name of service keystone tenant. Optional.
# Defaults to 'services'.
# Defaults to undef
#
# [*admin*]
# Admin user. Optional.
# Defaults to admin.
# Defaults to undef
#
# [*admin_tenant_desc*]
# Optional. Description for admin tenant,
# Defaults to 'admin tenant'
# Defaults to undef
#
# [*service_tenant_desc*]
# Optional. Description for admin tenant,
# Defaults to 'Tenant for the openstack services'
# Defaults to undef
#
# [*configure_user*]
# Optional. Should the admin user be created?
# Defaults to 'true'.
# Defaults to undef
#
# [*configure_user_role*]
# Optional. Should the admin role be configured for the admin user?
# Defaults to 'true'.
# Defaults to undef
#
# [*admin_user_domain*]
# Optional. Domain of the admin user
@ -79,85 +82,21 @@
# Copyright 2012 Puppetlabs Inc, unless otherwise noted.
#
class keystone::roles::admin(
$password,
$email = 'admin@localhost',
$admin = 'admin',
$password = undef,
$email = undef,
$admin = undef,
$admin_tenant = 'openstack',
$admin_roles = ['admin'],
$service_tenant = 'services',
$admin_tenant_desc = 'admin tenant',
$service_tenant_desc = 'Tenant for the openstack services',
$configure_user = true,
$configure_user_role = true,
$admin_roles = undef,
$service_tenant = undef,
$admin_tenant_desc = undef,
$service_tenant_desc = undef,
$configure_user = undef,
$configure_user_role = undef,
$admin_user_domain = undef,
$admin_project_domain = undef,
$service_project_domain = undef,
$target_admin_domain = undef,
) {
include keystone::deps
if $password != $keystone::admin_password_real {
warning('the main class is setting the admin password differently from this\
class when calling bootstrap. This will lead to the password\
flip-flopping and cause authentication issues for the admin user.\
Please ensure that keystone::roles::admin::password and\
keystone::admin_password are set the same.')
}
$domains = unique(delete_undef_values([ $admin_user_domain, $admin_project_domain, $service_project_domain, $target_admin_domain]))
keystone_domain { $domains:
ensure => present,
enabled => true,
}
keystone_tenant { $service_tenant:
ensure => present,
enabled => true,
description => $service_tenant_desc,
domain => $service_project_domain,
}
keystone_tenant { $admin_tenant:
ensure => present,
enabled => true,
description => $admin_tenant_desc,
domain => $admin_project_domain,
}
keystone_role { 'admin':
ensure => present,
}
if $configure_user {
keystone_user { $admin:
ensure => present,
enabled => true,
email => $email,
password => $password,
domain => $admin_user_domain,
}
}
if $configure_user_role {
keystone_user_role { "${admin}@${admin_tenant}":
ensure => present,
user_domain => $admin_user_domain,
project_domain => $admin_project_domain,
roles => $admin_roles,
}
Keystone_tenant[$admin_tenant] -> Keystone_user_role["${admin}@${admin_tenant}"]
Keystone_user<| title == $admin |> -> Keystone_user_role["${admin}@${admin_tenant}"]
Keystone_user_role["${admin}@${admin_tenant}"] -> File<| tag == 'openrc' |>
if $target_admin_domain {
keystone_user_role { "${admin}@::${target_admin_domain}":
ensure => present,
user_domain => $admin_user_domain,
roles => $admin_roles,
}
Keystone_user_role["${admin}@::${target_admin_domain}"] -> File<| tag == 'openrc' |>
}
}
warning('The keystone::roles::admin class has been replaced with keystone::bootstrap class')
}

View File

@ -0,0 +1,19 @@
---
features:
- |
Added keystone::bootstrap class.
upgrade:
- |
Now that the keystone::endpoint and keystone::roles::admin classes is deprecated
and has no effect deployments must define the new keystone::bootstrap class with
the proper data that was earlier passed to those classes. Please go through the
parameters in keystone::bootstrap carefully and define the class.
- |
If you are using a multi-domain setup where you previously relied on keystone::endpoint
and/or keystone::roles::admin to create your domains and domain scoped admin accounts
the keystone::bootstrap does not do this and you need to ensure this is managed in your
deployment using the keystone provider resources.
deprecations:
- |
The keystone::endpoint and keystone::roles::admin classes is now deprecated
and has no effect. Please read the upgrade notes carefully!

View File

@ -21,7 +21,6 @@ describe 'keystone server running with Apache/WSGI as Identity Provider' do
internal_url => 'http://127.0.0.1:1234',
}
# v3 admin
# we don't use ::keystone::roles::admin but still create resources manually:
keystone_domain { 'admin_domain':
ensure => present,
enabled => true,

View File

@ -21,7 +21,6 @@ describe 'keystone server running with Apache/WSGI as Service Provider with Shib
internal_url => 'http://127.0.0.1:1234',
}
# v3 admin
# we don't use ::keystone::roles::admin but still create resources manually:
keystone_domain { 'admin_domain':
ensure => present,
enabled => true,

View File

@ -21,7 +21,6 @@ describe 'keystone server running with Apache/WSGI with resources' do
internal_url => 'http://127.0.0.1:1234',
}
# v3 admin
# we don't use ::keystone::roles::admin but still create resources manually:
keystone_domain { 'admin_domain':
ensure => present,
enabled => true,

View File

@ -0,0 +1,229 @@
require 'spec_helper'
describe 'keystone::bootstrap' do
shared_examples 'keystone::bootstrap' do
context 'with required parameters' do
let :params do
{
:password => 'secret'
}
end
it { is_expected.to contain_class('keystone::deps') }
it { is_expected.to contain_exec('keystone bootstrap').with(
:command => 'keystone-manage bootstrap',
:environment => [
"OS_BOOTSTRAP_USERNAME=admin",
"OS_BOOTSTRAP_PASSWORD=secret",
"OS_BOOTSTRAP_PROJECT_NAME=admin",
"OS_BOOTSTRAP_ROLE_NAME=admin",
"OS_BOOTSTRAP_SERVICE_NAME=keystone",
"OS_BOOTSTRAP_ADMIN_URL=http://127.0.0.1:5000",
"OS_BOOTSTRAP_PUBLIC_URL=http://127.0.0.1:5000",
"OS_BOOTSTRAP_INTERNAL_URL=http://127.0.0.1:5000",
"OS_BOOTSTRAP_REGION_ID=RegionOne",
],
:user => platform_params[:keystone_user],
:path => '/usr/bin',
:refreshonly => true,
:subscribe => 'Anchor[keystone::dbsync::end]',
:notify => 'Anchor[keystone::service::begin]',
:tag => 'keystone-bootstrap',
)}
it { is_expected.to contain_keystone_role('admin').with_ensure('present') }
it { is_expected.to contain_keystone_user('admin').with(
:ensure => 'present',
:enabled => true,
:email => 'admin@localhost',
:password => 'secret',
)}
it { is_expected.to contain_keystone_tenant('services').with(
:ensure => 'present',
:enabled => true,
)}
it { is_expected.to contain_keystone_tenant('admin').with(
:ensure => 'present',
:enabled => true,
)}
it { is_expected.to contain_keystone_user_role('admin@admin').with(
:ensure => 'present',
:roles => ['admin'],
)}
it { is_expected.to contain_keystone_service('keystone::identity').with_ensure('present') }
it { is_expected.to contain_keystone_endpoint('RegionOne/keystone::identity').with(
:ensure => 'present',
:public_url => 'http://127.0.0.1:5000',
:admin_url => 'http://127.0.0.1:5000',
:internal_url => 'http://127.0.0.1:5000',
)}
it { is_expected.to contain_file('/etc/keystone/puppet.conf').with(
:ensure => 'present',
:replace => false,
:content => '',
:owner => 'root',
:group => 'root',
:mode => '0600',
:require => 'Anchor[keystone::install::end]',
)}
it { is_expected.to contain_keystone__resource__authtoken('keystone_puppet_config').with(
:username => 'admin',
:password => 'secret',
:auth_url => 'http://127.0.0.1:5000',
:project_name => 'admin',
:region_name => 'RegionOne',
:interface => 'public',
)}
end
context 'with specified parameters' do
let :params do
{
:password => 'secret',
:username => 'user',
:email => 'some@email',
:project_name => 'adminproj',
:service_project_name => 'serviceproj',
:role_name => 'adminrole',
:service_name => 'servicename',
:admin_url => 'http://admin:1234',
:public_url => 'http://public:4321',
:internal_url => 'http://internal:1342',
:region => 'RegionTwo',
:interface => 'admin'
}
end
it { is_expected.to contain_class('keystone::deps') }
it { is_expected.to contain_exec('keystone bootstrap').with(
:command => 'keystone-manage bootstrap',
:environment => [
"OS_BOOTSTRAP_USERNAME=user",
"OS_BOOTSTRAP_PASSWORD=secret",
"OS_BOOTSTRAP_PROJECT_NAME=adminproj",
"OS_BOOTSTRAP_ROLE_NAME=adminrole",
"OS_BOOTSTRAP_SERVICE_NAME=servicename",
"OS_BOOTSTRAP_ADMIN_URL=http://admin:1234",
"OS_BOOTSTRAP_PUBLIC_URL=http://public:4321",
"OS_BOOTSTRAP_INTERNAL_URL=http://internal:1342",
"OS_BOOTSTRAP_REGION_ID=RegionTwo",
],
:user => platform_params[:keystone_user],
:path => '/usr/bin',
:refreshonly => true,
:subscribe => 'Anchor[keystone::dbsync::end]',
:notify => 'Anchor[keystone::service::begin]',
:tag => 'keystone-bootstrap',
)}
it { is_expected.to contain_keystone_role('adminrole').with_ensure('present') }
it { is_expected.to contain_keystone_user('user').with(
:ensure => 'present',
:enabled => true,
:email => 'some@email',
:password => 'secret',
)}
it { is_expected.to contain_keystone_tenant('serviceproj').with(
:ensure => 'present',
:enabled => true,
)}
it { is_expected.to contain_keystone_tenant('adminproj').with(
:ensure => 'present',
:enabled => true,
)}
it { is_expected.to contain_keystone_user_role('user@adminproj').with(
:ensure => 'present',
:roles => ['adminrole'],
)}
it { is_expected.to contain_keystone_service('servicename::identity').with_ensure('present') }
it { is_expected.to contain_keystone_endpoint('RegionTwo/servicename::identity').with(
:ensure => 'present',
:public_url => 'http://public:4321',
:admin_url => 'http://admin:1234',
:internal_url => 'http://internal:1342',
)}
it { is_expected.to contain_file('/etc/keystone/puppet.conf').with(
:ensure => 'present',
:replace => false,
:content => '',
:owner => 'root',
:group => 'root',
:mode => '0600',
:require => 'Anchor[keystone::install::end]',
)}
it { is_expected.to contain_keystone__resource__authtoken('keystone_puppet_config').with(
:username => 'user',
:password => 'secret',
:auth_url => 'http://admin:1234',
:project_name => 'adminproj',
:region_name => 'RegionTwo',
:interface => 'admin',
)}
end
context 'when setting keystone_user param in keystone' do
let :params do
{
:password => 'secret'
}
end
let :pre_condition do
"class { '::keystone':
keystone_user => 'some',
}"
end
it { is_expected.to contain_exec('keystone bootstrap').with_user('some') }
end
context 'when setting interface to internal' do
let :params do
{
:password => 'secret',
:internal_url => 'http://internal:1234',
:interface => 'internal',
}
end
it { is_expected.to contain_keystone__resource__authtoken('keystone_puppet_config').with(
:auth_url => 'http://internal:1234',
:interface => 'internal',
)}
end
end
on_supported_os({
:supported_os => OSDefaults.get_supported_os
}).each do |os,facts|
context "on #{os}" do
let(:facts) do
facts.merge!(OSDefaults.get_facts())
end
let(:platform_params) do
{ :keystone_user => 'keystone' }
end
it_behaves_like 'keystone::bootstrap'
end
end
end

View File

@ -1,82 +0,0 @@
require 'spec_helper'
describe 'keystone::endpoint' do
it { is_expected.to contain_keystone_service('keystone::identity').with(
:ensure => 'present',
:description => 'OpenStack Identity Service'
)}
describe 'with default parameters' do
it { is_expected.to contain_keystone_endpoint('RegionOne/keystone::identity').with(
:ensure => 'present',
:public_url => 'http://127.0.0.1:5000',
:admin_url => 'http://127.0.0.1:5000',
:internal_url => 'http://127.0.0.1:5000',
:region => 'RegionOne'
)}
end
describe 'with overridden parameters' do
let :params do
{ :version => 'v42.6',
:public_url => 'https://identity.some.tld/the/main/endpoint',
:admin_url => 'https://identity-int.some.tld/some/admin/endpoint',
:internal_url => 'https://identity-int.some.tld/some/internal/endpoint',
:region => 'East'
}
end
it { is_expected.to contain_keystone_endpoint('East/keystone::identity').with(
:ensure => 'present',
:public_url => 'https://identity.some.tld/the/main/endpoint/v42.6',
:admin_url => 'https://identity-int.some.tld/some/admin/endpoint/v42.6',
:internal_url => 'https://identity-int.some.tld/some/internal/endpoint/v42.6',
:region => 'East'
)}
end
describe 'with unset version to test backward compatibility' do
let :params do
{ :version => 'unset' }
end
it { is_expected.to contain_keystone_endpoint('RegionOne/keystone::identity').with(
:ensure => 'present',
:public_url => 'http://127.0.0.1:5000/v2.0',
:admin_url => 'http://127.0.0.1:5000/v2.0',
:internal_url => 'http://127.0.0.1:5000/v2.0'
)}
end
describe 'without internal_url parameter' do
let :params do
{ :public_url => 'https://identity.some.tld/the/main/endpoint' }
end
it 'internal_url should default to public_url' do
is_expected.to contain_keystone_endpoint('RegionOne/keystone::identity').with(
:ensure => 'present',
:public_url => 'https://identity.some.tld/the/main/endpoint',
:internal_url => 'https://identity.some.tld/the/main/endpoint'
)
end
end
describe 'with domain parameters' do
let :params do
{ :user_domain => 'userdomain',
:project_domain => 'projectdomain',
:default_domain => 'defaultdomain' }
end
it { is_expected.to contain_keystone__resource__service_identity('keystone').with(
:user_domain => 'userdomain',
:project_domain => 'projectdomain',
:default_domain => 'defaultdomain'
)}
end
end

View File

@ -19,8 +19,6 @@ describe 'keystone' do
end
default_params = {
'admin_token' => 'service_token',
'admin_password' => 'special_password',
'package_ensure' => 'present',
'client_package_ensure' => 'present',
'public_bind_host' => '0.0.0.0',
@ -63,8 +61,6 @@ describe 'keystone' do
'client_package_ensure' => 'latest',
'public_bind_host' => '0.0.0.0',
'public_port' => '5001',
'admin_token' => 'service_token_override',
'admin_password' => 'admin_openstack_password',
'catalog_type' => 'template',
'token_provider' => 'uuid',
'password_hash_algorithm' => 'pbkdf2_sha512',
@ -125,17 +121,6 @@ describe 'keystone' do
end
end
it 'should bootstrap $enable_bootstrap is true' do
if param_hash['enable_bootstrap']
is_expected.to contain_exec('keystone-manage bootstrap').with(
:command => 'keystone-manage bootstrap',
:environment => 'OS_BOOTSTRAP_PASSWORD=service_password',
:user => param_hash['keystone_user'],
:refreshonly => true
)
end
end
it 'passes purge to resource' do
is_expected.to contain_resources('keystone_config').with({
:purge => false
@ -151,10 +136,6 @@ describe 'keystone' do
end
end
it 'should contain correct admin_token config' do
is_expected.to contain_keystone_config('DEFAULT/admin_token').with_value(param_hash['admin_token']).with_secret(true)
end
it 'should contain correct mysql config' do
is_expected.to contain_class('keystone::db')
end
@ -288,7 +269,6 @@ describe 'keystone' do
describe 'when ipv6 loopback is set' do
let :params do
{
:admin_token => 'service_token',
:public_bind_host => '::0'
}
end
@ -298,7 +278,6 @@ describe 'keystone' do
describe 'when ipv4 address is set' do
let :params do
{
:admin_token => 'service_token',
:public_bind_host => '192.168.0.1',
:public_port => '15000'
}
@ -309,7 +288,6 @@ describe 'keystone' do
describe 'when unenclosed ipv6 address is set' do
let :params do
{
:admin_token => 'service_token',
:public_bind_host => '2001:db8::1'
}
end
@ -319,7 +297,6 @@ describe 'keystone' do
describe 'when enclosed ipv6 address is set' do
let :params do
{
:admin_token => 'service_token',
:public_bind_host => '[2001:db8::1]'
}
end
@ -335,8 +312,7 @@ describe 'keystone' do
describe 'with disabled service managing' do
let :params do
{ :admin_token => 'service_token',
:manage_service => false,
{ :manage_service => false,
:enabled => false }
end
@ -354,7 +330,6 @@ describe 'keystone' do
describe 'when configuring as UUID' do
let :params do
{
'admin_token' => 'service_token',
'token_provider' => 'keystone.token.providers.uuid.Provider'
}
end
@ -362,8 +337,7 @@ describe 'keystone' do
describe 'with invalid catalog_type' do
let :params do
{ :admin_token => 'service_token',
:catalog_type => 'invalid' }
{ :catalog_type => 'invalid' }
end
it { should raise_error(Puppet::Error) }
@ -371,8 +345,7 @@ describe 'keystone' do
describe 'when configuring catalog driver' do
let :params do
{ :admin_token => 'service_token',
:catalog_driver => 'alien' }
{ :catalog_driver => 'alien' }
end
it { is_expected.to contain_keystone_config('catalog/driver').with_value(params[:catalog_driver]) }
@ -382,7 +355,6 @@ describe 'keystone' do
describe 'when configuring token expiration' do
let :params do
{
'admin_token' => 'service_token',
'token_expiration' => '42',
}
end
@ -392,9 +364,7 @@ describe 'keystone' do
describe 'when not configuring token expiration' do
let :params do
{
'admin_token' => 'service_token',
}
{}
end
it { is_expected.to contain_keystone_config("token/expiration").with_value('3600') }
@ -403,29 +373,16 @@ describe 'keystone' do
describe 'when sync_db is set to false' do
let :params do
{
'admin_token' => 'service_token',
'sync_db' => false,
'sync_db' => false,
}
end
it { is_expected.not_to contain_exec('keystone-manage db_sync') }
end
describe 'when enable_bootstrap is set to false' do
let :params do
{
'admin_token' => 'service_token',
'enable_bootstrap' => false,
}
end
it { is_expected.not_to contain_exec('keystone-manage bootstrap') }
end
describe 'configure memcache servers if set' do
let :params do
{
'admin_token' => 'service_token',
'cache_backend' => 'dogpile.cache.memcached',
'cache_backend_argument' => ['url:SERVER1:12211'],
'cache_memcache_servers' => 'SERVER1:11211,SERVER2:11211,[fd12:3456:789a:1::1]:11211',
@ -454,7 +411,6 @@ describe 'keystone' do
describe 'configure cache memcache servers if set' do
let :params do
{
'admin_token' => 'service_token',
'cache_backend' => 'dogpile.cache.memcached',
'cache_backend_argument' => ['url:SERVER3:12211'],
'cache_memcache_servers' => [ 'SERVER1:11211', 'SERVER2:11211', '[fd12:3456:789a:1::1]:11211' ],
@ -487,7 +443,6 @@ describe 'keystone' do
describe 'configure cache enabled if set' do
let :params do
{
'admin_token' => 'service_token',
'cache_backend' => 'dogpile.cache.memcached',
'cache_backend_argument' => ['url:SERVER3:12211'],
'cache_enabled' => true,
@ -550,7 +505,6 @@ describe 'keystone' do
describe 'when enabling SSL' do
let :params do
{
'admin_token' => 'service_token',
'enable_ssl' => true,
'public_endpoint' => 'https://localhost:5000',
}
@ -567,8 +521,7 @@ describe 'keystone' do
describe 'when disabling SSL' do
let :params do
{
'admin_token' => 'service_token',
'enable_ssl' => false,
'enable_ssl'=> false,
}
end
it {is_expected.to contain_keystone_config('ssl/enable').with_value(false)}
@ -706,7 +659,6 @@ describe 'keystone' do
describe 'setting default template catalog' do
let :params do
{
:admin_token => 'service_token',
:catalog_type => 'template'
}
end
@ -718,7 +670,6 @@ describe 'keystone' do
describe 'setting another template catalog' do
let :params do
{
:admin_token => 'service_token',
:catalog_type => 'template',
:catalog_template_file => '/some/template_file'
}

View File

@ -1,262 +0,0 @@
require 'spec_helper'
describe 'keystone::roles::admin' do
let :pre_condition do
"class { 'keystone':
admin_token => 'dummy',
admin_password => 'ChangeMe' }"
end
let :facts do
@default_facts.merge({
:osfamily => 'Debian',
:operatingsystem => 'Debian',
:operatingsystemrelease => '7.0',
:os_workers => 1,
:os => { :name => 'Debian', :family => 'Debian', :release => { :major => '7', :minor => '0' } },
})
end
describe 'with only the required params set' do
let :params do
{
:password => 'ChangeMe'
}
end
it { is_expected.to contain_keystone_tenant('services').with(
:ensure => 'present',
:enabled => true,
:description => 'Tenant for the openstack services'
)}
it { is_expected.to contain_keystone_tenant('openstack').with(
:ensure => 'present',
:enabled => true,
:description => 'admin tenant'
)}
it { is_expected.to contain_keystone_user('admin').with(
:ensure => 'present',
:enabled => true,
:email => 'admin@localhost',
:password => 'ChangeMe',
)}
it { is_expected.to contain_keystone_role('admin').with_ensure('present') }
it { is_expected.to contain_keystone_user_role('admin@openstack').with(
:roles => ['admin'],
:ensure => 'present',
:user_domain => nil,
:project_domain => nil,
)}
end
describe 'when overriding optional params' do
let :pre_condition do
"class { 'keystone':
admin_token => 'dummy',
admin_password => 'foo' }"
end
let :params do
{
:admin => 'admin',
:email => 'foo@baz',
:password => 'foo',
:admin_tenant => 'admin',
:admin_roles => ['admin', 'heat_stack_owner'],
:service_tenant => 'foobar',
:admin_tenant_desc => 'admin something else',
:service_tenant_desc => 'foobar description',
}
end
it { is_expected.to contain_keystone_tenant('foobar').with(
:ensure => 'present',
:enabled => true,
:description => 'foobar description'
)}
it { is_expected.to contain_keystone_tenant('admin').with(
:ensure => 'present',
:enabled => true,
:description => 'admin something else'
)}
it { is_expected.to contain_keystone_user('admin').with(
:ensure => 'present',
:enabled => true,
:email => 'foo@baz',
:password => 'foo',
)}
it { is_expected.to contain_keystone_user_role('admin@admin').with(
:roles => ['admin', 'heat_stack_owner'],
:ensure => 'present',
:user_domain => nil,
:project_domain => nil,
)}
end
describe 'when disabling user configuration' do
before do
let :params do
{
:configure_user => false
}
end
it { is_expected.to_not contain_keystone_user('keystone') }
it { is_expected.to contain_keystone_user_role('keystone@openstack') }
end
end
describe 'when disabling user and role configuration' do
before do
let :params do
{
:configure_user => false,
:configure_user_role => false
}
end
it { is_expected.to_not contain_keystone_user('keystone') }
it { is_expected.to_not contain_keystone_user_role('keystone@openstack') }
end
end
describe 'when specifying admin_user_domain and admin_project_domain' do
let :params do
{
:email => 'foo@bar',
:password => 'ChangeMe',
:admin_tenant => 'admin_tenant',
:admin_user_domain => 'admin_user_domain',
:admin_project_domain => 'admin_project_domain',
}
end
it { is_expected.to contain_keystone_user('admin').with(
:domain => 'admin_user_domain',
)}
it { is_expected.to contain_keystone_tenant('admin_tenant').with(:domain => 'admin_project_domain') }
it { is_expected.to contain_keystone_domain('admin_user_domain') }
it { is_expected.to contain_keystone_domain('admin_project_domain') }
it { is_expected.to contain_keystone_user_role('admin@admin_tenant').with(
:roles => ['admin'],
:ensure => 'present',
:user_domain => 'admin_user_domain',
:project_domain => 'admin_project_domain',
)}
end
describe 'when specifying admin_user_domain and admin_project_domain' do
let :params do
{
:email => 'foo@bar',
:password => 'ChangeMe',
:admin_tenant => 'admin_tenant::admin_project_domain',
:admin_user_domain => 'admin_user_domain',
:admin_project_domain => 'admin_project_domain',
}
end
it { is_expected.to contain_keystone_user('admin').with(
:domain => 'admin_user_domain',
)}
it { is_expected.to contain_keystone_tenant('admin_tenant::admin_project_domain').with(:domain => 'admin_project_domain') }
it { is_expected.to contain_keystone_domain('admin_user_domain') }
it { is_expected.to contain_keystone_domain('admin_project_domain') }
it { is_expected.to contain_keystone_user_role('admin@admin_tenant::admin_project_domain').with(
:roles => ['admin'],
:ensure => 'present',
:user_domain => 'admin_user_domain',
:project_domain => 'admin_project_domain',
)}
end
describe 'when specifying a service domain' do
let :params do
{
:email => 'foo@bar',
:password => 'ChangeMe',
:service_tenant => 'service_project',
:service_project_domain => 'service_domain'
}
end
it { is_expected.to contain_keystone_tenant('service_project').with(:domain => 'service_domain') }
it { is_expected.to contain_keystone_domain('service_domain') }
end
describe 'when specifying a service domain and service tenant domain' do
let :params do
{
:email => 'foo@bar',
:password => 'ChangeMe',
:service_tenant => 'service_project::service_domain',
:service_project_domain => 'service_domain'
}
end
it { is_expected.to contain_keystone_tenant('service_project::service_domain').with(:domain => 'service_domain') }
it { is_expected.to contain_keystone_domain('service_domain') }
end
describe 'when admin_user_domain and admin_project_domain are equal' do
let :params do
{
:email => 'foo@bar',
:password => 'ChangeMe',
:admin_user_domain => 'admin_domain',
:admin_project_domain => 'admin_domain',
}
end
it { is_expected.to contain_keystone_domain('admin_domain') }
end
describe 'when specifying a target admin domain' do
let :params do
{
:email => 'foo@bar',
:password => 'ChangeMe',
:admin_user_domain => 'admin_domain',
:admin_project_domain => 'admin_domain',
:target_admin_domain => 'admin_domain_target'
}
end
let :pre_condition do
["class { 'keystone':
admin_token => 'dummy',
admin_password => 'ChangeMe' }",
"file { '/root/openrc': tag => ['openrc']}"]
end
it { is_expected.to contain_keystone_domain('admin_domain_target') }
it { is_expected.to contain_keystone_user_role('admin@::admin_domain_target')
.with(
:roles => ['admin'],
:ensure => 'present',
:user_domain => 'admin_domain',
)
.that_comes_before('File[/root/openrc]')
}
end
describe 'when admin_password and password do not match' do
let :pre_condition do
"class { 'keystone':
admin_token => 'dummy',
admin_password => 'foo' }"
end
let :params do
{
:email => 'foo@bar',
:password => 'bar',
:service_tenant => 'services'
}
end
it { is_expected.to contain_keystone_role('admin').with_ensure('present') }
it { is_expected.to contain_keystone_user_role('admin@openstack').with(
:roles => ['admin'],
:ensure => 'present',
:user_domain => nil,
:project_domain => nil,
)}
end
end

View File

@ -0,0 +1,57 @@
# 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_puppet_config).provider(:ini_setting)
describe provider_class do
it 'should default to the default setting when no other one is specified' do
resource = Puppet::Type::Keystone_puppet_config.new(
{:name => 'DEFAULT/foo', :value => 'bar'}
)
provider = provider_class.new(resource)
expect(provider.section).to eq('DEFAULT')
expect(provider.setting).to eq('foo')
end
it 'should allow setting to be set explicitly' do
resource = Puppet::Type::Keystone_puppet_config.new(
{:name => 'dude/foo', :value => 'bar'}
)
provider = provider_class.new(resource)
expect(provider.section).to eq('dude')
expect(provider.setting).to eq('foo')
end
it 'should ensure absent when <SERVICE DEFAULT> is specified as a value' do
resource = Puppet::Type::Keystone_puppet_config.new(
{:name => 'dude/foo', :value => '<SERVICE DEFAULT>'}
)
provider = provider_class.new(resource)
provider.exists?
expect(resource[:ensure]).to eq :absent
end
it 'should ensure absent when value matches ensure_absent_val' do
resource = Puppet::Type::Keystone_puppet_config.new(
{:name => 'dude/foo', :value => 'foo', :ensure_absent_val => 'foo' }
)
provider = provider_class.new(resource)
provider.exists?
expect(resource[:ensure]).to eq :absent
end
end

View File

@ -126,44 +126,13 @@ id="the_user_id"
end
end
describe '#get_public_endpoint' do
it 'should return nothing if there is no keystone config file' do
expect(klass.get_public_endpoint).to be_nil
end
it 'should return nothing if the keystone config file does not have a DEFAULT section' do
mock = {}
File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true)
Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf')
expect(klass.get_public_endpoint).to be_nil
end
it 'should fail if the keystone config file does not contain public endpoint' do
mock = {'DEFAULT' => {}}
File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true)
Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf')
expect(klass.get_public_endpoint).to be_nil
end
it 'should use the public_endpoint from keystone config file with no trailing slash' do
mock = {'DEFAULT' => {'public_endpoint' => 'https://keystone.example.com/'}}
File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true)
Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf')
expect(klass.get_public_endpoint).to eq('https://keystone.example.com')
end
end
describe '#get_auth_url' do
it 'should return nothing when OS_AUTH_URL is no defined in either the environment or the openrc file and there is no keystone configuration file' do
it 'should raise when OS_AUTH_URL is no defined in either the environment or the openrc file and there is no keystone puppet config file' do
home = ENV['HOME']
ENV.clear
File.expects(:exists?).with("#{home}/openrc").returns(false)
File.expects(:exists?).with('/root/openrc').returns(false)
File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(false)
expect(klass.get_auth_url).to be_nil
expect { klass.get_auth_url }.to raise_error(Puppet::Error, "File: /etc/keystone/puppet.conf does not contain all required configuration keys. Cannot authenticate to Keystone.")
end
it 'should return the OS_AUTH_URL from the environment' do
@ -180,33 +149,14 @@ id="the_user_id"
expect(klass.get_auth_url).to eq('http://127.0.0.1:5001')
end
it 'should use public_endpoint when nothing else is available' do
it 'should use auth_endpoint when nothing else is available' do
ENV.clear
mock = 'http://127.0.0.1:5001'
klass.expects(:public_endpoint).returns(mock)
klass.expects(:auth_endpoint).returns(mock)
expect(klass.get_auth_url).to eq('http://127.0.0.1:5001')
end
end
describe '#get_service_url when retrieving the security token' do
it 'should return nothing when OS_ENDPOINT is not defined in environment' do
ENV.clear
expect(klass.get_service_url).to be_nil
end
it 'should return the OS_ENDPOINT from the environment' do
ENV['OS_ENDPOINT'] = 'http://127.0.0.1:5001/v3'
expect(klass.get_service_url).to eq('http://127.0.0.1:5001/v3')
end
it 'should use public_endpoint with the API version number' do
ENV.clear
mock = 'http://127.0.0.1:5001'
klass.expects(:public_endpoint).twice.returns(mock)
expect(klass.get_service_url).to eq('http://127.0.0.1:5001/v3')
end
end
describe '#set_domain_for_name' do
it 'should raise an error if the domain is not provided' do
expect do
@ -248,37 +198,6 @@ id="other_domain_id"
end
end
describe 'when retrieving the security token' do
it 'should return nothing if there is no keystone config file' do
File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(false)
expect(klass.get_admin_token).to be_nil
end
it 'should return nothing if the keystone config file does not have a DEFAULT section' do
mock = {}
File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true)
Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf')
expect(klass.get_admin_token).to be_nil
end
it 'should fail if the keystone config file does not contain an admin token' do
mock = {'DEFAULT' => {'not_a_token' => 'foo'}}
File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true)
Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf')
expect(klass.get_admin_token).to be_nil
end
it 'should parse the admin token if it is in the config file' do
mock = {'DEFAULT' => {'admin_token' => 'foo'}}
File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true)
Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf')
expect(klass.get_admin_token).to eq('foo')
end
end
describe 'when using domains' do
before(:each) do
set_env

View File

@ -0,0 +1,78 @@
require 'spec_helper'
# this hack is required for now to ensure that the path is set up correctly
# to retrieve the parent provider
$LOAD_PATH.push(
File.join(
File.dirname(__FILE__),
'..',
'..',
'fixtures',
'modules',
'inifile',
'lib')
)
require 'puppet'
require 'puppet/type/keystone_puppet_config'
describe 'Puppet::Type.type(:keystone_puppet_config)' do
before :each do
@keystone_puppet_config = Puppet::Type.type(:keystone_puppet_config).new(:name => 'DEFAULT/foo', :value => 'bar')
end
it 'should require a name' do
expect {
Puppet::Type.type(:keystone_puppet_config).new({})
}.to raise_error(Puppet::Error, 'Title or name must be provided')
end
it 'should not expect a name with whitespace' do
expect {
Puppet::Type.type(:keystone_puppet_config).new(:name => 'f oo')
}.to raise_error(Puppet::Error, /Parameter name failed/)
end
it 'should fail when there is no section' do
expect {
Puppet::Type.type(:keystone_puppet_config).new(:name => 'foo')
}.to raise_error(Puppet::Error, /Parameter name failed/)
end
it 'should not require a value when ensure is absent' do
Puppet::Type.type(:keystone_puppet_config).new(:name => 'DEFAULT/foo', :ensure => :absent)
end
it 'should accept a valid value' do
@keystone_puppet_config[:value] = 'bar'
expect(@keystone_puppet_config[:value]).to eq('bar')
end
it 'should not accept a value with whitespace' do
@keystone_puppet_config[:value] = 'b ar'
expect(@keystone_puppet_config[:value]).to eq('b ar')
end
it 'should accept valid ensure values' do
@keystone_puppet_config[:ensure] = :present
expect(@keystone_puppet_config[:ensure]).to eq(:present)
@keystone_puppet_config[:ensure] = :absent
expect(@keystone_puppet_config[:ensure]).to eq(:absent)
end
it 'should not accept invalid ensure values' do
expect {
@keystone_puppet_config[:ensure] = :latest
}.to raise_error(Puppet::Error, /Invalid value/)
end
it 'should autorequire the config file' do
catalog = Puppet::Resource::Catalog.new
config_file = Puppet::Type.type(:file).new(:name => '/etc/keystone/puppet.conf')
catalog.add_resource config_file, @keystone_puppet_config
dependency = @keystone_puppet_config.autorequire
expect(dependency.size).to eq(1)
expect(dependency[0].target).to eq(@keystone_puppet_config)
expect(dependency[0].source).to eq(config_file)
end
end