sync keystone with upstream

master de419015bb96d83135b306d9fb34e77e033c26cb
  sources https://github.com/openstack/puppet-keystone

Partially Implements: blueprint upgrade-openstack-puppet-modules
Fuel-CI: disable

Change-Id: Idedef32288e214486d05225b09147b5b1c30cdab
This commit is contained in:
vsaienko 2015-06-22 18:50:19 +03:00 committed by Vasyl Saienko
parent 10a2fe87b9
commit 252969895a
89 changed files with 5785 additions and 2798 deletions

View File

@ -1,17 +1,14 @@
fixtures: fixtures:
repositories: repositories:
'apache': 'git://github.com/puppetlabs/puppetlabs-apache.git' 'apache': 'git://github.com/puppetlabs/puppetlabs-apache.git'
'apt': 'git://github.com/puppetlabs/puppetlabs-apt.git'
'mysql':
repo: 'git://github.com/puppetlabs/puppetlabs-mysql.git'
ref: 'origin/0.x'
'stdlib': 'git://github.com/puppetlabs/puppetlabs-stdlib.git'
'inifile': 'git://github.com/puppetlabs/puppetlabs-inifile'
'postgresql':
repo: 'git://github.com/puppetlabs/puppetlabs-postgresql.git'
ref: '2.5.0'
'concat': 'concat':
'repo': 'git://github.com/puppetlabs/puppetlabs-concat.git' 'repo': 'git://github.com/puppetlabs/puppetlabs-concat.git'
'ref': '1.2.1' 'ref': '1.2.1'
'apt': 'git://github.com/puppetlabs/puppetlabs-apt.git'
'mysql': 'git://github.com/puppetlabs/puppetlabs-mysql.git'
'openstacklib': 'git://github.com/stackforge/puppet-openstacklib.git'
'stdlib': 'git://github.com/puppetlabs/puppetlabs-stdlib.git'
'inifile': 'git://github.com/puppetlabs/puppetlabs-inifile'
'postgresql': 'git://github.com/puppetlabs/puppetlabs-postgresql.git'
symlinks: symlinks:
'keystone': "#{source_dir}" 'keystone': "#{source_dir}"

View File

@ -1,4 +0,0 @@
[gerrit]
host=review.openstack.org
port=29418
project=stackforge/puppet-keystone.git

View File

@ -2,8 +2,23 @@ source 'https://rubygems.org'
group :development, :test do group :development, :test do
gem 'puppetlabs_spec_helper', :require => false gem 'puppetlabs_spec_helper', :require => false
gem 'puppet-lint', '~> 0.3.2' gem 'rspec-puppet', '~> 2.1.0', :require => false
gem 'rake', '10.1.1'
gem 'metadata-json-lint'
gem 'puppet-lint-param-docs'
gem 'puppet-lint-absolute_classname-check'
gem 'puppet-lint-absolute_template_path'
gem 'puppet-lint-trailing_newline-check'
# Puppet 4.x related lint checks
gem 'puppet-lint-unquoted_string-check'
gem 'puppet-lint-leading_zero-check'
gem 'puppet-lint-variable_contains_upcase'
gem 'puppet-lint-numericvariable'
gem 'json'
gem 'webmock'
gem 'beaker-rspec', :require => false
end end
if puppetversion = ENV['PUPPET_GEM_VERSION'] if puppetversion = ENV['PUPPET_GEM_VERSION']

View File

@ -1,8 +1,4 @@
Puppet Labs Keystone Module - Puppet module for managing Keystone Copyright 2012 OpenStack Foundation
Copyright (C) 2012 Puppet Labs Inc
Puppet Labs can be contacted at: info@puppetlabs.com
Licensed under the Apache License, Version 2.0 (the "License"); Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License. you may not use this file except in compliance with the License.

View File

@ -1,13 +0,0 @@
name 'puppetlabs-keystone'
version '4.0.0'
source 'https://github.com/stackforge/puppet-keystone'
author 'Puppet Labs'
license 'Apache License 2.0'
summary 'Puppet Labs Keystone Module'
description 'Puppet module to install and configure the Openstack identity service'
project_page 'https://launchpad.net/puppet-keystone'
dependency 'puppetlabs/apache', '>=1.0.0 <2.0.0'
dependency 'puppetlabs/inifile', '>=1.0.0 <2.0.0'
dependency 'puppetlabs/mysql', '>=0.9.0 <3.0.0'
dependency 'puppetlabs/stdlib', '>= 3.2.0'

View File

@ -1,7 +1,7 @@
keystone keystone
======= =======
4.0.0 - 2014.1.0 - Icehouse 5.1.0 - 2014.2 - Juno
#### Table of Contents #### Table of Contents
@ -45,10 +45,10 @@ To utilize the keystone module's functionality you will need to declare multiple
```puppet ```puppet
class { 'keystone': class { 'keystone':
verbose => True, verbose => True,
catalog_type => 'sql', catalog_type => 'sql',
admin_token => 'random_uuid', admin_token => 'random_uuid',
sql_connection => 'mysql://keystone_admin:super_secret_db_password@openstack-controller.example.com/keystone', database_connection => 'mysql://keystone_admin:super_secret_db_password@openstack-controller.example.com/keystone',
} }
# Adds the admin credential to keystone. # Adds the admin credential to keystone.
@ -59,10 +59,10 @@ class { 'keystone::roles::admin':
# Installs the service user endpoint. # Installs the service user endpoint.
class { 'keystone::endpoint': class { 'keystone::endpoint':
public_address => '10.16.0.101', public_url => 'http://10.16.0.101:5000/v2.0',
admin_address => '10.16.1.101', admin_url => 'http://10.16.1.101:35357/v2.0',
internal_address => '10.16.2.101', internal_url => 'http://10.16.2.101:5000/v2.0',
region => 'example-1', region => 'example-1',
} }
``` ```
@ -148,7 +148,17 @@ Limitations
* If you've setup Openstack using previous versions of this module you need to be aware that it used UUID as the dedault to the token_format parameter but now defaults to PKI. If you're using this module to manage a Grizzly Openstack deployment that was set up using a development release of the modules or are attempting an upgrade from Folsom then you'll need to make sure you set the token_format to UUID at classification time. * If you've setup Openstack using previous versions of this module you need to be aware that it used UUID as the dedault to the token_format parameter but now defaults to PKI. If you're using this module to manage a Grizzly Openstack deployment that was set up using a development release of the modules or are attempting an upgrade from Folsom then you'll need to make sure you set the token_format to UUID at classification time.
* The Keystone Openstack service depends on a sqlalchemy database. If you are using puppetlabs-mysql to achieve this, there is a parameter called mysql_module that can be used to swap between the two supported versions: 0.9 and 2.2. This is needed because the puppetlabs-mysql module was rewritten and the custom type names have changed between versions. Beaker-Rspec
------------
This module has beaker-rspec tests
To run:
``shell
bundle install
bundle exec rspec spec/acceptance
``
Development Development
----------- -----------
@ -165,6 +175,78 @@ Contributors
Release Notes Release Notes
------------- -------------
**5.1.0**
* Allow disabling or delaying the token_flush cron
* crontab: ensure the script is run with shell
* Use openstackclient for keystone_* providers
* Add lib directories to $LOAD_PATH if not present
* Remove keystone.rb provider for keystone_endpoint
* Add timeout to API requests
* Test keystone_user password with Net::HTTP
* service_identity: add user/role ordering
* Fix password check for SSL endpoints
* add require json for to_json dependency
* spec: pin rspec-puppet to 1.0.1
* Switch to TLSv1
* handle missing project/tenant when using ldap backend
* Add support for LDAP connection pools
* Sync keystone.py with upstream to function with Juno
* Create resource cache upon creation
* Implement caching lookup for keystone_user_role
* Remove warnings from openstack responses
* Properly handle embedded newlines in csv
* support the ldap user_enabled_invert parameter
* Shorten HTTP request timeout length
* Tag packages with 'openstack'
* Allow Keystone to be queried when using IPv6 ::0
* Add ::keystone::policy class for policy management
* New option replace_password for keystone_user
* Pin puppetlabs-concat to 1.2.1 in fixtures
* Set WSGI process display-name
* Rename resource instance variable
* Add native types for keystone paste configuration
* Update .gitreview file for project rename
**5.0.0**
* Stable Juno release
* Updated token driver, logging, and ldap config parameters for Juno
* Changed admin_roles parameter to accept an array in order to configure multiple admin roles
* Installs python-ldappool package for ldap
* Added new parameters to keystone class to configure pki signing
* Changed keystone class to inherit from keystone::params
* Changed pki_setup to run regardless of token provider
* Made UUID the default token provider
* Made keystone_user_role idempotent
* Added parameters to control whether to configure users
* Stopped managing _member_ role since it is created automatically
* Stopped overriding token_flush log file
* Changed the usage of admin_endpoint to not include the API version
* Allowed keystone_user_role to accept email as username
* Added ability to set up keystone using Apache mod_wsgi
* Migrated the keystone::db::mysql class to use openstacklib::db::mysql and deprecated the mysql_module parameter
* Installs python-memcache when using token driver memcache
* Enabled setting cert and key paths for PKI token signing
* Added parameters for SSL communication between keystone and rabbitmq
* Added parameter ignore_default_tenant to keystone::role::admin
* Added parameter service_provider to keystone class
* Added parameters for service validation to keystone class
**4.2.0**
* Added class for extended logging options
* Fixed rabbit password leaking
* Added parameters to set tenant descriptions
* Fixed keystone user authorization error handling
**4.1.0**
* Added token flushing with cron.
* Updated database api for consistency with other projects.
* Fixed admin_token with secret parameter.
* Fixed deprecated catalog driver.
**4.0.0** **4.0.0**
* Stable Icehouse release. * Stable Icehouse release.

View File

@ -20,30 +20,30 @@
Exec { logoutput => 'on_failure' } Exec { logoutput => 'on_failure' }
class { 'mysql::server': } class { '::mysql::server': }
class { 'keystone::db::mysql': class { '::keystone::db::mysql':
password => 'keystone', password => 'keystone',
} }
class { 'keystone': class { '::keystone':
verbose => true, verbose => true,
debug => true, debug => true,
sql_connection => 'mysql://keystone:keystone@127.0.0.1/keystone', database_connection => 'mysql://keystone:keystone@127.0.0.1/keystone',
catalog_type => 'sql', catalog_type => 'sql',
admin_token => 'admin_token', admin_token => 'admin_token',
enabled => false, enabled => false,
} }
class { 'keystone::roles::admin': class { '::keystone::roles::admin':
email => 'test@puppetlabs.com', email => 'test@puppetlabs.com',
password => 'ChangeMe', password => 'ChangeMe',
} }
class { 'keystone::endpoint': class { '::keystone::endpoint':
public_url => "https://${::fqdn}:5000/", public_url => "https://${::fqdn}:5000/",
admin_url => "https://${::fqdn}:35357/", admin_url => "https://${::fqdn}:35357/",
} }
keystone_config { 'ssl/enable': value => true } keystone_config { 'ssl/enable': value => true }
include apache include ::apache
class { 'keystone::wsgi::apache': class { '::keystone::wsgi::apache':
ssl => true ssl => true
} }

View File

@ -20,31 +20,32 @@
Exec { logoutput => 'on_failure' } Exec { logoutput => 'on_failure' }
class { 'mysql::server': } class { '::mysql::server': }
class { 'keystone::db::mysql': class { '::keystone::db::mysql':
password => 'keystone', password => 'keystone',
} }
class { 'keystone': class { '::keystone':
verbose => true, verbose => true,
debug => true, debug => true,
sql_connection => 'mysql://keystone_admin:keystone@127.0.0.1/keystone', database_connection => 'mysql://keystone_admin:keystone@127.0.0.1/keystone',
catalog_type => 'sql', catalog_type => 'sql',
admin_token => 'admin_token', admin_token => 'admin_token',
enabled => true, enabled => true,
} }
class { 'keystone::roles::admin': class { '::keystone::cron::token_flush': }
class { '::keystone::roles::admin':
email => 'test@puppetlabs.com', email => 'test@puppetlabs.com',
password => 'ChangeMe', password => 'ChangeMe',
} }
class { 'keystone::endpoint': class { '::keystone::endpoint':
public_url => "https://${::fqdn}:443/main/", public_url => "https://${::fqdn}:443/main/",
admin_address => "https://${::fqdn}:443/admin/", admin_url => "https://${::fqdn}:443/admin/",
} }
keystone_config { 'ssl/enable': ensure => absent } keystone_config { 'ssl/enable': ensure => absent }
include apache include ::apache
class { 'keystone::wsgi::apache': class { '::keystone::wsgi::apache':
ssl => true, ssl => true,
public_port => 443, public_port => 443,
admin_port => 443, admin_port => 443,

View File

@ -3,7 +3,7 @@
# Ensure this matches what is in LDAP or keystone will try to recreate # Ensure this matches what is in LDAP or keystone will try to recreate
# the admin user # the admin user
class { 'keystone::roles::admin': class { '::keystone::roles::admin':
email => 'test@example.com', email => 'test@example.com',
password => 'ChangeMe', password => 'ChangeMe',
} }
@ -12,55 +12,61 @@ class { 'keystone::roles::admin':
# LDAP configurations are *highly* dependent on your setup and this file # LDAP configurations are *highly* dependent on your setup and this file
# will need to be tweaked. This sample talks to ldap.example.com, here is # will need to be tweaked. This sample talks to ldap.example.com, here is
# an example of ldapsearch that will search users on this box: # an example of ldapsearch that will search users on this box:
# ldapsearch -v -x -H 'ldap://69.134.70.154:389' -D \ # ldapsearch -v -x -H 'ldap://example.com:389' -D \
# "uid=bind,cn=users,cn=accounts,dc=example,dc=com" -w SecretPass \ # "uid=bind,cn=users,cn=accounts,dc=example,dc=com" -w SecretPass \
# -b cn=users,cn=accounts,dc=example,dc=com # -b cn=users,cn=accounts,dc=example,dc=com
class { 'keystone:ldap': class { '::keystone:ldap':
url => 'ldap://ldap.example.com:389', url => 'ldap://ldap.example.com:389',
user => 'uid=bind,cn=users,cn=accounts,dc=example,dc=com', user => 'uid=bind,cn=users,cn=accounts,dc=example,dc=com',
password => 'SecretPass', password => 'SecretPass',
suffix => 'dc=example,dc=com', suffix => 'dc=example,dc=com',
query_scope => 'sub', query_scope => 'sub',
user_tree_dn => 'cn=users,cn=accounts,dc=example,dc=com', user_tree_dn => 'cn=users,cn=accounts,dc=example,dc=com',
user_id_attribute => 'uid', user_id_attribute => 'uid',
user_name_attribute => 'uid', user_name_attribute => 'uid',
user_mail_attribute => 'mail', user_mail_attribute => 'mail',
user_allow_create => 'False', user_allow_create => 'False',
user_allow_update => 'False', user_allow_update => 'False',
user_allow_delete => 'False', user_allow_delete => 'False',
user_enabled_emulation => 'True', user_enabled_emulation => 'True',
user_enabled_emulation_dn => 'cn=openstack-enabled,cn=groups,cn=accounts,dc=example,dc=com', user_enabled_emulation_dn => 'cn=openstack-enabled,cn=groups,cn=accounts,dc=example,dc=com',
group_tree_dn => 'ou=groups,ou=openstack,dc=example,dc=com', group_tree_dn => 'ou=groups,ou=openstack,dc=example,dc=com',
group_objectclass => 'organizationalRole', group_objectclass => 'organizationalRole',
group_id_attribute => 'cn', group_id_attribute => 'cn',
group_name_attribute => 'cn', group_name_attribute => 'cn',
group_member_attribute => 'RoleOccupant', group_member_attribute => 'RoleOccupant',
group_desc_attribute => 'description', group_desc_attribute => 'description',
group_allow_create => 'True', group_allow_create => 'True',
group_allow_update => 'True', group_allow_update => 'True',
group_allow_delete => 'True', group_allow_delete => 'True',
tenant_tree_dn => 'ou=projects,ou=openstack,dc=example,dc=com', project_tree_dn => 'ou=projects,ou=openstack,dc=example,dc=com',
tenant_objectclass => 'organizationalUnit', project_objectclass => 'organizationalUnit',
tenant_id_attribute => 'ou', project_id_attribute => 'ou',
tenant_member_attribute => 'member', project_member_attribute => 'member',
tenant_name_attribute => 'ou', project_name_attribute => 'ou',
tenant_desc_attribute => 'description', project_desc_attribute => 'description',
tenant_allow_create => 'True', project_allow_create => 'True',
tenant_allow_update => 'True', project_allow_update => 'True',
tenant_allow_delete => 'True', project_allow_delete => 'True',
tenant_enabled_emulation => 'True', project_enabled_emulation => 'True',
tenant_enabled_emulation_dn => 'cn=enabled,ou=openstack,dc=example,dc=com', project_enabled_emulation_dn => 'cn=enabled,ou=openstack,dc=example,dc=com',
role_tree_dn => 'ou=roles,ou=openstack,dc=example,dc=com', role_tree_dn => 'ou=roles,ou=openstack,dc=example,dc=com',
role_objectclass => 'organizationalRole', role_objectclass => 'organizationalRole',
role_id_attribute => 'cn', role_id_attribute => 'cn',
role_name_attribute => 'cn', role_name_attribute => 'cn',
role_member_attribute => 'roleOccupant', role_member_attribute => 'roleOccupant',
role_allow_create => 'True', role_allow_create => 'True',
role_allow_update => 'True', role_allow_update => 'True',
role_allow_delete => 'True', role_allow_delete => 'True',
identity_driver => 'keystone.identity.backends.ldap.Identity', identity_driver => 'keystone.identity.backends.ldap.Identity',
assignment_driver => 'keystone.assignment.backends.ldap.Assignment', assignment_driver => 'keystone.assignment.backends.ldap.Assignment',
use_tls => 'True', use_tls => 'True',
tls_cacertfile => '/etc/ssl/certs/ca-certificates.crt', tls_cacertfile => '/etc/ssl/certs/ca-certificates.crt',
tls_req_cert => 'demand', tls_req_cert => 'demand',
use_pool => 'True',
use_auth_pool => 'True',
pool_size => 5,
auth_pool_size => 5,
pool_retry_max => 3,
pool_connection_timeout => 120,
} }

View File

@ -3,7 +3,7 @@
# Ensure this matches what is in LDAP or keystone will try to recreate # Ensure this matches what is in LDAP or keystone will try to recreate
# the admin user # the admin user
class { 'keystone::roles::admin': class { '::keystone::roles::admin':
email => 'test@example.com', email => 'test@example.com',
password => 'ChangeMe', password => 'ChangeMe',
} }
@ -11,18 +11,18 @@ class { 'keystone::roles::admin':
# You can test this connection with ldapsearch first to ensure it works. # You can test this connection with ldapsearch first to ensure it works.
# This was tested against a FreeIPA box, you will likely need to change the # This was tested against a FreeIPA box, you will likely need to change the
# attributes to match your configuration. # attributes to match your configuration.
class { 'keystone:ldap': class { '::keystone:ldap':
identity_driver => 'keystone.identity.backends.ldap.Identity', identity_driver => 'keystone.identity.backends.ldap.Identity',
url => 'ldap://ldap.example.com:389', url => 'ldap://ldap.example.com:389',
user => 'uid=bind,cn=users,cn=accounts,dc=example,dc=com', user => 'uid=bind,cn=users,cn=accounts,dc=example,dc=com',
password => 'SecretPass', password => 'SecretPass',
suffix => 'dc=example,dc=com', suffix => 'dc=example,dc=com',
query_scope => 'sub', query_scope => 'sub',
user_tree_dn => 'cn=users,cn=accounts,dc=example,dc=com', user_tree_dn => 'cn=users,cn=accounts,dc=example,dc=com',
user_id_attribute => 'uid', user_id_attribute => 'uid',
user_name_attribute => 'uid', user_name_attribute => 'uid',
user_mail_attribute => 'mail', user_mail_attribute => 'mail',
user_allow_create => 'False', user_allow_create => 'False',
user_allow_update => 'False', user_allow_update => 'False',
user_allow_delete => 'False' user_allow_delete => 'False'
} }

View File

@ -13,6 +13,7 @@
# under the License. # under the License.
# #
# This file was copied from https://github.com/openstack/keystone/raw/0b676730347c76c7f64a67c1ad0135663e99c4fc/httpd/keystone.py
# It's only required for platforms on which it is not packaged yet. # It's only required for platforms on which it is not packaged yet.
# It should be removed when available everywhere in a package. # It should be removed when available everywhere in a package.
# #

View File

@ -1,7 +1,35 @@
require 'puppet/util/inifile' require 'puppet/util/inifile'
class Puppet::Provider::Keystone < Puppet::Provider require 'puppet/provider/openstack'
require 'puppet/provider/openstack/auth'
require 'puppet/provider/openstack/credentials'
class Puppet::Provider::Keystone < Puppet::Provider::Openstack
extend Puppet::Provider::Openstack::Auth
INI_FILENAME = '/etc/keystone/keystone.conf'
def self.get_endpoint
endpoint = nil
if ENV['OS_AUTH_URL']
endpoint = ENV['OS_AUTH_URL']
else
endpoint = get_os_vars_from_rcfile(rc_filename)['OS_AUTH_URL']
unless endpoint
# This is from legacy but seems wrong, we want auth_url not url!
endpoint = get_admin_endpoint
end
end
unless endpoint
raise(Puppet::Error::OpenstackAuthInputError, 'Could not find auth url to check user password.')
end
endpoint
end
def self.admin_endpoint
@admin_endpoint ||= get_admin_endpoint
end
# retrieves the current token from keystone.conf
def self.admin_token def self.admin_token
@admin_token ||= get_admin_token @admin_token ||= get_admin_token
end end
@ -10,181 +38,79 @@ class Puppet::Provider::Keystone < Puppet::Provider
if keystone_file and keystone_file['DEFAULT'] and keystone_file['DEFAULT']['admin_token'] if keystone_file and keystone_file['DEFAULT'] and keystone_file['DEFAULT']['admin_token']
return "#{keystone_file['DEFAULT']['admin_token'].strip}" return "#{keystone_file['DEFAULT']['admin_token'].strip}"
else else
raise(Puppet::Error, "File: /etc/keystone/keystone.conf does not contain a section DEFAULT with the admin_token specified. Keystone types will not work if keystone is not correctly configured") return nil
end end
end end
def self.admin_endpoint
@admin_endpoint ||= get_admin_endpoint
end
def self.get_admin_endpoint def self.get_admin_endpoint
admin_endpoint = keystone_file['DEFAULT']['admin_endpoint'] ? keystone_file['DEFAULT']['admin_endpoint'].strip : nil if keystone_file
return admin_endpoint if admin_endpoint if keystone_file['DEFAULT']
if keystone_file['DEFAULT']['admin_endpoint']
auth_url = keystone_file['DEFAULT']['admin_endpoint'].strip.chomp('/')
return "#{auth_url}/v#{@credentials.version}/"
end
admin_port = keystone_file['DEFAULT']['admin_port'] ? keystone_file['DEFAULT']['admin_port'].strip : '35357' if keystone_file['DEFAULT']['admin_port']
ssl = keystone_file['ssl'] && keystone_file['ssl']['enable'] ? keystone_file['ssl']['enable'].strip.downcase == 'true' : false admin_port = keystone_file['DEFAULT']['admin_port'].strip
protocol = ssl ? 'https' : 'http' else
if keystone_file and keystone_file['DEFAULT'] and keystone_file['DEFAULT']['admin_bind_host'] admin_port = '35357'
host = keystone_file['DEFAULT']['admin_bind_host'].strip end
if host == "0.0.0.0"
host = "127.0.0.1" if keystone_file['DEFAULT']['admin_bind_host']
host = keystone_file['DEFAULT']['admin_bind_host'].strip
if host == "0.0.0.0"
host = "127.0.0.1"
elsif host == '::0'
host = '[::1]'
end
else
host = "127.0.0.1"
end
end
if keystone_file['ssl'] && keystone_file['ssl']['enable'] && keystone_file['ssl']['enable'].strip.downcase == 'true'
protocol = 'https'
else
protocol = 'http'
end end
else
host = "127.0.0.1"
end end
"#{protocol}://#{host}:#{admin_port}/v2.0/"
"#{protocol}://#{host}:#{admin_port}/v#{@credentials.version}/"
end
def self.request(service, action, properties=nil)
super
rescue Puppet::Error::OpenstackAuthInputError => error
request_by_service_token(service, action, error, properties)
end
def self.request_by_service_token(service, action, error, properties=nil)
properties ||= []
@credentials.token = get_admin_token
@credentials.url = get_admin_endpoint
raise error unless @credentials.service_token_set?
Puppet::Provider::Openstack.request(service, action, properties, @credentials)
end
def self.ini_filename
INI_FILENAME
end end
def self.keystone_file def self.keystone_file
return @keystone_file if @keystone_file return @keystone_file if @keystone_file
@keystone_file = Puppet::Util::IniConfig::File.new if File.exists?(ini_filename)
@keystone_file.read('/etc/keystone/keystone.conf') @keystone_file = Puppet::Util::IniConfig::File.new
@keystone_file @keystone_file.read(ini_filename)
end @keystone_file
def self.tenant_hash
@tenant_hash = build_tenant_hash
end
def tenant_hash
self.class.tenant_hash
end
def self.reset
@admin_endpoint = nil
@tenant_hash = nil
@admin_token = nil
@keystone_file = nil
end
# the path to withenv changes between versions of puppet, so redefining this function here,
# Run some code with a specific environment. Resets the environment at the end of the code.
def self.withenv(hash, &block)
saved = ENV.to_hash
hash.each do |name, val|
ENV[name.to_s] = val
end
block.call
ensure
ENV.clear
saved.each do |name, val|
ENV[name] = val
end end
end end
def self.auth_keystone(*args) # Helper functions to use on the pre-validated enabled field
authenv = {:OS_SERVICE_TOKEN => admin_token} def bool_to_sym(bool)
begin bool == true ? :true : :false
withenv authenv do
remove_warnings(keystone('--os-endpoint', admin_endpoint, args))
end
rescue Exception => e
if e.message =~ /(\(HTTP\s+400\))|(\[Errno 111\]\s+Connection\s+refused)|(503\s+Service\s+Unavailable)|(Max\s+retries\s+exceeded)|(Unable\s+to\s+establish\s+connection)/
sleep 10
withenv authenv do
remove_warnings(keystone('--os-endpoint', admin_endpoint, args))
end
else
raise(e)
end
end
end end
def auth_keystone(*args) def sym_to_bool(sym)
self.class.auth_keystone(args) sym == :true ? true : false
end end
def self.creds_keystone(name, tenant, password, *args)
authenv = {:OS_USERNAME => name, :OS_TENANT_NAME => tenant, :OS_PASSWORD => password}
begin
withenv authenv do
remove_warnings(keystone('--os-auth-url', admin_endpoint, args))
end
rescue Exception => e
if e.message =~ /(\(HTTP\s+400\))|(\[Errno 111\]\s+Connection\s+refused)|(503\s+Service\s+Unavailable)|(Max\s+retries\s+exceeded)|(Unable\s+to\s+establish\s+connection)/
sleep 10
withenv authenv do
remove_warnings(keystone('--os-auth-url', admin_endpoint, args))
end
else
raise(e)
end
end
end
def creds_keystone(name, tenant, password, *args)
self.class.creds_keystone(name, tenant, password, args)
end
def self.parse_keystone_object(data)
# Parse the output of [type]-{create,get} into a hash
attrs = {}
header_lines = 3
footer_lines = 1
data.split("\n")[header_lines...-footer_lines].each do |line|
if match_data = /\|\s([^|]+)\s\|\s([^|]+)\s\|/.match(line)
attrs[match_data[1].strip] = match_data[2].strip
end
end
attrs
end
private
def self.list_keystone_objects(type, number_columns, *args)
# this assumes that all returned objects are of the form
# id, name, enabled_state, OTHER
# number_columns can be a Fixnum or an Array of possible values that can be returned
list = (auth_keystone("#{type}-list", args).split("\n")[3..-2] || []).collect do |line|
row = line.split(/\|/)[1..-1]
row = row.map {|x| x.strip }
# if both checks fail then we have a mismatch between what was expected and what was received
if (number_columns.class == Array and !number_columns.include? row.size) or (number_columns.class == Fixnum and row.size != number_columns)
raise(Puppet::Error, "Expected #{number_columns} columns for #{type} row, found #{row.size}. Line #{line}")
end
row
end
list
end
def self.get_keystone_object(type, id, attr)
id = id.chomp
auth_keystone("#{type}-get", id).split(/\|\n/m).each do |line|
if line =~ /\|(\s+)?#{attr}(\s+)?\|/
if line.kind_of?(Array)
return line[0].split("|")[2].strip
else
return line.split("|")[2].strip
end
else
nil
end
end
raise(Puppet::Error, "Could not find colummn #{attr} when getting #{type} #{id}")
end
# remove warning from the output. this is a temporary hack until
# I refactor things to use the the rest API
def self.remove_warnings(results)
found_header = false
in_warning = false
results.split("\n").collect do |line|
unless found_header
if line =~ /^\+[-\+]+\+$/
in_warning = false
found_header = true
line
elsif line =~ /^WARNING/ or line =~ /UserWarning/ or in_warning
# warnings can be multi line, we have to skip all of them
in_warning = true
nil
else
line
end
else
line
end
end.compact.join("\n")
end
end end

View File

@ -1,125 +0,0 @@
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', '..'))
require 'puppet/provider/keystone'
Puppet::Type.type(:keystone_endpoint).provide(
:keystone,
:parent => Puppet::Provider::Keystone
) do
desc <<-EOT
Provider that uses the keystone client tool to
manage keystone endpoints
This provider makes a few assumptions/
1. assumes that the admin endpoint can be accessed via localhost.
2. Assumes that the admin token and port can be accessed from
/etc/keystone/keystone.conf
EOT
optional_commands :keystone => "keystone"
def initialize(resource = nil)
super(resource)
@property_flush = {}
end
def self.prefetch(resources)
endpoints = instances
resources.keys.each do |name|
if provider = endpoints.find{ |endpoint| endpoint.name == name }
resources[name].provider = provider
end
end
end
def self.instances
list_keystone_objects('endpoint', [5,6]).collect do |endpoint|
service_name = get_keystone_object('service', endpoint[5], 'name')
new(
:name => "#{endpoint[1]}/#{service_name}",
:ensure => :present,
:id => endpoint[0],
:region => endpoint[1],
:public_url => endpoint[2],
:internal_url => endpoint[3],
:admin_url => endpoint[4],
:service_id => endpoint[5],
:service_name => service_name
)
end
end
def create
optional_opts = []
{
:public_url => '--publicurl',
:internal_url => '--internalurl',
:admin_url => '--adminurl'
}.each do |param, opt|
if resource[param]
optional_opts.push(opt).push(resource[param])
end
end
(region, service_name) = resource[:name].split('/')
resource[:region] = region
optional_opts.push('--region').push(resource[:region])
service_id = self.class.list_keystone_objects('service', 4).detect do |s|
s[1] == service_name
end.first
auth_keystone('endpoint-create', '--service-id', service_id, optional_opts)
end
def exists?
@property_hash[:ensure] == :present
end
def destroy
auth_keystone('endpoint-delete', @property_hash[:id])
end
def flush
if ! @property_flush.empty?
destroy
create
@property_flush.clear
end
@property_hash = resource.to_hash
end
def id
@property_hash[:id]
end
def region
@property_hash[:region]
end
def public_url
@property_hash[:public_url]
end
def internal_url
@property_hash[:internal_url]
end
def admin_url
@property_hash[:admin_url]
end
def public_url=(value)
@property_hash[:public_url] = value
@property_flush[:public_url] = value
end
def internal_url=(value)
@property_hash[:internal_url] = value
@property_flush[:internal_url] = value
end
def admin_url=(value)
@property_hash[:admin_url] = value
@property_flush[:admin_url] = value
end
end

View File

@ -0,0 +1,112 @@
require 'puppet/provider/keystone'
Puppet::Type.type(:keystone_endpoint).provide(
:openstack,
:parent => Puppet::Provider::Keystone
) do
desc "Provider to manage keystone endpoints."
@credentials = Puppet::Provider::Openstack::CredentialsV2_0.new
def initialize(value={})
super(value)
@property_flush = {}
end
def create
properties = []
# The region property is just ignored. We should fix this in kilo.
region, name = resource[:name].split('/')
properties << name
properties << '--region'
properties << region
if resource[:public_url]
properties << '--publicurl'
properties << resource[:public_url]
end
if resource[:internal_url]
properties << '--internalurl'
properties << resource[:internal_url]
end
if resource[:admin_url]
properties << '--adminurl'
properties << resource[:admin_url]
end
self.class.request('endpoint', 'create', properties)
@property_hash[:ensure] = :present
end
def destroy
self.class.request('endpoint', 'delete', @property_hash[:id])
@property_hash.clear
end
def exists?
@property_hash[:ensure] == :present
end
def region
@property_hash[:region]
end
def public_url=(value)
@property_flush[:public_url] = value
end
def public_url
@property_hash[:public_url]
end
def internal_url=(value)
@property_flush[:internal_url] = value
end
def internal_url
@property_hash[:internal_url]
end
def admin_url=(value)
@property_flush[:admin_url] = value
end
def admin_url
@property_hash[:admin_url]
end
def id
@property_hash[:id]
end
def self.instances
list = request('endpoint', 'list', '--long')
list.collect do |endpoint|
new(
:name => "#{endpoint[:region]}/#{endpoint[:service_name]}",
:ensure => :present,
:id => endpoint[:id],
:region => endpoint[:region],
:public_url => endpoint[:publicurl],
:internal_url => endpoint[:internalurl],
:admin_url => endpoint[:adminurl]
)
end
end
def self.prefetch(resources)
endpoints = instances
resources.keys.each do |name|
if provider = endpoints.find{ |endpoint| endpoint.name == name }
resources[name].provider = provider
end
end
end
def flush
if ! @property_flush.empty?
destroy
create
@property_flush.clear
end
end
end

View File

@ -0,0 +1,27 @@
Puppet::Type.type(:keystone_paste_ini).provide(
:ini_setting,
:parent => Puppet::Type.type(:ini_setting).provider(:ruby)
) do
def section
resource[:name].split('/', 2).first
end
def setting
resource[:name].split('/', 2).last
end
def separator
'='
end
def self.file_path
'/etc/keystone/keystone-paste.ini'
end
# this needs to be removed. This has been replaced with the class method
def file_path
self.class.file_path
end
end

View File

@ -1,65 +0,0 @@
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', '..'))
require 'puppet/provider/keystone'
Puppet::Type.type(:keystone_role).provide(
:keystone,
:parent => Puppet::Provider::Keystone
) do
desc <<-EOT
Provider that uses the keystone client tool to
manage keystone roles
EOT
optional_commands :keystone => "keystone"
def self.prefetch(resource)
# rebuild the cahce for every puppet run
@role_hash = nil
end
def self.role_hash
@role_hash = build_role_hash
end
def role_hash
self.class.role_hash
end
def self.instances
role_hash.collect do |k, v|
new(:name => k)
end
end
def create
auth_keystone(
'role-create',
'--name', resource[:name]
)
end
def exists?
role_hash[resource[:name]]
end
def destroy
auth_keystone('role-delete', role_hash[resource[:name]][:id])
end
def id
role_hash[resource[:name]][:id]
end
private
def self.build_role_hash
hash = {}
list_keystone_objects('role', 2).each do |role|
hash[role[1]] = {
:id => role[0],
}
end
hash
end
end

View File

@ -0,0 +1,54 @@
require 'puppet/provider/keystone'
Puppet::Type.type(:keystone_role).provide(
:openstack,
:parent => Puppet::Provider::Keystone
) do
desc 'Provider for keystone roles.'
@credentials = Puppet::Provider::Openstack::CredentialsV2_0.new
def initialize(value={})
super(value)
@property_flush = {}
end
def create
self.class.request('role', 'create', name)
@property_hash[:ensure] = :present
end
def destroy
self.class.request('role', 'delete', @property_hash[:id])
@property_hash.clear
end
def exists?
@property_hash[:ensure] == :present
end
def id
@property_hash[:id]
end
def self.instances
list = request('role', 'list')
list.collect do |role|
new(
:name => role[:name],
:ensure => :present,
:id => role[:id]
)
end
end
def self.prefetch(resources)
roles = instances
resources.keys.each do |name|
if provider = roles.find{ |role| role.name == name }
resources[name].provider = provider
end
end
end
end

View File

@ -1,97 +0,0 @@
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', '..'))
require 'puppet/provider/keystone'
Puppet::Type.type(:keystone_service).provide(
:keystone,
:parent => Puppet::Provider::Keystone
) do
desc <<-EOT
Provider that uses the keystone client tool to
manage keystone services
This provider makes a few assumptions/
1. assumes that the admin endpoint can be accessed via localhost.
2. Assumes that the admin token and port can be accessed from
/etc/keystone/keystone.conf
Does not support the ability to list all
EOT
optional_commands :keystone => "keystone"
def self.prefetch(resource)
# rebuild the cahce for every puppet run
@service_hash = nil
end
def self.service_hash
@service_hash = build_service_hash
end
def service_hash
self.class.service_hash
end
def self.instances
service_hash.collect do |k, v|
new(:name => k)
end
end
def create
optional_opts = []
raise(Puppet::Error, "Required property type not specified for KeystoneService[#{resource[:name]}]") unless resource[:type]
if resource[:description]
optional_opts.push('--description').push(resource[:description])
end
auth_keystone(
'service-create',
'--name', resource[:name],
'--type', resource[:type],
optional_opts
)
end
def exists?
service_hash[resource[:name]]
end
def destroy
auth_keystone('service-delete', service_hash[resource[:name]][:id])
end
def id
service_hash[resource[:name]][:id]
end
def type
service_hash[resource[:name]][:type]
end
def type=(value)
raise(Puppet::Error, "service-update is not currently supported by the keystone sql driver")
end
def description
service_hash[resource[:name]][:description]
end
def description=(value)
raise(Puppet::Error, "service-update is not currently supported by the keystone sql driver")
end
private
def self.build_service_hash
hash = {}
list_keystone_objects('service', 4).each do |user|
hash[user[1]] = {
:id => user[0],
:type => user[2],
:description => user[3]
}
end
hash
end
end

View File

@ -0,0 +1,88 @@
require 'puppet/provider/keystone'
Puppet::Type.type(:keystone_service).provide(
:openstack,
:parent => Puppet::Provider::Keystone
) do
desc "Provider to manage keystone services."
@credentials = Puppet::Provider::Openstack::CredentialsV2_0.new
def initialize(value={})
super(value)
@property_flush = {}
end
def create
properties = ['--name']
properties << resource[:name]
if resource[:description]
properties << '--description'
properties << resource[:description]
end
raise(Puppet::Error, 'The service type is mandatory') unless resource[:type]
properties << resource[:type]
self.class.request('service', 'create', properties)
@property_hash[:ensure] = :present
end
def exists?
@property_hash[:ensure] == :present
end
def destroy
self.class.request('service', 'delete', @property_hash[:id])
@property_hash.clear
end
def description=(value)
@property_flush[:description] = value
end
def description
@property_hash[:description]
end
def type=(value)
@property_flush[:type] = value
end
def type
@property_hash[:type]
end
def id
@property_hash[:id]
end
def self.instances
list = request('service', 'list', '--long')
list.collect do |service|
new(
:name => service[:name],
:ensure => :present,
:type => service[:type],
:description => service[:description],
:id => service[:id]
)
end
end
def self.prefetch(resources)
services = instances
resources.keys.each do |name|
if provider = services.find{ |service| service.name == name }
resources[name].provider = provider
end
end
end
def flush
if ! @property_flush.empty?
destroy
create
@property_flush.clear
end
end
end

View File

@ -1,120 +0,0 @@
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', '..'))
require 'puppet/provider/keystone'
Puppet::Type.type(:keystone_tenant).provide(
:keystone,
:parent => Puppet::Provider::Keystone
) do
desc <<-EOT
Provider that uses the keystone client tool to
manage keystone tenants
This provider makes a few assumptions/
1. assumes that the admin endpoint can be accessed via localhost.
2. Assumes that the admin token and port can be accessed from
/etc/keystone/keystone.conf
One string difference, is that it does not know how to change the
name of a tenant
EOT
optional_commands :keystone => "keystone"
def self.prefetch(resource)
# rebuild the cahce for every puppet run
@tenant_hash = nil
end
def self.tenant_hash
@tenant_hash = build_tenant_hash
end
def tenant_hash
self.class.tenant_hash
end
def instance
tenant_hash[resource[:name]]
end
def self.instances
tenant_hash.collect do |k, v|
new(
:name => k,
:id => v[:id]
)
end
end
def create
optional_opts = []
if resource[:description]
optional_opts.push('--description').push(resource[:description])
end
results = auth_keystone(
'tenant-create',
'--name', resource[:name],
'--enabled', resource[:enabled],
optional_opts
)
if results =~ /Property\s|\sValue/
attrs = self.class.parse_keystone_object(results)
tenant_hash[resource[:name]] = {
:ensure => :present,
:name => resource[:name],
:id => attrs['id'],
:enabled => attrs['enabled'],
:description => attrs['description'],
}
else
fail("did not get expected message on tenant creation, got #{results}")
end
end
def exists?
instance
end
def destroy
auth_keystone('tenant-delete', instance[:id])
instance[:ensure] = :absent
end
def enabled=(value)
Puppet.warning("I am not sure if this is supported yet")
auth_keystone("tenant-update", '--enabled', value, instance[:id])
instance[:enabled] = value
end
def description
self.class.get_keystone_object('tenant', instance[:id], 'description')
end
def description=(value)
auth_keystone("tenant-update", '--description', value, instance[:id])
instance[:description] = value
end
[
:id,
:enabled,
].each do |attr|
define_method(attr.to_s) do
instance[attr] || :absent
end
end
private
def self.build_tenant_hash
hash = {}
list_keystone_objects('tenant', 3).each do |tenant|
hash[tenant[1]] = {
:id => tenant[0],
:enabled => tenant[2],
}
end
hash
end
end

View File

@ -0,0 +1,99 @@
require 'puppet/provider/keystone'
Puppet::Type.type(:keystone_tenant).provide(
:openstack,
:parent => Puppet::Provider::Keystone
) do
desc "Provider to manage keystone tenants/projects."
@credentials = Puppet::Provider::Openstack::CredentialsV2_0.new
def initialize(value={})
super(value)
@property_flush = {}
end
def create
properties = [resource[:name]]
if resource[:enabled] == :true
properties << '--enable'
elsif resource[:enabled] == :false
properties << '--disable'
end
if resource[:description]
properties << '--description'
properties << resource[:description]
end
self.class.request('project', 'create', properties)
@property_hash[:ensure] = :present
end
def exists?
@property_hash[:ensure] == :present
end
def destroy
self.class.request('project', 'delete', @property_hash[:id])
@property_hash.clear
end
def enabled=(value)
@property_flush[:enabled] = value
end
def enabled
bool_to_sym(@property_hash[:enabled])
end
def description=(value)
@property_flush[:description] = value
end
def description
@property_hash[:description]
end
def id
@property_hash[:id]
end
def self.instances
list = request('project', 'list', '--long')
list.collect do |project|
new(
:name => project[:name],
:ensure => :present,
:enabled => project[:enabled].downcase.chomp == 'true' ? true : false,
:description => project[:description],
:id => project[:id]
)
end
end
def self.prefetch(resources)
tenants = instances
resources.keys.each do |name|
if provider = tenants.find{ |tenant| tenant.name == name }
resources[name].provider = provider
end
end
end
def flush
options = []
if @property_flush && !@property_flush.empty?
case @property_flush[:enabled]
when :true
options << '--enable'
when :false
options << '--disable'
end
(options << "--description=#{resource[:description]}") if @property_flush[:description]
options << @property_hash[:id]
self.class.request('project', 'set', options) unless options.empty?
@property_flush.clear
end
end
end

View File

@ -1,172 +0,0 @@
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', '..'))
require 'puppet/provider/keystone'
Puppet::Type.type(:keystone_user).provide(
:keystone,
:parent => Puppet::Provider::Keystone
) do
desc <<-EOT
Provider that uses the keystone client tool to
manage keystone users
This provider makes a few assumptions/
1. assumes that the admin endpoint can be accessed via localhost.
2. Assumes that the admin token and port can be accessed from
/etc/keystone/keystone.conf
Does not support the ability to update the user's name
EOT
optional_commands :keystone => "keystone"
def self.prefetch(resource)
# rebuild the cahce for every puppet run
@user_hash = nil
end
def self.user_hash
@user_hash = build_user_hash
end
def user_hash
self.class.user_hash
end
def self.instances
user_hash.collect do |k, v|
new(:name => k)
end
end
def create
optional_opts = []
if resource[:email]
optional_opts.push('--email').push(resource[:email])
end
if resource[:password]
optional_opts.push('--pass').push(resource[:password])
end
if resource[:tenant]
tenant_id = self.class.list_keystone_objects('tenant', 3).collect {|x|
x[0] if x[1] == resource[:tenant]
}.compact[0]
optional_opts.push('--tenant_id').push(tenant_id)
end
auth_keystone(
'user-create',
'--name', resource[:name],
'--enabled', resource[:enabled],
optional_opts
)
end
def exists?
user_hash[resource[:name]]
end
def destroy
auth_keystone('user-delete', user_hash[resource[:name]][:id])
end
def enabled
user_hash[resource[:name]][:enabled]
end
def enabled=(value)
auth_keystone(
"user-update",
'--enabled', value,
user_hash[resource[:name]][:id]
)
end
def password
# if we don't know a password we can't test it
return nil if resource[:password] == nil
# we can't get the value of the password but we can test to see if the one we know
# about works, if it doesn't then return nil, causing it to be reset
begin
token_out = creds_keystone(resource[:name], resource[:tenant], resource[:password], "token-get")
rescue Exception => e
return nil if e.message =~ /Not Authorized/ or e.message =~ /HTTP 401/
raise e
end
return resource[:password]
end
def password=(value)
if resource[:replace_password] == 'True'
auth_keystone('user-password-update', '--pass', value, user_hash[resource[:name]][:id])
end
end
def tenant
return resource[:tenant] if resource[:ignore_default_tenant]
user_id = user_hash[resource[:name]][:id]
begin
tenantId = self.class.get_keystone_object('user', user_id, 'tenantId')
rescue
tenantId = nil
end
if tenantId.nil? or tenantId == 'None' or tenantId.empty?
tenant = 'None'
else
# this prevents is from failing if tenant no longer exists
begin
tenant = self.class.get_keystone_object('tenant', tenantId, 'name')
rescue
tenant = 'None'
end
end
tenant
end
def tenant=(value)
fail("tenant cannot be updated. Transition requested: #{user_hash[resource[:name]][:tenant]} -> #{value}")
end
def email
user_hash[resource[:name]][:email]
end
def email=(value)
auth_keystone(
"user-update",
'--email', value,
user_hash[resource[:name]][:id]
)
end
def replace_password
user_hash[resource[:name]][:replace_password]
end
def replace_password=(value)
user_hash[resource[:name]][:replace_password]
end
def id
user_hash[resource[:name]][:id]
end
private
def self.build_user_hash
hash = {}
list_keystone_objects('user', 4).each do |user|
password = 'nil'
replace_password = 'True',
hash[user[1]] = {
:id => user[0],
:enabled => user[2],
:email => user[3],
:name => user[1],
:password => password,
:replace_password => replace_password,
}
end
hash
end
end

View File

@ -0,0 +1,204 @@
require 'puppet/provider/keystone'
Puppet::Type.type(:keystone_user).provide(
:openstack,
:parent => Puppet::Provider::Keystone
) do
desc "Provider to manage keystone users."
@credentials = Puppet::Provider::Openstack::CredentialsV2_0.new
def initialize(value={})
super(value)
@property_flush = {}
end
def create
properties = [resource[:name]]
if resource[:enabled] == :true
properties << '--enable'
elsif resource[:enabled] == :false
properties << '--disable'
end
if resource[:password]
properties << '--password' << resource[:password]
end
if resource[:tenant]
properties << '--project' << resource[:tenant]
end
if resource[:email]
properties << '--email' << resource[:email]
end
self.class.request('user', 'create', properties)
@property_hash[:ensure] = :present
end
def destroy
self.class.request('user', 'delete', @property_hash[:id])
@property_hash.clear
end
def flush
options = []
if @property_flush && !@property_flush.empty?
options << '--enable' if @property_flush[:enabled] == :true
options << '--disable' if @property_flush[:enabled] == :false
# There is a --description flag for the set command, but it does not work if the value is empty
options << '--password' << resource[:password] if @property_flush[:password]
options << '--email' << resource[:email] if @property_flush[:email]
# project handled in tenant= separately
unless options.empty?
options << @property_hash[:id]
self.class.request('user', 'set', options)
end
@property_flush.clear
end
end
def exists?
@property_hash[:ensure] == :present
end
# Types properties
def enabled
bool_to_sym(@property_hash[:enabled])
end
def enabled=(value)
@property_flush[:enabled] = value
end
def email
@property_hash[:email]
end
def email=(value)
@property_flush[:email] = value
end
def id
@property_hash[:id]
end
def password
res = nil
return res if resource[:password] == nil
if resource[:enabled] == :false || resource[:replace_password] == :false
# Unchanged password
res = resource[:password]
else
# Password validation
credentials = Puppet::Provider::Openstack::CredentialsV2_0.new
credentials.auth_url = self.class.get_endpoint
credentials.password = resource[:password]
credentials.project_name = resource[:tenant]
credentials.username = resource[:name]
begin
token = Puppet::Provider::Openstack.request('token', 'issue', ['--format', 'value'], credentials)
rescue Puppet::Error::OpenstackUnauthorizedError
# password is invalid
else
res = resource[:password] unless token.empty?
end
end
return res
end
def password=(value)
@property_flush[:password] = value
end
def replace_password
@property_hash[:replace_password]
end
def replace_password=(value)
@property_flush[:replace_password] = value
end
def tenant
return resource[:tenant] if sym_to_bool(resource[:ignore_default_tenant])
# use the one returned from instances
tenant_name = @property_hash[:project]
if tenant_name.nil? or tenant_name.empty?
# if none (i.e. ldap backend) use the given one
tenant_name = resource[:tenant]
else
return tenant_name
end
if tenant_name.nil? or tenant_name.empty?
return nil # nothing found, nothing given
end
# If the user list command doesn't report the project, it might still be there
# We don't need to know exactly what it is, we just need to know whether it's
# the one we're trying to set.
roles = self.class.request('user role', 'list', [resource[:name], '--project', tenant_name])
if roles.empty?
return nil
else
return tenant_name
end
end
def tenant=(value)
self.class.request('user', 'set', [resource[:name], '--project', value])
rescue Puppet::ExecutionFailure => e
if e.message =~ /You are not authorized to perform the requested action: LDAP user update/
# read-only LDAP identity backend - just fall through
else
raise e
end
# note: read-write ldap will silently fail, not raise an exception
else
@property_hash[:tenant] = self.class.set_project(value, resource[:name])
end
def self.instances
list = request('user', 'list', '--long')
list.collect do |user|
new(
:name => user[:name],
:ensure => :present,
:enabled => user[:enabled].downcase.chomp == 'true' ? true : false,
:password => user[:password],
:project => user[:project],
:email => user[:email],
:id => user[:id]
)
end
end
def self.prefetch(resources)
users = instances
resources.keys.each do |name|
if provider = users.find{ |user| user.name == name }
resources[name].provider = provider
end
end
end
def self.set_project(newproject, name)
# some backends do not store the project/tenant in the user object, so we have to
# to modify the project/tenant instead
# First, see if the project actually needs to change
roles = request('user role', 'list', [name, '--project', newproject])
unless roles.empty?
return # if already set, just skip
end
# Currently the only way to assign a user to a tenant not using user-create
# is to use user-role-add - this means we also need a role - there is usual
# a default role called _member_ which can be used for this purpose. What
# usually happens in a puppet module is that immediately after calling
# keystone_user, the module will then assign a role to that user. It is
# ok for a user to have the _member_ role and another role.
default_role = "_member_"
begin
request('role', 'show', [default_role])
rescue
debug("Keystone role #{default_role} does not exist - creating")
request('role', 'create', [default_role])
end
request('role', 'add', [default_role, '--project', newproject, '--user', name])
end
end

View File

@ -1,229 +0,0 @@
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', '..'))
require 'puppet/provider/keystone'
Puppet::Type.type(:keystone_user_role).provide(
:keystone,
:parent => Puppet::Provider::Keystone
) do
desc <<-EOT
Provider that uses the keystone client tool to
manage keystone role assignments to users
EOT
optional_commands :keystone => "keystone"
def self.prefetch(resource)
# rebuild the cahce for every puppet run
@user_role_hash = nil
end
def self.user_role_hash
@user_role_hash = build_user_role_hash
end
def user_role_hash
self.class.user_role_hash
end
def self.instances
user_role_hash.collect do |k, v|
new(:name => k)
end
end
def create
user_id, tenant_id = get_user_and_tenant
resource[:roles].each do |role_name|
role_id = self.class.get_role(role_name)
auth_keystone(
'user-role-add',
'--user-id', user_id,
'--tenant-id', tenant_id,
'--role-id', role_id
)
end
end
def self.get_user_and_tenant(user, tenant)
@tenant_hash ||= {}
@user_hash ||= {}
@tenant_hash[tenant] = @tenant_hash[tenant] || get_tenant(tenant)
[
get_user(@tenant_hash[tenant], user),
@tenant_hash[tenant]
]
end
def get_user_and_tenant
user, tenant = resource[:name].split('@', 2)
self.class.get_user_and_tenant(user, tenant)
end
def exists?
user_id, tenant_id = get_user_and_tenant
get_user_tenant_hash(user_id, tenant_id)
end
def destroy
user_id, tenant_id = get_user_and_tenant
get_user_tenant_hash(user_id, tenant_id)[:role_ids].each do |role_id|
auth_keystone(
'user-role-remove',
'--user-id', user_id,
'--tenant-id', tenant_id,
'--role-id', role_id
)
end
end
def id
user_id, tenant_id = get_user_and_tenant
get_user_tenant_hash(user_id, tenant_id)[:id]
end
def roles
user_id, tenant_id = get_user_and_tenant
get_user_tenant_hash(user_id, tenant_id)[:role_names]
end
def roles=(value)
# determine the roles to be added and removed
remove = roles - Array(value)
add = Array(value) - roles
user_id, tenant_id = get_user_and_tenant
add.each do |role_name|
role_id = self.class.get_role(role_name)
auth_keystone(
'user-role-add',
'--user-id', user_id,
'--tenant-id', tenant_id,
'--role-id', role_id
)
end
remove.each do |role_name|
role_id = self.class.get_role(role_name)
auth_keystone(
'user-role-remove',
'--user-id', user_id,
'--tenant-id', tenant_id,
'--role-id', role_id
)
end
end
private
def self.build_user_role_hash
hash = {}
get_tenants.each do |tenant_name, tenant_id|
get_users(tenant_id).each do |user_name, user_id|
list_user_roles(user_id, tenant_id).sort.each do |role|
hash["#{user_name}@#{tenant_name}"] ||= {
:user_id => user_id,
:tenant_id => tenant_id,
:role_names => [],
:role_ids => []
}
hash["#{user_name}@#{tenant_name}"][:role_names].push(role[1])
hash["#{user_name}@#{tenant_name}"][:role_ids].push(role[0])
end
end
end
hash
end
# lookup the roles for a single tenant/user combination
def get_user_tenant_hash(user_id, tenant_id)
@user_tenant_hash ||= {}
unless @user_tenant_hash["#{user_id}@#{tenant_id}"]
list_user_roles(user_id, tenant_id).sort.each do |role|
@user_tenant_hash["#{user_id}@#{tenant_id}"] ||= {
:user_id => user_id,
:tenant_id => tenant_id,
:role_names => [],
:role_ids => []
}
@user_tenant_hash["#{user_id}@#{tenant_id}"][:role_names].push(role[1])
@user_tenant_hash["#{user_id}@#{tenant_id}"][:role_ids].push(role[0])
end
end
@user_tenant_hash["#{user_id}@#{tenant_id}"]
end
def self.list_user_roles(user_id, tenant_id)
# this assumes that all returned objects are of the form
# id, name, enabled_state, OTHER
number_columns = 4
role_output = auth_keystone('user-role-list', '--user-id', user_id, '--tenant-id', tenant_id)
list = (role_output.split("\n")[3..-2] || []).collect do |line|
row = line.split(/\s*\|\s*/)[1..-1]
if row.size != number_columns
raise(Puppet::Error, "Expected #{number_columns} columns for #{type} row, found #{row.size}. Line #{line}")
end
row
end
list
end
def list_user_roles(user_id, tenant_id)
self.class.list_user_roles(user_id, tenant_id)
end
def self.get_user(tenant_id, name)
@users ||= {}
user_key = "#{name}@#{tenant_id}"
unless @users[user_key]
list_keystone_objects('user', 4, '--tenant-id', tenant_id).each do |user|
@users["#{user[1]}@#{tenant_id}"] = user[0]
end
end
@users[user_key]
end
def self.get_users(tenant_id='')
@users = {}
list_keystone_objects('user', 4, '--tenant-id', tenant_id).each do |user|
@users[user[1]] = user[0]
end
@users
end
def self.get_tenants
unless @tenants
@tenants = {}
list_keystone_objects('tenant', 3).each do |tenant|
@tenants[tenant[1]] = tenant[0]
end
end
@tenants
end
def self.get_tenant(name)
unless (@tenants and @tenants[name])
@tenants = {}
list_keystone_objects('tenant', 3).each do |tenant|
if tenant[1] == name
@tenants[tenant[1]] = tenant[0]
#tenant
end
end
end
@tenants[name]
end
def self.get_role(name)
@roles ||= {}
unless @roles[name]
list_keystone_objects('role', 2).each do |role|
@roles[role[1]] = role[0]
end
end
@roles[name]
end
end

View File

@ -0,0 +1,131 @@
require 'puppet/provider/keystone'
Puppet::Type.type(:keystone_user_role).provide(
:openstack,
:parent => Puppet::Provider::Keystone
) do
desc "Provider to manage keystone role assignments to users."
@credentials = Puppet::Provider::Openstack::CredentialsV2_0.new
def initialize(value={})
super(value)
@property_flush = {}
end
def create
properties = []
properties << '--project' << get_project
properties << '--user' << get_user
if resource[:roles]
resource[:roles].each do |role|
self.class.request('role', 'add', [role] + properties)
end
end
end
def destroy
properties = []
properties << '--project' << get_project
properties << '--user' << get_user
if @property_hash[:roles]
@property_hash[:roles].each do |role|
self.class.request('role', 'remove', [role] + properties)
end
end
@property_hash[:ensure] = :absent
end
def exists?
if @user_role_hash
return ! @property_hash[:name].empty?
else
roles = self.class.request('user role', 'list', [get_user, '--project', get_project])
# Since requesting every combination of users, roles, and
# projects is so expensive, construct the property hash here
# instead of in self.instances so it can be used in the role
# and destroy methods
@property_hash[:name] = resource[:name]
if roles.empty?
@property_hash[:ensure] = :absent
else
@property_hash[:ensure] = :present
@property_hash[:roles] = roles.collect do |role|
role[:name]
end
end
return @property_hash[:ensure] == :present
end
end
def roles
@property_hash[:roles]
end
def roles=(value)
current_roles = roles
# determine the roles to be added and removed
remove = current_roles - Array(value)
add = Array(value) - current_roles
user = get_user
project = get_project
add.each do |role_name|
self.class.request('role', 'add', [role_name, '--project', project, '--user', user])
end
remove.each do |role_name|
self.class.request('role', 'remove', [role_name, '--project', project, '--user', user])
end
end
def self.instances
instances = build_user_role_hash
instances.collect do |title, roles|
new(
:name => title,
:ensure => :present,
:roles => roles
)
end
end
private
def get_user
resource[:name].rpartition('@').first
end
def get_project
resource[:name].rpartition('@').last
end
def self.get_projects
request('project', 'list').collect { |project| project[:name] }
end
def self.get_users(project)
request('user', 'list', ['--project', project]).collect { |user| user[:name] }
end
def self.set_user_role_hash(user_role_hash)
@user_role_hash = user_role_hash
end
def self.build_user_role_hash
hash = @user_role_hash || {}
return hash unless hash.empty?
projects = get_projects
projects.each do |project|
users = get_users(project)
users.each do |user|
user_roles = request('user role', 'list', [user, '--project', project])
hash["#{user}@#{project}"] = []
user_roles.each do |role|
hash["#{user}@#{project}"] << role[:name]
end
end
end
set_user_role_hash(hash)
hash
end
end

View File

@ -1,9 +1,10 @@
# LP#1408531
File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
File.expand_path('../../../../openstacklib/lib', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
Puppet::Type.newtype(:keystone_endpoint) do Puppet::Type.newtype(:keystone_endpoint) do
desc <<-EOT desc 'Type for managing keystone endpoints.'
This is currently used to model the management of
keystone endpoint.
EOT
ensurable ensurable
@ -20,7 +21,6 @@ Puppet::Type.newtype(:keystone_endpoint) do
newproperty(:region) do newproperty(:region) do
end end
# TODO I should do some url validation
newproperty(:public_url) do newproperty(:public_url) do
end end
@ -39,5 +39,4 @@ Puppet::Type.newtype(:keystone_endpoint) do
(region, service_name) = self[:name].split('/') (region, service_name) = self[:name].split('/')
[service_name] [service_name]
end end
end end

View File

@ -0,0 +1,43 @@
Puppet::Type.newtype(:keystone_paste_ini) do
ensurable
newparam(:name, :namevar => true) do
desc 'Section/setting name to manage from keystone/keystone-paste.ini'
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
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
end

View File

@ -1,3 +1,7 @@
# LP#1408531
File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
File.expand_path('../../../../openstacklib/lib', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
Puppet::Type.newtype(:keystone_role) do Puppet::Type.newtype(:keystone_role) do
desc <<-EOT desc <<-EOT
@ -21,5 +25,4 @@ Puppet::Type.newtype(:keystone_role) do
autorequire(:service) do autorequire(:service) do
['keystone'] ['keystone']
end end
end end

View File

@ -1,13 +1,15 @@
# LP#1408531
File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
File.expand_path('../../../../openstacklib/lib', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
Puppet::Type.newtype(:keystone_service) do Puppet::Type.newtype(:keystone_service) do
desc <<-EOT desc 'This type can be used to manage keystone services.'
This is currently used to model the management of
keystone services.
EOT
ensurable ensurable
newparam(:name, :namevar => true) do newparam(:name, :namevar => true) do
desc 'The name of the service.'
newvalues(/\S+/) newvalues(/\S+/)
end end
@ -18,14 +20,22 @@ Puppet::Type.newtype(:keystone_service) do
end end
newproperty(:type) do newproperty(:type) do
desc 'The type of service'
validate do |value|
fail('The service type is required.') unless value
end
end end
newproperty(:description) do newproperty(:description) do
desc 'A description of the service.'
defaultto('')
end end
# we should not do anything until the keystone service is started # This ensures the service is started and therefore the keystone
# config is configured IF we need them for authentication.
# If there is no keystone config, authentication credentials
# need to come from another source.
autorequire(:service) do autorequire(:service) do
['keystone'] ['keystone']
end end
end end

View File

@ -1,38 +1,44 @@
# LP#1408531
File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
File.expand_path('../../../../openstacklib/lib', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
Puppet::Type.newtype(:keystone_tenant) do Puppet::Type.newtype(:keystone_tenant) do
desc <<-EOT desc 'This type can be used to manage keystone tenants.'
This type can be used to manage
keystone tenants.
This is assumed to be running on the same node
as your keystone API server.
EOT
ensurable ensurable
newparam(:name, :namevar => true) do newparam(:name, :namevar => true) do
desc 'The name of the tenant.'
newvalues(/\w+/) newvalues(/\w+/)
end end
newproperty(:enabled) do newproperty(:enabled) do
newvalues(/(t|T)rue/, /(f|F)alse/) desc 'Whether the tenant should be enabled. Defaults to true.'
defaultto('True') newvalues(/(t|T)rue/, /(f|F)alse/, true, false )
defaultto(true)
munge do |value| munge do |value|
value.to_s.capitalize value.to_s.downcase.to_sym
end end
end end
newproperty(:description) newproperty(:description) do
desc 'A description of the tenant.'
defaultto('')
end
newproperty(:id) do newproperty(:id) do
desc 'Read-only property of the tenant.'
validate do |v| validate do |v|
raise(Puppet::Error, 'This is a read only property') raise(Puppet::Error, 'This is a read only property')
end end
end end
# we should not do anything until the keystone service is started # This ensures the service is started and therefore the keystone
# config is configured IF we need them for authentication.
# If there is no keystone config, authentication credentials
# need to come from another source.
autorequire(:service) do autorequire(:service) do
['keystone'] ['keystone']
end end
end end

View File

@ -1,14 +1,10 @@
# LP#1408531
File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
File.expand_path('../../../../openstacklib/lib', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
Puppet::Type.newtype(:keystone_user) do Puppet::Type.newtype(:keystone_user) do
desc <<-EOT desc 'Type for managing keystone users.'
This is currently used to model the creation of
keystone users.
It currently requires that both the password
as well as the tenant are specified.
EOT
# TODO support description??
ensurable ensurable
@ -16,16 +12,19 @@ Puppet::Type.newtype(:keystone_user) do
newvalues(/\S+/) newvalues(/\S+/)
end end
newparam(:ignore_default_tenant, :boolean => true) do newparam(:ignore_default_tenant) do
newvalues(:true, :false) newvalues(/(t|T)rue/, /(f|F)alse/, true, false)
defaultto false defaultto(false)
munge do |value|
value.to_s.downcase.to_sym
end
end end
newproperty(:enabled) do newproperty(:enabled) do
newvalues(/(t|T)rue/, /(f|F)alse/) newvalues(/(t|T)rue/, /(f|F)alse/, true, false)
defaultto('True') defaultto(true)
munge do |value| munge do |value|
value.to_s.capitalize value.to_s.downcase.to_sym
end end
end end
@ -53,7 +52,7 @@ Puppet::Type.newtype(:keystone_user) do
end end
newproperty(:email) do newproperty(:email) do
newvalues(/\S+@\S+/) newvalues(/^(\S+@\S+)|$/)
end end
newproperty(:id) do newproperty(:id) do
@ -62,11 +61,11 @@ Puppet::Type.newtype(:keystone_user) do
end end
end end
newproperty(:replace_password) do newparam(:replace_password) do
newvalues(/(t|T)rue/, /(f|F)alse/) newvalues(/(t|T)rue/, /(f|F)alse/, true, false)
defaultto('True') defaultto(true)
munge do |value| munge do |value|
value.to_s.capitalize value.to_s.downcase.to_sym
end end
end end
@ -78,5 +77,4 @@ Puppet::Type.newtype(:keystone_user) do
autorequire(:service) do autorequire(:service) do
['keystone'] ['keystone']
end end
end end

View File

@ -1,42 +1,37 @@
# LP#1408531
File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
File.expand_path('../../../../openstacklib/lib', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
Puppet::Type.newtype(:keystone_user_role) do Puppet::Type.newtype(:keystone_user_role) do
desc <<-EOT desc <<-EOT
This is currently used to model the creation of This is currently used to model the creation of
keystone users roles. keystone users roles.
User roles are an assigment of a role to a user on User roles are an assignment of a role to a user on
a certain tenant. The combintation of all of these a certain tenant. The combination of all of these
attributes is unique. attributes is unique.
EOT EOT
ensurable ensurable
newparam(:name, :namevar => true) do newparam(:name, :namevar => true) do
newvalues(/^\S+@\S+$/)
#munge do |value|
# matchdata = /(\S+)@(\S+)/.match(value)
# {
# :user => matchdata[1],
# :tenant => matchdata[2]
# }
#nd
end end
newproperty(:roles, :array_matching => :all) do newproperty(:roles, :array_matching => :all) do
end def insync?(is)
return false unless is.is_a? Array
newproperty(:id) do # order of roles does not matter
validate do |v| is.sort == self.should.sort
raise(Puppet::Error, 'This is a read only property')
end end
end end
autorequire(:keystone_user) do autorequire(:keystone_user) do
self[:name].split('@', 2).first self[:name].rpartition('@').first
end end
autorequire(:keystone_tenant) do autorequire(:keystone_tenant) do
self[:name].split('@', 2).last self[:name].rpartition('@').last
end end
autorequire(:keystone_role) do autorequire(:keystone_role) do
@ -47,5 +42,4 @@ Puppet::Type.newtype(:keystone_user_role) do
autorequire(:service) do autorequire(:service) do
['keystone'] ['keystone']
end end
end end

View File

@ -5,7 +5,8 @@
# === Parameters # === Parameters
# #
# [*ensure*] # [*ensure*]
# (optional) Ensure state of the package. Defaults to 'present'. # (optional) Ensure state of the package.
# Defaults to 'present'.
# #
class keystone::client ( class keystone::client (
$ensure = 'present' $ensure = 'present'
@ -13,5 +14,6 @@ class keystone::client (
package { 'python-keystoneclient': package { 'python-keystoneclient':
ensure => $ensure, ensure => $ensure,
tag => 'openstack',
} }
} }

View File

@ -0,0 +1,75 @@
#
# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# == Class: keystone::cron::token_flush
#
# Installs a cron job to purge expired tokens.
#
# === Parameters
#
# [*ensure*]
# (optional) Defaults to present.
# Valid values are present, absent.
#
# [*minute*]
# (optional) Defaults to '1'.
#
# [*hour*]
# (optional) Defaults to '0'.
#
# [*monthday*]
# (optional) Defaults to '*'.
#
# [*month*]
# (optional) Defaults to '*'.
#
# [*weekday*]
# (optional) Defaults to '*'.
#
# [*maxdelay*]
# (optional) Seconds. Defaults to 0. Should be a positive integer.
# Induces a random delay before running the cronjob to avoid running all
# cron jobs at the same time on all hosts this job is configured.
#
class keystone::cron::token_flush (
$ensure = present,
$minute = 1,
$hour = 0,
$monthday = '*',
$month = '*',
$weekday = '*',
$maxdelay = 0,
) {
if $maxdelay == 0 {
$sleep = ''
} else {
$sleep = "sleep `expr \${RANDOM} \\% ${maxdelay}`; "
}
cron { 'keystone-manage token_flush':
ensure => $ensure,
command => "${sleep}keystone-manage token_flush >>/var/log/keystone/keystone-tokenflush.log 2>&1",
environment => 'PATH=/bin:/usr/bin:/usr/sbin SHELL=/bin/sh',
user => 'keystone',
minute => $minute,
hour => $hour,
monthday => $monthday,
month => $month,
weekday => $weekday
}
}

View File

@ -1,27 +1,43 @@
# # The keystone::db::mysql class implements mysql backend for keystone
# implements mysql backend for keystone
# #
# This class can be used to create tables, users and grant # This class can be used to create tables, users and grant
# privelege for a mysql keystone database. # privelege for a mysql keystone database.
# #
# == parameters # == parameters
# #
# [password] Password that will be used for the keystone db user. # [*password*]
# Optional. Defaults to: 'keystone_default_password' # (Mandatory) Password to connect to the database.
# Defaults to 'false'.
# #
# [dbname] Name of keystone database. Optional. Defaults to keystone. # [*dbname*]
# (Optional) Name of the database.
# Defaults to 'keystone'.
# #
# [user] Name of keystone user. Optional. Defaults to keystone. # [*user*]
# (Optional) User to connect to the database.
# Defaults to 'keystone'.
# #
# [host] Host where user should be allowed all priveleges for database. # [*host*]
# Optional. Defaults to 127.0.0.1. # (Optional) The default source host user is allowed to connect from.
# Defaults to '127.0.0.1'
# #
# [allowed_hosts] Hosts allowed to use the database # [*allowed_hosts*]
# (Optional) Other hosts the user is allowed to connect from.
# Defaults to 'undef'.
# #
# [*mysql_module*] # [*charset*]
# (optional) The mysql puppet module version to use # (Optional) The database charset.
# Tested versions include 0.9 and 2.2 # Defaults to 'utf8'
# Default to '0.9' #
# [*collate*]
# (Optional) The database collate.
# Only used with mysql modules >= 2.2.
# Defaults to 'utf8_general_ci'
#
# === Deprecated Parameters
#
# [*mysql_module*]
# (Optional) Does nothing.
# #
# == Dependencies # == Dependencies
# Class['mysql::server'] # Class['mysql::server']
@ -41,53 +57,26 @@ class keystone::db::mysql(
$user = 'keystone', $user = 'keystone',
$host = '127.0.0.1', $host = '127.0.0.1',
$charset = 'utf8', $charset = 'utf8',
$collate = 'utf8_unicode_ci', $collate = 'utf8_general_ci',
$mysql_module = '0.9', $mysql_module = undef,
$allowed_hosts = undef $allowed_hosts = undef
) { ) {
Class['keystone::db::mysql'] -> Exec<| title == 'keystone-manage db_sync' |> if $mysql_module {
Class['keystone::db::mysql'] -> Service<| title == 'keystone' |> warning('The mysql_module parameter is deprecated. The latest 2.x mysql module will be used.')
Mysql::Db[$dbname] ~> Exec<| title == 'keystone-manage db_sync' |>
if ($mysql_module >= 2.2) {
mysql::db { $dbname:
user => $user,
password => $password,
host => $host,
charset => $charset,
collate => $collate,
require => Service['mysqld'],
}
} else {
require mysql::python
mysql::db { $dbname:
user => $user,
password => $password,
host => $host,
charset => $charset,
require => Class['mysql::config'],
}
} }
# Check allowed_hosts to avoid duplicate resource declarations validate_string($password)
if is_array($allowed_hosts) and delete($allowed_hosts,$host) != [] {
$real_allowed_hosts = delete($allowed_hosts,$host) ::openstacklib::db::mysql { 'keystone':
} elsif is_string($allowed_hosts) and ($allowed_hosts != $host) { user => $user,
$real_allowed_hosts = $allowed_hosts password_hash => mysql_password($password),
} dbname => $dbname,
host => $host,
if $real_allowed_hosts { charset => $charset,
keystone::db::mysql::host_access { $real_allowed_hosts: collate => $collate,
user => $user, allowed_hosts => $allowed_hosts,
password => $password,
database => $dbname,
mysql_module => $mysql_module,
}
Keystone::Db::Mysql::Host_access[$real_allowed_hosts] -> Exec<| title == 'keystone-manage db_sync' |>
} }
::Openstacklib::Db::Mysql['keystone'] ~> Exec<| title == 'keystone-manage db_sync' |>
} }

View File

@ -1,34 +0,0 @@
#
define keystone::db::mysql::host_access(
$user,
$password,
$database,
$mysql_module = '0.9'
) {
if ($mysql_module >= 2.2) {
mysql_user { "${user}@${name}":
password_hash => mysql_password($password),
require => Mysql_database[$database],
}
mysql_grant { "${user}@${name}/${database}.*":
privileges => ['ALL'],
options => ['GRANT'],
table => "${database}.*",
require => Mysql_user["${user}@${name}"],
user => "${user}@${name}"
}
} else {
database_user { "${user}@${name}":
password_hash => mysql_password($password),
provider => 'mysql',
require => Database[$database],
}
database_grant { "${user}@${name}/${database}":
# TODO figure out which privileges to grant.
privileges => 'all',
provider => 'mysql',
require => Database_user["${user}@${name}"]
}
}
}

View File

@ -1,47 +1,57 @@
# == Class: keystone::db::postgresql
# #
# implements postgresql backend for keystone # Class that configures postgresql for keystone
# Requires the Puppetlabs postgresql module.
# #
# This class can be used to create tables, users and grant
# privelege for a postgresql keystone database.
#
# Requires Puppetlabs Postgresql module.
#
# [*Parameters*]
#
# [password] Password that will be used for the keystone db user.
# Optional. Defaults to: 'keystone_default_password'
#
# [dbname] Name of keystone database. Optional. Defaults to keystone.
#
# [user] Name of keystone user. Optional. Defaults to keystone.
#
# == Dependencies
# Class['postgresql::server']
#
# == Examples
# == Authors # == Authors
# #
# Stackforge Contributors puppet-openstack@puppetlabs.com
# Etienne Pelletier epelletier@morphlabs.com # Etienne Pelletier epelletier@morphlabs.com
# #
# == Copyright # == Copyright
# #
# Copyright 2013-2014 Stackforge Contributors
# Copyright 2012 Etienne Pelletier, unless otherwise noted. # Copyright 2012 Etienne Pelletier, unless otherwise noted.
# #
# === Parameters
#
# [*password*]
# (Required) Password to connect to the database.
#
# [*dbname*]
# (Optional) Name of the database.
# Defaults to 'keystone'.
#
# [*user*]
# (Optional) User to connect to the database.
# Defaults to 'keystone'.
#
# [*encoding*]
# (Optional) The charset to use for the database.
# Default to undef.
#
# [*privileges*]
# (Optional) Privileges given to the database user.
# Default to 'ALL'
#
class keystone::db::postgresql( class keystone::db::postgresql(
$password, $password,
$dbname = 'keystone', $dbname = 'keystone',
$user = 'keystone' $user = 'keystone',
$encoding = undef,
$privileges = 'ALL',
) { ) {
Class['keystone::db::postgresql'] -> Service<| title == 'keystone' |> Class['keystone::db::postgresql'] -> Service<| title == 'keystone' |>
require postgresql::python ::openstacklib::db::postgresql { 'keystone':
password_hash => postgresql_password($user, $password),
postgresql::db { $dbname: dbname => $dbname,
user => $user, user => $user,
password => $password, encoding => $encoding,
privileges => $privileges,
} }
Postgresql::Server::Db[$dbname] ~> Exec<| title == 'keystone-manage db_sync' |> ::Openstacklib::Db::Postgresql['keystone'] ~> Exec<| title == 'keystone-manage db_sync' |>
} }

View File

@ -9,4 +9,6 @@ class keystone::db::sync {
subscribe => [Package['keystone'], Keystone_config['database/connection']], subscribe => [Package['keystone'], Keystone_config['database/connection']],
require => User['keystone'], require => User['keystone'],
} }
Exec['keystone-manage db_sync'] ~> Service<| title == 'keystone' |>
} }

View File

@ -1,6 +1,12 @@
# #
# Installs keystone from source. This is not yet fully implemented # Installs keystone from source. This is not yet fully implemented
# #
# == Parameters
#
# [*source_dir*]
# (optional) The source dire for dev installation
# Defaults to '/usr/local/keystone'
#
# == Dependencies # == Dependencies
# == Examples # == Examples
# == Authors # == Authors

View File

@ -6,12 +6,15 @@
# #
# [*public_url*] # [*public_url*]
# (optional) Public url for keystone endpoint. (Defaults to 'http://127.0.0.1:5000') # (optional) Public url for keystone endpoint. (Defaults to 'http://127.0.0.1:5000')
# This url should *not* contain any version or trailing '/'.
# #
# [*internal_url*] # [*internal_url*]
# (optional) Internal url for keystone endpoint. (Defaults to $public_url) # (optional) Internal url for keystone endpoint. (Defaults to $public_url)
# This url should *not* contain any version or trailing '/'.
# #
# [*admin_url*] # [*admin_url*]
# (optional) Admin url for keystone endpoint. (Defaults to 'http://127.0.0.1:35357') # (optional) Admin url for keystone endpoint. (Defaults to 'http://127.0.0.1:35357')
# This url should *not* contain any version or trailing '/'.
# #
# [*region*] # [*region*]
# (optional) Region for endpoint. (Defaults to 'RegionOne') # (optional) Region for endpoint. (Defaults to 'RegionOne')
@ -19,58 +22,6 @@
# [*version*] # [*version*]
# (optional) API version for endpoint. Appended to all endpoint urls. (Defaults to 'v2.0') # (optional) API version for endpoint. Appended to all endpoint urls. (Defaults to 'v2.0')
# #
# [*public_url*]
# (optional) The endpoint's public url. (Defaults to 'http://127.0.0.1:5000')
# This url should *not* contain any version or trailing '/'.
#
# [*admin_url*]
# (optional) The endpoint's admin url. (Defaults to 'http://127.0.0.1:5000')
# This url should *not* contain any version or trailing '/'.
#
# [*internal_url*]
# (optional) The endpoint's internal url. (Defaults to 'http://127.0.0.1:35357')
# This url should *not* contain any version or trailing '/'.
#
# [*public_protocol*]
# (optional) DEPRECATED: Use public_url instead.
# Protocol for public access to keystone endpoint. (Defaults to 'http')
# Setting this parameter overrides public_url parameter.
#
# [*public_address*]
# (optional) DEPRECATED: Use public_url instead.
# Public address for keystone endpoint. (Defaults to '127.0.0.1')
# Setting this parameter overrides public_url parameter.
#
# [*public_port*]
# (optional) DEPRECATED: Use public_url instead.
# Port for non-admin access to keystone endpoint. (Defaults to 5000)
# Setting this parameter overrides public_url parameter.
#
# [*internal_address*]
# (optional) DEPRECATED: Use internal_url instead.
# Internal address for keystone endpoint. (Defaults to '127.0.0.1')
# Setting this parameter overrides internal_url parameter.
#
# [*internal_port*]
# (optional) DEPRECATED: Use internal_url instead.
# Port for internal access to keystone endpoint. (Defaults to $public_port)
# Setting this parameter overrides internal_url parameter.
#
# [*admin_address*]
# (optional) DEPRECATED: Use admin_url instead.
# Admin address for keystone endpoint. (Defaults to '127.0.0.1')
# Setting this parameter overrides admin_url parameter.
#
# [*admin_port*]
# (optional) DEPRECATED: Use admin_url instead.
# Port for admin access to keystone endpoint. (Defaults to 35357)
# Setting this parameter overrides admin_url parameter.
#
# === Deprecation notes
#
# If any value is provided for public_protocol, public_address or public_port parameters,
# public_url will be completely ignored. The same applies for internal and admin parameters.
#
# === Examples # === Examples
# #
# class { 'keystone::endpoint': # class { 'keystone::endpoint':
@ -85,85 +36,26 @@ class keystone::endpoint (
$admin_url = 'http://127.0.0.1:35357', $admin_url = 'http://127.0.0.1:35357',
$version = 'v2.0', $version = 'v2.0',
$region = 'RegionOne', $region = 'RegionOne',
# DEPRECATED PARAMETERS
$public_protocol = undef,
$public_address = undef,
$public_port = undef,
$internal_address = undef,
$internal_port = undef,
$admin_address = undef,
$admin_port = undef,
) { ) {
if $public_port { $public_url_real = "${public_url}/${version}"
warning('The public_port parameter is deprecated, use public_url instead.') $admin_url_real = "${admin_url}/${version}"
if $internal_url {
$internal_url_real = "${internal_url}/${version}"
} else {
$internal_url_real = "${public_url}/${version}"
} }
if $public_protocol { keystone::resource::service_identity { 'keystone':
warning('The public_protocol parameter is deprecated, use public_url instead.') 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,
} }
if $public_address {
warning('The public_address parameter is deprecated, use public_url instead.')
}
if $internal_address {
warning('The internal_address parameter is deprecated, use internal_url instead.')
}
if $internal_port {
warning('The internal_port parameter is deprecated, use internal_url instead.')
}
if $admin_address {
warning('The admin_address parameter is deprecated, use admin_url instead.')
}
if $admin_port {
warning('The admin_port parameter is deprecated, use admin_url instead.')
}
$public_url_real = inline_template('<%=
if (!@public_protocol.nil?) || (!@public_address.nil?) || (!@public_port.nil?)
@public_protocol ||= "http"
@public_address ||= "127.0.0.1"
@public_port ||= "5000"
"#{@public_protocol}://#{@public_address}:#{@public_port}/#{@version}"
else
"#{@public_url}/#{@version}"
end %>')
$internal_url_real = inline_template('<%=
if (!@internal_address.nil?) || (!@internal_port.nil?) || (!@public_port.nil?)
@internal_address ||= @public_address ||= "127.0.0.1"
@internal_port ||= @public_port ||= "5000"
"http://#{@internal_address}:#{@internal_port}/#{@version}"
elsif (!@internal_url.nil?)
"#{@internal_url}/#{@version}"
else
"#{@public_url}/#{@version}"
end %>')
$admin_url_real = inline_template('<%=
if (!@admin_address.nil?) || (!@admin_port.nil?)
@admin_address ||= "127.0.0.1"
@admin_port ||= "35357"
"http://#{@admin_address}:#{@admin_port}/#{@version}"
else
"#{@admin_url}/#{@version}"
end %>')
keystone_service { 'keystone':
ensure => present,
type => 'identity',
description => 'OpenStack Identity Service',
}
keystone_endpoint { "${region}/keystone":
ensure => present,
public_url => $public_url_real,
admin_url => $admin_url_real,
internal_url => $internal_url_real,
region => $region,
}
} }

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,380 @@
# == class: keystone::ldap
# #
# Implements ldap configuration for keystone. # Implements ldap configuration for keystone.
# #
# === parameters:
#
# [*url*]
# URL for connecting to the LDAP server. (string value)
# Defaults to 'undef'
#
# [*user*]
# User BindDN to query the LDAP server. (string value)
# Defaults to 'undef'
#
# [*password*]
# Password for the BindDN to query the LDAP server. (string value)
# Defaults to 'undef'
#
# [*suffix*]
# LDAP server suffix (string value)
# Defaults to 'undef'
#
# [*query_scope*]
# The LDAP scope for queries, this can be either "one"
# (onelevel/singleLevel) or "sub" (subtree/wholeSubtree). (string value)
# Defaults to 'undef'
#
# [*page_size*]
# Maximum results per page; a value of zero ("0") disables paging. (integer value)
# Defaults to 'undef'
#
# [*user_tree_dn*]
# Search base for users. (string value)
# Defaults to 'undef'
#
# [*user_filter*]
# LDAP search filter for users. (string value)
# Defaults to 'undef'
#
# [*user_objectclass*]
# LDAP objectclass for users. (string value)
# Defaults to 'undef'
#
# [*user_id_attribute*]
# LDAP attribute mapped to user id. WARNING: must not be a multivalued attribute. (string value)
# Defaults to 'undef'
#
# [*user_name_attribute*]
# LDAP attribute mapped to user name. (string value)
# Defaults to 'undef'
#
# [*user_mail_attribute*]
# LDAP attribute mapped to user email. (string value)
#
# [*user_enabled_attribute*]
# LDAP attribute mapped to user enabled flag. (string value)
# Defaults to 'undef'
#
# [*user_enabled_mask*]
# Bitmask integer to indicate the bit that the enabled value is stored in if
# the LDAP server represents "enabled" as a bit on an integer rather than a
# boolean. A value of "0" indicates the mask is not used. If this is not set
# to "0" the typical value is "2". This is typically used when
# "user_enabled_attribute = userAccountControl". (integer value)
# Defaults to 'undef'
#
# [*user_enabled_default*]
# Default value to enable users. This should match an appropriate int value
# if the LDAP server uses non-boolean (bitmask) values to indicate if a user
# is enabled or disabled. If this is not set to "True" the typical value is
# "512". This is typically used when "user_enabled_attribute =
# userAccountControl". (string value)
# Defaults to 'undef'
#
# [*user_enabled_invert*]
# Invert the meaning of the boolean enabled values. Some LDAP servers use a
# boolean lock attribute where "true" means an account is disabled. Setting
# "user_enabled_invert = true" will allow these lock attributes to be used.
# This setting will have no effect if "user_enabled_mask" or
# "user_enabled_emulation" settings are in use. (boolean value)
# Defaults to 'undef'
#
# [*user_attribute_ignore*]
# List of attributes stripped off the user on update. (list value)
# Defaults to 'undef'
#
# [*user_default_project_id_attribute*]
# LDAP attribute mapped to default_project_id for users. (string value)
# Defaults to 'undef'
#
# [*user_allow_create*]
# Allow user creation in LDAP backend. (boolean value)
# Defaults to 'undef'
#
# [*user_allow_update*]
# Allow user updates in LDAP backend. (boolean value)
# Defaults to 'undef'
#
# [*user_allow_delete*]
# Allow user deletion in LDAP backend. (boolean value)
# Defaults to 'undef'
#
# [*user_pass_attribute*]
# LDAP attribute mapped to password. (string value)
# Defaults to 'undef'
#
# [*user_enabled_emulation*]
# If true, Keystone uses an alternative method to determine if
# a user is enabled or not by checking if they are a member of
# the "user_enabled_emulation_dn" group. (boolean value)
# Defaults to 'undef'
#
# [*user_enabled_emulation_dn*]
# DN of the group entry to hold enabled users when using enabled emulation.
# (string value)
# Defaults to 'undef'
#
# [*user_additional_attribute_mapping*]
# List of additional LDAP attributes used for mapping
# additional attribute mappings for users. Attribute mapping
# format is <ldap_attr>:<user_attr>, where ldap_attr is the
# attribute in the LDAP entry and user_attr is the Identity
# API attribute. (list value)
# Defaults to 'undef'
#
# [*project_tree_dn*]
# Search base for projects (string value)
# Defaults to 'undef'
#
# [*project_filter*]
# LDAP search filter for projects. (string value)
# Defaults to 'undef'
#
# [*project_objectclass*]
# LDAP objectclass for projects. (string value)
# Defaults to 'undef'
#
# [*project_id_attribute*]
# LDAP attribute mapped to project id. (string value)
# Defaults to 'undef'
#
# [*project_member_attribute*]
# LDAP attribute mapped to project membership for user. (string value)
# Defaults to 'undef'
#
# [*project_name_attribute*]
# LDAP attribute mapped to project name. (string value)
# Defaults to 'undef'
#
# [*project_desc_attribute*]
# LDAP attribute mapped to project description. (string value)
# Defaults to 'undef'
#
# [*project_enabled_attribute*]
# LDAP attribute mapped to project enabled. (string value)
# Defaults to 'undef'
#
# [*project_domain_id_attribute*]
# LDAP attribute mapped to project domain_id. (string value)
# Defaults to 'undef'
#
# [*project_attribute_ignore*]
# List of attributes stripped off the project on update. (list value)
# Defaults to 'undef'
#
# [*project_allow_create*]
# Allow project creation in LDAP backend. (boolean value)
# Defaults to 'undef'
#
# [*project_allow_update*]
# Allow project update in LDAP backend. (boolean value)
# Defaults to 'undef'
#
# [*project_allow_delete*]
# Allow project deletion in LDAP backend. (boolean value)
# Defaults to 'undef'
#
# [*project_enabled_emulation*]
# If true, Keystone uses an alternative method to determine if
# a project is enabled or not by checking if they are a member
# of the "project_enabled_emulation_dn" group. (boolean value)
# Defaults to 'undef'
#
# [*project_enabled_emulation_dn*]
# DN of the group entry to hold enabled projects when using
# enabled emulation. (string value)
# Defaults to 'undef'
#
# [*project_additional_attribute_mapping*]
# Additional attribute mappings for projects. Attribute
# mapping format is <ldap_attr>:<user_attr>, where ldap_attr
# is the attribute in the LDAP entry and user_attr is the
# Identity API attribute. (list value)
# Defaults to 'undef'
#
# [*role_tree_dn*]
# Search base for roles. (string value)
# Defaults to 'undef'
#
# [*role_filter*]
# LDAP search filter for roles. (string value)
# Defaults to 'undef'
#
# [*role_objectclass*]
# LDAP objectclass for roles. (string value)
# Defaults to 'undef'
#
# [*role_id_attribute*]
# LDAP attribute mapped to role id. (string value)
# Defaults to 'undef'
#
# [*role_name_attribute*]
# LDAP attribute mapped to role name. (string value)
# Defaults to 'undef'
#
# [*role_member_attribute*]
# LDAP attribute mapped to role membership. (string value)
# Defaults to 'undef'
#
# [*role_attribute_ignore*]
# List of attributes stripped off the role on update. (list value)
# Defaults to 'undef'
#
# [*role_allow_create*]
# Allow role creation in LDAP backend. (boolean value)
# Defaults to 'undef'
#
# [*role_allow_update*]
# Allow role update in LDAP backend. (boolean value)
# Defaults to 'undef'
#
# [*role_allow_delete*]
# Allow role deletion in LDAP backend. (boolean value)
# Defaults to 'undef'
#
# [*role_additional_attribute_mapping*]
# Additional attribute mappings for roles. Attribute mapping
# format is <ldap_attr>:<user_attr>, where ldap_attr is the
# attribute in the LDAP entry and user_attr is the Identity
# API attribute. (list value)
# Defaults to 'undef'
#
# [*group_tree_dn*]
# Search base for groups. (string value)
# Defaults to 'undef'
#
# [*group_filter*]
# LDAP search filter for groups. (string value)
# Defaults to 'undef'
#
# [*group_objectclass*]
# LDAP objectclass for groups. (string value)
# Defaults to 'undef'
#
# [*group_id_attribute*]
# LDAP attribute mapped to group id. (string value)
# Defaults to 'undef'
#
# [*group_name_attribute*]
# LDAP attribute mapped to group name. (string value)
# Defaults to 'undef'
#
# [*group_member_attribute*]
# LDAP attribute mapped to show group membership. (string value)
# Defaults to 'undef'
#
# [*group_desc_attribute*]
# LDAP attribute mapped to group description. (string value)
# Defaults to 'undef'
#
# [*group_attribute_ignore*]
# List of attributes stripped off the group on update. (list value)
# Defaults to 'undef'
#
# [*group_allow_create*]
# Allow group creation in LDAP backend. (boolean value)
# Defaults to 'undef'
#
# [*group_allow_update*]
# Allow group update in LDAP backend. (boolean value)
# Defaults to 'undef'
#
# [*group_allow_delete*]
# Allow group deletion in LDAP backend. (boolean value)
# Defaults to 'undef'
#
# [*group_additional_attribute_mapping*]
# Additional attribute mappings for groups. Attribute mapping
# format is <ldap_attr>:<user_attr>, where ldap_attr is the
# attribute in the LDAP entry and user_attr is the Identity
# API attribute. (list value)
# Defaults to 'undef'
#
# [*use_tls*]
# Enable TLS for communicating with LDAP servers. (boolean value)
# Defaults to 'undef'
#
# [*tls_cacertfile*]
# CA certificate file path for communicating with LDAP servers. (string value)
# Defaults to 'undef'
#
# [*tls_cacertdir*]
# CA certificate directory path for communicating with LDAP servers. (string value)
# Defaults to 'undef'
#
# [*tls_req_cert*]
# Valid options for tls_req_cert are demand, never, and allow. (string value)
# Defaults to 'undef'
#
# [*identity_driver*]
# Identity backend driver. (string value)
# Defaults to 'undef'
#
# [*credential_driver*]
# Credential backend driver. (string value)
# Defaults to 'undef'
#
# [*assignment_driver*]
# Assignment backend driver. (string value)
# Defaults to 'undef'
#
# [*use_pool*]
# Enable LDAP connection pooling. (boolean value)
# Defaults to false
#
# [*pool_size*]
# Connection pool size. (integer value)
# Defaults to '10'
#
# [*pool_retry_max*]
# Maximum count of reconnect trials. (integer value)
# Defaults to '3'
#
# [*pool_retry_delay*]
# Time span in seconds to wait between two reconnect trials. (floating point value)
# Defaults to '0.1'
#
# [*pool_connection_timeout*]
# Connector timeout in seconds. Value -1 indicates indefinite wait for response. (integer value)
# Defaults to '-1'
#
# [*pool_connection_lifetime*]
# Connection lifetime in seconds. (integer value)
# Defaults to '600'
#
# [*use_auth_pool*]
# Enable LDAP connection pooling for end user authentication.
# If use_pool is disabled, then this setting is meaningless and is not used at all. (boolean value)
# Defaults to false
#
# [*auth_pool_size*]
# End user auth connection pool size. (integer value)
# Defaults to '100'
#
# [*auth_pool_connection_lifetime*]
# End user auth connection lifetime in seconds. (integer value)
# Defaults to '60'
#
# === DEPRECATED group/name
#
# [*tenant_tree_dn*]
# [*tenant_filter*]
# [*tenant_objectclass*]
# [*tenant_id_attribute*]
# [*tenant_member_attribute*]
# [*tenant_name_attribute*]
# [*tenant_desc_attribute*]
# [*tenant_enabled_attribute*]
# [*tenant_domain_id_attribute*]
# [*tenant_attribute_ignore*]
# [*tenant_allow_create*]
# [*tenant_allow_update*]
# [*tenant_enabled_emulation*]
# [*tenant_enabled_emulation_dn*]
# [*tenant_additional_attribute_mapping*]
# [*tenant_allow_delete*]
#
# == Dependencies # == Dependencies
# == Examples # == Examples
# == Authors # == Authors
@ -28,6 +402,7 @@ class keystone::ldap(
$user_enabled_attribute = undef, $user_enabled_attribute = undef,
$user_enabled_mask = undef, $user_enabled_mask = undef,
$user_enabled_default = undef, $user_enabled_default = undef,
$user_enabled_invert = undef,
$user_attribute_ignore = undef, $user_attribute_ignore = undef,
$user_default_project_id_attribute = undef, $user_default_project_id_attribute = undef,
$user_allow_create = undef, $user_allow_create = undef,
@ -37,22 +412,38 @@ class keystone::ldap(
$user_enabled_emulation = undef, $user_enabled_emulation = undef,
$user_enabled_emulation_dn = undef, $user_enabled_emulation_dn = undef,
$user_additional_attribute_mapping = undef, $user_additional_attribute_mapping = undef,
$tenant_tree_dn = undef, $tenant_tree_dn = undef, #DEPRECATED
$tenant_filter = undef, $project_tree_dn = undef,
$tenant_objectclass = undef, $tenant_filter = undef, #DEPRECATED
$tenant_id_attribute = undef, $project_filter = undef,
$tenant_member_attribute = undef, $tenant_objectclass = undef, #DEPRECATED
$tenant_desc_attribute = undef, $project_objectclass = undef,
$tenant_name_attribute = undef, $tenant_id_attribute = undef, #DEPRECATED
$tenant_enabled_attribute = undef, $project_id_attribute = undef,
$tenant_domain_id_attribute = undef, $tenant_member_attribute = undef, #DEPRECATED
$tenant_attribute_ignore = undef, $project_member_attribute = undef,
$tenant_allow_create = undef, $tenant_desc_attribute = undef, #DEPRECATED
$tenant_allow_update = undef, $project_desc_attribute = undef,
$tenant_allow_delete = undef, $tenant_name_attribute = undef, #DEPRECATED
$tenant_enabled_emulation = undef, $project_name_attribute = undef,
$tenant_enabled_emulation_dn = undef, $tenant_enabled_attribute = undef, #DEPRECATED
$tenant_additional_attribute_mapping = undef, $project_enabled_attribute = undef,
$tenant_domain_id_attribute = undef, #DEPRECATED
$project_domain_id_attribute = undef,
$tenant_attribute_ignore = undef, #DEPRECATED
$project_attribute_ignore = undef,
$tenant_allow_create = undef, #DEPRECATED
$project_allow_create = undef,
$tenant_allow_update = undef, #DEPRECATED
$project_allow_update = undef,
$tenant_allow_delete = undef, #DEPRECATED
$project_allow_delete = undef,
$tenant_enabled_emulation = undef, #DEPRECATED
$project_enabled_emulation = undef,
$tenant_enabled_emulation_dn = undef, #DEPRECATED
$project_enabled_emulation_dn = undef,
$tenant_additional_attribute_mapping = undef, #DEPRECATED
$project_additional_attribute_mapping= undef,
$role_tree_dn = undef, $role_tree_dn = undef,
$role_filter = undef, $role_filter = undef,
$role_objectclass = undef, $role_objectclass = undef,
@ -76,17 +467,205 @@ class keystone::ldap(
$group_allow_update = undef, $group_allow_update = undef,
$group_allow_delete = undef, $group_allow_delete = undef,
$group_additional_attribute_mapping = undef, $group_additional_attribute_mapping = undef,
$tenant_tree_dn = undef,
$role_tree_dn = undef,
$use_tls = undef, $use_tls = undef,
$tls_cacertdir = undef, $tls_cacertdir = undef,
$tls_cacertfile = undef, $tls_cacertfile = undef,
$tls_req_cert = undef, $tls_req_cert = undef,
$identity_driver = undef, $identity_driver = undef,
$assignment_driver = undef, $assignment_driver = undef,
$credential_driver = undef,
$use_pool = false,
$pool_size = 10,
$pool_retry_max = 3,
$pool_retry_delay = 0.1,
$pool_connection_timeout = -1,
$pool_connection_lifetime = 600,
$use_auth_pool = false,
$auth_pool_size = 100,
$auth_pool_connection_lifetime = 60,
) { ) {
package { 'python-ldap': # In Juno the term "tenant" was deprecated in the config in favor of "project"
# Let's assume project_ is being used and warning otherwise. If both are set we will
# fail, because having both set may cause unexpected results in Keystone.
if ($tenant_tree_dn) {
$project_tree_dn_real = $tenant_tree_dn
warning ('tenant_tree_dn is deprecated in Juno. switch to project_tree_dn')
if ($project_tree_dn) {
fail ('tenant_tree_dn and project_tree_dn are both set. results may be unexpected')
}
}
else {
$project_tree_dn_real = $project_tree_dn
}
if ($tenant_filter) {
$project_filter_real = $tenant_filter
warning ('tenant_filter is deprecated in Juno. switch to project_filter')
if ($project_filter) {
fail ('tenant_filter and project_filter are both set. results may be unexpected')
}
}
else {
$project_filter_real = $project_filter
}
if ($tenant_objectclass) {
$project_objectclass_real = $tenant_objectclass
warning ('tenant_objectclass is deprecated in Juno. switch to project_objectclass')
if ($project_objectclass) {
fail ('tenant_objectclass and project_objectclass are both set. results may be unexpected')
}
}
else {
$project_objectclass_real = $project_objectclass
}
if ($tenant_id_attribute) {
$project_id_attribute_real = $tenant_id_attribute
warning ('tenant_id_attribute is deprecated in Juno. switch to project_id_attribute')
if ($project_id_attribute) {
fail ('tenant_id_attribute and project_id_attribute are both set. results may be unexpected')
}
}
else {
$project_id_attribute_real = $project_id_attribute
}
if ($tenant_member_attribute) {
$project_member_attribute_real = $tenant_member_attribute
warning ('tenant_member_attribute is deprecated in Juno. switch to project_member_attribute')
if ($project_member_attribute) {
fail ('tenant_member_attribute and project_member_attribute are both set. results may be unexpected')
}
}
else {
$project_member_attribute_real = $project_member_attribute
}
if ($tenant_desc_attribute) {
$project_desc_attribute_real = $tenant_desc_attribute
warning ('tenant_desc_attribute is deprecated in Juno. switch to project_desc_attribute')
if ($project_desc_attribute) {
fail ('tenant_desc_attribute and project_desc_attribute are both set. results may be unexpected')
}
}
else {
$project_desc_attribute_real = $project_desc_attribute
}
if ($tenant_name_attribute) {
$project_name_attribute_real = $tenant_name_attribute
warning ('tenant_name_attribute is deprecated in Juno. switch to project_name_attribute')
if ($project_name_attribute) {
fail ('tenant_name_attribute and project_name_attribute are both set. results may be unexpected')
}
}
else {
$project_name_attribute_real = $project_name_attribute
}
if ($tenant_enabled_attribute) {
$project_enabled_attribute_real = $tenant_enabled_attribute
warning ('tenant_enabled_attribute is deprecated in Juno. switch to project_enabled_attribute')
if ($project_enabled_attribute) {
fail ('tenant_enabled_attribute and project_enabled_attribute are both set. results may be unexpected')
}
}
else {
$project_enabled_attribute_real = $project_enabled_attribute
}
if ($tenant_attribute_ignore) {
$project_attribute_ignore_real = $tenant_attribute_ignore
warning ('tenant_attribute_ignore is deprecated in Juno. switch to project_attribute_ignore')
if ($project_attribute_ignore) {
fail ('tenant_attribute_ignore and project_attribute_ignore are both set. results may be unexpected')
}
}
else {
$project_attribute_ignore_real = $project_attribute_ignore
}
if ($tenant_domain_id_attribute) {
$project_domain_id_attribute_real = $tenant_domain_id_attribute
warning ('tenant_domain_id_attribute is deprecated in Juno. switch to project_domain_id_attribute')
if ($project_domain_id_attribute) {
fail ('tenant_domain_id_attribute and project_domain_id_attribute are both set. results may be unexpected')
}
}
else {
$project_domain_id_attribute_real = $project_domain_id_attribute
}
if ($tenant_allow_create) {
$project_allow_create_real = $tenant_allow_create
warning ('tenant_allow_create is deprecated in Juno. switch to project_allow_create')
if ($project_allow_create) {
fail ('tenant_allow_create and project_allow_create are both set. results may be unexpected')
}
}
else {
$project_allow_create_real = $project_allow_create
}
if ($tenant_allow_update) {
$project_allow_update_real = $tenant_allow_update
warning ('tenant_allow_update is deprecated in Juno. switch to project_allow_update')
if ($project_allow_update) {
fail ('tenant_allow_update and project_allow_update are both set. results may be unexpected')
}
}
else {
$project_allow_update_real = $project_allow_update
}
if ($tenant_allow_delete) {
$project_allow_delete_real = $tenant_allow_delete
warning ('tenant_allow_delete is deprecated in Juno. switch to project_allow_delete')
if ($project_allow_delete) {
fail ('tenant_allow_delete and project_allow_delete are both set. results may be unexpected')
}
}
else {
$project_allow_delete_real = $project_allow_delete
}
if ($tenant_enabled_emulation) {
$project_enabled_emulation_real = $tenant_enabled_emulation
warning ('tenant_enabled_emulation is deprecated in Juno. switch to project_enabled_emulation')
if ($project_enabled_emulation) {
fail ('tenant_enabled_emulation and project_enabled_emulation are both set. results may be unexpected')
}
}
else {
$project_enabled_emulation_real = $project_enabled_emulation
}
if ($tenant_enabled_emulation_dn) {
$project_enabled_emulation_dn_real = $tenant_enabled_emulation_dn
warning ('tenant_enabled_emulation_dn is deprecated in Juno. switch to project_enabled_emulation_dn')
if ($project_enabled_emulation_dn) {
fail ('tenant_enabled_emulation_dn and project_enabled_emulation_dn are both set. results may be unexpected')
}
}
else {
$project_enabled_emulation_dn_real = $project_enabled_emulation_dn
}
if ($tenant_additional_attribute_mapping) {
$project_additional_attribute_mapping_real = $tenant_additional_attribute_mapping
warning ('tenant_additional_attribute_mapping is deprecated in Juno. switch to project_additional_attribute_mapping')
if ($project_additional_attribute_mapping) {
fail ('tenant_additional_attribute_mapping and project_additional_attribute_mapping are both set. results may be unexpected')
}
}
else {
$project_additional_attribute_mapping_real = $project_additional_attribute_mapping
}
$ldap_packages = ['python-ldap', 'python-ldappool']
package { $ldap_packages:
ensure => present, ensure => present,
} }
@ -103,6 +682,12 @@ class keystone::ldap(
} }
} }
if ($credential_driver != undef) {
if ! ($credential_driver =~ /^keystone.credential.backends.*Credential$/) {
fail('credential driver should be of the form \'keystone.credential.backends.*Credential\'')
}
}
if ($tls_cacertdir != undef) { if ($tls_cacertdir != undef) {
file { $tls_cacertdir: file { $tls_cacertdir:
ensure => directory ensure => directory
@ -110,74 +695,85 @@ class keystone::ldap(
} }
keystone_config { keystone_config {
'ldap/url': value => $url; 'ldap/url': value => $url;
'ldap/user': value => $user; 'ldap/user': value => $user;
'ldap/password': value => $password, secret => true; 'ldap/password': value => $password, secret => true;
'ldap/suffix': value => $suffix; 'ldap/suffix': value => $suffix;
'ldap/query_scope': value => $query_scope; 'ldap/query_scope': value => $query_scope;
'ldap/page_size': value => $page_size; 'ldap/page_size': value => $page_size;
'ldap/user_tree_dn': value => $user_tree_dn; 'ldap/user_tree_dn': value => $user_tree_dn;
'ldap/user_filter': value => $user_filter; 'ldap/user_filter': value => $user_filter;
'ldap/user_objectclass': value => $user_objectclass; 'ldap/user_objectclass': value => $user_objectclass;
'ldap/user_id_attribute': value => $user_id_attribute; 'ldap/user_id_attribute': value => $user_id_attribute;
'ldap/user_name_attribute': value => $user_name_attribute; 'ldap/user_name_attribute': value => $user_name_attribute;
'ldap/user_mail_attribute': value => $user_mail_attribute; 'ldap/user_mail_attribute': value => $user_mail_attribute;
'ldap/user_enabled_attribute': value => $user_enabled_attribute; 'ldap/user_enabled_attribute': value => $user_enabled_attribute;
'ldap/user_enabled_mask': value => $user_enabled_mask; 'ldap/user_enabled_mask': value => $user_enabled_mask;
'ldap/user_enabled_default': value => $user_enabled_default; 'ldap/user_enabled_default': value => $user_enabled_default;
'ldap/user_attribute_ignore': value => $user_attribute_ignore; 'ldap/user_enabled_invert': value => $user_enabled_invert;
'ldap/user_default_project_id_attribute': value => $user_default_project_id_attribute; 'ldap/user_attribute_ignore': value => $user_attribute_ignore;
'ldap/user_allow_create': value => $user_allow_create; 'ldap/user_default_project_id_attribute': value => $user_default_project_id_attribute;
'ldap/user_allow_update': value => $user_allow_update; 'ldap/user_allow_create': value => $user_allow_create;
'ldap/user_allow_delete': value => $user_allow_delete; 'ldap/user_allow_update': value => $user_allow_update;
'ldap/user_pass_attribute': value => $user_pass_attribute; 'ldap/user_allow_delete': value => $user_allow_delete;
'ldap/user_enabled_emulation': value => $user_enabled_emulation; 'ldap/user_pass_attribute': value => $user_pass_attribute;
'ldap/user_enabled_emulation_dn': value => $user_enabled_emulation_dn; 'ldap/user_enabled_emulation': value => $user_enabled_emulation;
'ldap/user_additional_attribute_mapping': value => $user_additional_attribute_mapping; 'ldap/user_enabled_emulation_dn': value => $user_enabled_emulation_dn;
'ldap/tenant_tree_dn': value => $tenant_tree_dn; 'ldap/user_additional_attribute_mapping': value => $user_additional_attribute_mapping;
'ldap/tenant_filter': value => $tenant_filter; 'ldap/project_tree_dn': value => $project_tree_dn_real;
'ldap/tenant_objectclass': value => $tenant_objectclass; 'ldap/project_filter': value => $project_filter_real;
'ldap/tenant_id_attribute': value => $tenant_id_attribute; 'ldap/project_objectclass': value => $project_objectclass_real;
'ldap/tenant_member_attribute': value => $tenant_member_attribute; 'ldap/project_id_attribute': value => $project_id_attribute_real;
'ldap/tenant_desc_attribute': value => $tenant_desc_attribute; 'ldap/project_member_attribute': value => $project_member_attribute_real;
'ldap/tenant_name_attribute': value => $tenant_name_attribute; 'ldap/project_desc_attribute': value => $project_desc_attribute_real;
'ldap/tenant_enabled_attribute': value => $tenant_enabled_attribute; 'ldap/project_name_attribute': value => $project_name_attribute_real;
'ldap/tenant_attribute_ignore': value => $tenant_attribute_ignore; 'ldap/project_enabled_attribute': value => $project_enabled_attribute_real;
'ldap/tenant_domain_id_attribute': value => $tenant_domain_id_attribute; 'ldap/project_attribute_ignore': value => $project_attribute_ignore_real;
'ldap/tenant_allow_create': value => $tenant_allow_create; 'ldap/project_domain_id_attribute': value => $project_domain_id_attribute_real;
'ldap/tenant_allow_update': value => $tenant_allow_update; 'ldap/project_allow_create': value => $project_allow_create_real;
'ldap/tenant_allow_delete': value => $tenant_allow_delete; 'ldap/project_allow_update': value => $project_allow_update_real;
'ldap/tenant_enabled_emulation': value => $tenant_enabled_emulation; 'ldap/project_allow_delete': value => $project_allow_delete_real;
'ldap/tenant_enabled_emulation_dn': value => $tenant_enabled_emulation_dn; 'ldap/project_enabled_emulation': value => $project_enabled_emulation_real;
'ldap/tenant_additional_attribute_mapping': value => $tenant_additional_attribute_mapping; 'ldap/project_enabled_emulation_dn': value => $project_enabled_emulation_dn_real;
'ldap/role_tree_dn': value => $role_tree_dn; 'ldap/project_additional_attribute_mapping': value => $project_additional_attribute_mapping_real;
'ldap/role_filter': value => $role_filter; 'ldap/role_tree_dn': value => $role_tree_dn;
'ldap/role_objectclass': value => $role_objectclass; 'ldap/role_filter': value => $role_filter;
'ldap/role_id_attribute': value => $role_id_attribute; 'ldap/role_objectclass': value => $role_objectclass;
'ldap/role_name_attribute': value => $role_name_attribute; 'ldap/role_id_attribute': value => $role_id_attribute;
'ldap/role_member_attribute': value => $role_member_attribute; 'ldap/role_name_attribute': value => $role_name_attribute;
'ldap/role_attribute_ignore': value => $role_attribute_ignore; 'ldap/role_member_attribute': value => $role_member_attribute;
'ldap/role_allow_create': value => $role_allow_create; 'ldap/role_attribute_ignore': value => $role_attribute_ignore;
'ldap/role_allow_update': value => $role_allow_update; 'ldap/role_allow_create': value => $role_allow_create;
'ldap/role_allow_delete': value => $role_allow_delete; 'ldap/role_allow_update': value => $role_allow_update;
'ldap/role_additional_attribute_mapping': value => $role_additional_attribute_mapping; 'ldap/role_allow_delete': value => $role_allow_delete;
'ldap/group_tree_dn': value => $group_tree_dn; 'ldap/role_additional_attribute_mapping': value => $role_additional_attribute_mapping;
'ldap/group_filter': value => $group_filter; 'ldap/group_tree_dn': value => $group_tree_dn;
'ldap/group_objectclass': value => $group_objectclass; 'ldap/group_filter': value => $group_filter;
'ldap/group_id_attribute': value => $group_id_attribute; 'ldap/group_objectclass': value => $group_objectclass;
'ldap/group_name_attribute': value => $group_name_attribute; 'ldap/group_id_attribute': value => $group_id_attribute;
'ldap/group_member_attribute': value => $group_member_attribute; 'ldap/group_name_attribute': value => $group_name_attribute;
'ldap/group_desc_attribute': value => $group_desc_attribute; 'ldap/group_member_attribute': value => $group_member_attribute;
'ldap/group_attribute_ignore': value => $group_attribute_ignore; 'ldap/group_desc_attribute': value => $group_desc_attribute;
'ldap/group_allow_create': value => $group_allow_create; 'ldap/group_attribute_ignore': value => $group_attribute_ignore;
'ldap/group_allow_update': value => $group_allow_update; 'ldap/group_allow_create': value => $group_allow_create;
'ldap/group_allow_delete': value => $group_allow_delete; 'ldap/group_allow_update': value => $group_allow_update;
'ldap/group_additional_attribute_mapping': value => $group_additional_attribute_mapping; 'ldap/group_allow_delete': value => $group_allow_delete;
'ldap/use_tls': value => $use_tls; 'ldap/group_additional_attribute_mapping': value => $group_additional_attribute_mapping;
'ldap/tls_cacertdir': value => $tls_cacertdir; 'ldap/use_tls': value => $use_tls;
'ldap/tls_cacertfile': value => $tls_cacertfile; 'ldap/tls_cacertdir': value => $tls_cacertdir;
'ldap/tls_req_cert': value => $tls_req_cert; 'ldap/tls_cacertfile': value => $tls_cacertfile;
'identity/driver': value => $identity_driver; 'ldap/tls_req_cert': value => $tls_req_cert;
'assignment/driver': value => $assignment_driver; 'ldap/use_pool': value => $use_pool;
'ldap/pool_size': value => $pool_size;
'ldap/pool_retry_max': value => $pool_retry_max;
'ldap/pool_retry_delay': value => $pool_retry_delay;
'ldap/pool_connection_timeout': value => $pool_connection_timeout;
'ldap/pool_connection_lifetime': value => $pool_connection_lifetime;
'ldap/use_auth_pool': value => $use_auth_pool;
'ldap/auth_pool_size': value => $auth_pool_size;
'ldap/auth_pool_connection_lifetime': value => $auth_pool_connection_lifetime;
'identity/driver': value => $identity_driver;
'credential/driver': value => $credential_driver;
'assignment/driver': value => $assignment_driver;
} }
} }

View File

@ -0,0 +1,211 @@
# Class keystone::logging
#
# keystone extended logging configuration
#
# == parameters
#
# [*logging_context_format_string*]
# (optional) Format string to use for log messages with context.
# Defaults to undef.
# Example: '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s\
# [%(request_id)s %(user_identity)s] %(instance)s%(message)s'
#
# [*logging_default_format_string*]
# (optional) Format string to use for log messages without context.
# Defaults to undef.
# Example: '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s\
# [-] %(instance)s%(message)s'
#
# [*logging_debug_format_suffix*]
# (optional) Formatted data to append to log format when level is DEBUG.
# Defaults to undef.
# Example: '%(funcName)s %(pathname)s:%(lineno)d'
#
# [*logging_exception_prefix*]
# (optional) Prefix each line of exception output with this format.
# Defaults to undef.
# Example: '%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s'
#
# [*log_config_append*]
# The name of an additional logging configuration file.
# Defaults to undef.
# See https://docs.python.org/2/howto/logging.html
#
# [*default_log_levels*]
# (optional) Hash of logger (keys) and level (values) pairs.
# Defaults to undef.
# Example:
# { 'amqp' => 'WARN', 'amqplib' => 'WARN', 'boto' => 'WARN',
# 'qpid' => 'WARN', 'sqlalchemy' => 'WARN', 'suds' => 'INFO',
# 'oslo.messaging' => 'INFO', 'iso8601' => 'WARN',
# 'requests.packages.urllib3.connectionpool' => 'WARN',
# 'urllib3.connectionpool' => 'WARN',
# 'websocket' => 'WARN', 'keystonemiddleware' => 'WARN',
# 'routes.middleware' => 'WARN', stevedore => 'WARN' }
#
# [*publish_errors*]
# (optional) Publish error events (boolean value).
# Defaults to undef (false if unconfigured).
#
# [*fatal_deprecations*]
# (optional) Make deprecations fatal (boolean value)
# Defaults to undef (false if unconfigured).
#
# [*instance_format*]
# (optional) If an instance is passed with the log message, format it
# like this (string value).
# Defaults to undef.
# Example: '[instance: %(uuid)s] '
#
# [*instance_uuid_format*]
# (optional) If an instance UUID is passed with the log message, format
# it like this (string value).
# Defaults to undef.
# Example: instance_uuid_format='[instance: %(uuid)s] '
# [*log_date_format*]
# (optional) Format string for %%(asctime)s in log records.
# Defaults to undef.
# Example: 'Y-%m-%d %H:%M:%S'
class keystone::logging(
$logging_context_format_string = undef,
$logging_default_format_string = undef,
$logging_debug_format_suffix = undef,
$logging_exception_prefix = undef,
$log_config_append = undef,
$default_log_levels = undef,
$publish_errors = undef,
$fatal_deprecations = undef,
$instance_format = undef,
$instance_uuid_format = undef,
$log_date_format = undef,
) {
if $logging_context_format_string {
keystone_config {
'DEFAULT/logging_context_format_string' :
value => $logging_context_format_string;
}
}
else {
keystone_config {
'DEFAULT/logging_context_format_string' : ensure => absent;
}
}
if $logging_default_format_string {
keystone_config {
'DEFAULT/logging_default_format_string' :
value => $logging_default_format_string;
}
}
else {
keystone_config {
'DEFAULT/logging_default_format_string' : ensure => absent;
}
}
if $logging_debug_format_suffix {
keystone_config {
'DEFAULT/logging_debug_format_suffix' :
value => $logging_debug_format_suffix;
}
}
else {
keystone_config {
'DEFAULT/logging_debug_format_suffix' : ensure => absent;
}
}
if $logging_exception_prefix {
keystone_config {
'DEFAULT/logging_exception_prefix' : value => $logging_exception_prefix;
}
}
else {
keystone_config {
'DEFAULT/logging_exception_prefix' : ensure => absent;
}
}
if $log_config_append {
keystone_config {
'DEFAULT/log_config_append' : value => $log_config_append;
}
}
else {
keystone_config {
'DEFAULT/log_config_append' : ensure => absent;
}
}
if $default_log_levels {
keystone_config {
'DEFAULT/default_log_levels' :
value => join(sort(join_keys_to_values($default_log_levels, '=')), ',');
}
}
else {
keystone_config {
'DEFAULT/default_log_levels' : ensure => absent;
}
}
if $publish_errors {
keystone_config {
'DEFAULT/publish_errors' : value => $publish_errors;
}
}
else {
keystone_config {
'DEFAULT/publish_errors' : ensure => absent;
}
}
if $fatal_deprecations {
keystone_config {
'DEFAULT/fatal_deprecations' : value => $fatal_deprecations;
}
}
else {
keystone_config {
'DEFAULT/fatal_deprecations' : ensure => absent;
}
}
if $instance_format {
keystone_config {
'DEFAULT/instance_format' : value => $instance_format;
}
}
else {
keystone_config {
'DEFAULT/instance_format' : ensure => absent;
}
}
if $instance_uuid_format {
keystone_config {
'DEFAULT/instance_uuid_format' : value => $instance_uuid_format;
}
}
else {
keystone_config {
'DEFAULT/instance_uuid_format' : ensure => absent;
}
}
if $log_date_format {
keystone_config {
'DEFAULT/log_date_format' : value => $log_date_format;
}
}
else {
keystone_config {
'DEFAULT/log_date_format' : ensure => absent;
}
}
}

View File

@ -6,26 +6,33 @@ class keystone::params {
case $::osfamily { case $::osfamily {
'Debian': { 'Debian': {
$package_name = 'keystone' $package_name = 'keystone'
$service_name = 'keystone' $service_name = 'keystone'
$keystone_wsgi_script_path = '/usr/lib/cgi-bin/keystone' $keystone_wsgi_script_path = '/usr/lib/cgi-bin/keystone'
$python_memcache_package_name = 'python-memcache'
$paste_config = undef
case $::operatingsystem { case $::operatingsystem {
'Debian': { 'Debian': {
$service_provider = undef $service_provider = undef
$keystone_wsgi_script_source = '/usr/share/keystone/wsgi.py' $keystone_wsgi_script_source = '/usr/share/keystone/wsgi.py'
} }
default: { default: {
# NOTE: Ubuntu does not currently provide the keystone wsgi script in the
# keystone packages. When Ubuntu does provide the script, change this
# to use the correct path (which I'm assuming will be the same as Debian).
$service_provider = 'upstart' $service_provider = 'upstart'
$keystone_wsgi_script_source = 'puppet:///modules/keystone/httpd/keystone.py' $keystone_wsgi_script_source = 'puppet:///modules/keystone/httpd/keystone.py'
} }
} }
} }
'RedHat': { 'RedHat': {
$package_name = 'openstack-keystone' $package_name = 'openstack-keystone'
$service_name = 'openstack-keystone' $service_name = 'openstack-keystone'
$keystone_wsgi_script_path = '/var/www/cgi-bin/keystone' $keystone_wsgi_script_path = '/var/www/cgi-bin/keystone'
$service_provider = undef $python_memcache_package_name = 'python-memcached'
$keystone_wsgi_script_source = 'puppet:///modules/keystone/httpd/keystone.py' $service_provider = undef
$keystone_wsgi_script_source = '/usr/share/keystone/keystone.wsgi'
$paste_config = '/usr/share/keystone/keystone-dist-paste.ini'
} }
} }
} }

View File

@ -0,0 +1,39 @@
# == Class: keystone::policy
#
# Configure the keystone policies
#
# === Parameters
#
# [*policies*]
# (optional) Set of policies to configure for keystone
# Example :
# {
# 'keystone-context_is_admin' => {
# 'key' => 'context_is_admin',
# 'value' => 'true'
# },
# 'keystone-default' => {
# 'key' => 'default',
# 'value' => 'rule:admin_or_owner'
# }
# }
# Defaults to empty hash.
#
# [*policy_path*]
# (optional) Path to the nova policy.json file
# Defaults to /etc/keystone/policy.json
#
class keystone::policy (
$policies = {},
$policy_path = '/etc/keystone/policy.json',
) {
validate_hash($policies)
Openstacklib::Policy::Base {
file_path => $policy_path,
}
create_resources('openstacklib::policy::base', $policies)
}

View File

@ -1,6 +1,16 @@
# == Class keystone::python
# #
# installs client python libraries for keystone # installs client python libraries for keystone
# #
# === Parameters:
#
# [*client_package_name*]
# (optional) The name of python keystone client package
# Defaults to $keystone::params::client_package_name
#
# [*ensure*]
# (optional) The state for the keystone client package
# Defaults to 'present'
# #
class keystone::python ( class keystone::python (
$client_package_name = $keystone::params::client_package_name, $client_package_name = $keystone::params::client_package_name,

View File

@ -0,0 +1,164 @@
#
# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
#
# == Definition: keystone::resource::service_identity
#
# This resource configures Keystone resources for an OpenStack service.
#
# == Parameters:
#
# [*password*]
# Password to create for the service user;
# string; required
#
# [*auth_name*]
# The name of the service user;
# string; optional; default to the $title of the resource, i.e. 'nova'
#
# [*service_name*]
# Name of the service;
# string; required
#
# [*service_type*]
# Type of the service;
# string; required
#
# [*service_description*]
# Description of the service;
# string; optional: default to '$name service'
#
# [*public_url*]
# Public endpoint URL;
# string; required
#
# [*internal_url*]
# Internal endpoint URL;
# string; required
#
# [*admin_url*]
# Admin endpoint URL;
# string; required
#
# [*region*]
# Endpoint region;
# string; optional: default to 'RegionOne'
#
# [*tenant*]
# Service tenant;
# string; optional: default to 'services'
#
# [*ignore_default_tenant*]
# Ignore setting the default tenant value when the user is created.
# string; optional: default to false
#
# [*roles*]
# List of roles;
# string; optional: default to ['admin']
#
# [*domain*]
# User domain (keystone v3), not implemented yet.
# string; optional: default to undef
#
# [*email*]
# Service email;
# string; optional: default to '$auth_name@localhost'
#
# [*configure_endpoint*]
# Whether to create the endpoint.
# string; optional: default to True
#
# [*configure_user*]
# Whether to create the user.
# string; optional: default to True
#
# [*configure_user_role*]
# Whether to create the user role.
# string; optional: default to True
#
# [*configure_service*]
# Whether to create the service.
# string; optional: default to True
#
define keystone::resource::service_identity(
$admin_url = false,
$internal_url = false,
$password = false,
$public_url = false,
$service_type = false,
$auth_name = $name,
$configure_endpoint = true,
$configure_user = true,
$configure_user_role = true,
$configure_service = true,
$domain = undef,
$email = "${name}@localhost",
$region = 'RegionOne',
$service_name = undef,
$service_description = "${name} service",
$tenant = 'services',
$ignore_default_tenant = false,
$roles = ['admin'],
) {
if $domain {
warning('Keystone domains are not yet managed by puppet-keystone.')
}
if $service_name == undef {
$service_name_real = $auth_name
} else {
$service_name_real = $service_name
}
if $configure_user {
ensure_resource('keystone_user', $auth_name, {
'ensure' => 'present',
'enabled' => true,
'password' => $password,
'email' => $email,
'tenant' => $tenant,
'ignore_default_tenant' => $ignore_default_tenant,
})
}
if $configure_user_role {
ensure_resource('keystone_user_role', "${auth_name}@${tenant}", {
'ensure' => 'present',
'roles' => $roles,
})
if $configure_user {
Keystone_user[$auth_name] -> Keystone_user_role["${auth_name}@${tenant}"]
}
}
if $configure_service {
ensure_resource('keystone_service', $service_name_real, {
'ensure' => 'present',
'type' => $service_type,
'description' => $service_description,
})
}
if $configure_endpoint {
ensure_resource('keystone_endpoint', "${region}/${service_name_real}", {
'ensure' => 'present',
'public_url' => $public_url,
'admin_url' => $admin_url,
'internal_url' => $internal_url,
})
}
}

View File

@ -1,3 +1,4 @@
# == Class: keystone::roles::admin
# #
# This class implements some reasonable admin defaults for keystone. # This class implements some reasonable admin defaults for keystone.
# #
@ -8,12 +9,49 @@
# * admin role # * admin role
# * adds admin role to admin user on the "admin" tenant # * adds admin role to admin user on the "admin" tenant
# #
# [*Parameters*] # === Parameters:
# #
# [email] The email address for the admin. Required. # [*email*]
# [password] The admin password. Required. # The email address for the admin. Required.
# [admin_tenant] The name of the tenant to be used for admin privileges. Optional. Defaults to openstack. #
# [admin] Admin user. Optional. Defaults to admin. # [*password*]
# The admin password. Required.
#
# [*admin_roles*]
# The list of the roles with admin privileges. Optional.
# Defaults to ['admin'].
#
# [*admin_tenant*]
# The name of the tenant to be used for admin privileges. Optional.
# Defaults to openstack.
#
# [*service_tenant*]
# The name of service keystone tenant. Optional.
# Defaults to 'services'.
#
# [*admin*]
# Admin user. Optional.
# Defaults to admin.
#
# [*ignore_default_tenant*]
# Ignore setting the default tenant value when the user is created. Optional.
# Defaults to false.
#
# [*admin_tenant_desc*]
# Optional. Description for admin tenant,
# Defaults to 'admin tenant'
#
# [*service_tenant_desc*]
# Optional. Description for admin tenant,
# Defaults to 'Tenant for the openstack services'
#
# [*configure_user*]
# Optional. Should the admin user be created?
# Defaults to 'true'.
#
# [*configure_user_role*]
# Optional. Should the admin role be configured for the admin user?
# Defaulst to 'true'.
# #
# == Dependencies # == Dependencies
# == Examples # == Examples
@ -28,34 +66,47 @@
class keystone::roles::admin( class keystone::roles::admin(
$email, $email,
$password, $password,
$admin = 'admin', $admin = 'admin',
$admin_tenant = 'openstack', $admin_tenant = 'openstack',
$service_tenant = 'services' $admin_roles = ['admin'],
$service_tenant = 'services',
$ignore_default_tenant = false,
$admin_tenant_desc = 'admin tenant',
$service_tenant_desc = 'Tenant for the openstack services',
$configure_user = true,
$configure_user_role = true,
) { ) {
keystone_tenant { $service_tenant: keystone_tenant { $service_tenant:
ensure => present, ensure => present,
enabled => true, enabled => true,
description => 'Tenant for the openstack services', description => $service_tenant_desc,
} }
keystone_tenant { $admin_tenant: keystone_tenant { $admin_tenant:
ensure => present, ensure => present,
enabled => true, enabled => true,
description => 'admin tenant', description => $admin_tenant_desc,
}
keystone_user { $admin:
ensure => present,
enabled => true,
tenant => $admin_tenant,
email => $email,
password => $password,
} }
keystone_role { 'admin': keystone_role { 'admin':
ensure => present, ensure => present,
} }
keystone_user_role { "${admin}@${admin_tenant}":
ensure => present, if $configure_user {
roles => 'admin', keystone_user { $admin:
ensure => present,
enabled => true,
tenant => $admin_tenant,
email => $email,
password => $password,
ignore_default_tenant => $ignore_default_tenant,
}
}
if $configure_user_role {
keystone_user_role { "${admin}@${admin_tenant}":
ensure => present,
roles => $admin_roles,
}
} }
} }

View File

@ -0,0 +1,123 @@
# == Class keystone::service
#
# Encapsulates the keystone service to a class.
# This allows resources that require keystone to
# require this class, which can optionally
# validate that the service can actually accept
# connections.
#
# === Parameters
#
# [*ensure*]
# (optional) The desired state of the keystone service
# Defaults to undef
#
# [*service_name*]
# (optional) The name of the keystone service
# Defaults to $::keystone::params::service_name
#
# [*enable*]
# (optional) Whether to enable the keystone service
# Defaults to true
#
# [*hasstatus*]
# (optional) Whether the keystone service has status
# Defaults to true
#
# [*hasrestart*]
# (optional) Whether the keystone service has restart
# Defaults to true
#
# [*provider*]
# (optional) Provider for keystone service
# Defaults to $::keystone::params::service_provider
#
# [*validate*]
# (optional) Whether to validate the service is working after any service refreshes
# Defaults to false
#
# [*admin_token*]
# (optional) The admin token to use for validation
# Defaults to undef
#
# [*admin_endpoint*]
# (optional) The admin endpont to use for validation
# Defaults to 'http://localhost:35357/v2.0'
#
# [*retries*]
# (optional) Number of times to retry validation
# Defaults to 10
#
# [*delay*]
# (optional) Number of seconds between validation attempts
# Defaults to 2
#
# [*insecure*]
# (optional) Whether to validate keystone connections
# using the --insecure option with keystone client.
# Defaults to false
#
# [*cacert*]
# (optional) Whether to validate keystone connections
# using the specified argument with the --os-cacert option
# with keystone client.
# Defaults to undef
#
class keystone::service(
$ensure = undef,
$service_name = $::keystone::params::service_name,
$enable = true,
$hasstatus = true,
$hasrestart = true,
$provider = $::keystone::params::service_provider,
$validate = false,
$admin_token = undef,
$admin_endpoint = 'http://localhost:35357/v2.0',
$retries = 10,
$delay = 2,
$insecure = false,
$cacert = undef,
) {
include ::keystone::params
service { 'keystone':
ensure => $ensure,
name => $service_name,
enable => $enable,
hasstatus => $hasstatus,
hasrestart => $hasrestart,
provider => $provider
}
if $insecure {
$insecure_s = '--insecure'
} else {
$insecure_s = ''
}
if $cacert {
$cacert_s = "--os-cacert ${cacert}"
} else {
$cacert_s = ''
}
if $validate and $admin_token and $admin_endpoint {
$cmd = "openstack --os-auth-url ${admin_endpoint} --os-token ${admin_token} ${insecure_s} ${cacert_s} user list"
$catch = 'name'
exec { 'validate_keystone_connection':
path => '/usr/bin:/bin:/usr/sbin:/sbin',
provider => shell,
command => $cmd,
subscribe => Service['keystone'],
refreshonly => true,
tries => $retries,
try_sleep => $delay
}
Exec['validate_keystone_connection'] -> Keystone_user<||>
Exec['validate_keystone_connection'] -> Keystone_role<||>
Exec['validate_keystone_connection'] -> Keystone_tenant<||>
Exec['validate_keystone_connection'] -> Keystone_service<||>
Exec['validate_keystone_connection'] -> Keystone_endpoint<||>
}
}

View File

@ -46,15 +46,41 @@
# Optional. Defaults to 1 # Optional. Defaults to 1
# #
# [*ssl_cert*] # [*ssl_cert*]
# (optional) Path to SSL certificate
# Default to apache::vhost 'ssl_*' defaults.
#
# [*ssl_key*] # [*ssl_key*]
# (optional) Path to SSL key
# Default to apache::vhost 'ssl_*' defaults.
#
# [*ssl_chain*] # [*ssl_chain*]
# (optional) SSL chain
# Default to apache::vhost 'ssl_*' defaults.
#
# [*ssl_ca*] # [*ssl_ca*]
# (optional) Path to SSL certificate authority
# Default to apache::vhost 'ssl_*' defaults.
#
# [*ssl_crl_path*] # [*ssl_crl_path*]
# (optional) Path to SSL certificate revocation list
# Default to apache::vhost 'ssl_*' defaults.
#
# [*ssl_crl*] # [*ssl_crl*]
# (optional) SSL certificate revocation list name
# Default to apache::vhost 'ssl_*' defaults.
#
# [*ssl_certs_dir*] # [*ssl_certs_dir*]
# apache::vhost ssl parameters. # apache::vhost ssl parameters.
# Optional. Default to apache::vhost 'ssl_*' defaults. # Optional. Default to apache::vhost 'ssl_*' defaults.
# #
# [*priority*]
# (optional) The priority for the vhost.
# Defaults to '10'
#
# [*threads*]
# (optional) The number of threads for the vhost.
# Defaults to $::processorcount
#
# == Dependencies # == Dependencies
# #
# requires Class['apache'] & Class['keystone'] # requires Class['apache'] & Class['keystone']
@ -72,41 +98,40 @@
# #
# == Authors # == Authors
# #
# François Charlier <francois.charlier@enovance.com> # Francois Charlier <francois.charlier@enovance.com>
# #
# == Copyright # == Copyright
# #
# Copyright 2013 eNovance <licensing@enovance.com> # Copyright 2013 eNovance <licensing@enovance.com>
# #
class keystone::wsgi::apache ( class keystone::wsgi::apache (
$servername = $::fqdn, $servername = $::fqdn,
$public_port = 5000, $public_port = 5000,
$admin_port = 35357, $admin_port = 35357,
$bind_host = undef, $bind_host = undef,
$public_path = '/', $public_path = '/',
$admin_path = '/', $admin_path = '/',
$ssl = true, $ssl = true,
$workers = 1, $workers = 1,
$ssl_cert = undef, $ssl_cert = undef,
$ssl_key = undef, $ssl_key = undef,
$ssl_chain = undef, $ssl_chain = undef,
$ssl_ca = undef, $ssl_ca = undef,
$ssl_crl_path = undef, $ssl_crl_path = undef,
$ssl_crl = undef, $ssl_crl = undef,
$ssl_certs_dir = undef, $ssl_certs_dir = undef,
$threads = $::processorcount, $threads = $::processorcount,
$priority = '10', $priority = '10',
$wsgi_script_ensure = 'file',
$wsgi_script_source = undef,
) { ) {
include keystone::params include ::keystone::params
include ::apache include ::apache
include ::apache::mod::wsgi include ::apache::mod::wsgi
include keystone::db::sync if $ssl {
include ::apache::mod::ssl
}
Exec <| title == 'keystone-manage pki_setup' |> ~> Service['httpd'] Package['keystone'] -> Package['httpd']
Exec <| title == 'keystone-manage db_sync' |> ~> Service['httpd']
Package['keystone'] ~> Service['httpd'] Package['keystone'] ~> Service['httpd']
Keystone_config <| |> ~> Service['httpd'] Keystone_config <| |> ~> Service['httpd']
Service['httpd'] -> Keystone_endpoint <| |> Service['httpd'] -> Keystone_endpoint <| |>
@ -134,41 +159,44 @@ class keystone::wsgi::apache (
require => Package['httpd'], require => Package['httpd'],
} }
$wsgi_files = { file { 'keystone_wsgi_admin':
'keystone_wsgi_admin' => { ensure => file,
'path' => "${::keystone::params::keystone_wsgi_script_path}/admin", path => "${::keystone::params::keystone_wsgi_script_path}/admin",
}, source => $::keystone::params::keystone_wsgi_script_source,
'keystone_wsgi_main' => { owner => 'keystone',
'path' => "${::keystone::params::keystone_wsgi_script_path}/main", group => 'keystone',
}, mode => '0644',
# source file provided by keystone package
require => [File[$::keystone::params::keystone_wsgi_script_path], Package['keystone']],
} }
$wsgi_file_defaults = { file { 'keystone_wsgi_main':
'ensure' => $wsgi_script_ensure, ensure => file,
'owner' => 'keystone', path => "${::keystone::params::keystone_wsgi_script_path}/main",
'group' => 'keystone', source => $::keystone::params::keystone_wsgi_script_source,
'mode' => '0644', owner => 'keystone',
'require' => File[$::keystone::params::keystone_wsgi_script_path], group => 'keystone',
mode => '0644',
# source file provided by keystone package
require => [File[$::keystone::params::keystone_wsgi_script_path], Package['keystone']],
} }
$wsgi_script_source_real = $wsgi_script_source ? { $wsgi_daemon_process_options_main = {
default => $wsgi_script_source, user => 'keystone',
undef => $::keystone::params::keystone_wsgi_script_source, group => 'keystone',
processes => $workers,
threads => $threads,
display-name => 'keystone-main',
} }
case $wsgi_script_ensure { $wsgi_daemon_process_options_admin = {
default: { $wsgi_file_source = { 'source' => $wsgi_script_source_real } } user => 'keystone',
'link': { $wsgi_file_source = { 'target' => $wsgi_script_source_real } } group => 'keystone',
processes => $workers,
threads => $threads,
display-name => 'keystone-admin',
} }
create_resources('file', $wsgi_files, merge($wsgi_file_defaults, $wsgi_file_source))
$wsgi_daemon_process_options = {
user => 'keystone',
group => 'keystone',
processes => $workers,
threads => $threads
}
$wsgi_script_aliases_main = hash([$public_path_real,"${::keystone::params::keystone_wsgi_script_path}/main"]) $wsgi_script_aliases_main = hash([$public_path_real,"${::keystone::params::keystone_wsgi_script_path}/main"])
$wsgi_script_aliases_admin = hash([$admin_path_real, "${::keystone::params::keystone_wsgi_script_path}/admin"]) $wsgi_script_aliases_admin = hash([$admin_path_real, "${::keystone::params::keystone_wsgi_script_path}/admin"])
@ -178,7 +206,8 @@ class keystone::wsgi::apache (
$wsgi_script_aliases_main_real = $wsgi_script_aliases_main $wsgi_script_aliases_main_real = $wsgi_script_aliases_main
} }
apache::vhost { 'keystone_wsgi_main': ::apache::vhost { 'keystone_wsgi_main':
ensure => 'present',
servername => $servername, servername => $servername,
ip => $bind_host, ip => $bind_host,
port => $public_port, port => $public_port,
@ -195,14 +224,15 @@ class keystone::wsgi::apache (
ssl_crl => $ssl_crl, ssl_crl => $ssl_crl,
ssl_certs_dir => $ssl_certs_dir, ssl_certs_dir => $ssl_certs_dir,
wsgi_daemon_process => 'keystone_main', wsgi_daemon_process => 'keystone_main',
wsgi_daemon_process_options => $wsgi_daemon_process_options, wsgi_daemon_process_options => $wsgi_daemon_process_options_main,
wsgi_process_group => 'keystone_main', wsgi_process_group => 'keystone_main',
wsgi_script_aliases => $wsgi_script_aliases_main_real, wsgi_script_aliases => $wsgi_script_aliases_main_real,
require => [Class['apache::mod::wsgi'], File['keystone_wsgi_main']], require => File['keystone_wsgi_main'],
} }
if $public_port != $admin_port { if $public_port != $admin_port {
apache::vhost { 'keystone_wsgi_admin': ::apache::vhost { 'keystone_wsgi_admin':
ensure => 'present',
servername => $servername, servername => $servername,
ip => $bind_host, ip => $bind_host,
port => $admin_port, port => $admin_port,
@ -219,10 +249,10 @@ class keystone::wsgi::apache (
ssl_crl => $ssl_crl, ssl_crl => $ssl_crl,
ssl_certs_dir => $ssl_certs_dir, ssl_certs_dir => $ssl_certs_dir,
wsgi_daemon_process => 'keystone_admin', wsgi_daemon_process => 'keystone_admin',
wsgi_daemon_process_options => $wsgi_daemon_process_options, wsgi_daemon_process_options => $wsgi_daemon_process_options_admin,
wsgi_process_group => 'keystone_admin', wsgi_process_group => 'keystone_admin',
wsgi_script_aliases => $wsgi_script_aliases_admin, wsgi_script_aliases => $wsgi_script_aliases_admin,
require => [Class['apache::mod::wsgi'], File['keystone_wsgi_admin']], require => File['keystone_wsgi_admin'],
} }
} }
} }

View File

@ -0,0 +1,39 @@
{
"name": "stackforge-keystone",
"version": "5.1.0",
"author": "Puppet Labs and OpenStack Contributors",
"summary": "Puppet module for OpenStack Keystone",
"license": "Apache-2.0",
"source": "git://github.com/openstack/puppet-keystone.git",
"project_page": "https://launchpad.net/puppet-keystone",
"issues_url": "https://bugs.launchpad.net/puppet-keystone",
"requirements": [
{ "name": "pe","version_requirement": "3.x" },
{ "name": "puppet","version_requirement": "3.x" }
],
"operatingsystem_support": [
{
"operatingsystem": "Debian",
"operatingsystemrelease": ["7"]
},
{
"operatingsystem": "Fedora",
"operatingsystemrelease": ["20"]
},
{
"operatingsystem": "RedHat",
"operatingsystemrelease": ["6.5","7"]
},
{
"operatingsystem": "Ubuntu",
"operatingsystemrelease": ["12.04","14.04"]
}
],
"description": "Installs and configures OpenStack Keystone (Identity).",
"dependencies": [
{ "name": "puppetlabs/apache", "version_requirement": ">=1.0.0 <2.0.0" },
{ "name": "puppetlabs/inifile", "version_requirement": ">=1.0.0 <2.0.0" },
{ "name": "puppetlabs/stdlib", "version_requirement": ">=4.0.0 <5.0.0" },
{ "name": "stackforge/openstacklib", "version_requirement": ">=5.0.0 <6.0.0" }
]
}

View File

@ -0,0 +1,92 @@
require 'spec_helper_acceptance'
describe 'basic keystone server with resources' do
context 'default parameters' do
it 'should work with no errors' do
pp= <<-EOS
Exec { logoutput => 'on_failure' }
# Common resources
case $::osfamily {
'Debian': {
include ::apt
class { '::openstack_extras::repo::debian::ubuntu':
release => 'kilo',
package_require => true,
}
}
'RedHat': {
class { '::openstack_extras::repo::redhat::redhat':
# Kilo is not GA yet, so let's use the testing repo
manage_rdo => false,
repo_hash => {
'rdo-kilo-testing' => {
'baseurl' => 'https://repos.fedorapeople.org/repos/openstack/openstack-kilo/testing/el7/',
# packages are not GA so not signed
'gpgcheck' => '0',
'priority' => 97,
},
},
}
}
default: {
fail("Unsupported osfamily (${::osfamily})")
}
}
class { '::mysql::server': }
# Keystone resources
class { '::keystone::client': }
class { '::keystone::cron::token_flush': }
class { '::keystone::db::mysql':
password => 'keystone',
}
class { '::keystone':
verbose => true,
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',
}
class { '::keystone::endpoint':
public_url => "https://${::fqdn}:5000/",
admin_url => "https://${::fqdn}:35357/",
}
::keystone::resource::service_identity { 'beaker-ci':
service_type => 'beaker',
service_description => 'beaker service',
service_name => 'beaker',
password => 'secret',
public_url => 'http://127.0.0.1:1234',
admin_url => 'http://127.0.0.1:1234',
internal_url => 'http://127.0.0.1:1234',
}
EOS
# Run it twice and test for idempotency
apply_manifest(pp, :catch_failures => true)
apply_manifest(pp, :catch_changes => true)
end
describe port(5000) do
it { is_expected.to be_listening.with('tcp') }
end
describe port(35357) do
it { is_expected.to be_listening.with('tcp') }
end
describe cron do
it { should have_entry('1 0 * * * keystone-manage token_flush >>/var/log/keystone/keystone-tokenflush.log 2>&1').with_user('keystone') }
end
end
end

View File

@ -0,0 +1,9 @@
HOSTS:
ubuntu-14.04-amd64:
roles:
- master
platform: ubuntu-14.04-amd64
hypervisor : none
ip: 127.0.0.1
CONFIG:
type: foss

View File

@ -0,0 +1,10 @@
HOSTS:
centos-70-x64:
roles:
- master
platform: el-7-x86_64
hypervisor : none
ip: 127.0.0.1
CONFIG:
type: foss
set_env: false

View File

@ -0,0 +1,10 @@
HOSTS:
ubuntu-14.04-amd64:
roles:
- master
platform: ubuntu-14.04-amd64
hypervisor : none
ip: 127.0.0.1
CONFIG:
type: foss
set_env: false

View File

@ -3,7 +3,10 @@ require 'spec_helper'
describe 'keystone::client' do describe 'keystone::client' do
describe "with default parameters" do describe "with default parameters" do
it { should contain_package('python-keystoneclient').with_ensure('present') } it { is_expected.to contain_package('python-keystoneclient').with(
'ensure' => 'present',
'tag' => 'openstack'
) }
end end
describe "with specified version" do describe "with specified version" do
@ -11,6 +14,9 @@ describe 'keystone::client' do
{:ensure => '2013.1'} {:ensure => '2013.1'}
end end
it { should contain_package('python-keystoneclient').with_ensure('2013.1') } it { is_expected.to contain_package('python-keystoneclient').with(
'ensure' => '2013.1',
'tag' => 'openstack'
) }
end end
end end

View File

@ -0,0 +1,68 @@
require 'spec_helper'
describe 'keystone::cron::token_flush' do
let :facts do
{ :osfamily => 'Debian' }
end
describe 'with default parameters' do
it 'configures a cron' do
is_expected.to contain_cron('keystone-manage token_flush').with(
:ensure => 'present',
:command => 'keystone-manage token_flush >>/var/log/keystone/keystone-tokenflush.log 2>&1',
:environment => 'PATH=/bin:/usr/bin:/usr/sbin SHELL=/bin/sh',
:user => 'keystone',
:minute => 1,
:hour => 0,
:monthday => '*',
:month => '*',
:weekday => '*'
)
end
end
describe 'when specifying a maxdelay param' do
let :params do
{
:maxdelay => 600
}
end
it 'configures a cron with delay' do
is_expected.to contain_cron('keystone-manage token_flush').with(
:ensure => 'present',
:command => 'sleep `expr ${RANDOM} \\% 600`; keystone-manage token_flush >>/var/log/keystone/keystone-tokenflush.log 2>&1',
:environment => 'PATH=/bin:/usr/bin:/usr/sbin SHELL=/bin/sh',
:user => 'keystone',
:minute => 1,
:hour => 0,
:monthday => '*',
:month => '*',
:weekday => '*'
)
end
end
describe 'when specifying a maxdelay param' do
let :params do
{
:ensure => 'absent'
}
end
it 'configures a cron with delay' do
is_expected.to contain_cron('keystone-manage token_flush').with(
:ensure => 'absent',
:command => 'keystone-manage token_flush >>/var/log/keystone/keystone-tokenflush.log 2>&1',
:environment => 'PATH=/bin:/usr/bin:/usr/sbin SHELL=/bin/sh',
:user => 'keystone',
:minute => 1,
:hour => 0,
:monthday => '*',
:month => '*',
:weekday => '*'
)
end
end
end

View File

@ -13,48 +13,23 @@ describe 'keystone::db::mysql' do
{ :osfamily => 'Debian' } { :osfamily => 'Debian' }
end end
let :param_defaults do let :params do
{ {
'password' => 'keystone_default_password', 'password' => 'keystone_default_password',
'dbname' => 'keystone', }
end
describe 'with only required params' do
it { is_expected.to contain_openstacklib__db__mysql('keystone').with(
'user' => 'keystone', 'user' => 'keystone',
'charset' => 'utf8', 'password_hash' => '*B552157B14BCEDDCEAA06767A012F31BDAA9CE3D',
'collate' => 'utf8_unicode_ci', 'dbname' => 'keystone',
'host' => '127.0.0.1', 'host' => '127.0.0.1',
'allowed_hosts' => ['127.0.0.%', '192.168.1.%'] 'charset' => 'utf8',
} :collate => 'utf8_general_ci',
end
[
{},
{
'password' => 'password',
'dbname' => 'not_keystone',
'user' => 'dan',
'host' => '127.0.0.2',
'charset' => 'utf8'
}
].each do |p|
let :params do
p
end
let :param_values do
param_defaults.merge(p)
end
it { should contain_class('mysql::python') }
it { should contain_mysql__db(param_values['dbname']).with(
'user' => param_values['user'],
'password' => param_values['password'],
'host' => param_values['host'],
'charset' => param_values['charset'],
'require' => 'Class[Mysql::Config]'
)} )}
end end
describe "overriding allowed_hosts param to array" do describe "overriding allowed_hosts param to array" do
let :params do let :params do
{ {
@ -63,16 +38,6 @@ describe 'keystone::db::mysql' do
} }
end end
it {should_not contain_keystone__db__mysql__host_access("127.0.0.1").with(
:user => 'keystone',
:password => 'keystonepass',
:database => 'keystone'
)}
it {should contain_keystone__db__mysql__host_access("%").with(
:user => 'keystone',
:password => 'keystonepass',
:database => 'keystone'
)}
end end
describe "overriding allowed_hosts param to string" do describe "overriding allowed_hosts param to string" do
let :params do let :params do
@ -82,11 +47,6 @@ describe 'keystone::db::mysql' do
} }
end end
it {should contain_keystone__db__mysql__host_access("192.168.1.1").with(
:user => 'keystone',
:password => 'keystonepass2',
:database => 'keystone'
)}
end end
describe "overriding allowed_hosts param equals to host param " do describe "overriding allowed_hosts param equals to host param " do
@ -97,11 +57,6 @@ describe 'keystone::db::mysql' do
} }
end end
it {should_not contain_keystone__db__mysql__host_access("127.0.0.1").with(
:user => 'keystone',
:password => 'keystonepass2',
:database => 'keystone'
)}
end end
end end

View File

@ -3,24 +3,56 @@ require 'spec_helper'
describe 'keystone::db::postgresql' do describe 'keystone::db::postgresql' do
let :req_params do let :req_params do
{:password => 'pw'} { :password => 'pw' }
end end
let :facts do let :pre_condition do
{ 'include postgresql::server'
:postgres_default_version => '8.4',
:osfamily => 'RedHat',
}
end end
describe 'with only required params' do context 'on a RedHat osfamily' do
let :params do let :facts do
req_params {
:osfamily => 'RedHat',
:operatingsystemrelease => '7.0',
:concat_basedir => '/var/lib/puppet/concat'
}
end end
it { should contain_postgresql__db('keystone').with(
:user => 'keystone', context 'with only required parameters' do
:password => 'pw' let :params do
) } req_params
end
it { is_expected.to contain_postgresql__server__db('keystone').with(
:user => 'keystone',
:password => 'md5c530c33636c58ae83ca933f39319273e'
)}
end
end
context 'on a Debian osfamily' do
let :facts do
{
:operatingsystemrelease => '7.8',
:operatingsystem => 'Debian',
:osfamily => 'Debian',
:concat_basedir => '/var/lib/puppet/concat'
}
end
context 'with only required parameters' do
let :params do
req_params
end
it { is_expected.to contain_postgresql__server__db('keystone').with(
:user => 'keystone',
:password => 'md5c530c33636c58ae83ca933f39319273e'
)}
end
end end
end end

View File

@ -2,14 +2,14 @@ require 'spec_helper'
describe 'keystone::endpoint' do describe 'keystone::endpoint' do
it { should contain_keystone_service('keystone').with( it { is_expected.to contain_keystone_service('keystone').with(
:ensure => 'present', :ensure => 'present',
:type => 'identity', :type => 'identity',
:description => 'OpenStack Identity Service' :description => 'OpenStack Identity Service'
)} )}
describe 'with default parameters' do describe 'with default parameters' do
it { should contain_keystone_endpoint('RegionOne/keystone').with( it { is_expected.to contain_keystone_endpoint('RegionOne/keystone').with(
:ensure => 'present', :ensure => 'present',
:public_url => 'http://127.0.0.1:5000/v2.0', :public_url => 'http://127.0.0.1:5000/v2.0',
:admin_url => 'http://127.0.0.1:35357/v2.0', :admin_url => 'http://127.0.0.1:35357/v2.0',
@ -26,7 +26,7 @@ describe 'keystone::endpoint' do
:internal_url => 'https://identity-int.some.tld/some/internal/endpoint' } :internal_url => 'https://identity-int.some.tld/some/internal/endpoint' }
end end
it { should contain_keystone_endpoint('RegionOne/keystone').with( it { is_expected.to contain_keystone_endpoint('RegionOne/keystone').with(
:ensure => 'present', :ensure => 'present',
:public_url => 'https://identity.some.tld/the/main/endpoint/v42.6', :public_url => 'https://identity.some.tld/the/main/endpoint/v42.6',
:admin_url => 'https://identity-int.some.tld/some/admin/endpoint/v42.6', :admin_url => 'https://identity-int.some.tld/some/admin/endpoint/v42.6',
@ -41,59 +41,11 @@ describe 'keystone::endpoint' do
end end
it 'internal_url should default to public_url' do it 'internal_url should default to public_url' do
should contain_keystone_endpoint('RegionOne/keystone').with( is_expected.to contain_keystone_endpoint('RegionOne/keystone').with(
:ensure => 'present', :ensure => 'present',
:public_url => 'https://identity.some.tld/the/main/endpoint/v2.0', :public_url => 'https://identity.some.tld/the/main/endpoint/v2.0',
:internal_url => 'https://identity.some.tld/the/main/endpoint/v2.0' :internal_url => 'https://identity.some.tld/the/main/endpoint/v2.0'
) )
end end
end end
describe 'with deprecated parameters' do
let :params do
{ :public_address => '10.0.0.1',
:admin_address => '10.0.0.2',
:internal_address => '10.0.0.3',
:public_port => '23456',
:admin_port => '12345',
:region => 'RegionTwo',
:version => 'v3.0' }
end
it { should contain_keystone_endpoint('RegionTwo/keystone').with(
:ensure => 'present',
:public_url => 'http://10.0.0.1:23456/v3.0',
:admin_url => 'http://10.0.0.2:12345/v3.0',
:internal_url => 'http://10.0.0.3:23456/v3.0'
)}
describe 'public_address overrides public_url' do
let :params do
{ :public_address => '10.0.0.1',
:public_port => '12345',
:public_url => 'http://10.10.10.10:23456/v3.0' }
end
it { should contain_keystone_endpoint('RegionOne/keystone').with(
:ensure => 'present',
:public_url => 'http://10.0.0.1:12345/v2.0'
)}
end
end
describe 'with overridden deprecated internal_port' do
let :params do
{ :internal_port => '12345' }
end
it { should contain_keystone_endpoint('RegionOne/keystone').with(
:ensure => 'present',
:public_url => 'http://127.0.0.1:5000/v2.0',
:admin_url => 'http://127.0.0.1:35357/v2.0',
:internal_url => 'http://127.0.0.1:12345/v2.0'
)}
end
end end

View File

@ -2,7 +2,7 @@ require 'spec_helper'
describe 'keystone::ldap' do describe 'keystone::ldap' do
describe 'with basic params' do describe 'with basic params' do
let :params do let :params do
{ {
:url => 'ldap://foo', :url => 'ldap://foo',
:user => 'cn=foo,dc=example,dc=com', :user => 'cn=foo,dc=example,dc=com',
@ -19,6 +19,7 @@ describe 'keystone::ldap' do
:user_enabled_attribute => 'UserAccountControl', :user_enabled_attribute => 'UserAccountControl',
:user_enabled_mask => '2', :user_enabled_mask => '2',
:user_enabled_default => '512', :user_enabled_default => '512',
:user_enabled_invert => 'False',
:user_attribute_ignore => '', :user_attribute_ignore => '',
:user_default_project_id_attribute => 'defaultProject', :user_default_project_id_attribute => 'defaultProject',
:user_allow_create => 'False', :user_allow_create => 'False',
@ -28,22 +29,22 @@ describe 'keystone::ldap' do
:user_enabled_emulation => 'True', :user_enabled_emulation => 'True',
:user_enabled_emulation_dn => 'cn=openstack-enabled,cn=groups,cn=accounts,dc=example,dc=com', :user_enabled_emulation_dn => 'cn=openstack-enabled,cn=groups,cn=accounts,dc=example,dc=com',
:user_additional_attribute_mapping => 'description:name, gecos:name', :user_additional_attribute_mapping => 'description:name, gecos:name',
:tenant_tree_dn => 'ou=projects,ou=openstack,dc=example,dc=com', :project_tree_dn => 'ou=projects,ou=openstack,dc=example,dc=com',
:tenant_filter => '', :project_filter => '',
:tenant_objectclass => 'organizationalUnit', :project_objectclass => 'organizationalUnit',
:tenant_id_attribute => 'ou', :project_id_attribute => 'ou',
:tenant_member_attribute => 'member', :project_member_attribute => 'member',
:tenant_desc_attribute => 'description', :project_desc_attribute => 'description',
:tenant_name_attribute => 'ou', :project_name_attribute => 'ou',
:tenant_enabled_attribute => 'enabled', :project_enabled_attribute => 'enabled',
:tenant_domain_id_attribute => 'businessCategory', :project_domain_id_attribute => 'businessCategory',
:tenant_attribute_ignore => '', :project_attribute_ignore => '',
:tenant_allow_create => 'True', :project_allow_create => 'True',
:tenant_allow_update => 'True', :project_allow_update => 'True',
:tenant_allow_delete => 'True', :project_allow_delete => 'True',
:tenant_enabled_emulation => 'False', :project_enabled_emulation => 'False',
:tenant_enabled_emulation_dn => 'True', :project_enabled_emulation_dn => 'True',
:tenant_additional_attribute_mapping => 'cn=enabled,ou=openstack,dc=example,dc=com', :project_additional_attribute_mapping => 'cn=enabled,ou=openstack,dc=example,dc=com',
:role_tree_dn => 'ou=roles,ou=openstack,dc=example,dc=com', :role_tree_dn => 'ou=roles,ou=openstack,dc=example,dc=com',
:role_filter => '', :role_filter => '',
:role_objectclass => 'organizationalRole', :role_objectclass => 'organizationalRole',
@ -72,85 +73,170 @@ describe 'keystone::ldap' do
:tls_cacertfile => '/etc/ssl/certs/ca-certificates.crt', :tls_cacertfile => '/etc/ssl/certs/ca-certificates.crt',
:tls_req_cert => 'demand', :tls_req_cert => 'demand',
:identity_driver => 'keystone.identity.backends.ldap.Identity', :identity_driver => 'keystone.identity.backends.ldap.Identity',
:credential_driver => 'keystone.credential.backends.ldap.Credential',
:assignment_driver => 'keystone.assignment.backends.ldap.Assignment', :assignment_driver => 'keystone.assignment.backends.ldap.Assignment',
:use_pool => 'True',
:pool_size => 20,
:pool_retry_max => 2,
:pool_retry_delay => 0.2,
:pool_connection_timeout => 222,
:pool_connection_lifetime => 222,
:use_auth_pool => 'True',
:auth_pool_size => 20,
:auth_pool_connection_lifetime => 200,
} }
end end
it { should contain_package('python-ldap') } it { is_expected.to contain_package('python-ldap') }
it { is_expected.to contain_package('python-ldappool') }
it 'should have basic params' do it 'should have basic params' do
should contain_keystone_config('ldap/url').with_value('ldap://foo') # basic params
should contain_keystone_config('ldap/user').with_value('cn=foo,dc=example,dc=com') is_expected.to contain_keystone_config('ldap/url').with_value('ldap://foo')
should contain_keystone_config('ldap/password').with_value('abcdefg').with_secret(true) is_expected.to contain_keystone_config('ldap/user').with_value('cn=foo,dc=example,dc=com')
should contain_keystone_config('ldap/suffix').with_value('dc=example,dc=com') is_expected.to contain_keystone_config('ldap/password').with_value('abcdefg').with_secret(true)
should contain_keystone_config('ldap/query_scope').with_value('sub') is_expected.to contain_keystone_config('ldap/suffix').with_value('dc=example,dc=com')
should contain_keystone_config('ldap/page_size').with_value('50') is_expected.to contain_keystone_config('ldap/query_scope').with_value('sub')
is_expected.to contain_keystone_config('ldap/page_size').with_value('50')
should contain_keystone_config('ldap/user_tree_dn').with_value('cn=users,dc=example,dc=com') # users
should contain_keystone_config('ldap/user_filter').with_value('(memberOf=cn=openstack,cn=groups,cn=accounts,dc=example,dc=com)') is_expected.to contain_keystone_config('ldap/user_tree_dn').with_value('cn=users,dc=example,dc=com')
should contain_keystone_config('ldap/user_objectclass').with_value('inetUser') is_expected.to contain_keystone_config('ldap/user_filter').with_value('(memberOf=cn=openstack,cn=groups,cn=accounts,dc=example,dc=com)')
should contain_keystone_config('ldap/user_id_attribute').with_value('uid') is_expected.to contain_keystone_config('ldap/user_objectclass').with_value('inetUser')
should contain_keystone_config('ldap/user_name_attribute').with_value('cn') is_expected.to contain_keystone_config('ldap/user_id_attribute').with_value('uid')
should contain_keystone_config('ldap/user_mail_attribute').with_value('mail') is_expected.to contain_keystone_config('ldap/user_name_attribute').with_value('cn')
should contain_keystone_config('ldap/user_enabled_attribute').with_value('UserAccountControl') is_expected.to contain_keystone_config('ldap/user_mail_attribute').with_value('mail')
should contain_keystone_config('ldap/user_enabled_mask').with_value('2') is_expected.to contain_keystone_config('ldap/user_enabled_attribute').with_value('UserAccountControl')
should contain_keystone_config('ldap/user_enabled_default').with_value('512') is_expected.to contain_keystone_config('ldap/user_enabled_mask').with_value('2')
should contain_keystone_config('ldap/user_attribute_ignore').with_value('') is_expected.to contain_keystone_config('ldap/user_enabled_default').with_value('512')
should contain_keystone_config('ldap/user_default_project_id_attribute').with_value('defaultProject') is_expected.to contain_keystone_config('ldap/user_enabled_invert').with_value('False')
should contain_keystone_config('ldap/user_tree_dn').with_value('cn=users,dc=example,dc=com') is_expected.to contain_keystone_config('ldap/user_attribute_ignore').with_value('')
should contain_keystone_config('ldap/user_allow_create').with_value('False') is_expected.to contain_keystone_config('ldap/user_default_project_id_attribute').with_value('defaultProject')
should contain_keystone_config('ldap/user_allow_update').with_value('False') is_expected.to contain_keystone_config('ldap/user_tree_dn').with_value('cn=users,dc=example,dc=com')
should contain_keystone_config('ldap/user_allow_delete').with_value('False') is_expected.to contain_keystone_config('ldap/user_allow_create').with_value('False')
should contain_keystone_config('ldap/user_pass_attribute').with_value('krbPassword') is_expected.to contain_keystone_config('ldap/user_allow_update').with_value('False')
should contain_keystone_config('ldap/user_enabled_emulation').with_value('True') is_expected.to contain_keystone_config('ldap/user_allow_delete').with_value('False')
should contain_keystone_config('ldap/user_enabled_emulation_dn').with_value('cn=openstack-enabled,cn=groups,cn=accounts,dc=example,dc=com') is_expected.to contain_keystone_config('ldap/user_pass_attribute').with_value('krbPassword')
should contain_keystone_config('ldap/user_additional_attribute_mapping').with_value('description:name, gecos:name') is_expected.to contain_keystone_config('ldap/user_enabled_emulation').with_value('True')
is_expected.to contain_keystone_config('ldap/user_enabled_emulation_dn').with_value('cn=openstack-enabled,cn=groups,cn=accounts,dc=example,dc=com')
is_expected.to contain_keystone_config('ldap/user_additional_attribute_mapping').with_value('description:name, gecos:name')
should contain_keystone_config('ldap/tenant_tree_dn').with_value('ou=projects,ou=openstack,dc=example,dc=com') # projects/tenants
should contain_keystone_config('ldap/tenant_filter').with_value('') is_expected.to contain_keystone_config('ldap/project_tree_dn').with_value('ou=projects,ou=openstack,dc=example,dc=com')
should contain_keystone_config('ldap/tenant_objectclass').with_value('organizationalUnit') is_expected.to contain_keystone_config('ldap/project_filter').with_value('')
should contain_keystone_config('ldap/tenant_id_attribute').with_value('ou') is_expected.to contain_keystone_config('ldap/project_objectclass').with_value('organizationalUnit')
should contain_keystone_config('ldap/tenant_member_attribute').with_value('member') is_expected.to contain_keystone_config('ldap/project_id_attribute').with_value('ou')
should contain_keystone_config('ldap/tenant_desc_attribute').with_value('description') is_expected.to contain_keystone_config('ldap/project_member_attribute').with_value('member')
should contain_keystone_config('ldap/tenant_name_attribute').with_value('ou') is_expected.to contain_keystone_config('ldap/project_desc_attribute').with_value('description')
should contain_keystone_config('ldap/tenant_enabled_attribute').with_value('enabled') is_expected.to contain_keystone_config('ldap/project_name_attribute').with_value('ou')
should contain_keystone_config('ldap/tenant_domain_id_attribute').with_value('businessCategory') is_expected.to contain_keystone_config('ldap/project_enabled_attribute').with_value('enabled')
should contain_keystone_config('ldap/tenant_attribute_ignore').with_value('') is_expected.to contain_keystone_config('ldap/project_domain_id_attribute').with_value('businessCategory')
should contain_keystone_config('ldap/tenant_allow_create').with_value('True') is_expected.to contain_keystone_config('ldap/project_attribute_ignore').with_value('')
should contain_keystone_config('ldap/tenant_allow_update').with_value('True') is_expected.to contain_keystone_config('ldap/project_allow_create').with_value('True')
should contain_keystone_config('ldap/tenant_allow_delete').with_value('True') is_expected.to contain_keystone_config('ldap/project_allow_update').with_value('True')
should contain_keystone_config('ldap/tenant_enabled_emulation').with_value('False') is_expected.to contain_keystone_config('ldap/project_allow_delete').with_value('True')
should contain_keystone_config('ldap/tenant_enabled_emulation_dn').with_value('True') is_expected.to contain_keystone_config('ldap/project_enabled_emulation').with_value('False')
should contain_keystone_config('ldap/tenant_additional_attribute_mapping').with_value('cn=enabled,ou=openstack,dc=example,dc=com') is_expected.to contain_keystone_config('ldap/project_enabled_emulation_dn').with_value('True')
should contain_keystone_config('ldap/role_tree_dn').with_value('ou=roles,ou=openstack,dc=example,dc=com') is_expected.to contain_keystone_config('ldap/project_additional_attribute_mapping').with_value('cn=enabled,ou=openstack,dc=example,dc=com')
should contain_keystone_config('ldap/role_filter').with_value('')
should contain_keystone_config('ldap/role_objectclass').with_value('organizationalRole')
should contain_keystone_config('ldap/role_id_attribute').with_value('cn')
should contain_keystone_config('ldap/role_name_attribute').with_value('ou')
should contain_keystone_config('ldap/role_member_attribute').with_value('roleOccupant')
should contain_keystone_config('ldap/role_attribute_ignore').with_value('description')
should contain_keystone_config('ldap/role_allow_create').with_value('True')
should contain_keystone_config('ldap/role_allow_update').with_value('True')
should contain_keystone_config('ldap/role_allow_delete').with_value('True')
should contain_keystone_config('ldap/role_additional_attribute_mapping').with_value('')
should contain_keystone_config('ldap/group_tree_dn').with_value('ou=groups,ou=openstack,dc=example,dc=com') # roles
should contain_keystone_config('ldap/group_filter').with_value('cn=enabled-groups,cn=groups,cn=accounts,dc=example,dc=com') is_expected.to contain_keystone_config('ldap/role_tree_dn').with_value('ou=roles,ou=openstack,dc=example,dc=com')
should contain_keystone_config('ldap/group_objectclass').with_value('organizationalRole') is_expected.to contain_keystone_config('ldap/role_filter').with_value('')
should contain_keystone_config('ldap/group_id_attribute').with_value('cn') is_expected.to contain_keystone_config('ldap/role_objectclass').with_value('organizationalRole')
should contain_keystone_config('ldap/group_member_attribute').with_value('roleOccupant') is_expected.to contain_keystone_config('ldap/role_id_attribute').with_value('cn')
should contain_keystone_config('ldap/group_desc_attribute').with_value('description') is_expected.to contain_keystone_config('ldap/role_name_attribute').with_value('ou')
should contain_keystone_config('ldap/group_name_attribute').with_value('cn') is_expected.to contain_keystone_config('ldap/role_member_attribute').with_value('roleOccupant')
should contain_keystone_config('ldap/group_attribute_ignore').with_value('') is_expected.to contain_keystone_config('ldap/role_attribute_ignore').with_value('description')
should contain_keystone_config('ldap/group_allow_create').with_value('False') is_expected.to contain_keystone_config('ldap/role_allow_create').with_value('True')
should contain_keystone_config('ldap/group_allow_update').with_value('False') is_expected.to contain_keystone_config('ldap/role_allow_update').with_value('True')
should contain_keystone_config('ldap/group_allow_delete').with_value('False') is_expected.to contain_keystone_config('ldap/role_allow_delete').with_value('True')
should contain_keystone_config('ldap/group_additional_attribute_mapping').with_value('') is_expected.to contain_keystone_config('ldap/role_additional_attribute_mapping').with_value('')
should contain_keystone_config('ldap/use_tls').with_value('False')
should contain_keystone_config('ldap/tls_cacertdir').with_value('/etc/ssl/certs/') # groups
should contain_keystone_config('ldap/tls_cacertfile').with_value('/etc/ssl/certs/ca-certificates.crt') is_expected.to contain_keystone_config('ldap/group_tree_dn').with_value('ou=groups,ou=openstack,dc=example,dc=com')
should contain_keystone_config('ldap/tls_req_cert').with_value('demand') is_expected.to contain_keystone_config('ldap/group_filter').with_value('cn=enabled-groups,cn=groups,cn=accounts,dc=example,dc=com')
should contain_keystone_config('identity/driver').with_value('keystone.identity.backends.ldap.Identity') is_expected.to contain_keystone_config('ldap/group_objectclass').with_value('organizationalRole')
should contain_keystone_config('assignment/driver').with_value('keystone.assignment.backends.ldap.Assignment') is_expected.to contain_keystone_config('ldap/group_id_attribute').with_value('cn')
is_expected.to contain_keystone_config('ldap/group_member_attribute').with_value('roleOccupant')
is_expected.to contain_keystone_config('ldap/group_desc_attribute').with_value('description')
is_expected.to contain_keystone_config('ldap/group_name_attribute').with_value('cn')
is_expected.to contain_keystone_config('ldap/group_attribute_ignore').with_value('')
is_expected.to contain_keystone_config('ldap/group_allow_create').with_value('False')
is_expected.to contain_keystone_config('ldap/group_allow_update').with_value('False')
is_expected.to contain_keystone_config('ldap/group_allow_delete').with_value('False')
is_expected.to contain_keystone_config('ldap/group_additional_attribute_mapping').with_value('')
# tls
is_expected.to contain_keystone_config('ldap/use_tls').with_value('False')
is_expected.to contain_keystone_config('ldap/tls_cacertdir').with_value('/etc/ssl/certs/')
is_expected.to contain_keystone_config('ldap/tls_cacertfile').with_value('/etc/ssl/certs/ca-certificates.crt')
is_expected.to contain_keystone_config('ldap/tls_req_cert').with_value('demand')
# ldap pooling
is_expected.to contain_keystone_config('ldap/use_pool').with_value('True')
is_expected.to contain_keystone_config('ldap/pool_size').with_value('20')
is_expected.to contain_keystone_config('ldap/pool_retry_max').with_value('2')
is_expected.to contain_keystone_config('ldap/pool_retry_delay').with_value('0.2')
is_expected.to contain_keystone_config('ldap/pool_connection_timeout').with_value('222')
is_expected.to contain_keystone_config('ldap/pool_connection_lifetime').with_value('222')
is_expected.to contain_keystone_config('ldap/use_auth_pool').with_value('True')
is_expected.to contain_keystone_config('ldap/auth_pool_size').with_value('20')
is_expected.to contain_keystone_config('ldap/auth_pool_connection_lifetime').with_value('200')
# drivers
is_expected.to contain_keystone_config('identity/driver').with_value('keystone.identity.backends.ldap.Identity')
is_expected.to contain_keystone_config('credential/driver').with_value('keystone.credential.backends.ldap.Credential')
is_expected.to contain_keystone_config('assignment/driver').with_value('keystone.assignment.backends.ldap.Assignment')
end end
end end
end
describe 'with deprecated params' do
let :params do
{
:tenant_tree_dn => 'ou=projects,ou=openstack,dc=example,dc=com',
:tenant_filter => '',
:tenant_objectclass => 'organizationalUnit',
:tenant_id_attribute => 'ou',
:tenant_member_attribute => 'member',
:tenant_desc_attribute => 'description',
:tenant_name_attribute => 'ou',
:tenant_enabled_attribute => 'enabled',
:tenant_domain_id_attribute => 'businessCategory',
:tenant_attribute_ignore => '',
:tenant_allow_create => 'True',
:tenant_allow_update => 'True',
:tenant_allow_delete => 'True',
:tenant_enabled_emulation => 'False',
:tenant_enabled_emulation_dn => 'True',
:tenant_additional_attribute_mapping => 'cn=enabled,ou=openstack,dc=example,dc=com',
}
end
it 'should work with deprecated params' do
is_expected.to contain_keystone_config('ldap/project_tree_dn').with_value('ou=projects,ou=openstack,dc=example,dc=com')
is_expected.to contain_keystone_config('ldap/project_filter')
is_expected.to contain_keystone_config('ldap/project_objectclass').with_value('organizationalUnit')
is_expected.to contain_keystone_config('ldap/project_id_attribute').with_value('ou')
is_expected.to contain_keystone_config('ldap/project_member_attribute').with_value('member')
is_expected.to contain_keystone_config('ldap/project_desc_attribute').with_value('description')
is_expected.to contain_keystone_config('ldap/project_name_attribute').with_value('ou')
is_expected.to contain_keystone_config('ldap/project_enabled_attribute').with_value('enabled')
is_expected.to contain_keystone_config('ldap/project_domain_id_attribute').with_value('businessCategory')
is_expected.to contain_keystone_config('ldap/project_attribute_ignore')
is_expected.to contain_keystone_config('ldap/project_allow_create').with_value('True')
is_expected.to contain_keystone_config('ldap/project_allow_update').with_value('True')
is_expected.to contain_keystone_config('ldap/project_allow_delete').with_value('True')
is_expected.to contain_keystone_config('ldap/project_enabled_emulation').with_value('False')
is_expected.to contain_keystone_config('ldap/project_enabled_emulation_dn').with_value('True')
is_expected.to contain_keystone_config('ldap/project_additional_attribute_mapping').with_value('cn=enabled,ou=openstack,dc=example,dc=com')
end
end
describe 'with deprecated and new params both set' do
let :params do
{
:tenant_tree_dn => 'ou=projects,ou=old-openstack,dc=example,dc=com',
:project_tree_dn => 'ou=projects,ou=new-openstack,dc=example,dc=com',
}
end
it_raises 'a Puppet::Error', /tenant_tree_dn and project_tree_dn are both set. results may be unexpected/
end
end

View File

@ -0,0 +1,107 @@
require 'spec_helper'
describe 'keystone::logging' do
let :params do
{
}
end
let :log_params do
{
:logging_context_format_string => '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s',
:logging_default_format_string => '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s',
:logging_debug_format_suffix => '%(funcName)s %(pathname)s:%(lineno)d',
:logging_exception_prefix => '%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s',
:log_config_append => '/etc/keystone/logging.conf',
:publish_errors => true,
:default_log_levels => {
'amqp' => 'WARN', 'amqplib' => 'WARN', 'boto' => 'WARN',
'qpid' => 'WARN', 'sqlalchemy' => 'WARN', 'suds' => 'INFO',
'iso8601' => 'WARN',
'requests.packages.urllib3.connectionpool' => 'WARN' },
:fatal_deprecations => true,
:instance_format => '[instance: %(uuid)s] ',
:instance_uuid_format => '[instance: %(uuid)s] ',
:log_date_format => '%Y-%m-%d %H:%M:%S',
}
end
shared_examples_for 'keystone-logging' do
context 'with extended logging options' do
before { params.merge!( log_params ) }
it_configures 'logging params set'
end
context 'without extended logging options' do
it_configures 'logging params unset'
end
end
shared_examples_for 'logging params set' do
it 'enables logging params' do
is_expected.to contain_keystone_config('DEFAULT/logging_context_format_string').with_value(
'%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s')
is_expected.to contain_keystone_config('DEFAULT/logging_default_format_string').with_value(
'%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s')
is_expected.to contain_keystone_config('DEFAULT/logging_debug_format_suffix').with_value(
'%(funcName)s %(pathname)s:%(lineno)d')
is_expected.to contain_keystone_config('DEFAULT/logging_exception_prefix').with_value(
'%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s')
is_expected.to contain_keystone_config('DEFAULT/log_config_append').with_value(
'/etc/keystone/logging.conf')
is_expected.to contain_keystone_config('DEFAULT/publish_errors').with_value(
true)
is_expected.to contain_keystone_config('DEFAULT/default_log_levels').with_value(
'amqp=WARN,amqplib=WARN,boto=WARN,iso8601=WARN,qpid=WARN,requests.packages.urllib3.connectionpool=WARN,sqlalchemy=WARN,suds=INFO')
is_expected.to contain_keystone_config('DEFAULT/fatal_deprecations').with_value(
true)
is_expected.to contain_keystone_config('DEFAULT/instance_format').with_value(
'[instance: %(uuid)s] ')
is_expected.to contain_keystone_config('DEFAULT/instance_uuid_format').with_value(
'[instance: %(uuid)s] ')
is_expected.to contain_keystone_config('DEFAULT/log_date_format').with_value(
'%Y-%m-%d %H:%M:%S')
end
end
shared_examples_for 'logging params unset' do
[ :logging_context_format_string, :logging_default_format_string,
:logging_debug_format_suffix, :logging_exception_prefix,
:log_config_append, :publish_errors,
:default_log_levels, :fatal_deprecations,
:instance_format, :instance_uuid_format,
:log_date_format, ].each { |param|
it { is_expected.to contain_keystone_config("DEFAULT/#{param}").with_ensure('absent') }
}
end
context 'on Debian platforms' do
let :facts do
{ :osfamily => 'Debian' }
end
it_configures 'keystone-logging'
end
context 'on RedHat platforms' do
let :facts do
{ :osfamily => 'RedHat' }
end
it_configures 'keystone-logging'
end
end

View File

@ -0,0 +1,41 @@
require 'spec_helper'
describe 'keystone::policy' do
shared_examples_for 'keystone policies' do
let :params do
{
:policy_path => '/etc/keystone/policy.json',
:policies => {
'context_is_admin' => {
'key' => 'context_is_admin',
'value' => 'foo:bar'
}
}
}
end
it 'set up the policies' do
is_expected.to contain_openstacklib__policy__base('context_is_admin').with({
:key => 'context_is_admin',
:value => 'foo:bar'
})
end
end
context 'on Debian platforms' do
let :facts do
{ :osfamily => 'Debian' }
end
it_configures 'keystone policies'
end
context 'on RedHat platforms' do
let :facts do
{ :osfamily => 'RedHat' }
end
it_configures 'keystone policies'
end
end

View File

@ -6,12 +6,12 @@ describe 'keystone::python' do
{ :osfamily => 'Debian' } { :osfamily => 'Debian' }
end end
it { should contain_package('python-keystone').with_ensure("present") } it { is_expected.to contain_package('python-keystone').with_ensure("present") }
describe 'override ensure' do describe 'override ensure' do
let(:params) { { :ensure => "latest" } } let(:params) { { :ensure => "latest" } }
it { should contain_package('python-keystone').with_ensure("latest") } it { is_expected.to contain_package('python-keystone').with_ensure("latest") }
end end
end end

View File

@ -11,26 +11,27 @@ describe 'keystone::roles::admin' do
} }
end end
it { should contain_keystone_tenant('services').with( it { is_expected.to contain_keystone_tenant('services').with(
:ensure => 'present', :ensure => 'present',
:enabled => true, :enabled => true,
:description => 'Tenant for the openstack services' :description => 'Tenant for the openstack services'
)} )}
it { should contain_keystone_tenant('openstack').with( it { is_expected.to contain_keystone_tenant('openstack').with(
:ensure => 'present', :ensure => 'present',
:enabled => true, :enabled => true,
:description => 'admin tenant' :description => 'admin tenant'
)} )}
it { should contain_keystone_user('admin').with( it { is_expected.to contain_keystone_user('admin').with(
:ensure => 'present', :ensure => 'present',
:enabled => true, :enabled => true,
:tenant => 'openstack', :tenant => 'openstack',
:email => 'foo@bar', :email => 'foo@bar',
:password => 'ChangeMe' :password => 'ChangeMe',
:ignore_default_tenant => 'false'
)} )}
it { should contain_keystone_role('admin').with_ensure('present') } it { is_expected.to contain_keystone_role('admin').with_ensure('present') }
it { should contain_keystone_user_role('admin@openstack').with( it { is_expected.to contain_keystone_user_role('admin@openstack').with(
:roles => 'admin', :roles => ['admin'],
:ensure => 'present' :ensure => 'present'
)} )}
@ -40,36 +41,68 @@ describe 'keystone::roles::admin' do
let :params do let :params do
{ {
:admin => 'admin', :admin => 'admin',
:email => 'foo@baz', :email => 'foo@baz',
:password => 'foo', :password => 'foo',
:admin_tenant => 'admin', :admin_tenant => 'admin',
:service_tenant => 'foobar' :admin_roles => ['admin', 'heat_stack_owner'],
:service_tenant => 'foobar',
:ignore_default_tenant => 'true',
:admin_tenant_desc => 'admin something else',
:service_tenant_desc => 'foobar description',
} }
end end
it { should contain_keystone_tenant('foobar').with( it { is_expected.to contain_keystone_tenant('foobar').with(
:ensure => 'present', :ensure => 'present',
:enabled => true, :enabled => true,
:description => 'Tenant for the openstack services' :description => 'foobar description'
)} )}
it { should contain_keystone_tenant('admin').with( it { is_expected.to contain_keystone_tenant('admin').with(
:ensure => 'present', :ensure => 'present',
:enabled => true, :enabled => true,
:description => 'admin tenant' :description => 'admin something else'
)} )}
it { should contain_keystone_user('admin').with( it { is_expected.to contain_keystone_user('admin').with(
:ensure => 'present', :ensure => 'present',
:enabled => true, :enabled => true,
:tenant => 'admin', :tenant => 'admin',
:email => 'foo@baz', :email => 'foo@baz',
:password => 'foo' :password => 'foo',
:ignore_default_tenant => 'true'
)} )}
it { should contain_keystone_user_role('admin@admin').with( it { is_expected.to contain_keystone_user_role('admin@admin').with(
:roles => 'admin', :roles => ['admin', 'heat_stack_owner'],
:ensure => 'present' :ensure => 'present'
)} )}
end 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
end end

View File

@ -0,0 +1,31 @@
require 'spec_helper'
describe 'keystone::service' do
describe "with default parameters" do
it { is_expected.to contain_service('keystone').with(
:ensure => nil,
:enable => true,
:hasstatus => true,
:hasrestart => true
) }
it { is_expected.to_not contain_exec('validate_keystone_connection') }
end
describe "with validation on" do
let :params do
{
:validate => 'true',
:admin_token => 'admintoken'
}
end
it { is_expected.to contain_service('keystone').with(
:ensure => nil,
:enable => true,
:hasstatus => true,
:hasrestart => true
) }
it { is_expected.to contain_exec('validate_keystone_connection') }
end
end

File diff suppressed because it is too large Load Diff

View File

@ -11,47 +11,48 @@ describe 'keystone::wsgi::apache' do
end end
let :pre_condition do let :pre_condition do
'include apache [
class { keystone: admin_token => "dummy" }' 'class { keystone: admin_token => "dummy", service_name => "httpd", enable_ssl => true }'
]
end end
shared_examples_for 'apache serving keystone with mod_wsgi' do shared_examples_for 'apache serving keystone with mod_wsgi' do
it { should contain_service('httpd').with_name(platform_parameters[:httpd_service_name]) } it { is_expected.to contain_service('httpd').with_name(platform_parameters[:httpd_service_name]) }
it { should contain_class('keystone::params') } it { is_expected.to contain_class('keystone::params') }
it { should contain_class('apache') } it { is_expected.to contain_class('apache') }
it { should contain_class('apache::mod::wsgi') } it { is_expected.to contain_class('apache::mod::wsgi') }
it { should contain_class('keystone::db::sync') } it { is_expected.to contain_class('keystone::db::sync') }
describe 'with default parameters' do describe 'with default parameters' do
it { should contain_file("#{platform_parameters[:wsgi_script_path]}").with( it { is_expected.to contain_file("#{platform_parameters[:wsgi_script_path]}").with(
'ensure' => 'directory', 'ensure' => 'directory',
'owner' => 'keystone', 'owner' => 'keystone',
'group' => 'keystone', 'group' => 'keystone',
'require' => 'Package[httpd]' 'require' => 'Package[httpd]'
)} )}
it { should contain_file('keystone_wsgi_admin').with( it { is_expected.to contain_file('keystone_wsgi_admin').with(
'ensure' => 'file', 'ensure' => 'file',
'path' => "#{platform_parameters[:wsgi_script_path]}/admin", 'path' => "#{platform_parameters[:wsgi_script_path]}/admin",
'source' => platform_parameters[:wsgi_script_source], 'source' => platform_parameters[:wsgi_script_source],
'owner' => 'keystone', 'owner' => 'keystone',
'group' => 'keystone', 'group' => 'keystone',
'mode' => '0644', 'mode' => '0644',
'require' => "File[#{platform_parameters[:wsgi_script_path]}]" 'require' => ["File[#{platform_parameters[:wsgi_script_path]}]", "Package[keystone]"]
)} )}
it { should contain_file('keystone_wsgi_main').with( it { is_expected.to contain_file('keystone_wsgi_main').with(
'ensure' => 'file', 'ensure' => 'file',
'path' => "#{platform_parameters[:wsgi_script_path]}/main", 'path' => "#{platform_parameters[:wsgi_script_path]}/main",
'source' => platform_parameters[:wsgi_script_source], 'source' => platform_parameters[:wsgi_script_source],
'owner' => 'keystone', 'owner' => 'keystone',
'group' => 'keystone', 'group' => 'keystone',
'mode' => '0644', 'mode' => '0644',
'require' => "File[#{platform_parameters[:wsgi_script_path]}]" 'require' => ["File[#{platform_parameters[:wsgi_script_path]}]", "Package[keystone]"]
)} )}
it { should contain_apache__vhost('keystone_wsgi_admin').with( it { is_expected.to contain_apache__vhost('keystone_wsgi_admin').with(
'servername' => 'some.host.tld', 'servername' => 'some.host.tld',
'ip' => nil, 'ip' => nil,
'port' => '35357', 'port' => '35357',
@ -59,12 +60,20 @@ describe 'keystone::wsgi::apache' do
'docroot_owner' => 'keystone', 'docroot_owner' => 'keystone',
'docroot_group' => 'keystone', 'docroot_group' => 'keystone',
'ssl' => 'true', 'ssl' => 'true',
'wsgi_daemon_process' => 'keystone_admin',
'wsgi_daemon_process_options' => {
'user' => 'keystone',
'group' => 'keystone',
'processes' => '1',
'threads' => '42',
'display-name' => 'keystone-admin',
},
'wsgi_process_group' => 'keystone_admin', 'wsgi_process_group' => 'keystone_admin',
'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/admin" }, 'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/admin" },
'require' => ['Class[Apache::Mod::Wsgi]', 'File[keystone_wsgi_admin]'] 'require' => 'File[keystone_wsgi_admin]'
)} )}
it { should contain_apache__vhost('keystone_wsgi_main').with( it { is_expected.to contain_apache__vhost('keystone_wsgi_main').with(
'servername' => 'some.host.tld', 'servername' => 'some.host.tld',
'ip' => nil, 'ip' => nil,
'port' => '5000', 'port' => '5000',
@ -73,15 +82,18 @@ describe 'keystone::wsgi::apache' do
'docroot_group' => 'keystone', 'docroot_group' => 'keystone',
'ssl' => 'true', 'ssl' => 'true',
'wsgi_daemon_process' => 'keystone_main', 'wsgi_daemon_process' => 'keystone_main',
'wsgi_daemon_process_options' => {
'user' => 'keystone',
'group' => 'keystone',
'processes' => '1',
'threads' => '42',
'display-name' => 'keystone-main',
},
'wsgi_process_group' => 'keystone_main', 'wsgi_process_group' => 'keystone_main',
'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/main" }, 'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/main" },
'require' => ['Class[Apache::Mod::Wsgi]', 'File[keystone_wsgi_main]'] 'require' => 'File[keystone_wsgi_main]'
)} )}
it "should set keystone wsgi options" do it { is_expected.to contain_file("#{platform_parameters[:httpd_ports_file]}") }
contain_file('25-keystone_wsgi_main.conf').with_content(
/^ WSGIDaemonProcess keystone group=keystone processes=1 threads=1 user=keystone$/
)
end
end end
describe 'when overriding parameters using different ports' do describe 'when overriding parameters using different ports' do
@ -96,7 +108,7 @@ describe 'keystone::wsgi::apache' do
} }
end end
it { should contain_apache__vhost('keystone_wsgi_admin').with( it { is_expected.to contain_apache__vhost('keystone_wsgi_admin').with(
'servername' => 'dummy.host', 'servername' => 'dummy.host',
'ip' => '10.42.51.1', 'ip' => '10.42.51.1',
'port' => '4142', 'port' => '4142',
@ -104,12 +116,20 @@ describe 'keystone::wsgi::apache' do
'docroot_owner' => 'keystone', 'docroot_owner' => 'keystone',
'docroot_group' => 'keystone', 'docroot_group' => 'keystone',
'ssl' => 'false', 'ssl' => 'false',
'wsgi_daemon_process' => 'keystone_admin',
'wsgi_daemon_process_options' => {
'user' => 'keystone',
'group' => 'keystone',
'processes' => '37',
'threads' => '42',
'display-name' => 'keystone-admin',
},
'wsgi_process_group' => 'keystone_admin', 'wsgi_process_group' => 'keystone_admin',
'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/admin" }, 'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/admin" },
'require' => ['Class[Apache::Mod::Wsgi]', 'File[keystone_wsgi_admin]'] 'require' => 'File[keystone_wsgi_admin]'
)} )}
it { should contain_apache__vhost('keystone_wsgi_main').with( it { is_expected.to contain_apache__vhost('keystone_wsgi_main').with(
'servername' => 'dummy.host', 'servername' => 'dummy.host',
'ip' => '10.42.51.1', 'ip' => '10.42.51.1',
'port' => '12345', 'port' => '12345',
@ -118,15 +138,19 @@ describe 'keystone::wsgi::apache' do
'docroot_group' => 'keystone', 'docroot_group' => 'keystone',
'ssl' => 'false', 'ssl' => 'false',
'wsgi_daemon_process' => 'keystone_main', 'wsgi_daemon_process' => 'keystone_main',
'wsgi_daemon_process_options' => {
'user' => 'keystone',
'group' => 'keystone',
'processes' => '37',
'threads' => '42',
'display-name' => 'keystone-main',
},
'wsgi_process_group' => 'keystone_main', 'wsgi_process_group' => 'keystone_main',
'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/main" }, 'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/main" },
'require' => ['Class[Apache::Mod::Wsgi]', 'File[keystone_wsgi_main]'] 'require' => 'File[keystone_wsgi_main]'
)} )}
it "should set keystone wsgi options" do
contain_file('25-keystone_wsgi_main.conf').with_content( it { is_expected.to contain_file("#{platform_parameters[:httpd_ports_file]}") }
/^ WSGIDaemonProcess keystone group=keystone processes=37 threads=1 user=keystone$/
)
end
end end
describe 'when overriding parameters using same port' do describe 'when overriding parameters using same port' do
@ -142,9 +166,9 @@ describe 'keystone::wsgi::apache' do
} }
end end
it { should_not contain_apache__vhost('keystone_wsgi_admin') } it { is_expected.to_not contain_apache__vhost('keystone_wsgi_admin') }
it { should contain_apache__vhost('keystone_wsgi_main').with( it { is_expected.to contain_apache__vhost('keystone_wsgi_main').with(
'servername' => 'dummy.host', 'servername' => 'dummy.host',
'ip' => nil, 'ip' => nil,
'port' => '4242', 'port' => '4242',
@ -153,18 +177,20 @@ describe 'keystone::wsgi::apache' do
'docroot_group' => 'keystone', 'docroot_group' => 'keystone',
'ssl' => 'true', 'ssl' => 'true',
'wsgi_daemon_process' => 'keystone_main', 'wsgi_daemon_process' => 'keystone_main',
'wsgi_daemon_process_options' => {
'user' => 'keystone',
'group' => 'keystone',
'processes' => '37',
'threads' => '42',
'display-name' => 'keystone-main',
},
'wsgi_process_group' => 'keystone_main', 'wsgi_process_group' => 'keystone_main',
'wsgi_script_aliases' => { 'wsgi_script_aliases' => {
'/main/endpoint' => "#{platform_parameters[:wsgi_script_path]}/main", '/main/endpoint' => "#{platform_parameters[:wsgi_script_path]}/main",
'/admin/endpoint' => "#{platform_parameters[:wsgi_script_path]}/admin" '/admin/endpoint' => "#{platform_parameters[:wsgi_script_path]}/admin"
}, },
'require' => ['Class[Apache::Mod::Wsgi]', 'File[keystone_wsgi_main]'] 'require' => 'File[keystone_wsgi_main]'
)} )}
it "should set keystone wsgi options" do
contain_file('25-keystone_wsgi_main.conf').with_content(
/^ WSGIDaemonProcess keystone group=keystone processes=37 threads=1 user=keystone$/
)
end
end end
describe 'when overriding parameters using same port and same path' do describe 'when overriding parameters using same port and same path' do
@ -182,35 +208,6 @@ describe 'keystone::wsgi::apache' do
it_raises 'a Puppet::Error', /When using the same port for public & private endpoints, public_path and admin_path should be different\./ it_raises 'a Puppet::Error', /When using the same port for public & private endpoints, public_path and admin_path should be different\./
end end
describe 'when overriding parameters using symlink and custom file source' do
let :params do
{
:wsgi_script_ensure => 'link',
:wsgi_script_source => '/opt/keystone/httpd/keystone.py',
}
end
it { is_expected.to contain_file('keystone_wsgi_admin').with(
'ensure' => 'link',
'path' => "#{platform_parameters[:wsgi_script_path]}/admin",
'target' => '/opt/keystone/httpd/keystone.py',
'owner' => 'keystone',
'group' => 'keystone',
'mode' => '0644',
'require' => "File[#{platform_parameters[:wsgi_script_path]}]"
)}
it { is_expected.to contain_file('keystone_wsgi_main').with(
'ensure' => 'link',
'path' => "#{platform_parameters[:wsgi_script_path]}/main",
'target' => '/opt/keystone/httpd/keystone.py',
'owner' => 'keystone',
'group' => 'keystone',
'mode' => '0644',
'require' => "File[#{platform_parameters[:wsgi_script_path]}]"
)}
end
end end
context 'on RedHat platforms' do context 'on RedHat platforms' do
@ -224,8 +221,9 @@ describe 'keystone::wsgi::apache' do
let :platform_parameters do let :platform_parameters do
{ {
:httpd_service_name => 'httpd', :httpd_service_name => 'httpd',
:httpd_ports_file => '/etc/httpd/conf/ports.conf',
:wsgi_script_path => '/var/www/cgi-bin/keystone', :wsgi_script_path => '/var/www/cgi-bin/keystone',
:wsgi_script_source => 'puppet:///modules/keystone/httpd/keystone.py' :wsgi_script_source => '/usr/share/keystone/keystone.wsgi'
} }
end end
@ -244,6 +242,7 @@ describe 'keystone::wsgi::apache' do
let :platform_parameters do let :platform_parameters do
{ {
:httpd_service_name => 'apache2', :httpd_service_name => 'apache2',
:httpd_ports_file => '/etc/apache2/ports.conf',
:wsgi_script_path => '/usr/lib/cgi-bin/keystone', :wsgi_script_path => '/usr/lib/cgi-bin/keystone',
:wsgi_script_source => '/usr/share/keystone/wsgi.py' :wsgi_script_source => '/usr/share/keystone/wsgi.py'
} }

View File

@ -0,0 +1,89 @@
#
# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
#
# Author: Emilien Macchi <emilien.macchi@enovance.com>
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
require 'spec_helper'
describe 'keystone::resource::service_identity' do
let (:title) { 'neutron' }
let :required_params do
{ :password => 'secrete',
:service_type => 'network',
:admin_url => 'http://192.168.0.1:9696',
:internal_url => 'http://10.0.0.1:9696',
:public_url => 'http://7.7.7.7:9696' }
end
shared_examples 'keystone::resource::service_identity examples' do
context 'with only required parameters' do
let :params do
required_params
end
it { is_expected.to contain_keystone_user(title).with(
:ensure => 'present',
:password => 'secrete',
:email => 'neutron@localhost',
:tenant => 'services',
)}
it { is_expected.to contain_keystone_user_role("#{title}@services").with(
:ensure => 'present',
:roles => ['admin'],
)}
it { is_expected.to contain_keystone_service(title).with(
:ensure => 'present',
:type => 'network',
:description => 'neutron service',
)}
it { is_expected.to contain_keystone_endpoint("RegionOne/#{title}").with(
:ensure => 'present',
:public_url => 'http://7.7.7.7:9696',
:internal_url => 'http://10.0.0.1:9696',
:admin_url => 'http://192.168.0.1:9696',
)}
end
context 'when omitting a required parameter password' do
let :params do
required_params.delete(:password)
end
it { expect { is_expected.to raise_error(Puppet::Error) } }
end
end
context 'on a Debian osfamily' do
let :facts do
{ :osfamily => "Debian" }
end
include_examples 'keystone::resource::service_identity examples'
end
context 'on a RedHat osfamily' do
let :facts do
{ :osfamily => 'RedHat' }
end
include_examples 'keystone::resource::service_identity examples'
end
end

View File

@ -1,5 +1,5 @@
shared_examples_for "a Puppet::Error" do |description| shared_examples_for "a Puppet::Error" do |description|
it "with message matching #{description.inspect}" do it "with message matching #{description.inspect}" do
expect { should have_class_count(1) }.to raise_error(Puppet::Error, description) expect { is_expected.to have_class_count(1) }.to raise_error(Puppet::Error, description)
end end
end end

View File

@ -1,8 +1,9 @@
# Load libraries from openstacklib here to simulate how they live together in a real puppet run (for provider unit tests)
$LOAD_PATH.push(File.join(File.dirname(__FILE__), 'fixtures', 'modules', 'openstacklib', 'lib'))
require 'puppetlabs_spec_helper/module_spec_helper' require 'puppetlabs_spec_helper/module_spec_helper'
require 'shared_examples' require 'shared_examples'
RSpec.configure do |c| RSpec.configure do |c|
c.alias_it_should_behave_like_to :it_configures, 'configures' c.alias_it_should_behave_like_to :it_configures, 'configures'
c.alias_it_should_behave_like_to :it_raises, 'raises' c.alias_it_should_behave_like_to :it_raises, 'raises'
end end

View File

@ -0,0 +1,46 @@
require 'beaker-rspec'
hosts.each do |host|
install_puppet
on host, "mkdir -p #{host['distmoduledir']}"
end
RSpec.configure do |c|
# Project root
proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..'))
# Readable test descriptions
c.formatter = :documentation
# Configure all nodes in nodeset
c.before :suite do
# Install module and dependencies
hosts.each do |host|
# install git
install_package host, 'git'
# clean out any module cruft
shell('rm -fr /etc/puppet/modules/*')
# install library modules from the forge
on host, puppet('module','install','puppetlabs-mysql'), { :acceptable_exit_codes => 0 }
on host, puppet('module','install','dprince/qpid'), { :acceptable_exit_codes => 0 }
on host, puppet('module','install','duritong/sysctl'), { :acceptable_exit_codes => 0 }
on host, puppet('module','install','puppetlabs-inifile'), { :acceptable_exit_codes => 0 }
on host, puppet('module','install','puppetlabs-rabbitmq'), { :acceptable_exit_codes => 0 }
on host, puppet('module','install','puppetlabs-apache'), { :acceptable_exit_codes => 0 }
# install puppet modules from git, use master
shell('git clone https://git.openstack.org/openstack/puppet-openstacklib /etc/puppet/modules/openstacklib')
shell('git clone https://git.openstack.org/openstack/puppet-openstack_extras /etc/puppet/modules/openstack_extras')
# Install the module being tested
puppet_module_install(:source => proj_root, :module_name => 'keystone')
# List modules installed to help with debugging
on hosts[0], puppet('module','list'), { :acceptable_exit_codes => 0 }
end
end
end

View File

@ -1,74 +0,0 @@
require 'puppet'
require 'spec_helper'
require 'puppet/provider/keystone_endpoint/keystone'
describe Puppet::Type.type(:keystone_endpoint).provider(:keystone) do
let :resource do
Puppet::Type::Keystone_endpoint.new(
:provider => :keystone,
:name => 'region/foo',
:ensure => :present,
:public_url => 'public_url',
:internal_url => 'internal_url',
:admin_url => 'admin_url'
)
end
let :provider do
described_class.new(resource)
end
before :each do
# keystone endpoint-list
described_class.stubs(:list_keystone_objects).with('endpoint', [5,6]).returns([
['endpoint-id', 'region', 'public_url', 'internal_url', 'admin_url', 4]
])
# keystone service-list
described_class.stubs(:list_keystone_objects).with('service', 4).returns([
[4, 'foo', 'type', 'description']
])
described_class.stubs(:get_keystone_object).with('service', 4, 'name').returns('foo')
described_class.prefetch('region/foo' => resource)
end
after :each do
described_class.prefetch({})
end
describe "self.instances" do
it "should have an instances method" do
provider.class.should respond_to(:instances)
end
it "should list instances" do
endpoints = described_class.instances
endpoints.size.should == 1
endpoints.map {|provider| provider.name} == ['region/foo']
end
end
describe '#create' do
it 'should call endpoint-create' do
provider.expects(:auth_keystone).with(
'endpoint-create', '--service-id', 4, includes(
'--publicurl', 'public_url', '--internalurl', 'internal_url',
'--region', 'region')
)
provider.create
end
end
describe '#flush' do
it 'should delete and create the endpoint once when any url gets updated' do
provider.expects(:destroy).times(1)
provider.expects(:create).times(1)
provider.public_url=('new-public_url')
provider.internal_url=('new-internal_url')
provider.admin_url=('new-admin_url')
provider.flush
end
end
end

View File

@ -0,0 +1,100 @@
require 'puppet'
require 'spec_helper'
require 'puppet/provider/keystone_endpoint/openstack'
provider_class = Puppet::Type.type(:keystone_endpoint).provider(:openstack)
describe provider_class do
shared_examples 'authenticated with environment variables' do
ENV['OS_USERNAME'] = 'test'
ENV['OS_PASSWORD'] = 'abc123'
ENV['OS_PROJECT_NAME'] = 'test'
ENV['OS_AUTH_URL'] = 'http://127.0.0.1:35357/v2.0'
end
describe 'when managing an endpoint' do
let(:endpoint_attrs) do
{
:name => 'foo/bar',
:ensure => 'present',
:public_url => 'http://127.0.0.1:5000/v2.0',
:internal_url => 'http://127.0.0.1:5001/v2.0',
:admin_url => 'http://127.0.0.1:5002/v2.0',
}
end
let(:resource) do
Puppet::Type::Keystone_endpoint.new(endpoint_attrs)
end
let(:provider) do
provider_class.new(resource)
end
it_behaves_like 'authenticated with environment variables' do
describe '#create' do
it 'creates an endpoint' do
provider.class.stubs(:openstack)
.with('endpoint', 'list', '--quiet', '--format', 'csv', '--long')
.returns('"ID","Region","Service Name","Service Type","PublicURL","AdminURL","InternalURL"
"1cb05cfed7c24279be884ba4f6520262","foo","bar","","http://127.0.0.1:5000/v2.0","http://127.0.0.1:5001/v2.0","http://127.0.0.1:5002/v2.0"
')
provider.class.stubs(:openstack)
.with('endpoint', 'create', '--format', 'shell', ['bar', '--region', 'foo', '--publicurl', 'http://127.0.0.1:5000/v2.0', '--internalurl', 'http://127.0.0.1:5001/v2.0', '--adminurl', 'http://127.0.0.1:5002/v2.0'])
.returns('adminurl="http://127.0.0.1:5002/v2.0"
id="3a5c4378981e4112a0d44902a43e16ef"
internalurl="http://127.0.0.1:5001/v2.0"
publicurl="http://127.0.0.1:5000/v2.0"
region="foo"
service_id="8137d72980fd462192f276585a002426"
service_name="bar"
service_type="test"
')
provider.create
expect(provider.exists?).to be_truthy
end
end
describe '#destroy' do
it 'destroys an endpoint' do
provider.class.stubs(:openstack)
.with('endpoint', 'list', '--quiet', '--format', 'csv', '--long')
.returns('"ID","Region","Service Name","Service Type","PublicURL","AdminURL","InternalURL"
"1cb05cfed7c24279be884ba4f6520262","foo","bar","test","http://127.0.0.1:5000/v2.0","http://127.0.0.1:5001/v2.0","http://127.0.0.1:5002/v2.0"
')
provider.class.stubs(:openstack)
.with('endpoint', 'delete', [])
provider.destroy
expect(provider.exists?).to be_falsey
end
end
describe '#exists' do
context 'when tenant does not exist' do
subject(:response) do
provider.class.stubs(:openstack)
.with('endpoint', 'list', '--quiet', '--format', 'csv', '--long')
.returns('"ID","Region","Service Name","Service Type","PublicURL","AdminURL","InternalURL"')
response = provider.exists?
end
it { is_expected.to be_falsey }
end
end
describe '#instances' do
it 'finds every tenant' do
provider.class.stubs(:openstack)
.with('endpoint', 'list', '--quiet', '--format', 'csv', '--long')
.returns('"ID","Region","Service Name","Service Type","PublicURL","AdminURL","InternalURL"
"3a5c4378981e4112a0d44902a43e16ef","foo","bar","test","http://127.0.0.1:5000/v2.0","http://127.0.0.1:5001/v2.0","http://127.0.0.1:5002/v2.0"
')
instances = Puppet::Type::Keystone_endpoint::ProviderOpenstack.instances
expect(instances.count).to eq(1)
end
end
end
end
end

View File

@ -0,0 +1,29 @@
#
# 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_paste_ini).provider(:ini_setting)
describe provider_class do
it 'should allow setting to be set explicitly' do
resource = Puppet::Type::Keystone_paste_ini.new(
{:name => 'dude/foo', :value => 'bar'}
)
provider = provider_class.new(resource)
provider.section.should == 'dude'
provider.setting.should == 'foo'
end
end

View File

@ -1,16 +0,0 @@
require 'puppet'
require 'spec_helper'
require 'puppet/provider/keystone_role/keystone'
provider_class = Puppet::Type.type(:keystone_role).provider(:keystone)
describe provider_class do
describe 'when query keystone objects' do
it 'should not cache keystone objects in catalog' do
provider_class.stubs(:build_role_hash).returns({ 'foo' => 'bar' })
provider_class.role_hash.should == ({ 'foo' => 'bar' })
provider_class.stubs(:build_role_hash).returns({ 'baz' => 'qux' })
provider_class.role_hash.should == ({ 'baz' => 'qux' })
end
end
end

View File

@ -0,0 +1,86 @@
require 'puppet'
require 'spec_helper'
require 'puppet/provider/keystone_role/openstack'
provider_class = Puppet::Type.type(:keystone_role).provider(:openstack)
describe provider_class do
shared_examples 'authenticated with environment variables' do
ENV['OS_USERNAME'] = 'test'
ENV['OS_PASSWORD'] = 'abc123'
ENV['OS_PROJECT_NAME'] = 'test'
ENV['OS_AUTH_URL'] = 'http://127.0.0.1:5000'
end
describe 'when creating a role' do
it_behaves_like 'authenticated with environment variables' do
let(:role_attrs) do
{
:name => 'foo',
:ensure => 'present',
}
end
let(:resource) do
Puppet::Type::Keystone_role.new(role_attrs)
end
let(:provider) do
provider_class.new(resource)
end
describe '#create' do
it 'creates a role' do
provider.class.stubs(:openstack)
.with('role', 'list', '--quiet', '--format', 'csv', [])
.returns('"ID","Name"
"1cb05cfed7c24279be884ba4f6520262","foo"
')
provider.class.stubs(:openstack)
.with('role', 'create', '--format', 'shell', 'foo')
.returns('name="foo"')
provider.create
expect(provider.exists?).to be_truthy
end
end
describe '#destroy' do
it 'destroys a role' do
provider.class.stubs(:openstack)
.with('role', 'list', '--quiet', '--format', 'csv', [])
.returns('"ID","Name"')
provider.class.stubs(:openstack)
.with('role', 'delete', [])
provider.destroy
expect(provider.exists?).to be_falsey
end
end
describe '#exists' do
context 'when role does not exist' do
subject(:response) do
provider.class.stubs(:openstack)
.with('role', 'list', '--quiet', '--format', 'csv', [])
.returns('"ID","Name"')
response = provider.exists?
end
it { is_expected.to be_falsey }
end
end
describe '#instances' do
it 'finds every role' do
provider.class.stubs(:openstack)
.with('role', 'list', '--quiet', '--format', 'csv', [])
.returns('"ID","Name"
"1cb05cfed7c24279be884ba4f6520262","foo"
')
instances = Puppet::Type::Keystone_role::ProviderOpenstack.instances
expect(instances.count).to eq(1)
end
end
end
end
end

View File

@ -1,16 +0,0 @@
require 'puppet'
require 'spec_helper'
require 'puppet/provider/keystone_service/keystone'
provider_class = Puppet::Type.type(:keystone_service).provider(:keystone)
describe provider_class do
describe 'when query keystone objects' do
it 'should not cache keystone objects in catalog' do
provider_class.stubs(:build_service_hash).returns({ 'foo' => 'bar' })
provider_class.service_hash.should == ({ 'foo' => 'bar' })
provider_class.stubs(:build_service_hash).returns({ 'baz' => 'qux' })
provider_class.service_hash.should == ({ 'baz' => 'qux' })
end
end
end

View File

@ -0,0 +1,93 @@
require 'puppet'
require 'spec_helper'
require 'puppet/provider/keystone_service/openstack'
provider_class = Puppet::Type.type(:keystone_service).provider(:openstack)
describe provider_class do
shared_examples 'authenticated with environment variables' do
ENV['OS_USERNAME'] = 'test'
ENV['OS_PASSWORD'] = 'abc123'
ENV['OS_PROJECT_NAME'] = 'test'
ENV['OS_AUTH_URL'] = 'http://127.0.0.1:35357/v2.0'
end
describe 'when managing a service' do
let(:service_attrs) do
{
:name => 'foo',
:description => 'foo',
:ensure => 'present',
:type => 'foo',
}
end
let(:resource) do
Puppet::Type::Keystone_service.new(service_attrs)
end
let(:provider) do
provider_class.new(resource)
end
it_behaves_like 'authenticated with environment variables' do
describe '#create' do
it 'creates a service' do
provider.class.stubs(:openstack)
.with('service', 'list', '--quiet', '--format', 'csv', '--long')
.returns('"ID","Name","Type","Description"
"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo"
')
provider.class.stubs(:openstack)
.with('service', 'create', '--format', 'shell', ['--name', 'foo', '--description', 'foo', 'foo'])
.returns('description="foo"
enabled="True"
id="8f0dd4c0abc44240998fbb3f5089ecbf"
name="foo"
type="foo"
')
provider.create
expect(provider.exists?).to be_truthy
end
end
describe '#destroy' do
it 'destroys a service' do
provider.class.stubs(:openstack)
.with('service', 'list', '--quiet', '--format', 'csv', '--long')
.returns('"ID","Name","Type","Description"
"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo"
')
provider.class.stubs(:openstack)
.with('service', 'delete', [])
provider.destroy
expect(provider.exists?).to be_falsey
end
context 'when service does not exist' do
subject(:response) do
provider.class.stubs(:openstack)
.with('service', 'list', '--quiet', '--format', 'csv', '--long')
.returns('"ID","Name","Type","Description"')
response = provider.exists?
end
it { is_expected.to be_falsey }
end
end
describe '#instances' do
it 'finds every service' do
provider.class.stubs(:openstack)
.with('service', 'list', '--quiet', '--format', 'csv', '--long')
.returns('"ID","Name","Type","Description"
"8f0dd4c0abc44240998fbb3f5089ecbf","foo","foo","foo"
')
instances = Puppet::Type::Keystone_service::ProviderOpenstack.instances
expect(instances.count).to eq(1)
end
end
end
end
end

View File

@ -3,164 +3,119 @@ require 'spec_helper'
require 'puppet/provider/keystone' require 'puppet/provider/keystone'
require 'tempfile' require 'tempfile'
klass = Puppet::Provider::Keystone klass = Puppet::Provider::Keystone
class Puppet::Provider::Keystone
@credentials = Puppet::Provider::Openstack::CredentialsV2_0.new
def self.reset
@admin_endpoint = nil
@tenant_hash = nil
@admin_token = nil
@keystone_file = nil
end
end
describe Puppet::Provider::Keystone do describe Puppet::Provider::Keystone do
after :each do after :each do
klass.reset klass.reset
end end
describe 'when retrieving the security token' do describe 'when retrieving the security token' do
it 'should return nothing if there is no keystone config file' do
it 'should fail if there is no keystone config file' do File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(false)
ini_file = Puppet::Util::IniConfig::File.new expect(klass.get_admin_token).to be_nil
t = Tempfile.new('foo')
path = t.path
t.unlink
ini_file.read(path)
expect do
klass.get_admin_token
end.to raise_error(Puppet::Error, /Keystone types will not work/)
end end
it 'should fail if the keystone config file does not have a DEFAULT section' do it 'should return nothing if the keystone config file does not have a DEFAULT section' do
mock = {} mock = {}
File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true)
Puppet::Util::IniConfig::File.expects(:new).returns(mock) Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf') mock.expects(:read).with('/etc/keystone/keystone.conf')
expect do expect(klass.get_admin_token).to be_nil
klass.get_admin_token
end.to raise_error(Puppet::Error, /Keystone types will not work/)
end end
it 'should fail if the keystone config file does not contain an admin token' do it 'should fail if the keystone config file does not contain an admin token' do
mock = {'DEFAULT' => {'not_a_token' => 'foo'}} mock = {'DEFAULT' => {'not_a_token' => 'foo'}}
File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true)
Puppet::Util::IniConfig::File.expects(:new).returns(mock) Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf') mock.expects(:read).with('/etc/keystone/keystone.conf')
expect do expect(klass.get_admin_token).to be_nil
klass.get_admin_token
end.to raise_error(Puppet::Error, /Keystone types will not work/)
end end
it 'should parse the admin token if it is in the config file' do it 'should parse the admin token if it is in the config file' do
mock = {'DEFAULT' => {'admin_token' => 'foo'}} mock = {'DEFAULT' => {'admin_token' => 'foo'}}
File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true)
Puppet::Util::IniConfig::File.expects(:new).returns(mock) Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf') mock.expects(:read).with('/etc/keystone/keystone.conf')
klass.get_admin_token.should == 'foo' expect(klass.get_admin_token).to eq('foo')
end end
it 'should use the specified bind_host in the admin endpoint' do it 'should use the specified bind_host in the admin endpoint' do
mock = {'DEFAULT' => {'admin_bind_host' => '192.168.56.210', 'admin_port' => '35357' }} mock = {'DEFAULT' => {'admin_bind_host' => '192.168.56.210', 'admin_port' => '35357' }}
File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true)
Puppet::Util::IniConfig::File.expects(:new).returns(mock) Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf') mock.expects(:read).with('/etc/keystone/keystone.conf')
klass.get_admin_endpoint.should == 'http://192.168.56.210:35357/v2.0/' expect(klass.get_admin_endpoint).to eq('http://192.168.56.210:35357/v2.0/')
end end
it 'should use localhost in the admin endpoint if bind_host is 0.0.0.0' do it 'should use localhost in the admin endpoint if bind_host is 0.0.0.0' do
mock = {'DEFAULT' => { 'admin_bind_host' => '0.0.0.0', 'admin_port' => '35357' }} mock = {'DEFAULT' => { 'admin_bind_host' => '0.0.0.0', 'admin_port' => '35357' }}
File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true)
Puppet::Util::IniConfig::File.expects(:new).returns(mock) Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf') mock.expects(:read).with('/etc/keystone/keystone.conf')
klass.get_admin_endpoint.should == 'http://127.0.0.1:35357/v2.0/' expect(klass.get_admin_endpoint).to eq('http://127.0.0.1:35357/v2.0/')
end
it 'should use [::1] in the admin endpoint if bind_host is ::0' do
mock = {'DEFAULT' => { 'admin_bind_host' => '::0', 'admin_port' => '35357' }}
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_endpoint).to eq('http://[::1]:35357/v2.0/')
end end
it 'should use localhost in the admin endpoint if bind_host is unspecified' do it 'should use localhost in the admin endpoint if bind_host is unspecified' do
mock = {'DEFAULT' => { 'admin_port' => '35357' }} mock = {'DEFAULT' => { 'admin_port' => '35357' }}
File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true)
Puppet::Util::IniConfig::File.expects(:new).returns(mock) Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf') mock.expects(:read).with('/etc/keystone/keystone.conf')
klass.get_admin_endpoint.should == 'http://127.0.0.1:35357/v2.0/' expect(klass.get_admin_endpoint).to eq('http://127.0.0.1:35357/v2.0/')
end end
it 'should use https if ssl is enabled' do it 'should use https if ssl is enabled' do
mock = {'DEFAULT' => {'admin_bind_host' => '192.168.56.210', 'admin_port' => '35357' }, 'ssl' => {'enable' => 'True'}} mock = {'DEFAULT' => {'admin_bind_host' => '192.168.56.210', 'admin_port' => '35357' }, 'ssl' => {'enable' => 'True'}}
File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true)
Puppet::Util::IniConfig::File.expects(:new).returns(mock) Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf') mock.expects(:read).with('/etc/keystone/keystone.conf')
klass.get_admin_endpoint.should == 'https://192.168.56.210:35357/v2.0/' expect(klass.get_admin_endpoint).to eq('https://192.168.56.210:35357/v2.0/')
end end
it 'should use http if ssl is disabled' do it 'should use http if ssl is disabled' do
mock = {'DEFAULT' => {'admin_bind_host' => '192.168.56.210', 'admin_port' => '35357' }, 'ssl' => {'enable' => 'False'}} mock = {'DEFAULT' => {'admin_bind_host' => '192.168.56.210', 'admin_port' => '35357' }, 'ssl' => {'enable' => 'False'}}
File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true)
Puppet::Util::IniConfig::File.expects(:new).returns(mock) Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf') mock.expects(:read).with('/etc/keystone/keystone.conf')
klass.get_admin_endpoint.should == 'http://192.168.56.210:35357/v2.0/' expect(klass.get_admin_endpoint).to eq('http://192.168.56.210:35357/v2.0/')
end end
it 'should use the defined admin_endpoint if available' do it 'should use the defined admin_endpoint if available' do
mock = {'DEFAULT' => {'admin_endpoint' => 'https://keystone.example.com/v2.0/' }, 'ssl' => {'enable' => 'False'}} mock = {'DEFAULT' => {'admin_endpoint' => 'https://keystone.example.com' }, 'ssl' => {'enable' => 'False'}}
File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true)
Puppet::Util::IniConfig::File.expects(:new).returns(mock) Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf') mock.expects(:read).with('/etc/keystone/keystone.conf')
klass.get_admin_endpoint.should == 'https://keystone.example.com/v2.0/' expect(klass.get_admin_endpoint).to eq('https://keystone.example.com/v2.0/')
end end
describe 'when testing keystone connection retries' do it 'should handle an admin_endpoint with a trailing slash' do
mock = {'DEFAULT' => {'admin_endpoint' => 'https://keystone.example.com/' }, 'ssl' => {'enable' => 'False'}}
['(HTTP 400)', File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true)
'[Errno 111] Connection refused',
'503 Service Unavailable',
'Max retries exceeded',
'HTTP Unable to establish connection',
'Unable to establish connection to http://127.0.0.1:35357/v2.0/OS-KSADM/roles'
].reverse.each do |valid_message|
it "should retry when keystone is not ready with error #{valid_message}" do
mock = {'DEFAULT' => {'admin_token' => 'foo'}}
Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf')
klass.expects(:sleep).with(10).returns(nil)
klass.expects(:keystone).twice.with('--os-endpoint', 'http://127.0.0.1:35357/v2.0/', ['test_retries']).raises(Exception, valid_message).then.returns('')
klass.auth_keystone('test_retries')
end
end
end
end
describe 'when keystone cli has warnings' do
it "should remove errors from results" do
mock = {'DEFAULT' => {'admin_token' => 'foo'}}
Puppet::Util::IniConfig::File.expects(:new).returns(mock) Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf') mock.expects(:read).with('/etc/keystone/keystone.conf')
klass.expects( expect(klass.get_admin_endpoint).to eq('https://keystone.example.com/v2.0/')
:keystone
).with(
'--os-endpoint',
'http://127.0.0.1:35357/v2.0/',
['test_retries']
).returns("WARNING\n+-+-+\nWARNING")
klass.auth_keystone('test_retries').should == "+-+-+\nWARNING"
end end
end
describe 'when query keystone objects' do
it 'should not cache keystone objects in catalog' do
klass.stubs(:build_tenant_hash).returns({ 'foo' => 'bar' })
klass.tenant_hash.should == ({ 'foo' => 'bar' })
klass.stubs(:build_tenant_hash).returns({ 'baz' => 'qux' })
klass.tenant_hash.should == ({ 'baz' => 'qux' })
end
end
describe 'when parsing keystone objects' do
it 'should parse valid output into a hash' do
data = <<-EOT
+-------------+----------------------------------+
| Property | Value |
+-------------+----------------------------------+
| description | default tenant |
| enabled | True |
| id | b71040f47e144399b7f10182918b5e2f |
| name | demo |
+-------------+----------------------------------+
EOT
expected = {
'description' => 'default tenant',
'enabled' => 'True',
'id' => 'b71040f47e144399b7f10182918b5e2f',
'name' => 'demo'
}
klass.parse_keystone_object(data).should == expected
end
end end
end end

View File

@ -1,65 +0,0 @@
require 'puppet'
require 'spec_helper'
require 'puppet/provider/keystone_tenant/keystone'
provider_class = Puppet::Type.type(:keystone_tenant).provider(:keystone)
describe provider_class do
describe 'when updating a tenant' do
let :tenant_name do
'foo'
end
let :tenant_attrs do
{
:name => tenant_name,
:description => '',
:ensure => 'present',
:enabled => 'True',
}
end
let :tenant_hash do
{ tenant_name => {
:id => 'id',
:name => tenant_name,
:description => '',
:ensure => 'present',
:enabled => 'True',
}
}
end
let :resource do
Puppet::Type::Keystone_tenant.new(tenant_attrs)
end
let :provider do
provider_class.new(resource)
end
before :each do
provider_class.expects(:build_tenant_hash).at_least(1).returns(tenant_hash)
end
it 'should call tenant-update to set enabled' do
provider.expects(:auth_keystone).with('tenant-update',
'--enabled',
'False',
'id')
provider.enabled=('False')
end
end
describe 'when query keystone objects' do
it 'should not cache keystone objects in catalog' do
provider_class.stubs(:build_tenant_hash).returns({ 'foo' => 'bar' })
provider_class.tenant_hash.should == ({ 'foo' => 'bar' })
provider_class.stubs(:build_tenant_hash).returns({ 'baz' => 'qux' })
provider_class.tenant_hash.should == ({ 'baz' => 'qux' })
end
end
end

View File

@ -0,0 +1,90 @@
require 'puppet'
require 'spec_helper'
require 'puppet/provider/keystone_tenant/openstack'
provider_class = Puppet::Type.type(:keystone_tenant).provider(:openstack)
describe provider_class do
shared_examples 'authenticated with environment variables' do
ENV['OS_USERNAME'] = 'test'
ENV['OS_PASSWORD'] = 'abc123'
ENV['OS_PROJECT_NAME'] = 'test'
ENV['OS_AUTH_URL'] = 'http://127.0.0.1:35357/v2.0'
end
describe 'when managing a tenant' do
let(:tenant_attrs) do
{
:name => 'foo',
:description => 'foo',
:ensure => 'present',
:enabled => 'True',
}
end
let(:resource) do
Puppet::Type::Keystone_tenant.new(tenant_attrs)
end
let(:provider) do
provider_class.new(resource)
end
it_behaves_like 'authenticated with environment variables' do
describe '#create' do
it 'creates a tenant' do
provider.class.stubs(:openstack)
.with('project', 'list', '--quiet', '--format', 'csv', '--long')
.returns('"ID","Name","Description","Enabled"
"1cb05cfed7c24279be884ba4f6520262","foo","foo",True
')
provider.class.stubs(:openstack)
.with('project', 'create', '--format', 'shell', ['foo', '--enable', '--description', 'foo'])
.returns('description="foo"
enabled="True"
name="foo"
')
provider.create
expect(provider.exists?).to be_truthy
end
end
describe '#destroy' do
it 'destroys a tenant' do
provider.class.stubs(:openstack)
.with('project', 'list', '--quiet', '--format', 'csv', '--long')
.returns('"ID","Name","Description","Enabled"')
provider.class.stubs(:openstack)
.with('project', 'delete', [])
provider.destroy
expect(provider.exists?).to be_falsey
end
end
context 'when tenant does not exist' do
subject(:response) do
provider.class.stubs(:openstack)
.with('project', 'list', '--quiet', '--format', 'csv', '--long')
.returns('"ID","Name","Description","Enabled"')
response = provider.exists?
end
it { is_expected.to be_falsey }
end
describe '#instances' do
it 'finds every tenant' do
provider.class.stubs(:openstack)
.with('project', 'list', '--quiet', '--format', 'csv', '--long')
.returns('"ID","Name","Description","Enabled"
"1cb05cfed7c24279be884ba4f6520262","foo","foo",True
')
instances = Puppet::Type::Keystone_tenant::ProviderOpenstack.instances
expect(instances.count).to eq(1)
end
end
end
end
end

View File

@ -1,78 +0,0 @@
require 'puppet'
require 'spec_helper'
require 'puppet/provider/keystone_user/keystone'
provider_class = Puppet::Type.type(:keystone_user).provider(:keystone)
describe provider_class do
describe 'when updating a user' do
let :resource do
Puppet::Type::Keystone_user.new(
{
:name => 'foo',
:ensure => 'present',
:enabled => 'True',
:tenant => 'foo2',
:email => 'foo@foo.com',
:password => 'passwd'
}
)
end
let :provider do
provider_class.new(resource)
end
before :each do
provider_class.expects(:build_user_hash).at_least(1).returns(
'foo' => {:id => 'id', :name => 'foo', :tenant => 'foo2', :password => 'passwd'}
)
end
after :each do
# reset global state
provider_class.prefetch(nil)
end
it 'should call user-password-update to change password' do
provider.expects(:auth_keystone).with('user-password-update', '--pass', 'newpassword', 'id')
provider.password=('newpassword')
end
end
describe 'when query keystone objects' do
it 'should not cache keystone objects in catalog' do
provider_class.stubs(:build_user_hash).returns({ 'foo' => 'bar' })
provider_class.user_hash.should == ({ 'foo' => 'bar' })
provider_class.stubs(:build_user_hash).returns({ 'baz' => 'qux' })
provider_class.user_hash.should == ({ 'baz' => 'qux' })
end
end
describe 'when updating a user with unmanaged password' do
let :resource do
Puppet::Type::Keystone_user.new(
{
:name => 'foo',
:ensure => 'present',
:enabled => 'True',
:tenant => 'foo2',
:email => 'foo@foo.com',
:password => 'passwd',
:replace_password => 'False',
}
)
end
let :provider do
provider_class.new(resource)
end
it 'should not call user-password-update to change password' do
provider.expects(:auth_keystone).with('user-password-update', '--pass', 'newpassword', 'id').times(0)
provider.password=('newpassword')
end
end
end

View File

@ -0,0 +1,277 @@
require 'puppet'
require 'spec_helper'
require 'puppet/provider/keystone_user/openstack'
provider_class = Puppet::Type.type(:keystone_user).provider(:openstack)
describe provider_class do
shared_examples 'authenticated with environment variables' do
ENV['OS_USERNAME'] = 'test'
ENV['OS_PASSWORD'] = 'abc123'
ENV['OS_PROJECT_NAME'] = 'test'
ENV['OS_AUTH_URL'] = 'http://127.0.0.1:5000'
end
let(:user_attrs) do
{
:name => 'foo',
:ensure => :present,
:enabled => 'True',
:password => 'foo',
:tenant => 'foo',
:email => 'foo@example.com',
}
end
let(:resource) do
Puppet::Type::Keystone_user.new(user_attrs)
end
let(:provider) do
provider_class.new(resource)
end
describe 'when managing a user' do
it_behaves_like 'authenticated with environment variables' do
describe '#create' do
it 'creates a user' do
provider.class.stubs(:openstack)
.with('user', 'list', '--quiet', '--format', 'csv', '--long')
.returns('"ID","Name","Project","Email","Enabled"
"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo@example.com",True
')
provider.class.stubs(:openstack)
.with('user', 'create', '--format', 'shell', ['foo', '--enable', '--password', 'foo', '--project', 'foo', '--email', 'foo@example.com'])
.returns('email="foo@example.com"
enabled="True"
id="12b23f07d4a3448d8189521ab09610b0"
name="foo"
project_id="5e2001b2248540f191ff22627dc0c2d7"
username="foo"
')
provider.create
expect(provider.exists?).to be_truthy
end
end
describe '#destroy' do
it 'destroys a user' do
provider.class.stubs(:openstack)
.with('user', 'list', '--quiet', '--format', 'csv', '--long')
.returns('"ID","Name","Project","Email","Enabled"')
provider.class.stubs(:openstack)
.with('user', 'delete', [])
provider.destroy
expect(provider.exists?).to be_falsey
end
end
describe '#exists' do
context 'when user does not exist' do
subject(:response) do
provider.class.stubs(:openstack)
.with('user', 'list', '--quiet', '--format', 'csv', '--long')
.returns('"ID","Name","Project","Email","Enabled"')
response = provider.exists?
end
it { is_expected.to be_falsey }
end
end
describe '#instances' do
it 'finds every user' do
provider.class.stubs(:openstack)
.with('user', 'list', '--quiet', '--format', 'csv', '--long')
.returns('"ID","Name","Project","Email","Enabled"
"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo@example.com",True
')
instances = Puppet::Type::Keystone_user::ProviderOpenstack.instances
expect(instances.count).to eq(1)
end
end
describe '#tenant' do
it 'gets the tenant with default backend' do
provider.class.stubs(:openstack)
.with('user', 'list', '--quiet', '--format', 'csv', '--long')
.returns('"ID","Name","Project","Email","Enabled"
"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo@example.com",True
')
provider.class.stubs(:openstack)
.with('user role', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'foo'])
.returns('"ID","Name","Project","User"
"9fe2ff9ee4384b1894a90878d3e92bab","_member_","foo","foo"
')
tenant = provider.tenant
expect(tenant).to eq('foo')
end
it 'gets the tenant with LDAP backend' do
provider.class.stubs(:openstack)
.with('user', 'list', '--quiet', '--format', 'csv', '--long')
.returns('"ID","Name","Project","Email","Enabled"
"1cb05cfed7c24279be884ba4f6520262","foo","","foo@example.com",True
')
provider.class.expects(:openstack)
.with('user role', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'foo'])
.returns('"ID","Name","Project","User"
"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo"
')
tenant = provider.tenant
expect(tenant).to eq('foo')
end
end
describe '#tenant=' do
context 'when using default backend' do
it 'sets the tenant' do
provider.class.expects(:openstack)
.with('user', 'set', ['foo', '--project', 'bar'])
provider.class.expects(:openstack)
.with('user role', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'bar'])
.returns('"ID","Name","Project","User"
"9fe2ff9ee4384b1894a90878d3e92bab","_member_","bar","foo"
')
provider.tenant=('bar')
end
end
context 'when using LDAP read-write backend' do
it 'sets the tenant when _member_ role exists' do
provider.class.expects(:openstack)
.with('user', 'set', ['foo', '--project', 'bar'])
provider.class.expects(:openstack)
.with('user role', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'bar'])
.returns('')
provider.class.expects(:openstack)
.with('role', 'show', '--format', 'shell', ['_member_'])
.returns('id="9fe2ff9ee4384b1894a90878d3e92bab"
name="_member_"
')
provider.class.expects(:openstack)
.with('role', 'add', ['_member_', '--project', 'bar', '--user', 'foo'])
provider.tenant=('bar')
end
it 'sets the tenant when _member_ role does not exist' do
provider.class.expects(:openstack)
.with('user', 'set', ['foo', '--project', 'bar'])
provider.class.expects(:openstack)
.with('user role', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'bar'])
.returns('')
provider.class.expects(:openstack)
.with('role', 'show', '--format', 'shell', ['_member_'])
.raises(Puppet::ExecutionFailure, 'no such role _member_')
provider.class.expects(:openstack)
.with('role', 'create', '--format', 'shell', ['_member_'])
.returns('name="_member_"')
provider.class.expects(:openstack)
.with('role', 'add', ['_member_', '--project', 'bar', '--user', 'foo'])
.returns('id="8wr2ff9ee4384b1894a90878d3e92bab"
name="_member_"
')
provider.tenant=('bar')
end
end
# This doesn't make sense, need to clarify what's happening with LDAP mock
=begin
context 'when using LDAP read-only backend' do
it 'sets the tenant when _member_ role exists' do
provider.class.expects(:openstack)
.with('user', 'set', [['foo', '--project', 'bar']])
.raises(Puppet::ExecutionFailure, 'You are not authorized to perform the requested action: LDAP user update')
provider.class.expects(:openstack)
.with('user role', 'list', '--quiet', '--format', 'csv', [['foo', '--project', 'bar']])
.returns('')
provider.class.expects(:openstack)
.with('role', 'show', '--format', 'shell', [['_member_']])
.returns('id="9fe2ff9ee4384b1894a90878d3e92bab"
name="_member_"
')
provider.class.expects(:openstack)
.with('role', 'add', [['_member_', '--project', 'bar', '--user', 'foo']])
provider.tenant=('bar')
end
it 'sets the tenant and gets an unexpected exception message' do
provider.class.expects(:openstack)
.with('user', 'set', [['foo', '--project', 'bar']])
.raises(Puppet::ExecutionFailure, 'unknown error message')
expect{ provider.tenant=('bar') }.to raise_error(Puppet::ExecutionFailure, /unknown error message/)
end
end
=end
end
end
end
describe "#password" do
let(:user_attrs) do
{
:name => 'foo',
:ensure => 'present',
:enabled => 'True',
:password => 'foo',
:tenant => 'foo',
:email => 'foo@example.com',
}
end
let(:resource) do
Puppet::Type::Keystone_user.new(user_attrs)
end
let :provider do
provider_class.new(resource)
end
shared_examples 'with auth-url environment variable' do
ENV['OS_AUTH_URL'] = 'http://localhost:5000'
end
it_behaves_like 'with auth-url environment variable' do
it 'checks the password' do
Puppet::Provider::Openstack.stubs(:openstack)
.with('token', 'issue', ['--format', 'value'])
.returns('2015-05-14T04:06:05Z
e664a386befa4a30878dcef20e79f167
8dce2ae9ecd34c199d2877bf319a3d06
ac43ec53d5a74a0b9f51523ae41a29f0
')
password = provider.password
expect(password).to eq('foo')
end
it 'fails the password check' do
Puppet::Provider::Openstack.stubs(:openstack)
.with('token', 'issue', ['--format', 'value'])
.raises(Puppet::ExecutionFailure, 'HTTP 401 invalid authentication')
password = provider.password
expect(password).to eq(nil)
end
end
describe 'when updating a user with unmanaged password' do
let(:user_attrs) do
{
:name => 'foo',
:ensure => 'present',
:enabled => 'True',
:password => 'foo',
:replace_password => 'False',
:tenant => 'foo',
:email => 'foo@example.com',
}
end
it 'should not try to check password' do
expect(provider.password).to eq('foo')
end
end
end
end

View File

@ -1,50 +0,0 @@
require 'puppet'
require 'spec_helper'
require 'puppet/provider/keystone_user_role/keystone'
provider_class = Puppet::Type.type(:keystone_user_role).provider(:keystone)
describe provider_class do
describe '#get_user_and_tenant' do
let :user do
'username'
end
let :tenant do
'test@example.org'
end
let :resource do
Puppet::Type::Keystone_user_role.new(
{
:name => "#{user}@#{tenant}",
:roles => [ '_member_' ],
}
)
end
let :provider do
provider_class.new(resource)
end
before :each do
provider_class.expects(:get_user_and_tenant).with(user,tenant).returns([user,tenant])
end
it 'should handle an email address as username' do
provider.get_user_and_tenant.should == [ user, tenant ]
end
end
describe 'when query keystone objects' do
it 'should not cache keystone objects in catalog' do
provider_class.stubs(:build_user_role_hash).returns({ 'foo' => 'bar' })
provider_class.user_role_hash.should == ({ 'foo' => 'bar' })
provider_class.stubs(:build_user_role_hash).returns({ 'baz' => 'qux' })
provider_class.user_role_hash.should == ({ 'baz' => 'qux' })
end
end
end

View File

@ -0,0 +1,89 @@
require 'puppet'
require 'spec_helper'
require 'puppet/provider/keystone_user_role/openstack'
provider_class = Puppet::Type.type(:keystone_user_role).provider(:openstack)
describe provider_class do
shared_examples 'authenticated with environment variables' do
ENV['OS_USERNAME'] = 'test'
ENV['OS_PASSWORD'] = 'abc123'
ENV['OS_PROJECT_NAME'] = 'test'
ENV['OS_AUTH_URL'] = 'http://127.0.0.1:5000'
end
describe 'when updating a user\'s role' do
it_behaves_like 'authenticated with environment variables' do
let(:user_role_attrs) do
{
:name => 'foo@foo',
:ensure => 'present',
:roles => ['foo', 'bar'],
}
end
let(:resource) do
Puppet::Type::Keystone_user_role.new(user_role_attrs)
end
let(:provider) do
provider_class.new(resource)
end
before(:each) do
provider.class.stubs(:openstack)
.with('user', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'foo'])
.returns('"ID","Name","Project","User"
"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo"
')
end
describe '#create' do
it 'adds all the roles to the user' do
provider.class.stubs(:openstack)
.with('role', 'add', ['foo', '--project', 'foo', '--user', 'foo'])
provider.class.stubs(:openstack)
.with('role', 'add', ['bar', '--project', 'foo', '--user', 'foo'])
provider.class.stubs(:openstack)
.with('user role', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'foo'])
.returns('"ID","Name","Project","User"
"1cb05ed7c24279be884ba4f6520262","foo","foo","foo"
"2cb05ed7c24279be884ba4f6520262","bar","foo","foo"
')
provider.create
expect(provider.exists?).to be_truthy
end
end
describe '#destroy' do
it 'removes all the roles from a user' do
provider.class.stubs(:openstack)
.with('user role', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'foo'])
.returns('"ID","Name","Project","User"')
provider.class.stubs(:openstack)
.with('role', 'remove', ['foo', '--project', 'foo', '--user', 'foo'])
provider.class.stubs(:openstack)
.with('role', 'remove', ['bar', '--project', 'foo', '--user', 'foo'])
provider.destroy
expect(provider.exists?).to be_falsey
end
end
describe '#exists' do
subject(:response) do
provider.class.stubs(:openstack)
.with('user role', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'foo'])
.returns('"ID","Name","Project","User"
"1cb05ed7c24279be884ba4f6520262","foo","foo","foo"
')
response = provider.exists?
end
it { is_expected.to be_truthy }
end
end
end
end

View File

@ -0,0 +1,23 @@
require 'spec_helper'
# this hack is required for now to ensure that the path is set up correctly
# to retrive the parent provider
$LOAD_PATH.push(
File.join(
File.dirname(__FILE__),
'..',
'..',
'fixtures',
'modules',
'inifile',
'lib')
)
require 'puppet/type/keystone_paste_ini'
describe 'Puppet::Type.type(:keystone_paste_ini)' do
before :each do
@keystone_paste_ini = Puppet::Type.type(:keystone_paste_ini).new(:name => 'DEFAULT/foo', :value => 'bar')
end
it 'should accept a valid value' do
@keystone_paste_ini[:value] = 'bar'
@keystone_paste_ini[:value].should == 'bar'
end
end

View File

@ -0,0 +1,28 @@
require 'spec_helper'
require 'puppet'
require 'puppet/type/keystone_user_role'
describe Puppet::Type.type(:keystone_user_role) do
before :each do
@user_roles = Puppet::Type.type(:keystone_user_role).new(
:name => 'foo@bar',
:roles => ['a', 'b']
)
@roles = @user_roles.parameter('roles')
end
it 'should not be in sync for' do
expect(@roles.insync?(['a', 'b', 'c'])).to be false
expect(@roles.insync?('a')).to be false
expect(@roles.insync?(['a'])).to be false
expect(@roles.insync?(nil)).to be false
end
it 'should be in sync for' do
expect(@roles.insync?(['a', 'b'])).to be true
expect(@roles.insync?(['b', 'a'])).to be true
end
end

View File

@ -5,36 +5,36 @@ package { 'curl': ensure => present }
# example of how to build a single node # example of how to build a single node
# keystone instance backed by sqlite # keystone instance backed by sqlite
# with all of the default admin roles # with all of the default admin roles
node keystone_sqlite { node 'keystone_sqlite' {
class { 'keystone': class { '::keystone':
verbose => true, verbose => true,
debug => true, debug => true,
catalog_type => 'sql', catalog_type => 'sql',
admin_token => 'admin_token', admin_token => 'admin_token',
} }
class { 'keystone::roles::admin': class { '::keystone::roles::admin':
email => 'example@abc.com', email => 'example@abc.com',
password => 'ChangeMe', password => 'ChangeMe',
} }
class { 'keystone::endpoint': class { '::keystone::endpoint':
public_url => "http://${::fqdn}:5000/", public_url => "http://${::fqdn}:5000/",
admin_url => "http://${::fqdn}:35357/", admin_url => "http://${::fqdn}:35357/",
} }
} }
node keystone_mysql { node keystone_mysql {
class { 'mysql::server': } class { '::mysql::server': }
class { 'keystone::db::mysql': class { '::keystone::db::mysql':
password => 'keystone', password => 'keystone',
} }
class { 'keystone': class { '::keystone':
verbose => true, verbose => true,
debug => true, debug => true,
sql_connection => 'mysql://keystone:keystone@127.0.0.1/keystone', database_connection => 'mysql://keystone:keystone@127.0.0.1/keystone',
catalog_type => 'sql', catalog_type => 'sql',
admin_token => 'admin_token', admin_token => 'admin_token',
} }
class { 'keystone::roles::admin': class { '::keystone::roles::admin':
email => 'test@puppetlabs.com', email => 'test@puppetlabs.com',
password => 'ChangeMe', password => 'ChangeMe',
} }
@ -43,21 +43,21 @@ node keystone_mysql {
# keystone with mysql on another node # keystone with mysql on another node
node keystone { node keystone {
class { 'keystone': class { '::keystone':
verbose => true, verbose => true,
debug => true, debug => true,
sql_connection => 'mysql://keystone:password@127.0.0.1/keystone', database_connection => 'mysql://keystone:password@127.0.0.1/keystone',
catalog_type => 'sql', catalog_type => 'sql',
admin_token => 'admin_token', admin_token => 'admin_token',
} }
class { 'keystone::db::mysql': class { '::keystone::db::mysql':
password => 'keystone', password => 'keystone',
} }
class { 'keystone::roles::admin': class { '::keystone::roles::admin':
email => 'example@abc.com', email => 'example@abc.com',
password => 'ChangeMe', password => 'ChangeMe',
} }
class { 'keystone::endpoint': class { '::keystone::endpoint':
public_url => "http://${::fqdn}:5000/", public_url => "http://${::fqdn}:5000/",
admin_url => "http://${::fqdn}:35357/", admin_url => "http://${::fqdn}:35357/",
} }