Sync puppet-keystone

77dbc80de15b5ef02a5e89c8ef040e70df576a1d 4.0.0

Partial blueprint merge-openstack-puppet-modules

Fuel-CI: disable
Change-Id: Id315262c7cc735bfdce41b2f5a20117bfd2b3a04
Signed-off-by: Bogdan Dobrelya <bdobrelia@mirantis.com>
This commit is contained in:
Bogdan Dobrelya 2014-04-07 15:31:19 +03:00 committed by Aleksandr Didenko
parent 804976736e
commit 01326ed62c
64 changed files with 3301 additions and 1040 deletions

View File

@ -1,10 +1,15 @@
fixtures:
repositories:
"apt": "git://github.com/puppetlabs/puppetlabs-apt.git"
"mysql":
repo: "git://github.com/puppetlabs/puppetlabs-mysql.git"
'apache': 'git://github.com/puppetlabs/puppetlabs-apache.git'
'concat': 'git://github.com/puppetlabs/puppetlabs-concat.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/cprice-puppet/puppetlabs-inifile'
'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'
symlinks:
"keystone": "#{source_dir}"
'keystone': "#{source_dir}"

View File

@ -1,5 +0,0 @@
source :rubygems
puppetversion = ENV.key?('PUPPET_VERSION') ? "= #{ENV['PUPPET_VERSION']}" : ['>= 2.7']
gem 'puppet', puppetversion
gem 'puppetlabs_spec_helper', '>= 0.1.0'

View File

@ -1,5 +1,5 @@
spec/fixtures/modules/*
spec/fixtures/manifests/*
pkg
Gemfile.lock
*.swp
pkg/
.DS_Store
metadata.json
coverage/

View File

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

View File

@ -1,28 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>keystone</name>
<comment></comment>
<projects>
<project>concat</project>
<project>mysql</project>
<project>postgresql</project>
<project>stdlib</project>
<project>vcsrepo</project>
</projects>
<buildSpec>
<buildCommand>
<name>org.cloudsmith.geppetto.pp.dsl.ui.modulefileBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.cloudsmith.geppetto.pp.dsl.ui.puppetNature</nature>
<nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
</natures>
</projectDescription>

View File

@ -1,7 +0,0 @@
2012-10-08 - Version 0.2.0
* add enable parameter
* add initial postgres classes
* keystone native type performance improvements
* support of multi-line field values for keystone native types
* add parameters for setting public, internal, and admin endpoints
* allow keystone to bind to non-localhost interfaces

View File

@ -0,0 +1,15 @@
source 'https://rubygems.org'
group :development, :test do
gem 'puppetlabs_spec_helper', :require => false
gem 'puppet-lint', '~> 0.3.2'
gem 'rake', '10.1.1'
end
if puppetversion = ENV['PUPPET_GEM_VERSION']
gem 'puppet', puppetversion, :require => false
else
gem 'puppet', :require => false
end
# vim:ft=ruby

View File

@ -1,4 +1,4 @@
Puppet Labs Swift Module - Puppet module for managing Swift
Puppet Labs Keystone Module - Puppet module for managing Keystone
Copyright (C) 2012 Puppet Labs Inc

View File

@ -1,10 +1,13 @@
name 'puppetlabs-keystone'
version '0.2.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'
author 'Puppet Labs'
license 'Apache'
project_page 'http://github.com/puppetlabs/puppetlabs-keystone'
source 'git://github.com/puppetlabs/puppetlabs-keystone'
summary 'Keystone Puppet Module'
description 'Openstack Keystone module. Tested on Ubuntu and RHEL 6'
dependency 'puppetlabs/mysql','>=0.3.0 <1.0.0'
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,143 +0,0 @@
# Overview #
The module contains a collection of manifests and native types that are capable
of installing/managing/configuring Keystone.
Keystone is the Identity service for OpenStack.
# Tested use cases #
This module has been tested against the dev version of Ubuntu Precise.
It has only currently been tested as a single node installation of keystone.
It is currently targetting essex support and is being actively developed against
packaging that are built off of trunk.
# Dependencies: #
This module has relatively few dependencies:
https://github.com/puppetlabs/puppet-concat
# if used on Ubuntu
https://github.com/puppetlabs/puppet-apt
# if using mysql as a backend
https://github.com/puppetlabs/puppetlabs-mysql
# Usage #
## Manifests ##
### class keystone ###
The keystone class sets up the basic configuration for the keystone service.
It must be used together with a class that expresses the db backend to use:
for example:
class { 'keystone':
verbose => true,
admin_token => 'my_secret_token'
}
needs to be configured to use a backend database with either:
class { 'keystone::config::sqlite': }
or
class { 'keystone::config::mysql':
password => 'keystone',
}
or
class { 'keystone::config::postgresql':
password => 'keystone',
}
### setting up a keystone mysql db ###
A keystone mysql database can be configured separately from
the service.
If you need to actually install a mysql database server, you can use
the mysql::server class from the puppetlabs mysql module
# check out the mysql module's README to learn more about
# how to more appropriately configure a server
class { 'mysql::server': }
class { 'keystone::mysql':
dbname => 'keystone',
user => 'keystone',
password => 'keystone_password',
}
### setting up a keystone postgresql db ###
A keystone postgresql database can be configured separately from
the service instead of mysql.
If you need to actually install a postgresql database server, you can use
the postgresql::server class from the puppetlabs postgresql module. You
will also need that module to install the postgresql python driver dependencies.
# check out the postgresql module's README to learn more about
# how to more appropriately configure a server
class { 'postgresql::server': }
class { 'keystone::postgresql':
dbname => 'keystone',
user => 'keystone',
password => 'keystone_password',
}
## Native Types ##
The Puppet support for keystone also includes native types that can be
used to manage the following keystone objects:
- keystone_tenant
- keystone_user
- keystone_role
- keystone_user_role
- keystone_service
- keystone_endpoint
These types will only work on an actual keystone node (and they read keystone.conf
to figure out the admin port and admin token, which is kind of hacky, but the best
way I could think of.)
- keystone_config - manages individual config file entries as resources.
### examples ###
keystone_tenant { 'openstack':
ensure => present,
enabled => 'True',
}
keystone_user { 'openstack':
ensure => present,
enabled => 'True'
}
keystone_role { 'admin':
ensure => present,
}
keystone_user_role { 'admin@openstack':
roles => ['admin', 'superawesomedue'],
ensure => present
}
### puppet resource ###
These native types also allow for some interesting introspection using puppet resource
To list all of the objects of a certain type in the keystone database, you can run:
puppet resource <type>
For example:
puppet resource keystone_tenant
would list all know keystone tenants for a given keystone instance.

View File

@ -0,0 +1,237 @@
keystone
=======
4.0.0 - 2014.1.0 - Icehouse
#### Table of Contents
1. [Overview - What is the keystone module?](#overview)
2. [Module Description - What does the module do?](#module-description)
3. [Setup - The basics of getting started with keystone](#setup)
4. [Implementation - An under-the-hood peek at what the module is doing](#implementation)
5. [Limitations - OS compatibility, etc.](#limitations)
6. [Development - Guide for contributing to the module](#development)
7. [Contributors - Those with commits](#contributors)
8. [Release Notes - Notes on the most recent updates to the module](#release-notes)
Overview
--------
The keystone module is a part of [Stackforge](https://github.com/stackfoge), an effort by the Openstack infrastructure team to provide continuous integration testing and code review for Openstack and Openstack community projects not part of the core software. The module its self is used to flexibly configure and manage the identify service for Openstack.
Module Description
------------------
The keystone module is a thorough attempt to make Puppet capable of managing the entirety of keystone. This includes manifests to provision region specific endpoint and database connections. Types are shipped as part of the keystone module to assist in manipulation of configuration files.
This module is tested in combination with other modules needed to build and leverage an entire Openstack software stack. These modules can be found, all pulled together in the [openstack module](https://github.com/stackfoge/puppet-openstack).
Setup
-----
**What the keystone module affects**
* keystone, the identify service for Openstack.
### Installing keystone
example% puppet module install puppetlabs/keystone
### Beginning with keystone
To utilize the keystone module's functionality you will need to declare multiple resources. The following is a modified excerpt from the [openstack module](https://github.com/stackfoge/puppet-openstack). This is not an exhaustive list of all the components needed, we recommend you consult and understand the [openstack module](https://github.com/stackforge/puppet-openstack) and the [core openstack](http://docs.openstack.org) documentation.
**Define a keystone node**
```puppet
class { 'keystone':
verbose => True,
catalog_type => 'sql',
admin_token => 'random_uuid',
sql_connection => 'mysql://keystone_admin:super_secret_db_password@openstack-controller.example.com/keystone',
}
# Adds the admin credential to keystone.
class { 'keystone::roles::admin':
email => 'admin@example.com',
password => 'super_secret',
}
# Installs the service user endpoint.
class { 'keystone::endpoint':
public_address => '10.16.0.101',
admin_address => '10.16.1.101',
internal_address => '10.16.2.101',
region => 'example-1',
}
```
**Leveraging the Native Types**
Keystone ships with a collection of native types that can be used to interact with the data stored in keystone. The following, related to user management could live throughout your Puppet code base. They even support puppet's ability to introspect the current environment much the same as `puppet resource user`, `puppet resouce keystone_tenant` will print out all the currently stored tenants and their parameters.
```puppet
keystone_tenant { 'openstack':
ensure => present,
enabled => True,
}
keystone_user { 'openstack':
ensure => present,
enabled => True,
}
keystone_role { 'admin':
ensure => present,
}
keystone_user_role { 'admin@openstack':
roles => ['admin', 'superawesomedude'],
ensure => present
}
```
These two will seldom be used outside openstack related classes, like nova or cinder. These are modified examples form Class['nova::keystone::auth'].
```puppet
# Setup the nova keystone service
keystone_service { 'nova':
ensure => present,
type => 'compute',
description => 'Openstack Compute Service',
}
# Setup nova keystone endpoint
keystone_endpoint { 'example-1-west/nova':
ensure => present,
public_url => "http://127.0.0.1:8774/v2/%(tenant_id)s",
admin_url => "http://127.0.0.1:8774/v2/%(tenant_id)s",
internal_url => "http://127.0.0.1:8774/v2/%(tenant_id)s",
}
```
**Setting up a database for keystone**
A keystone database can be configured separately from the keystone services.
If one needs to actually install a fresh database they have the choice of mysql or postgres. Use the mysql::server or postgreql::server classes to do this setup then the Class['keystone::db::mysql'] or Class['keystone::db::postgresql'] for adding the needed databases and users that will be needed by keystone.
* For mysql
```puppet
class { 'mysql::server': }
class { 'keystone::db::mysql':
password => 'super_secret_db_password',
allowed_hosts => '%',
}
```
* For postgresql
```puppet
class { 'postgresql::server': }
class { 'keystone::db::postgresql': password => 'super_secret_db_password', }
```
Implementation
--------------
### keystone
keystone is a combination of Puppet manifest and ruby code to delivery configuration and extra functionality through types and providers.
Limitations
------------
* All the keystone types use the CLI tools and so need to be ran on the keystone node.
### Upgrade warning
* 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.
Development
-----------
Developer documentation for the entire puppet-openstack project.
* https://wiki.openstack.org/wiki/Puppet-openstack#Developer_documentation
Contributors
------------
* https://github.com/stackforge/puppet-keystone/graphs/contributors
Release Notes
-------------
**4.0.0**
* Stable Icehouse release.
* Added template_file parameter to specify catalog.
* Added keystone::config to handle additional custom options.
* Added notification parameters.
* Added support for puppetlabs-mysql 2.2 and greater.
* Fixed deprecated sql section header in keystone.conf.
* Fixed deprecated bind_host parameter.
* Fixed example for native type keystone_service.
* Fixed LDAP module bugs.
* Fixed variable for host_access dependency.
* Reduced default token duration to one hour.
**3.2.0**
* Added ability to configure any catalog driver.
* Ensures log_file is absent when using syslog.
**3.1.1**
* Fixed inconsistent variable for mysql allowed hosts.
**3.1.0**
* Added ability to disable pki_setup.
* Load tenant un-lazily if needed.
* Add log_dir param, with option to disable.
* Updated endpoint argument.
* Added support to enable SSL.
* Removes setting of Keystone endpoint by default.
* Relaxed regex when keystone refuses connections.
**3.0.0**
* Major release for OpenStack Havana.
* Fixed duplicated keystone endpoints.
* Refactored keystone_endpoint to use prefetch and flush paradigm.
* Switched from signing/format to token/provider.
* Created memcache_servers option to allow for multiple cache servers.
* Enabled serving Keystone from Apache mod_wsgi.
* Moved db_sync to its own class.
* Removed creation of Member role.
* Improved performance of Keystone providers.
* Updated endpoints to support paths and ssl.
* Added support for token expiration parameter.
**2.2.0**
* Optimized tenant and user queries.
* Added syslog support.
* Added support for token driver backend.
* Various bug and lint fixes.
**2.1.0**
* Tracks release of puppet-quantum
* Fixed allowed_hosts contitional statement
* Pinned depedencies
* Select keystone endpoint based on SSL setting
* Improved tenant_hash usage in keystone_tenant
* Various cleanup and bug fixes.
**2.0.0**
* Upstream is now part of stackfoge.
* keystone_user can be used to change passwords.
* service tenant name now configurable.
* keystone_user is now idempotent.
* Various cleanups and bug fixes.

View File

@ -1 +1,7 @@
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'
PuppetLint.configuration.fail_on_warnings = true
PuppetLint.configuration.send('disable_80chars')
PuppetLint.configuration.send('disable_class_inherits_from_params_class')
PuppetLint.configuration.send('disable_class_parameter_defaults')

View File

@ -0,0 +1,49 @@
# Example using apache to serve keystone
#
# To be sure everything is working, run:
# $ export OS_USERNAME=admin
# $ export OS_PASSWORD=ChangeMe
# $ export OS_TENANT_NAME=openstack
# $ export OS_AUTH_URL=http://keystone.local/keystone/main/v2.0
# $ keystone catalog
# Service: identity
# +-------------+----------------------------------------------+
# | Property | Value |
# +-------------+----------------------------------------------+
# | adminURL | http://keystone.local:80/keystone/admin/v2.0 |
# | id | 4f0f55f6789d4c73a53c51f991559b72 |
# | internalURL | http://keystone.local:80/keystone/main/v2.0 |
# | publicURL | http://keystone.local:80/keystone/main/v2.0 |
# | region | RegionOne |
# +-------------+----------------------------------------------+
#
Exec { logoutput => 'on_failure' }
class { 'mysql::server': }
class { 'keystone::db::mysql':
password => 'keystone',
}
class { 'keystone':
verbose => true,
debug => true,
sql_connection => 'mysql://keystone:keystone@127.0.0.1/keystone',
catalog_type => 'sql',
admin_token => 'admin_token',
enabled => false,
}
class { 'keystone::roles::admin':
email => 'test@puppetlabs.com',
password => 'ChangeMe',
}
class { 'keystone::endpoint':
public_url => "https://${::fqdn}:5000/",
admin_url => "https://${::fqdn}:35357/",
}
keystone_config { 'ssl/enable': value => true }
include apache
class { 'keystone::wsgi::apache':
ssl => true
}

View File

@ -0,0 +1,53 @@
# Example using apache to serve keystone
#
# To be sure everything is working, run:
# $ export OS_USERNAME=admin
# $ export OS_PASSWORD=ChangeMe
# $ export OS_TENANT_NAME=openstack
# $ export OS_AUTH_URL=http://keystone.local/keystone/main/v2.0
# $ keystone catalog
# Service: identity
# +-------------+----------------------------------------------+
# | Property | Value |
# +-------------+----------------------------------------------+
# | adminURL | http://keystone.local:80/keystone/admin/v2.0 |
# | id | 4f0f55f6789d4c73a53c51f991559b72 |
# | internalURL | http://keystone.local:80/keystone/main/v2.0 |
# | publicURL | http://keystone.local:80/keystone/main/v2.0 |
# | region | RegionOne |
# +-------------+----------------------------------------------+
#
Exec { logoutput => 'on_failure' }
class { 'mysql::server': }
class { 'keystone::db::mysql':
password => 'keystone',
}
class { 'keystone':
verbose => true,
debug => true,
sql_connection => 'mysql://keystone_admin:keystone@127.0.0.1/keystone',
catalog_type => 'sql',
admin_token => 'admin_token',
enabled => true,
}
class { 'keystone::roles::admin':
email => 'test@puppetlabs.com',
password => 'ChangeMe',
}
class { 'keystone::endpoint':
public_url => "https://${::fqdn}:443/main/",
admin_address => "https://${::fqdn}:443/admin/",
}
keystone_config { 'ssl/enable': ensure => absent }
include apache
class { 'keystone::wsgi::apache':
ssl => true,
public_port => 443,
admin_port => 443,
public_path => '/main/',
admin_path => '/admin/'
}

View File

@ -1 +0,0 @@
class { 'keystone::roles::admin': }

View File

@ -0,0 +1,66 @@
# A full example from a real deployment that allows Keystone to modify
# everything except users, uses enabled_emulation, and ldaps
# Ensure this matches what is in LDAP or keystone will try to recreate
# the admin user
class { 'keystone::roles::admin':
email => 'test@example.com',
password => 'ChangeMe',
}
# You can test this connection with ldapsearch first to ensure it works.
# 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
# an example of ldapsearch that will search users on this box:
# ldapsearch -v -x -H 'ldap://69.134.70.154:389' -D \
# "uid=bind,cn=users,cn=accounts,dc=example,dc=com" -w SecretPass \
# -b cn=users,cn=accounts,dc=example,dc=com
class { 'keystone:ldap':
url => 'ldap://ldap.example.com:389',
user => 'uid=bind,cn=users,cn=accounts,dc=example,dc=com',
password => 'SecretPass',
suffix => 'dc=example,dc=com',
query_scope => 'sub',
user_tree_dn => 'cn=users,cn=accounts,dc=example,dc=com',
user_id_attribute => 'uid',
user_name_attribute => 'uid',
user_mail_attribute => 'mail',
user_allow_create => 'False',
user_allow_update => 'False',
user_allow_delete => 'False',
user_enabled_emulation => 'True',
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_objectclass => 'organizationalRole',
group_id_attribute => 'cn',
group_name_attribute => 'cn',
group_member_attribute => 'RoleOccupant',
group_desc_attribute => 'description',
group_allow_create => 'True',
group_allow_update => 'True',
group_allow_delete => 'True',
tenant_tree_dn => 'ou=projects,ou=openstack,dc=example,dc=com',
tenant_objectclass => 'organizationalUnit',
tenant_id_attribute => 'ou',
tenant_member_attribute => 'member',
tenant_name_attribute => 'ou',
tenant_desc_attribute => 'description',
tenant_allow_create => 'True',
tenant_allow_update => 'True',
tenant_allow_delete => 'True',
tenant_enabled_emulation => 'True',
tenant_enabled_emulation_dn => 'cn=enabled,ou=openstack,dc=example,dc=com',
role_tree_dn => 'ou=roles,ou=openstack,dc=example,dc=com',
role_objectclass => 'organizationalRole',
role_id_attribute => 'cn',
role_name_attribute => 'cn',
role_member_attribute => 'roleOccupant',
role_allow_create => 'True',
role_allow_update => 'True',
role_allow_delete => 'True',
identity_driver => 'keystone.identity.backends.ldap.Identity',
assignment_driver => 'keystone.assignment.backends.ldap.Assignment',
use_tls => 'True',
tls_cacertfile => '/etc/ssl/certs/ca-certificates.crt',
tls_req_cert => 'demand',
}

View File

@ -0,0 +1,28 @@
# Example using LDAP to manage user identity only.
# This setup will not allow changes to users.
# Ensure this matches what is in LDAP or keystone will try to recreate
# the admin user
class { 'keystone::roles::admin':
email => 'test@example.com',
password => 'ChangeMe',
}
# 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
# attributes to match your configuration.
class { 'keystone:ldap':
identity_driver => 'keystone.identity.backends.ldap.Identity',
url => 'ldap://ldap.example.com:389',
user => 'uid=bind,cn=users,cn=accounts,dc=example,dc=com',
password => 'SecretPass',
suffix => 'dc=example,dc=com',
query_scope => 'sub',
user_tree_dn => 'cn=users,cn=accounts,dc=example,dc=com',
user_id_attribute => 'uid',
user_name_attribute => 'uid',
user_mail_attribute => 'mail',
user_allow_create => 'False',
user_allow_update => 'False',
user_allow_delete => 'False'
}

View File

@ -1,53 +0,0 @@
Exec { logoutput => 'on_failure' }
# example of how to build a single node
# keystone instance backed by sqlite
# with all of the default admin roles
node keystone_sqlite {
class { 'keystone':
verbose => true,
debug => true,
catalog_type => 'sql',
}
class { 'keystone::roles::admin':
email => 'example@abc.com',
}
}
node keystone_mysql {
class { 'mysql::server': }
class { 'keystone::db::mysql':
password => 'keystone',
}
class { 'keystone':
verbose => true,
debug => true,
sql_connection => 'mysql://keystone_admin:keystone@127.0.0.1/keystone',
catalog_type => 'sql',
}
class { 'keystone::roles::admin':
email => 'test@puppetlabs.com',
}
}
# keystone with mysql on another node
node keystone {
class { 'keystone':
verbose => true,
debug => true,
sql_connection => 'mysql://keystone_admin:password@127.0.0.1/keystone',
catalog_type => 'sql',
}
class { 'keystone::db::mysql':
password => 'keystone',
}
class { 'keystone::roles::admin':
email => 'example@abc.com',
}
}
node default {
fail("could not find a matching node entry for ${clientcert}")
}

View File

@ -3,27 +3,53 @@
# been successfully installed using the instructions
# found here: http://keystone.openstack.org/configuration.html
begin
require 'rubygems'
rescue
puts 'Could not require rubygems. This assumes puppet is not installed as a gem'
end
require 'open3'
require 'fileutils'
require 'puppet'
get_token = %(curl -d '{"auth":{"passwordCredentials":{"username": "admin", "password": "ChangeMe"}}}' -H "Content-type: application/json" http://localhost:35357/v2.0/tokens)
token = nil
Open3.popen3(get_token) do |stdin, stdout, stderr|
begin
stdout = stdout.read
puts "Response from token request:#{stdout}"
token = PSON.load(stdout)["access"]["token"]["id"]
rescue Exception => e
puts "Could not retrieve token from response, this sh*t is borked :( : details: #{e}"
exit 1
username='admin'
password='admin_password'
# required to get a real services catalog
tenant='openstack'
# shared secret
service_token='service_token'
def run_command(cmd)
Open3.popen3(cmd) do |stdin, stdout, stderr|
begin
stdout = stdout.read
puts "Response from token request:#{stdout}"
return stdout
rescue Exception => e
puts "Request failed, this sh*t is borked :( : details: #{e}"
exit 1
end
end
end
puts `puppet apply -e "package {curl: ensure => present }"`
get_token = %(curl -d '{"auth":{"passwordCredentials":{"username": "#{username}", "password": "#{password}"}}}' -H "Content-type: application/json" http://localhost:35357/v2.0/tokens)
token = nil
puts "Running auth command: #{get_token}"
token = PSON.load(run_command(get_token))["access"]["token"]["id"]
if token
puts "We were able to retrieve a token"
puts token
verify_token = "curl -H 'X-Auth-Token: #{service_token}' http://localhost:35357/v2.0/tokens/#{token}"
puts 'verifying token'
run_command(verify_token)
['endpoints', 'tenants', 'users'].each do |x|
puts "getting #{x}"
get_keystone_data = "curl -H 'X-Auth-Token: #{service_token}' http://localhost:35357/v2.0/#{x}"
run_command(get_keystone_data)
end
end

View File

@ -0,0 +1,54 @@
# vim: tabstop=4 shiftwidth=4 softtabstop=4
# Copyright 2013 OpenStack Foundation
#
# 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.
#
# This file was copied from https://github.com/openstack/keystone/raw/c3b92295b718a41c3136876eb39297081015a97c/httpd/keystone.py
# It's only required for platforms on which it is not packaged yet.
# It should be removed when available everywhere in a package.
#
import logging
import os
from paste import deploy
from keystone.openstack.common import gettextutils
# NOTE(blk-u):
# gettextutils.install() must run to set _ before importing any modules that
# contain static translated strings.
gettextutils.install('keystone')
from keystone.common import environment
from keystone import config
from keystone.openstack.common import log
CONF = config.CONF
CONF(project='keystone')
config.setup_logging(CONF)
environment.use_stdlib()
name = os.path.basename(__file__)
if CONF.debug:
CONF.log_opt_values(log.getLogger(CONF.prog), logging.DEBUG)
# NOTE(ldbragst): 'application' is required in this context by WSGI spec.
# The following is a reference to Python Paste Deploy documentation
# http://pythonpaste.org/deploy/
application = deploy.loadapp('config:%s' % config.find_paste_config(),
name=name)

View File

@ -19,16 +19,21 @@ class Puppet::Provider::Keystone < Puppet::Provider
end
def self.get_admin_endpoint
admin_endpoint = keystone_file['DEFAULT']['admin_endpoint'] ? keystone_file['DEFAULT']['admin_endpoint'].strip : nil
return admin_endpoint if admin_endpoint
admin_port = keystone_file['DEFAULT']['admin_port'] ? keystone_file['DEFAULT']['admin_port'].strip : '35357'
if keystone_file and keystone_file['DEFAULT'] and keystone_file['DEFAULT']['bind_host']
host = keystone_file['DEFAULT']['bind_host'].strip
ssl = keystone_file['ssl'] && keystone_file['ssl']['enable'] ? keystone_file['ssl']['enable'].strip.downcase == 'true' : false
protocol = ssl ? 'https' : 'http'
if keystone_file and keystone_file['DEFAULT'] and 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"
end
else
host = "127.0.0.1"
end
"http://#{host}:#{admin_port}/v2.0/"
"#{protocol}://#{host}:#{admin_port}/v2.0/"
end
def self.keystone_file
@ -46,44 +51,92 @@ class Puppet::Provider::Keystone < Puppet::Provider
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
def self.auth_keystone(*args)
rv = nil
retries = 60
loop do
begin
rv = keystone('--os-token', admin_token, '--os-endpoint', admin_endpoint, args)
break
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\sto\sestablish\sconnection\sto)|\(HTTP\s+50[34]\)/
notice("Can't connect to keystone backend. Waiting for retry...")
retries -= 1
sleep 2
if retries <= 1
notice("Can't connect to keystone backend. No more retries, auth failed")
raise(e)
#break
end
else
raise(e)
#break
authenv = {:OS_SERVICE_TOKEN => admin_token}
begin
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
return rv
end
def auth_keystone(*args)
self.class.auth_keystone(args)
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] || []).select{ |line| line =~ /^\|.*\|$/ }.reject{ |line| line =~ /^\|\s+id\s+.*\|$/}.collect do |line|
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
@ -92,9 +145,9 @@ class Puppet::Provider::Keystone < Puppet::Provider
end
row
end
debug(list.inspect)
list
end
def self.get_keystone_object(type, id, attr)
id = id.chomp
auth_keystone("#{type}-get", id).split(/\|\n/m).each do |line|
@ -110,4 +163,28 @@ class Puppet::Provider::Keystone < Puppet::Provider
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

View File

@ -15,8 +15,13 @@ Puppet::Type.type(:keystone_config).provide(
'='
end
def file_path
def self.file_path
'/etc/keystone/keystone.conf'
end
# added for backwards compatibility with older versions of inifile
def file_path
self.class.file_path
end
end

View File

@ -17,22 +17,34 @@ Puppet::Type.type(:keystone_endpoint).provide(
optional_commands :keystone => "keystone"
def self.prefetch(resource)
# rebuild the cahce for every puppet run
@endpoint_hash = nil
def initialize(resource = nil)
super(resource)
@property_flush = {}
end
def self.endpoint_hash
@endpoint_hash ||= build_endpoint_hash
end
def endpoint_hash
self.class.endpoint_hash
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
endpoint_hash.collect do |k, v|
new(:name => k)
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
@ -48,105 +60,66 @@ Puppet::Type.type(:keystone_endpoint).provide(
end
end
if resource[:name].match('/')
(region, service_name) = resource[:name].split('/')
optional_opts.push('--region').push(region)
else
if resource[:region]
optional_opts.push('--region').push(resource[:region])
end
service_name = resource[:name]
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 |user|
user[1] == service_name
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 endpoint_hash_key
if resource[:name].match('/')
service_hash = resource[:name]
else
service_hash = "#{resource[:region]}/#{resource[:name]}"
end
service_hash
auth_keystone('endpoint-create', '--service-id', service_id, optional_opts)
end
def exists?
endpoint_hash[endpoint_hash_key]
@property_hash[:ensure] == :present
end
def destroy
auth_keystone('endpoint-delete', endpoint_hash[endpoint_hash_key][:id])
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
endpoint_hash[endpoint_hash_key][:id]
@property_hash[:id]
end
def region
endpoint_hash[endpoint_hash_key][:region]
@property_hash[:region]
end
def public_url
endpoint_hash[endpoint_hash_key][:public_url]
@property_hash[:public_url]
end
def internal_url
endpoint_hash[endpoint_hash_key][:internal_url]
@property_hash[:internal_url]
end
def admin_url
endpoint_hash[endpoint_hash_key][:admin_url]
@property_hash[:admin_url]
end
def public_url=(value)
destroy
endpoint_hash[endpoint_hash_key][:public_url] = value
create
@property_hash[:public_url] = value
@property_flush[:public_url] = value
end
def internal_url=(value)
destroy
endpoint_hash[endpoint_hash_key][:internal_url] = value
create
@property_hash[:internal_url] = value
@property_flush[:internal_url] = value
end
def admin_url=(value)
destroy
endpoint_hash[endpoint_hash_key][:admin_url] = value
create
@property_hash[:admin_url] = value
@property_flush[:admin_url] = value
end
private
def self.build_endpoint_hash
hash = {}
list_keystone_objects('endpoint', [5,6]).each do |endpoint|
service_id = get_service_id(endpoint[0])
service_name = get_keystone_object('service', service_id, 'name')
hash["#{endpoint[1]}/#{service_name}"] = {
:id => endpoint[0],
:region => endpoint[1],
:public_url => endpoint[2],
:internal_url => endpoint[3],
:admin_url => endpoint[4],
:service_id => service_id
}
end
hash
end
# TODO - this needs to be replaced with a call to endpoint-get
# but endpoint-get is not currently supported from the admin url
def self.get_service_id(endpoint_id)
`python -c "from keystoneclient.v2_0 import client ; import os ; print [e.service_id for e in client.Client(endpoint='#{admin_endpoint}', token='#{admin_token}').endpoints.list() if e.id == u'#{endpoint_id}'][0]"`.strip()
end
end

View File

@ -33,9 +33,16 @@ Puppet::Type.type(:keystone_tenant).provide(
self.class.tenant_hash
end
def instance
tenant_hash[resource[:name]]
end
def self.instances
tenant_hash.collect do |k, v|
new(:name => k)
new(
:name => k,
:id => v[:id]
)
end
end
@ -44,49 +51,58 @@ Puppet::Type.type(:keystone_tenant).provide(
if resource[:description]
optional_opts.push('--description').push(resource[:description])
end
auth_keystone(
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?
tenant_hash[resource[:name]]
instance
end
def destroy
auth_keystone('tenant-delete', tenant_hash[resource[:name]][:id])
end
def enabled
tenant_hash[resource[:name]][:enabled]
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,
tenant_hash[resource[:name]][:id]
)
auth_keystone("tenant-update", '--enabled', value, instance[:id])
instance[:enabled] = value
end
def description
tenant_hash[resource[:name]][:description]
self.class.get_keystone_object('tenant', instance[:id], 'description')
end
def description=(value)
auth_keystone(
"tenant-update",
'--description', value,
tenant_hash[resource[:name]][:id]
)
auth_keystone("tenant-update", '--description', value, instance[:id])
instance[:description] = value
end
def id
tenant_hash[resource[:name]][:id]
[
:id,
:enabled,
].each do |attr|
define_method(attr.to_s) do
instance[attr] || :absent
end
end
private
@ -94,11 +110,8 @@ Puppet::Type.type(:keystone_tenant).provide(
def self.build_tenant_hash
hash = {}
list_keystone_objects('tenant', 3).each do |tenant|
# I may need to make a call to get to get the description
description = get_keystone_object('tenant', tenant[0], 'description')
hash[tenant[1]] = {
:id => tenant[0],
:description => description,
:enabled => tenant[2],
}
end

View File

@ -80,23 +80,43 @@ Puppet::Type.type(:keystone_user).provide(
)
end
# def password
# Puppet.warning("Cannot retrieve password")
# user_hash[resource[:name]][:password]
# end
#
# def password=(value)
# Puppet.warning('Cannot update password')
# # user-password-update does not support the ability know what the
# # current value is
# #auth_keystone(
# # 'user-password-update',
# # '--pass', 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/
raise e
end
return resource[:password]
end
def password=(value)
auth_keystone('user-password-update', '--pass', value, user_hash[resource[:name]][:id])
end
def tenant
user_hash[resource[:name]][: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)
@ -124,12 +144,6 @@ Puppet::Type.type(:keystone_user).provide(
def self.build_user_hash
hash = {}
list_keystone_objects('user', 4).each do |user|
tenantId = get_keystone_object('user', user[0], 'tenantId')
if tenantId.nil? or tenantId == 'None' or tenantId.empty?
tenant = 'None'
else
tenant = get_keystone_object('tenant', tenantId, 'name')
end
password = 'nil'
hash[user[1]] = {
:id => user[0],
@ -137,7 +151,6 @@ Puppet::Type.type(:keystone_user).provide(
:email => user[3],
:name => user[1],
:password => password,
:tenant => tenant
}
end
hash

View File

@ -35,7 +35,7 @@ Puppet::Type.type(:keystone_user_role).provide(
def create
user_id, tenant_id = get_user_and_tenant
resource[:roles].each do |role_name|
role_id = self.class.get_roles[role_name]
role_id = self.class.get_role(role_name)
auth_keystone(
'user-role-add',
'--user-id', user_id,
@ -45,53 +45,57 @@ Puppet::Type.type(:keystone_user_role).provide(
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)
tenant_id = self.class.get_tenants[tenant]
[self.class.get_users(tenant_id)[user], self.class.get_tenants[tenant]]
self.class.get_user_and_tenant(user, tenant)
end
def exists?
user_role_hash[resource[:name]]
user_id, tenant_id = get_user_and_tenant
get_user_tenant_hash(user_id, tenant_id)
end
def destroy
user_role_hash[resource[:name]][:role_ids].each do |role_id|
begin
auth_keystone(
'user-role-remove',
'--user-id', user_role_hash[resource[:name]][:user_id],
'--tenant-id', user_role_hash[resource[:name]][:tenant_id],
'--role-id', role_id
)
rescue Exception => e
if e.message =~ /(\(HTTP\s+404\))/
notice("Role has been already deleted. Nothing to do")
else
raise(e)
end
end
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_role_hash[resource[:name]][:id]
user_id, tenant_id = get_user_and_tenant
get_user_tenant_hash(user_id, tenant_id)[:id]
end
def roles
user_role_hash[resource[:name]][:role_names]
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
# require 'ruby-debug';debugger
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_roles[role_name]
role_id = self.class.get_role(role_name)
auth_keystone(
'user-role-add',
'--user-id', user_id,
@ -100,22 +104,15 @@ Puppet::Type.type(:keystone_user_role).provide(
)
end
remove.each do |role_name|
role_id = self.class.get_roles[role_name]
begin
auth_keystone(
'user-role-remove',
'--user-id', user_id,
'--tenant-id', tenant_id,
'--role-id', role_id
)
rescue Exception => e
if e.message =~ /(\(HTTP\s+404\))/
notice("Role has been already deleted. Nothing to do")
else
raise(e)
end
end
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
@ -124,7 +121,7 @@ Puppet::Type.type(:keystone_user_role).provide(
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).each do |role|
list_user_roles(user_id, tenant_id).sort.each do |role|
hash["#{user_name}@#{tenant_name}"] ||= {
:user_id => user_id,
:tenant_id => tenant_id,
@ -136,21 +133,34 @@ Puppet::Type.type(:keystone_user_role).provide(
end
end
end
#require 'ruby-debug';debugger
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] || []).select do
|line| line =~ /^\|.*\|$/
end.reject do
|line| line =~ /^\|\s+id\s+\|\s+name\s+\|\s+user_id\s+\|\s+tenant_id\s+\|$/
end.collect do |line|
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}")
@ -160,9 +170,23 @@ Puppet::Type.type(:keystone_user_role).provide(
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
@ -170,19 +194,36 @@ Puppet::Type.type(:keystone_user_role).provide(
end
def self.get_tenants
@tenants = {}
list_keystone_objects('tenant', 3).each do |tenant|
@tenants[tenant[1]] = tenant[0]
unless @tenants
@tenants = {}
list_keystone_objects('tenant', 3).each do |tenant|
@tenants[tenant[1]] = tenant[0]
end
end
@tenants
end
def self.get_roles
@roles = {}
list_keystone_objects('role', 2).each do |role|
@roles[role[1]] = role[0]
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
@roles
@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

@ -9,10 +9,36 @@ Puppet::Type.newtype(:keystone_config) do
newproperty(:value) do
desc 'The value of the setting to be defined.'
munge do |v|
v.to_s.strip
munge do |value|
value = value.to_s.strip
value.capitalize! if value =~ /^(true|false)$/i
value
end
newvalues(/^[\S ]*$/)
def is_to_s( currentvalue )
if resource.secret?
return '[old secret redacted]'
else
return currentvalue
end
end
def should_to_s( newvalue )
if resource.secret?
return '[new secret redacted]'
else
return newvalue
end
end
end
newparam(:secret, :boolean => true) do
desc 'Whether to hide the value from Puppet logs. Defaults to `false`.'
newvalues(:true, :false)
defaultto false
end
end

View File

@ -8,7 +8,7 @@ Puppet::Type.newtype(:keystone_endpoint) do
ensurable
newparam(:name, :namevar => true) do
newvalues(/\S+/)
newvalues(/\S+\/\S+/)
end
newproperty(:id) do
@ -18,7 +18,6 @@ Puppet::Type.newtype(:keystone_endpoint) do
end
newproperty(:region) do
defaultto('RegionOne')
end
# TODO I should do some url validation
@ -37,12 +36,8 @@ Puppet::Type.newtype(:keystone_endpoint) do
end
autorequire(:keystone_service) do
if self[:name].match('/')
(region, service_name) = self[:name].split('/')
[service_name]
else
[self[:name]]
end
(region, service_name) = self[:name].split('/')
[service_name]
end
end

View File

@ -22,8 +22,7 @@ Puppet::Type.newtype(:keystone_tenant) do
end
end
newproperty(:description) do
end
newproperty(:description)
newproperty(:id) do
validate do |v|

View File

@ -16,6 +16,11 @@ Puppet::Type.newtype(:keystone_user) do
newvalues(/\S+/)
end
newparam(:ignore_default_tenant, :boolean => true) do
newvalues(:true, :false)
defaultto false
end
newproperty(:enabled) do
newvalues(/(t|T)rue/, /(f|F)alse/)
defaultto('True')
@ -24,8 +29,23 @@ Puppet::Type.newtype(:keystone_user) do
end
end
newparam(:password) do
newproperty(:password) do
newvalues(/\S+/)
def change_to_s(currentvalue, newvalue)
if currentvalue == :absent
return "created password"
else
return "changed password"
end
end
def is_to_s( currentvalue )
return '[old password redacted]'
end
def should_to_s( newvalue )
return '[new password redacted]'
end
end
newproperty(:tenant) do

View File

@ -0,0 +1,17 @@
# == Class: keystone::client
#
# Installs Keystone client.
#
# === Parameters
#
# [*ensure*]
# (optional) Ensure state of the package. Defaults to 'present'.
#
class keystone::client (
$ensure = 'present'
) {
package { 'python-keystoneclient':
ensure => $ensure,
}
}

View File

@ -1,62 +0,0 @@
#
# This define can be used to manage authtokens so that
# services can authenticate with keystone.
#
# == Parameters
# [name] Name of the target file for the authtoken fragment.
# [order] Used to determine the order of the fragments. Optional.
# Defaults to 80, which places it near to the end of the file.
# [admin_token] Keystone admin token that can serve as a shared secret
# for authenticating. If this is choosen if is used instead of a user,tenant,password.
# Optional. Defaults to false.
# [admin_user] User used to authenticate service.
# Optional. Defaults to admin
# [admin_tenant_name] Tenant used to authenticate service.
# Optional. Defaults to openstack.
# [admin_password] Password used with user to authenticate service.
# Optional. Defaults to ChangeMe.
# [admin_tenant_name]
# Optional. Defaults to openstack.
# [auth_host] Host providing the keystone service API endpoint. Optional.
# Defaults to 127.0.0.1
# [auth_port] Port where keystone service is listening. Optional.
# Defaults to 35357.
# [auth_protocol] Protocol to use to communicate with keystone. Optional.
# Defaults to http.
#
# == Authors
#
# Dan Bode dan@puppetlabs.com
#
# == Copyright
#
# Copyright 2012 Puppetlabs Inc, unless otherwise noted.
#
define keystone::client::authtoken(
$order = '80',
$admin_token = false,
$admin_user = 'admin',
$admin_tenant_name = 'openstack',
$admin_password = 'ChangeMe',
$delay_auth_decision = '0',
$auth_host = '127.0.0.1',
$auth_port = '35357',
$auth_protocol = 'http',
$signing_dir = undef,
# TODO implement these eventually
# $memcache_servers
# $token_cache_time
) {
$auth_uri = "${auth_protocol}://${auth_host}:${auth_port}"
$fragment_title = regsubst($name, '/', '_', 'G')
concat::fragment { "${fragment_title}_authtoken":
target => $name,
content => template('keystone/client/authtoken.conf.erb'),
order => $order,
}
include 'keystone::python'
}

View File

@ -0,0 +1,30 @@
# == Class: keystone::config
#
# This class is used to manage arbitrary keystone configurations.
#
# === Parameters
#
# [*keystone_config*]
# (optional) Allow configuration of arbitrary keystone configurations.
# The value is an hash of keystone_config resources. Example:
# { 'DEFAULT/foo' => { value => 'fooValue'},
# 'DEFAULT/bar' => { value => 'barValue'}
# }
# In yaml format, Example:
# keystone_config:
# DEFAULT/foo:
# value: fooValue
# DEFAULT/bar:
# value: barValue
#
# NOTE: The configuration MUST NOT be already handled by this module
# or Puppet catalog compilation will fail with duplicate resources.
#
class keystone::config (
$keystone_config = {},
) {
validate_hash($keystone_config)
create_resources('keystone_config', $keystone_config)
}

View File

@ -1,35 +0,0 @@
#
# This class implements a config fragment for
# the ldap specific backend for keystone.
#
# == Dependencies
# == Examples
# == Authors
#
# Dan Bode dan@puppetlabs.com
#
# == Copyright
#
# Copyright 2012 Puppetlabs Inc, unless otherwise noted.
#
class keystone::ldap(
$url = 'ldap://localhost',
$user = 'dc=Manager,dc=example,dc=com',
$password = 'None',
$suffix = 'cn=example,cn=com',
$user_tree_dn = 'ou=Users,dc=example,dc=com',
$tenant_tree_dn = 'ou=Roles,dc=example,dc=com',
$role_tree_dn = 'dc=example,dc=com'
) {
keystone_config {
'ldap/url': value => $url;
'ldap/user': value => $user;
'ldap/password': value => $password;
'ldap/suffix': value => $suffix;
'ldap/user_tree_dn': value => $user_tree_dn;
'ldap/tenant_tree_dn': value => $tenant_tree_dn;
'ldap/role_tree_dn': value => $role_tree_dn;
#"ldap/tree_dn" value => "dc=example,dc=com",
}
}

View File

@ -4,20 +4,25 @@
# This class can be used to create tables, users and grant
# privelege for a mysql keystone database.
#
# [*Parameters*]
# == 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_admin.
# [user] Name of keystone user. Optional. Defaults to keystone.
#
# [host] Host where user should be allowed all priveleges for database.
# Optional. Defaults to 127.0.0.1.
#
# [allowed_hosts] Hosts allowed to use the database
#
# [*mysql_module*]
# (optional) The mysql puppet module version to use
# Tested versions include 0.9 and 2.2
# Default to '0.9'
#
# == Dependencies
# Class['mysql::server']
#
@ -33,7 +38,7 @@
class keystone::db::mysql(
$password,
$dbname = 'keystone',
$user = 'keystone_admin',
$user = 'keystone',
$host = '127.0.0.1',
$charset = 'utf8',
$collate = 'utf8_unicode_ci',
@ -41,11 +46,9 @@ class keystone::db::mysql(
$allowed_hosts = undef
) {
Class['mysql::server'] -> Class['keystone::db::mysql']
Class['keystone::db::mysql'] -> Exec<| title == 'keystone-manage db_sync' |>
Class['keystone::db::mysql'] -> Exec<| title == 'keystone-manage db_sync' |>
Class['keystone::db::mysql'] -> Service<| title == 'keystone' |>
Mysql::Db[$dbname] ~> Exec<| title == 'keystone-manage db_sync' |>
Class['keystone::db::mysql'] -> Package<| title == 'keystone' |>
if ($mysql_module >= 2.2) {
mysql::db { $dbname:
@ -54,28 +57,36 @@ class keystone::db::mysql(
host => $host,
charset => $charset,
collate => $collate,
require => Service['mysql'],
require => Service['mysqld'],
}
} else {
require 'mysql::python'
require mysql::python
mysql::db { $dbname:
user => $user,
password => $password,
host => $host,
charset => $charset,
require => Class['mysql::server'],
require => Class['mysql::config'],
}
}
if $allowed_hosts {
keystone::db::mysql::host_access { $allowed_hosts:
user => $user,
password => $password,
database => $dbname,
# Check allowed_hosts to avoid duplicate resource declarations
if is_array($allowed_hosts) and delete($allowed_hosts,$host) != [] {
$real_allowed_hosts = delete($allowed_hosts,$host)
} elsif is_string($allowed_hosts) and ($allowed_hosts != $host) {
$real_allowed_hosts = $allowed_hosts
}
if $real_allowed_hosts {
keystone::db::mysql::host_access { $real_allowed_hosts:
user => $user,
password => $password,
database => $dbname,
mysql_module => $mysql_module,
}
Keystone::Db::Mysql::Host_access[$allowed_hosts] -> Exec<| title == 'keystone-manage db_sync' |>
Keystone::Db::Mysql::Host_access[$real_allowed_hosts] -> Exec<| title == 'keystone-manage db_sync' |>
}

View File

@ -1,19 +1,34 @@
#
define keystone::db::mysql::host_access(
$user,
$password,
$database
$database,
$mysql_module = '0.9'
) {
if ($mysql_module >= 2.2) {
mysql_user { "${user}@${name}":
password_hash => mysql_password($password),
require => Mysql_database[$database],
}
database_user { "${user}@${name}":
password_hash => mysql_password($password),
provider => 'mysql',
require => 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}"]
}
}
database_grant { "${user}@${name}/${database}":
# TODO figure out which privileges to grant.
privileges => 'all',
provider => 'mysql',
require => Database_user["${user}@${name}"]
}
}

View File

@ -13,12 +13,7 @@
#
# [dbname] Name of keystone database. Optional. Defaults to keystone.
#
# [user] Name of keystone user. Optional. Defaults to keystone_admin.
#
# [host] Host where user should be allowed all priveleges for database.
# Optional. Defaults to 127.0.0.1.
#
# [allowed_hosts] Hosts allowed to use the database
# [user] Name of keystone user. Optional. Defaults to keystone.
#
# == Dependencies
# Class['postgresql::server']
@ -35,18 +30,18 @@
class keystone::db::postgresql(
$password,
$dbname = 'keystone',
$user = 'keystone_admin',
$user = 'keystone'
) {
Class['keystone::db::postgresql'] -> Package<| title == 'keystone' |>
Class['keystone::db::postgresql'] -> Exec<| title == 'keystone-manage db_sync' |>
#require 'postgresql::python'
Class['keystone::db::postgresql'] -> Service<| title == 'keystone' |>
postgresql::server::db { "${dbname}":
user => "${user}",
password => "${password}",
}
require postgresql::python
Postgresql::Server::Db[$dbname] ~> Exec<| title == 'keystone-manage db_sync' |>
postgresql::db { $dbname:
user => $user,
password => $password,
}
Postgresql::Db[$dbname] ~> Exec<| title == 'keystone-manage db_sync' |>
}

View File

@ -0,0 +1,12 @@
#
# Class to execute "keystone-manage db_sync
#
class keystone::db::sync {
exec { 'keystone-manage db_sync':
path => '/usr/bin',
user => 'keystone',
refreshonly => true,
subscribe => [Package['keystone'], Keystone_config['database/connection']],
require => User['keystone'],
}
}

View File

@ -30,7 +30,7 @@ class keystone::dev::install(
'libldap2-dev',
'sqlite3'
]:
ensure => installed,
ensure => latest,
}
vcsrepo { $source_dir:

View File

@ -1,28 +1,169 @@
# == Class: keystone::endpoint
#
# Creates the auth endpoints for keystone
#
# * public_address - public address for keystone endpoint. Optional. Defaults to 127.0.0.1.
# * admin_address - admin address for keystone endpoint. Optional. Defaults to 127.0.0.1.
# * internal_address - internal address for keystone endpoint. Optional. Defaults to 127.0.0.1.
# * public_port - Port for non-admin access to keystone endpoint. Optional. Defaults to 5000.
# * admin_port - Port for admin access to keystone endpoint. Optional. Defaults to 35357.
# === Parameters
#
class keystone::endpoint(
$public_address = '127.0.0.1',
$admin_address = '127.0.0.1',
$internal_address = '127.0.0.1',
$public_port = '5000',
$admin_port = '35357'
# [*public_url*]
# (optional) Public url for keystone endpoint. (Defaults to 'http://127.0.0.1:5000')
#
# [*internal_url*]
# (optional) Internal url for keystone endpoint. (Defaults to $public_url)
#
# [*admin_url*]
# (optional) Admin url for keystone endpoint. (Defaults to 'http://127.0.0.1:35357')
#
# [*region*]
# (optional) Region for endpoint. (Defaults to 'RegionOne')
#
# [*version*]
# (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
#
# class { 'keystone::endpoint':
# public_url => 'https://154.10.10.23:5000',
# internal_url => 'https://11.0.1.7:5000',
# admin_url => 'https://10.0.1.7:35357',
# }
#
class keystone::endpoint (
$public_url = 'http://127.0.0.1:5000',
$internal_url = undef,
$admin_url = 'http://127.0.0.1:35357',
$version = 'v2.0',
$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 {
warning('The public_port parameter is deprecated, use public_url instead.')
}
if $public_protocol {
warning('The public_protocol parameter is deprecated, use public_url instead.')
}
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 { 'keystone':
keystone_endpoint { "${region}/keystone":
ensure => present,
public_url => "http://${public_address}:${public_port}/v2.0",
admin_url => "http://${admin_address}:${admin_port}/v2.0",
internal_url => "http://${internal_address}:${public_port}/v2.0",
public_url => $public_url_real,
admin_url => $admin_url_real,
internal_url => $internal_url_real,
region => $region,
}
}

View File

@ -4,7 +4,7 @@
# == Parameters
#
# [package_ensure] Desired ensure state of packages. Optional. Defaults to present.
# accepts installed or specific versions.
# accepts latest or specific versions.
# [bind_host] Host that keystone binds to.
# [bind_port] Port that keystone binds to.
# [public_port]
@ -14,36 +14,117 @@
# [admin_token] Admin token that can be used to authenticate as a keystone
# admin. Required.
# [verbose] Rather keystone should log at verbose level. Optional.
# Defaults to false.
# Defaults to False.
# [debug] Rather keystone should log at debug level. Optional.
# Defaults to false.
# [use_syslog] Rather or not keystone should log to syslog. Optional.
# Defaults to false.
# [syslog_log_facility] Facility for syslog, if used. Optional.
# [*log_dir*]
# (optional) Directory where logs should be stored
# If set to boolean false, it will not log to any directory
# Defaults to '/var/log/keystone'
# Defaults to False.
# [use_syslog] Use syslog for logging. Optional.
# Defaults to False.
# [log_facility] Syslog facility to receive log lines. Optional.
# [catalog_type] Type of catalog that keystone uses to store endpoints,services. Optional.
# Defaults to sql. (Also accepts template)
# [token_format] Format keystone uses for tokens. Optional. Defaults to UUID (PKI is grizzly native mode though).
# [catalog_driver] Catalog driver used by Keystone to store endpoints and services. Optional.
# Setting this value will override and ignore catalog_type.
# [catalog_template_file] Path to the catalog used if catalog_type equals 'template'.
# Defaults to '/etc/keystone/default_catalog.templates'
# [token_provider] Format keystone uses for tokens. Optional.
# Defaults to 'keystone.token.providers.pki.Provider'
# Supports PKI and UUID.
# [cache_dir] Directory created when token_format is PKI. Optional.
# [token_driver] Driver to use for managing tokens.
# Optional. Defaults to 'keystone.token.backends.sql.Token'
# [token_expiration] Amount of time a token should remain valid (seconds).
# Optional. Defaults to 3600 (1 hour).
# [token_format] Deprecated: Use token_provider instead.
# [cache_dir] Directory created when token_provider is pki. Optional.
# Defaults to /var/cache/keystone.
# [enalbles] If the keystone services should be enabled. Optioal. Default to true.
# [sql_conneciton] Url used to connect to database.
# [memcache_servers] List of memcache servers/ports. Optional. Used with
# token_driver keystone.token.backends.memcache.Token. Defaults to false.
# [enabled] If the keystone services should be enabled. Optional. Default to true.
# [sql_connection] Url used to connect to database.
# [idle_timeout] Timeout when db connections should be reaped.
# [enable_pki_setup] Enable call to pki_setup.
# [rabbit_host] Location of rabbitmq installation. Optional. Defaults to localhost.
# [rabbit_port] Port for rabbitmq instance. Optional. Defaults to 5672.
# [rabbit_hosts] Location of rabbitmq installation. Optional. Defaults to undef.
# [rabbit_password] Password used to connect to rabbitmq. Optional. Defaults to guest.
# [rabbit_userid] User used to connect to rabbitmq. Optional. Defaults to guest.
# [rabbit_virtual_host] The RabbitMQ virtual host. Optional. Defaults to /.
# [notification_driver] RPC driver. Not enabled by default
# [notification_topics] AMQP topics to publish to when using the RPC notification driver.
# [control_exchange] AMQP exchange to connect to if using RabbitMQ or Qpid
#
# [*public_bind_host*]
# (optional) The IP address of the public network interface to listen on
# Deprecates bind_host
# Default to '0.0.0.0'.
#
# [*admin_bind_host*]
# (optional) The IP address of the public network interface to listen on
# Deprecates bind_host
# Default to '0.0.0.0'.
#
# [*log_dir*]
# (optional) Directory where logs should be stored
# If set to boolean false, it will not log to any directory
# Defaults to '/var/log/keystone'
#
# [*log_file*]
# (optional) Where to log
# Defaults to false
#
# [*public_endpoint*]
# (optional) The base public endpoint URL for keystone that are
# advertised to clients (NOTE: this does NOT affect how
# keystone listens for connections) (string value)
# If set to false, no public_endpoint will be defined in keystone.conf.
# Sample value: 'http://localhost:5000/v2.0/'
# Defaults to false
#
# [*admin_endpoint*]
# (optional) The base admin endpoint URL for keystone that are
# advertised to clients (NOTE: this does NOT affect how keystone listens
# for connections) (string value)
# If set to false, no admin_endpoint will be defined in keystone.conf.
# Sample value: 'http://localhost:35357/v2.0/'
# Defaults to false
#
# [*enable_ssl*]
# (optional) Toggle for SSL support on the keystone eventlet servers.
# (boolean value)
# Defaults to false
#
# [*ssl_certfile*]
# (optional) Path of the certfile for SSL. (string value)
# Defaults to '/etc/keystone/ssl/certs/keystone.pem'
#
# [*ssl_keyfile*]
# (optional) Path of the keyfile for SSL. (string value)
# Defaults to '/etc/keystone/ssl/private/keystonekey.pem'
#
# [*ssl_ca_certs*]
# (optional) Path of the ca cert file for SSL. (string value)
# Defaults to '/etc/keystone/ssl/certs/ca.pem'
#
# [*ssl_ca_key*]
# (optional) Path of the CA key file for SSL (string value)
# Defaults to '/etc/keystone/ssl/private/cakey.pem'
#
# [*ssl_cert_subject*]
# (optional) SSL Certificate Subject (auto generated certificate)
# (string value)
# Defaults to '/C=US/ST=Unset/L=Unset/O=Unset/CN=localhost'
#
# [*mysql_module*]
# (optional) The mysql puppet module version to use
# Tested versions include 0.9 and 2.2
# Default to '0.9'
#
# == Dependencies
# None
#
# == Examples
#
# class { 'keystone':
# verbose => true,
# log_verbose => 'True',
# admin_token => 'my_special_token',
# }
#
@ -57,158 +138,167 @@
#
class keystone(
$admin_token,
$package_ensure = 'present',
$bind_host = '0.0.0.0',
$public_port = '5000',
$admin_port = '35357',
$compute_port = '3000',
$verbose = false,
$debug = false,
$use_syslog = false,
$syslog_log_facility = 'LOG_LOCAL7',
$log_dir = '/var/log/keystone',
$catalog_type = 'sql',
$token_format = 'UUID',
$cache_dir = '/var/cache/keystone',
$memcache_servers = false,
$memcache_server_port = false,
$enabled = true,
$sql_connection = 'sqlite:////var/lib/keystone/keystone.db',
$idle_timeout = '200',
$rabbit_host = 'localhost',
$rabbit_hosts = false,
$rabbit_password = 'guest',
$rabbit_port = '5672',
$rabbit_userid = 'guest',
$rabbit_virtual_host = '/',
$rabbit_use_ssl = false,
$notification_driver = false,
$notification_topics = false,
$control_exchange = false,
$max_pool_size = '10',
$max_overflow = '30',
$max_retries = '-1',
$package_ensure = 'present',
$bind_host = false,
$public_bind_host = '0.0.0.0',
$admin_bind_host = '0.0.0.0',
$public_port = '5000',
$admin_port = '35357',
$compute_port = '8774',
$verbose = false,
$debug = false,
$log_dir = '/var/log/keystone',
$log_file = false,
$use_syslog = false,
$log_facility = 'LOG_USER',
$catalog_type = 'sql',
$catalog_driver = false,
$catalog_template_file = '/etc/keystone/default_catalog.templates',
$token_format = false,
$token_provider = 'keystone.token.providers.pki.Provider',
$token_driver = 'keystone.token.backends.sql.Token',
$token_expiration = 3600,
$public_endpoint = false,
$admin_endpoint = false,
$enable_ssl = false,
$ssl_certfile = '/etc/keystone/ssl/certs/keystone.pem',
$ssl_keyfile = '/etc/keystone/ssl/private/keystonekey.pem',
$ssl_ca_certs = '/etc/keystone/ssl/certs/ca.pem',
$ssl_ca_key = '/etc/keystone/ssl/private/cakey.pem',
$ssl_cert_subject = '/C=US/ST=Unset/L=Unset/O=Unset/CN=localhost',
$cache_dir = '/var/cache/keystone',
$memcache_servers = false,
$enabled = true,
$sql_connection = 'sqlite:////var/lib/keystone/keystone.db',
$idle_timeout = '200',
$enable_pki_setup = true,
$mysql_module = '0.9',
$rabbit_host = 'localhost',
$rabbit_hosts = false,
$rabbit_password = 'guest',
$rabbit_port = '5672',
$rabbit_userid = 'guest',
$rabbit_virtual_host = '/',
$notification_driver = false,
$notification_topics = false,
$control_exchange = false
) {
validate_re($catalog_type, 'template|sql')
validate_re($token_format, 'UUID|PKI')
if ! $catalog_driver {
validate_re($catalog_type, 'template|sql')
}
Keystone_config<||> ~> Service['keystone']
File['/etc/keystone/keystone.conf'] -> Keystone_config<||> ~> Service['keystone']
Keystone_config<||> ~> Exec<| title == 'keystone-manage db_sync'|>
Package['keystone'] ~> Exec<| title == 'keystone-manage pki_setup'|> ~> Service['keystone']
Keystone_config<||> ~> Exec<| title == 'keystone-manage pki_setup'|>
include keystone::params
File {
ensure => present,
owner => 'keystone',
group => 'keystone',
mode => '0640',
require => Package['keystone'],
notify => Service['keystone'],
}
# logging config
if $log_dir {
keystone_config {
'DEFAULT/log_dir': value => $log_dir;
}
} else {
keystone_config {
'DEFAULT/log_dir': ensure => absent;
}
}
include 'keystone::params'
package { 'keystone':
name => $::keystone::params::package_name,
ensure => $package_ensure,
name => $::keystone::params::package_name,
}
group { 'keystone':
ensure => present,
system => true,
require => Package['keystone'],
}
user { 'keystone':
ensure => 'present',
gid => 'keystone',
system => true,
require => Package['keystone'],
}
file { ['/etc/keystone', '/var/log/keystone', '/var/lib/keystone']:
ensure => directory,
owner => 'keystone',
group => 'keystone',
mode => '0755',
notify => Service['keystone'],
}
if $::operatingsystem == 'Ubuntu' {
if $service_provider == 'pacemaker' {
file { '/etc/init/keystone.override':
ensure => present,
content => "manual",
mode => '0644',
replace => "no",
owner => 'root',
group => 'root',
}
File['/etc/init/keystone.override'] -> Package['keystone']
exec { 'remove-keystone-bootblockr':
command => 'rm -rf /etc/init/keystone.override',
path => ['/bin', '/usr/bin'],
require => Package['keystone']
}
}
mode => '0750',
}
Package['keystone'] -> User['keystone']
Package['keystone'] -> Group['keystone']
Package['keystone'] -> File['/etc/keystone']
Package['keystone'] -> Keystone_config <| |>
file { '/etc/keystone/keystone.conf':
mode => '0600',
}
if $bind_host {
warning('The bind_host parameter is deprecated, use public_bind_host and admin_bind_host instead.')
$public_bind_host_real = $bind_host
$admin_bind_host_real = $bind_host
} else {
$public_bind_host_real = $public_bind_host
$admin_bind_host_real = $admin_bind_host
}
# default config
keystone_config {
'DEFAULT/admin_token': value => $admin_token;
'DEFAULT/bind_host': value => $bind_host;
'DEFAULT/public_port': value => $public_port;
'DEFAULT/admin_port': value => $admin_port;
'DEFAULT/compute_port': value => $compute_port;
'DEFAULT/debug': value => $debug;
'DEFAULT/verbose': value => $verbose;
'identity/driver': value =>"keystone.identity.backends.sql.Identity";
'policy/driver': value =>"keystone.policy.backends.rules.Policy";
'ec2/driver': value =>"keystone.contrib.ec2.backends.sql.Ec2";
'filter:debug/paste.filter_factory': value =>"keystone.common.wsgi:Debug.factory";
'filter:token_auth/paste.filter_factory': value =>"keystone.middleware:TokenAuthMiddleware.factory";
'filter:admin_token_auth/paste.filter_factory': value =>"keystone.middleware:AdminTokenAuthMiddleware.factory";
'filter:xml_body/paste.filter_factory': value =>"keystone.middleware:XmlBodyMiddleware.factory";
'filter:json_body/paste.filter_factory': value =>"keystone.middleware:JsonBodyMiddleware.factory";
'filter:user_crud_extension/paste.filter_factory': value =>"keystone.contrib.user_crud:CrudExtension.factory";
'filter:crud_extension/paste.filter_factory': value =>"keystone.contrib.admin_crud:CrudExtension.factory";
'filter:ec2_extension/paste.filter_factory': value =>"keystone.contrib.ec2:Ec2Extension.factory";
'filter:s3_extension/paste.filter_factory': value =>"keystone.contrib.s3:S3Extension.factory";
'filter:url_normalize/paste.filter_factory': value =>"keystone.middleware:NormalizingFilter.factory";
'filter:stats_monitoring/paste.filter_factory': value =>"keystone.contrib.stats:StatsMiddleware.factory";
'filter:stats_reporting/paste.filter_factory': value =>"keystone.contrib.stats:StatsExtension.factory";
'app:public_service/paste.app_factory': value =>"keystone.service:public_app_factory";
'app:admin_service/paste.app_factory': value =>"keystone.service:admin_app_factory";
'pipeline:public_api/pipeline': value =>"stats_monitoring url_normalize token_auth admin_token_auth xml_body json_body debug ec2_extension user_crud_extension public_service";
'pipeline:admin_api/pipeline': value =>"stats_monitoring url_normalize token_auth admin_token_auth xml_body json_body debug stats_reporting ec2_extension s3_extension crud_extension admin_service";
'app:public_version_service/paste.app_factory': value =>"keystone.service:public_version_app_factory";
'app:admin_version_service/paste.app_factory': value =>"keystone.service:admin_version_app_factory";
'pipeline:public_version_api/pipeline': value =>"stats_monitoring url_normalize xml_body public_version_service";
'pipeline:admin_version_api/pipeline': value =>"stats_monitoring url_normalize xml_body admin_version_service";
'composite:main/use': value =>"egg:Paste#urlmap";
'composite:main//v2.0': value =>"public_api";
'composite:main//': value =>"public_version_api";
'composite:admin/use': value =>"egg:Paste#urlmap";
'composite:admin//v2.0': value =>"admin_api";
'composite:admin//': value =>"admin_version_api";
'DEFAULT/admin_token': value => $admin_token ,secret => true;
'DEFAULT/public_bind_host': value => $public_bind_host_real;
'DEFAULT/admin_bind_host': value => $admin_bind_host_real;
'DEFAULT/public_port': value => $public_port;
'DEFAULT/admin_port': value => $admin_port;
'DEFAULT/compute_port': value => $compute_port;
'DEFAULT/verbose': value => $verbose;
'DEFAULT/debug': value => $debug;
}
# Endpoint configuration
if $public_endpoint {
keystone_config {
'DEFAULT/public_endpoint': value => $public_endpoint;
}
} else {
keystone_config {
'DEFAULT/public_endpoint': ensure => absent;
}
}
if $admin_endpoint {
keystone_config {
'DEFAULT/admin_endpoint': value => $admin_endpoint;
}
} else {
keystone_config {
'DEFAULT/admin_endpoint': ensure => absent;
}
}
# token driver config
keystone_config {
'token/driver': value => $token_driver;
'token/expiration': value => $token_expiration;
}
# ssl config
if ($enable_ssl) {
keystone_config {
'ssl/enable': value => true;
'ssl/certfile': value => $ssl_certfile;
'ssl/keyfile': value => $ssl_keyfile;
'ssl/ca_certs': value => $ssl_ca_certs;
'ssl/ca_key': value => $ssl_ca_key;
'ssl/cert_subject': value => $ssl_cert_subject;
}
} else {
keystone_config {
'ssl/enable': value => false;
}
}
if($sql_connection =~ /mysql:\/\/\S+:\S+@\S+\/\S+/) {
require 'mysql::python'
if ($mysql_module >= 2.2) {
require 'mysql::bindings'
require 'mysql::bindings::python'
} else {
require 'mysql::python'
}
} elsif($sql_connection =~ /postgresql:\/\/\S+:\S+@\S+\/\S+/) {
} elsif($sql_connection =~ /sqlite:\/\//) {
@ -220,108 +310,65 @@ class keystone(
# memcache connection config
if $memcache_servers {
validate_array($memcache_servers)
Service<| title == 'memcached' |> -> Service['keystone']
keystone_config {
'token/driver': value => 'keystone.token.backends.memcache.Token';
'cache/enabled': value => 'true';
'cache/backend': value => 'keystone.cache.memcache_pool';
'memcache/servers': value => inline_template("<%= @memcache_servers.collect{|ip| ip + ':' + @memcache_server_port }.join ',' %>");
}
# work-arounding multi-line inifile limitations with file_line resource
file_line { 'backend_argument_pool':
line => 'backend_argument=pool_maxsize:100',
match => '^\s*backend_argument\s*=\s*pool_maxsize:',
path => '/etc/keystone/keystone.conf',
after => '^\s*backend\s*=',
require => Keystone_config['cache/backend'],
notify => Service['keystone'],
}
file_line { 'backend_argument_url':
line => inline_template("backend_argument=url:<%= @memcache_servers.collect{|ip| ip }.join ',' %>"),
match => '^\s*backend_argument\s*=\s*url:',
path => '/etc/keystone/keystone.conf',
after => '^\s*backend\s*=',
require => Keystone_config['cache/backend'],
notify => Service['keystone'],
'memcache/servers': value => join($memcache_servers, ',');
}
} else {
keystone_config {
'token/driver': value => 'keystone.token.backends.sql.Token';
'memcache/servers': ensure => absent;
}
}
# db connection config
keystone_config {
'database/connection': value => $sql_connection;
'database/idle_timeout': value => $idle_timeout;
'database/max_pool_size': value => $max_pool_size;
'database/max_retries': value => $max_retries;
'database/max_overflow': value => $max_overflow;
'database/connection': value => $sql_connection, secret => true;
'database/idle_timeout': value => $idle_timeout;
}
# configure based on the catalog backend
if($catalog_type == 'template') {
keystone_config {
'catalog/driver':
value => 'keystone.catalog.backends.templated.TemplatedCatalog';
'catalog/template_file':
value => '/etc/keystone/default_catalog.templates';
}
} elsif($catalog_type == 'sql' ) {
keystone_config { 'catalog/driver':
value => ' keystone.catalog.backends.sql.Catalog'
}
if $catalog_driver {
$catalog_driver_real = $catalog_driver
}
elsif ($catalog_type == 'template') {
$catalog_driver_real = 'keystone.catalog.backends.templated.Catalog'
}
elsif ($catalog_type == 'sql') {
$catalog_driver_real = 'keystone.catalog.backends.sql.Catalog'
}
if $enabled {
$service_ensure = 'running'
} else {
$service_ensure = 'stopped'
}
Keystone_config <| |> -> Service['keystone']
service { 'keystone':
name => $::keystone::params::service_name,
ensure => $service_ensure,
enable => $enabled,
hasstatus => true,
hasrestart => true,
require => [Package['keystone']],
provider => $::keystone::params::service_provider,
}
Package<| title == 'keystone'|> ~> Service<| title == 'keystone'|>
if !defined(Service['keystone']) {
notify{ "Module ${module_name} cannot notify service keystone on package update": }
keystone_config {
'catalog/driver': value => $catalog_driver_real;
'catalog/template_file': value => $catalog_template_file;
}
keystone_config { 'signing/token_format': value => $token_format }
if($token_format == 'PKI') {
if $token_format {
warning('token_format parameter is deprecated. Use token_provider instead.')
}
# remove the old format in case of an upgrade
keystone_config { 'signing/token_format': ensure => absent }
if ($token_format == false and $token_provider == 'keystone.token.providers.pki.Provider') or $token_format == 'PKI' {
keystone_config { 'token/provider': value => 'keystone.token.providers.pki.Provider' }
file { $cache_dir:
ensure => directory,
notify => Service['keystone'],
}
# keystone-manage pki_setup Should be run as the same system user that will be running the Keystone service to ensure
# proper ownership for the private key file and the associated certificates
exec { 'keystone-manage pki_setup':
path => '/usr/bin',
user => 'keystone',
refreshonly => true,
}
}
if $enabled {
# this probably needs to happen more often than just when the db is
# created
exec { 'keystone-manage db_sync':
user => 'keystone',
path => '/usr/bin',
refreshonly => true,
tries => 10, # waiting if haproxy was restarted
try_sleep => 6, # near at this exec
notify => Service['keystone'],
subscribe => Package['keystone'],
if $enable_pki_setup {
exec { 'keystone-manage pki_setup':
path => '/usr/bin',
user => 'keystone',
refreshonly => true,
creates => '/etc/keystone/ssl/private/signing_key.pem',
notify => Service['keystone'],
subscribe => Package['keystone'],
require => User['keystone'],
}
}
} elsif $token_format == 'UUID' {
keystone_config { 'token/provider': value => 'keystone.token.providers.uuid.Provider' }
} else {
keystone_config { 'token/provider': value => $token_provider }
}
if $notification_driver {
@ -341,32 +388,70 @@ class keystone(
}
keystone_config {
'DEFAULT/rabbit_password': value => $rabbit_password;
'DEFAULT/rabbit_userid': value => $rabbit_userid;
'DEFAULT/rabbit_password': value => $rabbit_password;
'DEFAULT/rabbit_userid': value => $rabbit_userid;
'DEFAULT/rabbit_virtual_host': value => $rabbit_virtual_host;
}
if $rabbit_hosts {
keystone_config { 'DEFAULT/rabbit_hosts': value => join($rabbit_hosts, ',') }
keystone_config { 'DEFAULT/rabbit_hosts': value => join($rabbit_hosts, ',') }
keystone_config { 'DEFAULT/rabbit_ha_queues': value => true }
} else {
keystone_config { 'DEFAULT/rabbit_host': value => $rabbit_host }
keystone_config { 'DEFAULT/rabbit_port': value => $rabbit_port }
keystone_config { 'DEFAULT/rabbit_hosts': value => "${rabbit_host}:${rabbit_port}" }
keystone_config { 'DEFAULT/rabbit_host': value => $rabbit_host }
keystone_config { 'DEFAULT/rabbit_port': value => $rabbit_port }
keystone_config { 'DEFAULT/rabbit_hosts': value => "${rabbit_host}:${rabbit_port}" }
keystone_config { 'DEFAULT/rabbit_ha_queues': value => false }
}
if $enabled {
$service_ensure = 'running'
} else {
$service_ensure = 'stopped'
}
service { 'keystone':
ensure => $service_ensure,
name => $::keystone::params::service_name,
enable => $enabled,
hasstatus => true,
hasrestart => true,
provider => $::keystone::params::service_provider,
}
if $enabled {
include keystone::db::sync
Class['keystone::db::sync'] ~> Service['keystone']
}
# Syslog configuration
if $use_syslog {
keystone_config {
'DEFAULT/use_syslog': value => true;
'DEFAULT/use_syslog_rfc_format': value => true;
'DEFAULT/syslog_log_facility': value => $syslog_log_facility;
'DEFAULT/use_syslog': value => true;
'DEFAULT/syslog_log_facility': value => $log_facility;
}
} else {
keystone_config {
'DEFAULT/use_syslog': value => false;
}
}
if $log_file {
keystone_config {
'DEFAULT/log_file': value => $log_file;
'DEFAULT/log_dir': value => $log_dir;
}
} else {
if $log_dir {
keystone_config {
'DEFAULT/log_dir': value => $log_dir;
'DEFAULT/log_file': ensure => absent;
}
} else {
keystone_config {
'DEFAULT/log_dir': ensure => absent;
'DEFAULT/log_file': ensure => absent;
}
}
}
}

View File

@ -0,0 +1,183 @@
#
# Implements ldap configuration for keystone.
#
# == Dependencies
# == Examples
# == Authors
#
# Dan Bode dan@puppetlabs.com
# Matt Fischer matt.fischer@twcable.com
#
# == Copyright
#
# Copyright 2012 Puppetlabs Inc, unless otherwise noted.
#
class keystone::ldap(
$url = undef,
$user = undef,
$password = undef,
$suffix = undef,
$query_scope = undef,
$page_size = undef,
$user_tree_dn = undef,
$user_filter = undef,
$user_objectclass = undef,
$user_id_attribute = undef,
$user_name_attribute = undef,
$user_mail_attribute = undef,
$user_enabled_attribute = undef,
$user_enabled_mask = undef,
$user_enabled_default = undef,
$user_attribute_ignore = undef,
$user_default_project_id_attribute = undef,
$user_allow_create = undef,
$user_allow_update = undef,
$user_allow_delete = undef,
$user_pass_attribute = undef,
$user_enabled_emulation = undef,
$user_enabled_emulation_dn = undef,
$user_additional_attribute_mapping = undef,
$tenant_tree_dn = undef,
$tenant_filter = undef,
$tenant_objectclass = undef,
$tenant_id_attribute = undef,
$tenant_member_attribute = undef,
$tenant_desc_attribute = undef,
$tenant_name_attribute = undef,
$tenant_enabled_attribute = undef,
$tenant_domain_id_attribute = undef,
$tenant_attribute_ignore = undef,
$tenant_allow_create = undef,
$tenant_allow_update = undef,
$tenant_allow_delete = undef,
$tenant_enabled_emulation = undef,
$tenant_enabled_emulation_dn = undef,
$tenant_additional_attribute_mapping = undef,
$role_tree_dn = undef,
$role_filter = undef,
$role_objectclass = undef,
$role_id_attribute = undef,
$role_name_attribute = undef,
$role_member_attribute = undef,
$role_attribute_ignore = undef,
$role_allow_create = undef,
$role_allow_update = undef,
$role_allow_delete = undef,
$role_additional_attribute_mapping = undef,
$group_tree_dn = undef,
$group_filter = undef,
$group_objectclass = undef,
$group_id_attribute = undef,
$group_name_attribute = undef,
$group_member_attribute = undef,
$group_desc_attribute = undef,
$group_attribute_ignore = undef,
$group_allow_create = undef,
$group_allow_update = undef,
$group_allow_delete = undef,
$group_additional_attribute_mapping = undef,
$tenant_tree_dn = undef,
$role_tree_dn = undef,
$use_tls = undef,
$tls_cacertdir = undef,
$tls_cacertfile = undef,
$tls_req_cert = undef,
$identity_driver = undef,
$assignment_driver = undef,
) {
package { 'python-ldap':
ensure => present,
}
# check for some common driver name mistakes
if ($assignment_driver != undef) {
if ! ($assignment_driver =~ /^keystone.assignment.backends.*Assignment$/) {
fail('assigment driver should be of the form \'keystone.assignment.backends.*Assignment\'')
}
}
if ($identity_driver != undef) {
if ! ($identity_driver =~ /^keystone.identity.backends.*Identity$/) {
fail('identity driver should be of the form \'keystone.identity.backends.*Identity\'')
}
}
if ($tls_cacertdir != undef) {
file { $tls_cacertdir:
ensure => directory
}
}
keystone_config {
'ldap/url': value => $url;
'ldap/user': value => $user;
'ldap/password': value => $password, secret => true;
'ldap/suffix': value => $suffix;
'ldap/query_scope': value => $query_scope;
'ldap/page_size': value => $page_size;
'ldap/user_tree_dn': value => $user_tree_dn;
'ldap/user_filter': value => $user_filter;
'ldap/user_objectclass': value => $user_objectclass;
'ldap/user_id_attribute': value => $user_id_attribute;
'ldap/user_name_attribute': value => $user_name_attribute;
'ldap/user_mail_attribute': value => $user_mail_attribute;
'ldap/user_enabled_attribute': value => $user_enabled_attribute;
'ldap/user_enabled_mask': value => $user_enabled_mask;
'ldap/user_enabled_default': value => $user_enabled_default;
'ldap/user_attribute_ignore': value => $user_attribute_ignore;
'ldap/user_default_project_id_attribute': value => $user_default_project_id_attribute;
'ldap/user_allow_create': value => $user_allow_create;
'ldap/user_allow_update': value => $user_allow_update;
'ldap/user_allow_delete': value => $user_allow_delete;
'ldap/user_pass_attribute': value => $user_pass_attribute;
'ldap/user_enabled_emulation': value => $user_enabled_emulation;
'ldap/user_enabled_emulation_dn': value => $user_enabled_emulation_dn;
'ldap/user_additional_attribute_mapping': value => $user_additional_attribute_mapping;
'ldap/tenant_tree_dn': value => $tenant_tree_dn;
'ldap/tenant_filter': value => $tenant_filter;
'ldap/tenant_objectclass': value => $tenant_objectclass;
'ldap/tenant_id_attribute': value => $tenant_id_attribute;
'ldap/tenant_member_attribute': value => $tenant_member_attribute;
'ldap/tenant_desc_attribute': value => $tenant_desc_attribute;
'ldap/tenant_name_attribute': value => $tenant_name_attribute;
'ldap/tenant_enabled_attribute': value => $tenant_enabled_attribute;
'ldap/tenant_attribute_ignore': value => $tenant_attribute_ignore;
'ldap/tenant_domain_id_attribute': value => $tenant_domain_id_attribute;
'ldap/tenant_allow_create': value => $tenant_allow_create;
'ldap/tenant_allow_update': value => $tenant_allow_update;
'ldap/tenant_allow_delete': value => $tenant_allow_delete;
'ldap/tenant_enabled_emulation': value => $tenant_enabled_emulation;
'ldap/tenant_enabled_emulation_dn': value => $tenant_enabled_emulation_dn;
'ldap/tenant_additional_attribute_mapping': value => $tenant_additional_attribute_mapping;
'ldap/role_tree_dn': value => $role_tree_dn;
'ldap/role_filter': value => $role_filter;
'ldap/role_objectclass': value => $role_objectclass;
'ldap/role_id_attribute': value => $role_id_attribute;
'ldap/role_name_attribute': value => $role_name_attribute;
'ldap/role_member_attribute': value => $role_member_attribute;
'ldap/role_attribute_ignore': value => $role_attribute_ignore;
'ldap/role_allow_create': value => $role_allow_create;
'ldap/role_allow_update': value => $role_allow_update;
'ldap/role_allow_delete': value => $role_allow_delete;
'ldap/role_additional_attribute_mapping': value => $role_additional_attribute_mapping;
'ldap/group_tree_dn': value => $group_tree_dn;
'ldap/group_filter': value => $group_filter;
'ldap/group_objectclass': value => $group_objectclass;
'ldap/group_id_attribute': value => $group_id_attribute;
'ldap/group_name_attribute': value => $group_name_attribute;
'ldap/group_member_attribute': value => $group_member_attribute;
'ldap/group_desc_attribute': value => $group_desc_attribute;
'ldap/group_attribute_ignore': value => $group_attribute_ignore;
'ldap/group_allow_create': value => $group_allow_create;
'ldap/group_allow_update': value => $group_allow_update;
'ldap/group_allow_delete': value => $group_allow_delete;
'ldap/group_additional_attribute_mapping': value => $group_additional_attribute_mapping;
'ldap/use_tls': value => $use_tls;
'ldap/tls_cacertdir': value => $tls_cacertdir;
'ldap/tls_cacertfile': value => $tls_cacertfile;
'ldap/tls_req_cert': value => $tls_req_cert;
'identity/driver': value => $identity_driver;
'assignment/driver': value => $assignment_driver;
}
}

View File

@ -6,21 +6,26 @@ class keystone::params {
case $::osfamily {
'Debian': {
$package_name = 'keystone'
$service_name = 'keystone'
$package_name = 'keystone'
$service_name = 'keystone'
$keystone_wsgi_script_path = '/usr/lib/cgi-bin/keystone'
case $::operatingsystem {
'Debian': {
$service_provider = undef
$service_provider = undef
$keystone_wsgi_script_source = '/usr/share/keystone/wsgi.py'
}
default: {
$service_provider = 'upstart'
$service_provider = 'upstart'
$keystone_wsgi_script_source = 'puppet:///modules/keystone/httpd/keystone.py'
}
}
}
'RedHat': {
$package_name = 'openstack-keystone'
$service_name = 'openstack-keystone'
$service_provider = undef
$package_name = 'openstack-keystone'
$service_name = 'openstack-keystone'
$keystone_wsgi_script_path = '/var/www/cgi-bin/keystone'
$service_provider = undef
$keystone_wsgi_script_source = 'puppet:///modules/keystone/httpd/keystone.py'
}
}
}

View File

@ -1,11 +1,15 @@
#
# installs client python libraries for keystone
#
#
class keystone::python (
$client_package_name = $keystone::params::client_package_name,
$ensure = 'present'
) inherits keystone::params {
package { 'python-keystone' :
name => $client_package_name,
ensure => $ensure,
name => $client_package_name,
}
}

View File

@ -1,23 +1,20 @@
#
# This class implements some reasonable admin defaults for keystone.
#
# It relies on the Puppet native types that wrap the
# keystone client command line tool.
#
# It creates the following keystone objects:
# - service tenant
# - "admin" tenant (defaults to "openstack")
# - admin user (that defaults to the "admin" tenant)
# - admin role
# - Member role
# - adds admin role to admin user on the "admin" tenant
# * service tenant (tenant used by all service users)
# * "admin" tenant (defaults to "openstack")
# * admin user (that defaults to the "admin" tenant)
# * admin role
# * _member_ role
# * adds admin role to admin user on the "admin" tenant
#
# [*Parameters*]
#
# [email] The email address for the admin. Optional. Defaults to demo@puppetlabs.com.
# TODO should be required.
# [password] The admin password. Optional. Defaults to ChangeMe
# TODO should be required.
# [email] The email address for the admin. Required.
# [password] The admin password. 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.
#
# == Dependencies
# == Examples
@ -32,33 +29,34 @@
class keystone::roles::admin(
$email,
$password,
$admin = 'admin',
$admin_tenant = 'openstack'
$admin = 'admin',
$admin_tenant = 'openstack',
$service_tenant = 'services'
) {
keystone_tenant { 'services':
keystone_tenant { $service_tenant:
ensure => present,
enabled => 'True',
enabled => true,
description => 'Tenant for the openstack services',
}
keystone_tenant { $admin_tenant:
ensure => present,
enabled => 'True',
enabled => true,
description => 'admin tenant',
}
keystone_user { $admin:
ensure => present,
enabled => 'True',
enabled => true,
tenant => $admin_tenant,
email => $email,
password => $password,
}
keystone_role { ['admin', 'Member']:
keystone_role { ['admin', '_member_']:
ensure => present,
}
keystone_user_role { "${admin}@${admin_tenant}":
roles => 'admin',
ensure => present,
roles => 'admin',
}
}

View File

@ -0,0 +1,211 @@
#
# Class to serve keystone with apache mod_wsgi in place of keystone service
#
# Serving keystone from apache is the recommended way to go for production
# systems as the current keystone implementation is not multi-processor aware,
# thus limiting the performance for concurrent accesses.
#
# See the following URIs for reference:
# https://etherpad.openstack.org/havana-keystone-performance
# http://adam.younglogic.com/2012/03/keystone-should-move-to-apache-httpd/
#
# When using this class you should disable your keystone service.
#
# == Parameters
#
# [*servername*]
# The servername for the virtualhost.
# Optional. Defaults to $::fqdn
#
# [*public_port*]
# The public port.
# Optional. Defaults to 5000
#
# [*admin_port*]
# The admin port.
# Optional. Defaults to 35357
#
# [*bind_host*]
# The host/ip address Apache will listen on.
# Optional. Defaults to undef (listen on all ip addresses).
#
# [*public_path*]
# The prefix for the public endpoint.
# Optional. Defaults to '/'
#
# [*admin_path*]
# The prefix for the admin endpoint.
# Optional. Defaults to '/'
#
# [*ssl*]
# Use ssl ? (boolean)
# Optional. Defaults to true
#
# [*workers*]
# Number of WSGI workers to spawn.
# Optional. Defaults to 1
#
# [*ssl_cert*]
# [*ssl_key*]
# [*ssl_chain*]
# [*ssl_ca*]
# [*ssl_crl_path*]
# [*ssl_crl*]
# [*ssl_certs_dir*]
# apache::vhost ssl parameters.
# Optional. Default to apache::vhost 'ssl_*' defaults.
#
# == Dependencies
#
# requires Class['apache'] & Class['keystone']
#
# == Examples
#
# include apache
#
# class { 'keystone::wsgi::apache': }
#
# == Note about ports & paths
#
# When using same port for both endpoints (443 anyone ?), you *MUST* use two
# different public_path & admin_path !
#
# == Authors
#
# François Charlier <francois.charlier@enovance.com>
#
# == Copyright
#
# Copyright 2013 eNovance <licensing@enovance.com>
#
class keystone::wsgi::apache (
$servername = $::fqdn,
$public_port = 5000,
$admin_port = 35357,
$bind_host = undef,
$public_path = '/',
$admin_path = '/',
$ssl = true,
$workers = 1,
$ssl_cert = undef,
$ssl_key = undef,
$ssl_chain = undef,
$ssl_ca = undef,
$ssl_crl_path = undef,
$ssl_crl = undef,
$ssl_certs_dir = undef
) {
include keystone::params
include ::apache
include ::apache::mod::wsgi
include keystone::db::sync
Exec <| title == 'keystone-manage pki_setup' |> ~> Service['httpd']
Exec <| title == 'keystone-manage db_sync' |> ~> Service['httpd']
Package['keystone'] ~> Service['httpd']
Keystone_config <| |> ~> Service['httpd']
Service['httpd'] -> Keystone_endpoint <| |>
Service['httpd'] -> Keystone_role <| |>
Service['httpd'] -> Keystone_service <| |>
Service['httpd'] -> Keystone_tenant <| |>
Service['httpd'] -> Keystone_user <| |>
Service['httpd'] -> Keystone_user_role <| |>
## Sanitize parameters
# Ensure there's no trailing '/' except if this is also the only character
$public_path_real = regsubst($public_path, '(^/.*)/$', '\1')
# Ensure there's no trailing '/' except if this is also the only character
$admin_path_real = regsubst($admin_path, '(^/.*)/$', '\1')
if $public_port == $admin_port and $public_path_real == $admin_path_real {
fail('When using the same port for public & private endpoints, public_path and admin_path should be different.')
}
file { $::keystone::params::keystone_wsgi_script_path:
ensure => directory,
owner => 'keystone',
group => 'keystone',
require => Package['httpd'],
}
file { 'keystone_wsgi_admin':
ensure => file,
path => "${::keystone::params::keystone_wsgi_script_path}/admin",
source => $::keystone::params::keystone_wsgi_script_source,
owner => 'keystone',
group => 'keystone',
mode => '0644',
require => File[$::keystone::params::keystone_wsgi_script_path],
}
file { 'keystone_wsgi_main':
ensure => file,
path => "${::keystone::params::keystone_wsgi_script_path}/main",
source => $::keystone::params::keystone_wsgi_script_source,
owner => 'keystone',
group => 'keystone',
mode => '0644',
require => File[$::keystone::params::keystone_wsgi_script_path],
}
$wsgi_daemon_process_options = {
user => 'keystone',
group => 'keystone',
processes => $workers,
threads => '1'
}
$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"])
if $public_port == $admin_port {
$wsgi_script_aliases_main_real = merge($wsgi_script_aliases_main, $wsgi_script_aliases_admin)
} else {
$wsgi_script_aliases_main_real = $wsgi_script_aliases_main
}
apache::vhost { 'keystone_wsgi_main':
servername => $servername,
ip => $bind_host,
port => $public_port,
docroot => $::keystone::params::keystone_wsgi_script_path,
docroot_owner => 'keystone',
docroot_group => 'keystone',
ssl => $ssl,
ssl_cert => $ssl_cert,
ssl_key => $ssl_key,
ssl_chain => $ssl_chain,
ssl_ca => $ssl_ca,
ssl_crl_path => $ssl_crl_path,
ssl_crl => $ssl_crl,
ssl_certs_dir => $ssl_certs_dir,
wsgi_daemon_process => 'keystone',
wsgi_daemon_process_options => $wsgi_daemon_process_options,
wsgi_process_group => 'keystone',
wsgi_script_aliases => $wsgi_script_aliases_main_real,
require => [Class['apache::mod::wsgi'], File['keystone_wsgi_main']],
}
if $public_port != $admin_port {
apache::vhost { 'keystone_wsgi_admin':
servername => $servername,
ip => $bind_host,
port => $admin_port,
docroot => $::keystone::params::keystone_wsgi_script_path,
docroot_owner => 'keystone',
docroot_group => 'keystone',
ssl => $ssl,
ssl_cert => $ssl_cert,
ssl_key => $ssl_key,
ssl_chain => $ssl_chain,
ssl_ca => $ssl_ca,
ssl_crl_path => $ssl_crl_path,
ssl_crl => $ssl_crl,
ssl_certs_dir => $ssl_certs_dir,
wsgi_process_group => 'keystone',
wsgi_script_aliases => $wsgi_script_aliases_admin,
require => [Class['apache::mod::wsgi'], File['keystone_wsgi_admin']],
}
}
}

View File

@ -0,0 +1,16 @@
require 'spec_helper'
describe 'keystone::client' do
describe "with default parameters" do
it { should contain_package('python-keystoneclient').with_ensure('present') }
end
describe "with specified version" do
let :params do
{:ensure => '2013.1'}
end
it { should contain_package('python-keystoneclient').with_ensure('2013.1') }
end
end

View File

@ -3,7 +3,10 @@ require 'spec_helper'
describe 'keystone::db::mysql' do
let :pre_condition do
'include mysql::server'
[
'include mysql::server',
'include keystone::db::sync'
]
end
let :facts do
@ -12,11 +15,13 @@ describe 'keystone::db::mysql' do
let :param_defaults do
{
'password' => 'keystone_default_password',
'dbname' => 'keystone',
'user' => 'keystone_admin',
'charset' => 'latin1',
'host' => '127.0.0.1'
'password' => 'keystone_default_password',
'dbname' => 'keystone',
'user' => 'keystone',
'charset' => 'utf8',
'collate' => 'utf8_unicode_ci',
'host' => '127.0.0.1',
'allowed_hosts' => ['127.0.0.%', '192.168.1.%']
}
end
@ -46,9 +51,57 @@ describe 'keystone::db::mysql' do
'password' => param_values['password'],
'host' => param_values['host'],
'charset' => param_values['charset'],
'require' => 'Class[Mysql::Server]'
'require' => 'Class[Mysql::Config]'
)}
end
describe "overriding allowed_hosts param to array" do
let :params do
{
:password => 'keystonepass',
:allowed_hosts => ['127.0.0.1','%']
}
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
describe "overriding allowed_hosts param to string" do
let :params do
{
:password => 'keystonepass2',
:allowed_hosts => '192.168.1.1'
}
end
it {should contain_keystone__db__mysql__host_access("192.168.1.1").with(
:user => 'keystone',
:password => 'keystonepass2',
:database => 'keystone'
)}
end
describe "overriding allowed_hosts param equals to host param " do
let :params do
{
:password => 'keystonepass2',
:allowed_hosts => '127.0.0.1'
}
end
it {should_not contain_keystone__db__mysql__host_access("127.0.0.1").with(
:user => 'keystone',
:password => 'keystonepass2',
:database => 'keystone'
)}
end
end

View File

@ -0,0 +1,26 @@
require 'spec_helper'
describe 'keystone::db::postgresql' do
let :req_params do
{:password => 'pw'}
end
let :facts do
{
:postgres_default_version => '8.4',
:osfamily => 'RedHat',
}
end
describe 'with only required params' do
let :params do
req_params
end
it { should contain_postgresql__db('keystone').with(
:user => 'keystone',
:password => 'pw'
) }
end
end

View File

@ -9,8 +9,8 @@ describe 'keystone::endpoint' do
)}
describe 'with default parameters' do
it { should contain_keystone_endpoint('keystone').with(
:ensure => 'present',
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:5000/v2.0'
@ -20,22 +20,80 @@ describe 'keystone::endpoint' do
describe 'with overridden parameters' do
let :params do
{
:public_address => '10.0.0.1',
{ :version => 'v42.6',
:public_url => 'https://identity.some.tld/the/main/endpoint',
:admin_url => 'https://identity-int.some.tld/some/admin/endpoint',
:internal_url => 'https://identity-int.some.tld/some/internal/endpoint' }
end
it { should contain_keystone_endpoint('RegionOne/keystone').with(
:ensure => 'present',
:public_url => 'https://identity.some.tld/the/main/endpoint/v42.6',
:admin_url => 'https://identity-int.some.tld/some/admin/endpoint/v42.6',
:internal_url => 'https://identity-int.some.tld/some/internal/endpoint/v42.6'
)}
end
describe 'without internal_url parameter' do
let :params do
{ :public_url => 'https://identity.some.tld/the/main/endpoint' }
end
it 'internal_url should default to public_url' do
should contain_keystone_endpoint('RegionOne/keystone').with(
:ensure => 'present',
:public_url => 'https://identity.some.tld/the/main/endpoint/v2.0',
:internal_url => 'https://identity.some.tld/the/main/endpoint/v2.0'
)
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'
}
:admin_port => '12345',
:region => 'RegionTwo',
:version => 'v3.0' }
end
it { should contain_keystone_endpoint('keystone').with(
:ensure => 'present',
:public_url => 'http://10.0.0.1:23456/v2.0',
:admin_url => 'http://10.0.0.2:12345/v2.0',
:internal_url => 'http://10.0.0.3:23456/v2.0'
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

View File

@ -0,0 +1,156 @@
require 'spec_helper'
describe 'keystone::ldap' do
describe 'with basic params' do
let :params do
{
:url => 'ldap://foo',
:user => 'cn=foo,dc=example,dc=com',
:password => 'abcdefg',
:suffix => 'dc=example,dc=com',
:query_scope => 'sub',
:page_size => '50',
:user_tree_dn => 'cn=users,dc=example,dc=com',
:user_filter => '(memberOf=cn=openstack,cn=groups,cn=accounts,dc=example,dc=com)',
:user_objectclass => 'inetUser',
:user_id_attribute => 'uid',
:user_name_attribute => 'cn',
:user_mail_attribute => 'mail',
:user_enabled_attribute => 'UserAccountControl',
:user_enabled_mask => '2',
:user_enabled_default => '512',
:user_attribute_ignore => '',
:user_default_project_id_attribute => 'defaultProject',
:user_allow_create => 'False',
:user_allow_update => 'False',
:user_allow_delete => 'False',
:user_pass_attribute => 'krbPassword',
:user_enabled_emulation => 'True',
:user_enabled_emulation_dn => 'cn=openstack-enabled,cn=groups,cn=accounts,dc=example,dc=com',
:user_additional_attribute_mapping => 'description:name, gecos:name',
: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',
:role_tree_dn => 'ou=roles,ou=openstack,dc=example,dc=com',
:role_filter => '',
:role_objectclass => 'organizationalRole',
:role_id_attribute => 'cn',
:role_name_attribute => 'ou',
:role_member_attribute => 'roleOccupant',
:role_attribute_ignore => 'description',
:role_allow_create => 'True',
:role_allow_update => 'True',
:role_allow_delete => 'True',
:role_additional_attribute_mapping => '',
:group_tree_dn => 'ou=groups,ou=openstack,dc=example,dc=com',
:group_filter => 'cn=enabled-groups,cn=groups,cn=accounts,dc=example,dc=com',
:group_objectclass => 'organizationalRole',
:group_id_attribute => 'cn',
:group_name_attribute => 'cn',
:group_member_attribute => 'roleOccupant',
:group_desc_attribute => 'description',
:group_attribute_ignore => '',
:group_allow_create => 'False',
:group_allow_update => 'False',
:group_allow_delete => 'False',
:group_additional_attribute_mapping => '',
:use_tls => 'False',
:tls_cacertdir => '/etc/ssl/certs/',
:tls_cacertfile => '/etc/ssl/certs/ca-certificates.crt',
:tls_req_cert => 'demand',
:identity_driver => 'keystone.identity.backends.ldap.Identity',
:assignment_driver => 'keystone.assignment.backends.ldap.Assignment',
}
end
it { should contain_package('python-ldap') }
it 'should have basic params' do
should contain_keystone_config('ldap/url').with_value('ldap://foo')
should contain_keystone_config('ldap/user').with_value('cn=foo,dc=example,dc=com')
should contain_keystone_config('ldap/password').with_value('abcdefg').with_secret(true)
should contain_keystone_config('ldap/suffix').with_value('dc=example,dc=com')
should contain_keystone_config('ldap/query_scope').with_value('sub')
should 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')
should 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_objectclass').with_value('inetUser')
should contain_keystone_config('ldap/user_id_attribute').with_value('uid')
should contain_keystone_config('ldap/user_name_attribute').with_value('cn')
should contain_keystone_config('ldap/user_mail_attribute').with_value('mail')
should contain_keystone_config('ldap/user_enabled_attribute').with_value('UserAccountControl')
should contain_keystone_config('ldap/user_enabled_mask').with_value('2')
should contain_keystone_config('ldap/user_enabled_default').with_value('512')
should contain_keystone_config('ldap/user_attribute_ignore').with_value('')
should contain_keystone_config('ldap/user_default_project_id_attribute').with_value('defaultProject')
should contain_keystone_config('ldap/user_tree_dn').with_value('cn=users,dc=example,dc=com')
should contain_keystone_config('ldap/user_allow_create').with_value('False')
should contain_keystone_config('ldap/user_allow_update').with_value('False')
should contain_keystone_config('ldap/user_allow_delete').with_value('False')
should contain_keystone_config('ldap/user_pass_attribute').with_value('krbPassword')
should contain_keystone_config('ldap/user_enabled_emulation').with_value('True')
should contain_keystone_config('ldap/user_enabled_emulation_dn').with_value('cn=openstack-enabled,cn=groups,cn=accounts,dc=example,dc=com')
should 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')
should contain_keystone_config('ldap/tenant_filter').with_value('')
should contain_keystone_config('ldap/tenant_objectclass').with_value('organizationalUnit')
should contain_keystone_config('ldap/tenant_id_attribute').with_value('ou')
should contain_keystone_config('ldap/tenant_member_attribute').with_value('member')
should contain_keystone_config('ldap/tenant_desc_attribute').with_value('description')
should contain_keystone_config('ldap/tenant_name_attribute').with_value('ou')
should contain_keystone_config('ldap/tenant_enabled_attribute').with_value('enabled')
should contain_keystone_config('ldap/tenant_domain_id_attribute').with_value('businessCategory')
should contain_keystone_config('ldap/tenant_attribute_ignore').with_value('')
should contain_keystone_config('ldap/tenant_allow_create').with_value('True')
should contain_keystone_config('ldap/tenant_allow_update').with_value('True')
should contain_keystone_config('ldap/tenant_allow_delete').with_value('True')
should contain_keystone_config('ldap/tenant_enabled_emulation').with_value('False')
should contain_keystone_config('ldap/tenant_enabled_emulation_dn').with_value('True')
should contain_keystone_config('ldap/tenant_additional_attribute_mapping').with_value('cn=enabled,ou=openstack,dc=example,dc=com')
should contain_keystone_config('ldap/role_tree_dn').with_value('ou=roles,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')
should contain_keystone_config('ldap/group_filter').with_value('cn=enabled-groups,cn=groups,cn=accounts,dc=example,dc=com')
should contain_keystone_config('ldap/group_objectclass').with_value('organizationalRole')
should contain_keystone_config('ldap/group_id_attribute').with_value('cn')
should contain_keystone_config('ldap/group_member_attribute').with_value('roleOccupant')
should contain_keystone_config('ldap/group_desc_attribute').with_value('description')
should contain_keystone_config('ldap/group_name_attribute').with_value('cn')
should contain_keystone_config('ldap/group_attribute_ignore').with_value('')
should contain_keystone_config('ldap/group_allow_create').with_value('False')
should contain_keystone_config('ldap/group_allow_update').with_value('False')
should contain_keystone_config('ldap/group_allow_delete').with_value('False')
should contain_keystone_config('ldap/group_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/')
should contain_keystone_config('ldap/tls_cacertfile').with_value('/etc/ssl/certs/ca-certificates.crt')
should contain_keystone_config('ldap/tls_req_cert').with_value('demand')
should contain_keystone_config('identity/driver').with_value('keystone.identity.backends.ldap.Identity')
should contain_keystone_config('assignment/driver').with_value('keystone.assignment.backends.ldap.Assignment')
end
end
end

View File

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

View File

@ -5,29 +5,30 @@ describe 'keystone::roles::admin' do
let :params do
{
:email => 'foo@bar',
:password => 'ChangeMe'
:email => 'foo@bar',
:password => 'ChangeMe',
:service_tenant => 'services'
}
end
it { should contain_keystone_tenant('services').with(
:ensure => 'present',
:enabled => 'True',
:enabled => true,
:description => 'Tenant for the openstack services'
)}
it { should contain_keystone_tenant('openstack').with(
:ensure => 'present',
:enabled => 'True',
:enabled => true,
:description => 'admin tenant'
)}
it { should contain_keystone_user('admin').with(
:ensure => 'present',
:enabled => 'True',
:enabled => true,
:tenant => 'openstack',
:email => 'foo@bar',
:password => 'ChangeMe'
)}
['admin', 'Member'].each do |role_name|
['admin', '_member_'].each do |role_name|
it { should contain_keystone_role(role_name).with_ensure('present') }
end
it { should contain_keystone_user_role('admin@openstack').with(
@ -41,21 +42,27 @@ describe 'keystone::roles::admin' do
let :params do
{
:admin => 'admin',
:email => 'foo@baz',
:password => 'foo',
:admin_tenant => 'admin'
:admin => 'admin',
:email => 'foo@baz',
:password => 'foo',
:admin_tenant => 'admin',
:service_tenant => 'foobar'
}
end
it { should contain_keystone_tenant('foobar').with(
:ensure => 'present',
:enabled => true,
:description => 'Tenant for the openstack services'
)}
it { should contain_keystone_tenant('admin').with(
:ensure => 'present',
:enabled => 'True',
:enabled => true,
:description => 'admin tenant'
)}
it { should contain_keystone_user('admin').with(
:ensure => 'present',
:enabled => 'True',
:enabled => true,
:tenant => 'admin',
:email => 'foo@baz',
:password => 'foo'

View File

@ -8,36 +8,64 @@ describe 'keystone' do
let :default_params do
{
'package_ensure' => 'present',
'bind_host' => '0.0.0.0',
'public_port' => '5000',
'admin_port' => '35357',
'admin_token' => 'service_token',
'compute_port' => '3000',
'verbose' => false,
'debug' => false,
'use_syslog' => false,
'catalog_type' => 'sql',
'enabled' => true,
'sql_connection' => 'sqlite:////var/lib/keystone/keystone.db',
'idle_timeout' => '200'
'package_ensure' => 'present',
'public_bind_host' => '0.0.0.0',
'admin_bind_host' => '0.0.0.0',
'public_port' => '5000',
'admin_port' => '35357',
'admin_token' => 'service_token',
'compute_port' => '8774',
'verbose' => false,
'debug' => false,
'catalog_type' => 'sql',
'catalog_driver' => false,
'token_provider' => 'keystone.token.providers.pki.Provider',
'token_driver' => 'keystone.token.backends.sql.Token',
'cache_dir' => '/var/cache/keystone',
'enable_ssl' => false,
'ssl_certfile' => '/etc/keystone/ssl/certs/keystone.pem',
'ssl_keyfile' => '/etc/keystone/ssl/private/keystonekey.pem',
'ssl_ca_certs' => '/etc/keystone/ssl/certs/ca.pem',
'ssl_ca_key' => '/etc/keystone/ssl/private/cakey.pem',
'ssl_cert_subject' => '/C=US/ST=Unset/L=Unset/O=Unset/CN=localhost',
'enabled' => true,
'sql_connection' => 'sqlite:////var/lib/keystone/keystone.db',
'idle_timeout' => '200',
'mysql_module' => '0.9',
'rabbit_host' => 'localhost',
'rabbit_password' => 'guest',
'rabbit_userid' => 'guest',
}
end
[{'admin_token' => 'service_token'},
{
'package_ensure' => 'latest',
'bind_host' => '127.0.0.1',
'public_port' => '5001',
'admin_port' => '35358',
'admin_token' => 'service_token_override',
'compute_port' => '3001',
'verbose' => true,
'debug' => true,
'catalog_type' => 'template',
'enabled' => false,
'sql_connection' => 'mysql://a:b@c/d',
'idle_timeout' => '300'
'package_ensure' => 'latest',
'public_bind_host' => '0.0.0.0',
'admin_bind_host' => '0.0.0.0',
'public_port' => '5001',
'admin_port' => '35358',
'admin_token' => 'service_token_override',
'compute_port' => '8778',
'verbose' => true,
'debug' => true,
'catalog_type' => 'template',
'token_provider' => 'keystone.token.providers.uuid.Provider',
'token_driver' => 'keystone.token.backends.kvs.Token',
'public_endpoint' => 'https://localhost:5000/v2.0/',
'admin_endpoint' => 'https://localhost:35357/v2.0/',
'enable_ssl' => true,
'ssl_certfile' => '/etc/keystone/ssl/certs/keystone.pem',
'ssl_keyfile' => '/etc/keystone/ssl/private/keystonekey.pem',
'ssl_ca_certs' => '/etc/keystone/ssl/certs/ca.pem',
'ssl_ca_key' => '/etc/keystone/ssl/private/cakey.pem',
'ssl_cert_subject' => '/C=US/ST=Unset/L=Unset/O=Unset/CN=localhost',
'enabled' => false,
'sql_connection' => 'mysql://a:b@c/d',
'idle_timeout' => '300',
'rabbit_host' => '127.0.0.1',
'rabbit_password' => 'openstack',
'rabbit_userid' => 'admin',
}
].each do |param_set|
@ -58,12 +86,12 @@ describe 'keystone' do
it { should contain_group('keystone').with(
'ensure' => 'present',
'system' => 'true'
'system' => true
) }
it { should contain_user('keystone').with(
'ensure' => 'present',
'gid' => 'keystone',
'system' => 'true'
'system' => true
) }
it 'should contain the expected directories' do
@ -72,8 +100,8 @@ describe 'keystone' do
'ensure' => 'directory',
'owner' => 'keystone',
'group' => 'keystone',
'mode' => '0755'
#'require' => 'Package[keystone]'
'mode' => '0750',
'require' => 'Package[keystone]'
)
end
end
@ -81,24 +109,25 @@ describe 'keystone' do
it { should contain_service('keystone').with(
'ensure' => param_hash['enabled'] ? 'running' : 'stopped',
'enable' => param_hash['enabled'],
'hasstatus' => 'true',
'hasrestart' => 'true'
'hasstatus' => true,
'hasrestart' => true
) }
it 'should only migrate the db if $enabled is true' do
if param_hash[:enabled]
if param_hash['enabled']
should contain_exec('keystone-manage db_sync').with(
:user => 'keystone',
:refreshonly => true,
:notify => 'Service[keystone]',
:subscribe => ['Package[keystone]', 'Concat[/etc/keystone/keystone.conf]']
:subscribe => ['Package[keystone]', 'Keystone_config[database/connection]'],
:require => 'User[keystone]'
)
end
end
it 'should contain correct config' do
[
'admin_token',
'bind_host',
'public_bind_host',
'admin_bind_host',
'public_port',
'admin_port',
'compute_port',
@ -109,10 +138,359 @@ describe 'keystone' do
end
end
it 'should contain correct admin_token config' do
should contain_keystone_config('DEFAULT/admin_token').with_value(param_hash['admin_token']).with_secret(true)
end
it 'should contain correct mysql config' do
should contain_keystone_config('sql/idle_timeout').with_value(param_hash['idle_timeout'])
should contain_keystone_config('sql/connection').with_value(param_hash['sql_connection'])
should contain_keystone_config('database/idle_timeout').with_value(param_hash['idle_timeout'])
should contain_keystone_config('database/connection').with_value(param_hash['sql_connection']).with_secret(true)
end
it { should contain_keystone_config('token/provider').with_value(
param_hash['token_provider']
) }
it 'should contain correct token driver' do
should contain_keystone_config('token/driver').with_value(param_hash['token_driver'])
end
it 'should ensure proper setting of admin_endpoint and public_endpoint' do
if param_hash['admin_endpoint']
should contain_keystone_config('DEFAULT/admin_endpoint').with_value(param_hash['admin_endpoint'])
else
should contain_keystone_config('DEFAULT/admin_endpoint').with_ensure('absent')
end
if param_hash['public_endpoint']
should contain_keystone_config('DEFAULT/public_endpoint').with_value(param_hash['public_endpoint'])
else
should contain_keystone_config('DEFAULT/public_endpoint').with_ensure('absent')
end
end
end
end
describe 'when configuring signing token provider' do
describe 'when configuring as UUID' do
let :params do
{
'admin_token' => 'service_token',
'token_provider' => 'keystone.token.providers.uuid.Provider'
}
end
it { should_not contain_exec('keystone-manage pki_setup') }
end
describe 'when configuring as PKI' do
let :params do
{
'admin_token' => 'service_token',
'token_provider' => 'keystone.token.providers.pki.Provider'
}
end
it { should contain_exec('keystone-manage pki_setup').with(
:creates => '/etc/keystone/ssl/private/signing_key.pem'
) }
it { should contain_file('/var/cache/keystone').with_ensure('directory') }
describe 'when overriding the cache dir' do
before do
params.merge!(:cache_dir => '/var/lib/cache/keystone')
end
it { should contain_file('/var/lib/cache/keystone') }
end
describe 'when disable pki_setup' do
before do
params.merge!(:enable_pki_setup => false)
end
it { should_not contain_exec('keystone-manage pki_setup') }
end
end
describe 'with invalid catalog_type' do
let :params do
{ :admin_token => 'service_token',
:catalog_type => 'invalid' }
end
it_raises "a Puppet::Error", /validate_re\(\): "invalid" does not match "template|sql"/
end
describe 'when configuring catalog driver' do
let :params do
{ :admin_token => 'service_token',
:catalog_driver => 'keystone.catalog.backends.alien.AlienCatalog' }
end
it { should contain_keystone_config('catalog/driver').with_value(params[:catalog_driver]) }
end
describe 'when configuring deprecated token_format as UUID' do
let :params do
{
'admin_token' => 'service_token',
'token_format' => 'UUID'
}
end
it { should_not contain_exec('keystone-manage pki_setup') }
end
describe 'when configuring deprecated token_format as PKI' do
let :params do
{
'admin_token' => 'service_token',
'token_format' => 'PKI'
}
end
it { should contain_exec('keystone-manage pki_setup').with(
:creates => '/etc/keystone/ssl/private/signing_key.pem'
) }
it { should contain_file('/var/cache/keystone').with_ensure('directory') }
describe 'when overriding the cache dir' do
let :params do
{
'admin_token' => 'service_token',
'token_provider' => 'keystone.token.providers.pki.Provider',
'cache_dir' => '/var/lib/cache/keystone'
}
end
it { should contain_file('/var/lib/cache/keystone') }
end
end
end
describe 'when configuring token expiration' do
let :params do
{
'admin_token' => 'service_token',
'token_expiration' => '42',
}
end
it { should contain_keystone_config("token/expiration").with_value('42') }
end
describe 'when not configuring token expiration' do
let :params do
{
'admin_token' => 'service_token',
}
end
it { should contain_keystone_config("token/expiration").with_value('3600') }
end
describe 'configure memcache servers if set' do
let :params do
{
'admin_token' => 'service_token',
'memcache_servers' => [ 'SERVER1:11211', 'SERVER2:11211' ],
'token_driver' => 'keystone.token.backends.memcache.Token'
}
end
it { should contain_keystone_config("memcache/servers").with_value('SERVER1:11211,SERVER2:11211') }
end
describe 'do not configure memcache servers when not set' do
let :params do
default_params
end
it { should contain_keystone_config("memcache/servers").with_ensure('absent') }
end
describe 'raise error if memcache_servers is not an array' do
let :params do
{
'admin_token' => 'service_token',
'memcache_servers' => 'ANY_SERVER:11211'
}
end
it { expect { should contain_class('keystone::params') }.to \
raise_error(Puppet::Error, /is not an Array/) }
end
describe 'with syslog disabled by default' do
let :params do
default_params
end
it { should contain_keystone_config('DEFAULT/use_syslog').with_value(false) }
it { should_not contain_keystone_config('DEFAULT/syslog_log_facility') }
end
describe 'with syslog enabled' do
let :params do
default_params.merge({
:use_syslog => 'true',
})
end
it { should contain_keystone_config('DEFAULT/use_syslog').with_value(true) }
it { should contain_keystone_config('DEFAULT/syslog_log_facility').with_value('LOG_USER') }
end
describe 'with syslog enabled and custom settings' do
let :params do
default_params.merge({
:use_syslog => 'true',
:log_facility => 'LOG_LOCAL0'
})
end
it { should contain_keystone_config('DEFAULT/use_syslog').with_value(true) }
it { should contain_keystone_config('DEFAULT/syslog_log_facility').with_value('LOG_LOCAL0') }
end
describe 'with log_file disabled by default' do
let :params do
default_params
end
it { should contain_keystone_config('DEFAULT/log_file').with_ensure('absent') }
end
describe 'with log_file and log_dir enabled' do
let :params do
default_params.merge({
:log_file => 'keystone.log',
:log_dir => '/var/lib/keystone'
})
end
it { should contain_keystone_config('DEFAULT/log_file').with_value('keystone.log') }
it { should contain_keystone_config('DEFAULT/log_dir').with_value('/var/lib/keystone') }
end
describe 'with log_file and log_dir disabled' do
let :params do
default_params.merge({
:log_file => false,
:log_dir => false
})
end
it { should contain_keystone_config('DEFAULT/log_file').with_ensure('absent') }
it { should contain_keystone_config('DEFAULT/log_dir').with_ensure('absent') }
end
describe 'when configuring api binding with deprecated parameter' do
let :params do
default_params.merge({
:bind_host => '10.0.0.2',
})
end
it { should contain_keystone_config('DEFAULT/public_bind_host').with_value('10.0.0.2') }
it { should contain_keystone_config('DEFAULT/admin_bind_host').with_value('10.0.0.2') }
end
describe 'when configuring as SSL' do
let :params do
{
'admin_token' => 'service_token',
'enable_ssl' => true
}
end
it { should contain_exec('keystone-manage pki_setup').with(
:creates => '/etc/keystone/ssl/private/signing_key.pem'
) }
it { should contain_file('/var/cache/keystone').with_ensure('directory') }
describe 'when overriding the cache dir' do
let :params do
{
'admin_token' => 'service_token',
'enable_ssl' => true,
'cache_dir' => '/var/lib/cache/keystone'
}
end
it { should contain_file('/var/lib/cache/keystone') }
end
end
describe 'when enabling SSL' do
let :params do
{
'admin_token' => 'service_token',
'enable_ssl' => true,
'public_endpoint' => 'https://localhost:5000/v2.0/',
'admin_endpoint' => 'https://localhost:35357/v2.0/',
}
end
it {should contain_keystone_config('ssl/enable').with_value(true)}
it {should contain_keystone_config('ssl/certfile').with_value('/etc/keystone/ssl/certs/keystone.pem')}
it {should contain_keystone_config('ssl/keyfile').with_value('/etc/keystone/ssl/private/keystonekey.pem')}
it {should contain_keystone_config('ssl/ca_certs').with_value('/etc/keystone/ssl/certs/ca.pem')}
it {should contain_keystone_config('ssl/ca_key').with_value('/etc/keystone/ssl/private/cakey.pem')}
it {should contain_keystone_config('ssl/cert_subject').with_value('/C=US/ST=Unset/L=Unset/O=Unset/CN=localhost')}
it {should contain_keystone_config('DEFAULT/public_endpoint').with_value('https://localhost:5000/v2.0/')}
it {should contain_keystone_config('DEFAULT/admin_endpoint').with_value('https://localhost:35357/v2.0/')}
end
describe 'when disabling SSL' do
let :params do
{
'admin_token' => 'service_token',
'enable_ssl' => false,
}
end
it {should contain_keystone_config('ssl/enable').with_value(false)}
it {should contain_keystone_config('DEFAULT/public_endpoint').with_ensure('absent')}
it {should contain_keystone_config('DEFAULT/admin_endpoint').with_ensure('absent')}
end
describe 'not setting notification settings by default' do
let :params do
default_params
end
it { should contain_keystone_config('DEFAULT/notification_driver').with_value(nil) }
it { should contain_keystone_config('DEFAULT/notification_topics').with_vaule(nil) }
it { should contain_keystone_config('DEFAULT/control_exchange').with_vaule(nil) }
end
describe 'setting notification settings' do
let :params do
default_params.merge({
:notification_driver => 'keystone.openstack.common.notifier.rpc_notifier',
:notification_topics => 'notifications',
:control_exchange => 'keystone'
})
end
it { should contain_keystone_config('DEFAULT/notification_driver').with_value('keystone.openstack.common.notifier.rpc_notifier') }
it { should contain_keystone_config('DEFAULT/notification_topics').with_value('notifications') }
it { should contain_keystone_config('DEFAULT/control_exchange').with_value('keystone') }
end
describe 'setting sql (default) catalog' do
let :params do
default_params
end
it { should contain_keystone_config('catalog/driver').with_value('keystone.catalog.backends.sql.Catalog') }
end
describe 'setting default template catalog' do
let :params do
{
:admin_token => 'service_token',
:catalog_type => 'template'
}
end
it { should contain_keystone_config('catalog/driver').with_value('keystone.catalog.backends.templated.Catalog') }
it { should contain_keystone_config('catalog/template_file').with_value('/etc/keystone/default_catalog.templates') }
end
describe 'setting another template catalog' do
let :params do
{
:admin_token => 'service_token',
:catalog_type => 'template',
:catalog_template_file => '/some/template_file'
}
end
it { should contain_keystone_config('catalog/driver').with_value('keystone.catalog.backends.templated.Catalog') }
it { should contain_keystone_config('catalog/template_file').with_value('/some/template_file') }
end
end

View File

@ -0,0 +1,225 @@
require 'spec_helper'
describe 'keystone::wsgi::apache' do
let :global_facts do
{
:processorcount => 42,
:concat_basedir => '/var/lib/puppet/concat',
:fqdn => 'some.host.tld'
}
end
let :pre_condition do
'include apache
class { keystone: admin_token => "dummy" }'
end
shared_examples_for 'apache serving keystone with mod_wsgi' do
it { should contain_service('httpd').with_name(platform_parameters[:httpd_service_name]) }
it { should contain_class('keystone::params') }
it { should contain_class('apache') }
it { should contain_class('apache::mod::wsgi') }
it { should contain_class('keystone::db::sync') }
describe 'with default parameters' do
it { should contain_file("#{platform_parameters[:wsgi_script_path]}").with(
'ensure' => 'directory',
'owner' => 'keystone',
'group' => 'keystone',
'require' => 'Package[httpd]'
)}
it { should contain_file('keystone_wsgi_admin').with(
'ensure' => 'file',
'path' => "#{platform_parameters[:wsgi_script_path]}/admin",
'source' => platform_parameters[:wsgi_script_source],
'owner' => 'keystone',
'group' => 'keystone',
'mode' => '0644',
'require' => "File[#{platform_parameters[:wsgi_script_path]}]"
)}
it { should contain_file('keystone_wsgi_main').with(
'ensure' => 'file',
'path' => "#{platform_parameters[:wsgi_script_path]}/main",
'source' => platform_parameters[:wsgi_script_source],
'owner' => 'keystone',
'group' => 'keystone',
'mode' => '0644',
'require' => "File[#{platform_parameters[:wsgi_script_path]}]"
)}
it { should contain_apache__vhost('keystone_wsgi_admin').with(
'servername' => 'some.host.tld',
'ip' => nil,
'port' => '35357',
'docroot' => "#{platform_parameters[:wsgi_script_path]}",
'docroot_owner' => 'keystone',
'docroot_group' => 'keystone',
'ssl' => 'true',
'wsgi_process_group' => 'keystone',
'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/admin" },
'require' => ['Class[Apache::Mod::Wsgi]', 'File[keystone_wsgi_admin]']
)}
it { should contain_apache__vhost('keystone_wsgi_main').with(
'servername' => 'some.host.tld',
'ip' => nil,
'port' => '5000',
'docroot' => "#{platform_parameters[:wsgi_script_path]}",
'docroot_owner' => 'keystone',
'docroot_group' => 'keystone',
'ssl' => 'true',
'wsgi_daemon_process' => 'keystone',
'wsgi_process_group' => 'keystone',
'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/main" },
'require' => ['Class[Apache::Mod::Wsgi]', '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=1 threads=1 user=keystone$/
)
end
end
describe 'when overriding parameters using different ports' do
let :params do
{
:servername => 'dummy.host',
:bind_host => '10.42.51.1',
:public_port => 12345,
:admin_port => 4142,
:ssl => false,
:workers => 37,
}
end
it { should contain_apache__vhost('keystone_wsgi_admin').with(
'servername' => 'dummy.host',
'ip' => '10.42.51.1',
'port' => '4142',
'docroot' => "#{platform_parameters[:wsgi_script_path]}",
'docroot_owner' => 'keystone',
'docroot_group' => 'keystone',
'ssl' => 'false',
'wsgi_process_group' => 'keystone',
'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/admin" },
'require' => ['Class[Apache::Mod::Wsgi]', 'File[keystone_wsgi_admin]']
)}
it { should contain_apache__vhost('keystone_wsgi_main').with(
'servername' => 'dummy.host',
'ip' => '10.42.51.1',
'port' => '12345',
'docroot' => "#{platform_parameters[:wsgi_script_path]}",
'docroot_owner' => 'keystone',
'docroot_group' => 'keystone',
'ssl' => 'false',
'wsgi_daemon_process' => 'keystone',
'wsgi_process_group' => 'keystone',
'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/main" },
'require' => ['Class[Apache::Mod::Wsgi]', '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
describe 'when overriding parameters using same port' do
let :params do
{
:servername => 'dummy.host',
:public_port => 4242,
:admin_port => 4242,
:public_path => '/main/endpoint/',
:admin_path => '/admin/endpoint/',
:ssl => true,
:workers => 37,
}
end
it { should_not contain_apache__vhost('keystone_wsgi_admin') }
it { should contain_apache__vhost('keystone_wsgi_main').with(
'servername' => 'dummy.host',
'ip' => nil,
'port' => '4242',
'docroot' => "#{platform_parameters[:wsgi_script_path]}",
'docroot_owner' => 'keystone',
'docroot_group' => 'keystone',
'ssl' => 'true',
'wsgi_daemon_process' => 'keystone',
'wsgi_process_group' => 'keystone',
'wsgi_script_aliases' => {
'/main/endpoint' => "#{platform_parameters[:wsgi_script_path]}/main",
'/admin/endpoint' => "#{platform_parameters[:wsgi_script_path]}/admin"
},
'require' => ['Class[Apache::Mod::Wsgi]', '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
describe 'when overriding parameters using same port and same path' do
let :params do
{
:servername => 'dummy.host',
:public_port => 4242,
:admin_port => 4242,
:public_path => '/endpoint/',
:admin_path => '/endpoint/',
:ssl => true,
:workers => 37,
}
end
it_raises 'a Puppet::Error', /When using the same port for public & private endpoints, public_path and admin_path should be different\./
end
end
context 'on RedHat platforms' do
let :facts do
global_facts.merge({
:osfamily => 'RedHat',
:operatingsystemrelease => '6.0'
})
end
let :platform_parameters do
{
:httpd_service_name => 'httpd',
:wsgi_script_path => '/var/www/cgi-bin/keystone',
:wsgi_script_source => 'puppet:///modules/keystone/httpd/keystone.py'
}
end
it_configures 'apache serving keystone with mod_wsgi'
end
context 'on Debian platforms' do
let :facts do
global_facts.merge({
:osfamily => 'Debian',
:operatingsystem => 'Debian',
:operatingsystemrelease => '7.0'
})
end
let :platform_parameters do
{
:httpd_service_name => 'apache2',
:wsgi_script_path => '/usr/lib/cgi-bin/keystone',
:wsgi_script_source => '/usr/share/keystone/wsgi.py'
}
end
it_configures 'apache serving keystone with mod_wsgi'
end
end

View File

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

View File

@ -1 +1,8 @@
require 'puppetlabs_spec_helper/module_spec_helper'
require 'shared_examples'
RSpec.configure do |c|
c.alias_it_should_behave_like_to :it_configures, 'configures'
c.alias_it_should_behave_like_to :it_raises, 'raises'
end

View File

@ -2,59 +2,73 @@ require 'puppet'
require 'spec_helper'
require 'puppet/provider/keystone_endpoint/keystone'
provider_class = Puppet::Type.type(:keystone_endpoint).provider(:keystone)
describe provider_class do
describe Puppet::Type.type(:keystone_endpoint).provider(:keystone) do
describe 'when updating the endpoint URLS' do
let :resource do
Puppet::Type::Keystone_endpoint.new(
{
:name => 'foo',
:public_url => 'public_url',
:internal_url => 'internal_url',
:admin_url => 'admin_url'
}
)
end
let :provider do
provider_class.new(resource)
end
before :each do
provider_class.expects(:build_endpoint_hash).returns(
'foo' => {:id => 'id'}
)
end
after :each do
# reset global state
provider_class.prefetch(nil)
end
it 'should delete endpoint for every url that gets synced' do
provider.expects(:create).times(3)
provider.expects(:auth_keystone).with('endpoint-delete', 'id').times(3)
provider.public_url=('public_url')
provider.internal_url=('internal_url')
provider.admin_url=('admin_url')
end
it 'should recreate endpoints for every url that gets synced' do
provider_class.expects(:list_keystone_objects).with('service', 4).times(3).returns(
[['id', 'foo']]
)
provider.expects(:destroy).times(3)
provider.expects(:auth_keystone).with do |a,b,c,d|
(
a == 'endpoint-create' &&
b == '--service-id' &&
c == 'id' &&
d[d.index('--publicurl') + 1 ] == 'public_url' &&
d[d.index('--adminurl') + 1 ] == 'admin_url' &&
d[d.index('--internalurl') + 1 ] == 'internal_url'
)
end.times(3)
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
provider.public_url=('public_url')
provider.internal_url=('internal_url')
provider.admin_url=('admin_url')
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

@ -8,11 +8,12 @@ klass = Puppet::Provider::Keystone
describe Puppet::Provider::Keystone do
describe 'when retrieving the security token' do
after :each do
klass.reset
end
after :each do
klass.instance_variable_set(:@keystone_file, nil)
end
describe 'when retrieving the security token' do
it 'should fail if there is no keystone config file' do
ini_file = Puppet::Util::IniConfig::File.new
@ -52,14 +53,14 @@ describe Puppet::Provider::Keystone do
end
it 'should use the specified bind_host in the admin endpoint' do
mock = {'DEFAULT' => {'bind_host' => '192.168.56.210', 'admin_port' => '35357' }}
mock = {'DEFAULT' => {'admin_bind_host' => '192.168.56.210', 'admin_port' => '35357' }}
Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf')
klass.get_admin_endpoint.should == 'http://192.168.56.210:35357/v2.0/'
end
it 'should use localhost in the admin endpoint if bind_host is 0.0.0.0' do
mock = {'DEFAULT' => { 'bind_host' => '0.0.0.0', 'admin_port' => '35357' }}
mock = {'DEFAULT' => { 'admin_bind_host' => '0.0.0.0', 'admin_port' => '35357' }}
Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf')
klass.get_admin_endpoint.should == 'http://127.0.0.1:35357/v2.0/'
@ -71,6 +72,86 @@ describe Puppet::Provider::Keystone do
mock.expects(:read).with('/etc/keystone/keystone.conf')
klass.get_admin_endpoint.should == 'http://127.0.0.1:35357/v2.0/'
end
it 'should use https if ssl is enabled' do
mock = {'DEFAULT' => {'admin_bind_host' => '192.168.56.210', 'admin_port' => '35357' }, 'ssl' => {'enable' => 'True'}}
Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf')
klass.get_admin_endpoint.should == 'https://192.168.56.210:35357/v2.0/'
end
it 'should use http if ssl is disabled' do
mock = {'DEFAULT' => {'admin_bind_host' => '192.168.56.210', 'admin_port' => '35357' }, 'ssl' => {'enable' => 'False'}}
Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf')
klass.get_admin_endpoint.should == 'http://192.168.56.210:35357/v2.0/'
end
it 'should use the defined admin_endpoint if available' do
mock = {'DEFAULT' => {'admin_endpoint' => 'https://keystone.example.com/v2.0/' }, 'ssl' => {'enable' => 'False'}}
Puppet::Util::IniConfig::File.expects(:new).returns(mock)
mock.expects(:read).with('/etc/keystone/keystone.conf')
klass.get_admin_endpoint.should == 'https://keystone.example.com/v2.0/'
end
describe 'when testing keystone connection retries' do
['(HTTP 400)',
'[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)
mock.expects(:read).with('/etc/keystone/keystone.conf')
klass.expects(
: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
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

View File

@ -0,0 +1,55 @@
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).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
end

View File

@ -0,0 +1,44 @@
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).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
end

View File

@ -0,0 +1,9 @@
describe Puppet::Type.type(:keystone_endpoint) do
it 'should fail when the namevar does not contain a region' do
expect do
Puppet::Type.type(:keystone_endpoint).new(:name => 'foo')
end.to raise_error(Puppet::Error, /Invalid value/)
end
end

View File

@ -1,22 +0,0 @@
#
# used to specify connection information to keystone
#
[filter:authtoken]
paste.filter_factory = keystoneclient.middleware.auth_token:filter_factory
auth_host = <%= @auth_host %>
auth_port = <%= @auth_port %>
auth_protocol = <%= @auth_protocol %>
auth_uri = <%= @auth_uri %>
# if its defined
<% if @admin_token -%>
admin_token = <%= @admin_token %>
<% else -%>
admin_tenant_name = <%= @admin_tenant_name %>
admin_user = <%= @admin_user %>
admin_password = <%= @admin_password %>
<% end -%>
delay_auth_decision = <%= @delay_auth_decision %>
<% if @signing_dir -%>
signing_dir = <%= @signing_dir %>
<% end -%>

View File

@ -0,0 +1,68 @@
Exec { logoutput => 'on_failure' }
package { 'curl': ensure => present }
# example of how to build a single node
# keystone instance backed by sqlite
# with all of the default admin roles
node keystone_sqlite {
class { 'keystone':
verbose => true,
debug => true,
catalog_type => 'sql',
admin_token => 'admin_token',
}
class { 'keystone::roles::admin':
email => 'example@abc.com',
password => 'ChangeMe',
}
class { 'keystone::endpoint':
public_url => "http://${::fqdn}:5000/",
admin_url => "http://${::fqdn}:35357/",
}
}
node keystone_mysql {
class { 'mysql::server': }
class { 'keystone::db::mysql':
password => 'keystone',
}
class { 'keystone':
verbose => true,
debug => true,
sql_connection => 'mysql://keystone:keystone@127.0.0.1/keystone',
catalog_type => 'sql',
admin_token => 'admin_token',
}
class { 'keystone::roles::admin':
email => 'test@puppetlabs.com',
password => 'ChangeMe',
}
}
# keystone with mysql on another node
node keystone {
class { 'keystone':
verbose => true,
debug => true,
sql_connection => 'mysql://keystone:password@127.0.0.1/keystone',
catalog_type => 'sql',
admin_token => 'admin_token',
}
class { 'keystone::db::mysql':
password => 'keystone',
}
class { 'keystone::roles::admin':
email => 'example@abc.com',
password => 'ChangeMe',
}
class { 'keystone::endpoint':
public_url => "http://${::fqdn}:5000/",
admin_url => "http://${::fqdn}:35357/",
}
}
node default {
fail("could not find a matching node entry for ${clientcert}")
}