Move Puppet resources to outside repos
This commit is contained in:
@@ -1,17 +1,21 @@
|
||||
import click
|
||||
import json
|
||||
import requests
|
||||
import sys
|
||||
import time
|
||||
|
||||
from solar.core import actions
|
||||
from solar.core import resource
|
||||
from solar.core.resource_provider import GitProvider
|
||||
from solar.core import signals
|
||||
from solar.core import validation
|
||||
|
||||
from solar.interfaces.db import get_db
|
||||
|
||||
|
||||
GIT_PUPPET_LIBS_URL = 'https://github.com/CGenie/puppet-libs-resource'
|
||||
GIT_KEYSTONE_PUPPET_RESOURCE_URL = 'https://github.com/CGenie/keystone-puppet-resource'
|
||||
|
||||
|
||||
@click.group()
|
||||
def main():
|
||||
pass
|
||||
@@ -26,15 +30,15 @@ def deploy():
|
||||
|
||||
node1 = resource.create('node1', 'resources/ro_node/', {'ip': '10.0.0.3', 'ssh_key': '/vagrant/.vagrant/machines/solar-dev1/virtualbox/private_key', 'ssh_user': 'vagrant'})
|
||||
|
||||
puppet_inifile = resource.create('puppet_inifile', 'resources/puppet_inifile/', {})
|
||||
puppet_mysql = resource.create('puppet_mysql', 'resources/puppet_mysql/', {})
|
||||
puppet_stdlib = resource.create('puppet_stdlib', 'resources/puppet_stdlib/', {})
|
||||
puppet_inifile = resource.create('puppet_inifile', GitProvider(GIT_PUPPET_LIBS_URL, path='puppet_inifile'), {})
|
||||
puppet_mysql = resource.create('puppet_mysql', GitProvider(GIT_PUPPET_LIBS_URL, path='puppet_mysql'), {})
|
||||
puppet_stdlib = resource.create('puppet_stdlib', GitProvider(GIT_PUPPET_LIBS_URL, path='puppet_stdlib'), {})
|
||||
|
||||
mariadb_service1 = resource.create('mariadb_service1', 'resources/mariadb_service', {'image': 'mariadb', 'root_password': 'mariadb', 'port': 3306})
|
||||
keystone_db = resource.create('keystone_db', 'resources/mariadb_keystone_db/', {'db_name': 'keystone_db', 'login_user': 'root'})
|
||||
keystone_db_user = resource.create('keystone_db_user', 'resources/mariadb_keystone_user/', {'new_user_name': 'keystone', 'new_user_password': 'keystone', 'login_user': 'root'})
|
||||
|
||||
keystone_puppet = resource.create('keystone_puppet', 'resources/keystone_puppet/', {})
|
||||
keystone_puppet = resource.create('keystone_config1', GitProvider(GIT_KEYSTONE_PUPPET_RESOURCE_URL, path='keystone_puppet'), {})
|
||||
|
||||
signals.connect(node1, puppet_inifile)
|
||||
signals.connect(node1, puppet_mysql)
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
class {'keystone':
|
||||
admin_token => '{{ admin_token }}',
|
||||
package_ensure => 'absent'
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
$resource = hiera('{{ name }}')
|
||||
$ip = $resource['input']['ip']['value']
|
||||
$admin_token = $resource['input']['admin_token']['value']
|
||||
$db_user = $resource['input']['db_user']['value']
|
||||
$db_password = $resource['input']['db_password']['value']
|
||||
$db_name = $resource['input']['db_name']['value']
|
||||
$port = $resource['input']['port']['value']
|
||||
|
||||
class {'keystone':
|
||||
verbose => True,
|
||||
catalog_type => 'sql',
|
||||
admin_token => $admin_token,
|
||||
sql_connection => "mysql://$db_user:$db_password@$ip/$db_name",
|
||||
public_port => "$port"
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
class {'keystone':
|
||||
verbose => True,
|
||||
catalog_type => 'sql',
|
||||
admin_token => '{{ admin_token }}',
|
||||
sql_connection => 'mysql://{{ db_user }}:{{ db_password }}@{{ ip }}/{{ db_name }}',
|
||||
public_port => '{{ port }}'
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
id: keystone_puppet
|
||||
handler: puppet
|
||||
puppet_module: keystone
|
||||
version: 1.0.0
|
||||
input:
|
||||
admin_token:
|
||||
schema: str!
|
||||
value: admin_token
|
||||
db_user:
|
||||
schema: str!
|
||||
value: keystone
|
||||
db_password:
|
||||
schema: str!
|
||||
value: keystone
|
||||
db_name:
|
||||
schema: str!
|
||||
value: keystone
|
||||
|
||||
port:
|
||||
schema: int!
|
||||
value: 5000
|
||||
|
||||
ip:
|
||||
schema: str!
|
||||
value:
|
||||
ssh_key:
|
||||
schema: str!
|
||||
value:
|
||||
ssh_user:
|
||||
schema: str!
|
||||
value:
|
||||
|
||||
tags: [resource/keystone_service, resources/keystone]
|
||||
@@ -1,15 +0,0 @@
|
||||
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
|
||||
@@ -1,17 +0,0 @@
|
||||
Puppet Labs Keystone Module - Puppet module for managing Keystone
|
||||
|
||||
Copyright (C) 2012 Puppet Labs Inc
|
||||
|
||||
Puppet Labs can be contacted at: info@puppetlabs.com
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
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.
|
||||
@@ -1,13 +0,0 @@
|
||||
name 'puppetlabs-keystone'
|
||||
version '4.0.0'
|
||||
source 'https://github.com/stackforge/puppet-keystone'
|
||||
author 'Puppet Labs'
|
||||
license 'Apache License 2.0'
|
||||
summary 'Puppet Labs Keystone Module'
|
||||
description 'Puppet module to install and configure the Openstack identity service'
|
||||
project_page 'https://launchpad.net/puppet-keystone'
|
||||
|
||||
dependency 'puppetlabs/apache', '>=1.0.0 <2.0.0'
|
||||
dependency 'puppetlabs/inifile', '>=1.0.0 <2.0.0'
|
||||
dependency 'puppetlabs/mysql', '>=0.9.0 <3.0.0'
|
||||
dependency 'puppetlabs/stdlib', '>= 3.2.0'
|
||||
@@ -1,237 +0,0 @@
|
||||
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.
|
||||
@@ -1,7 +0,0 @@
|
||||
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')
|
||||
@@ -1,49 +0,0 @@
|
||||
# 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
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
# 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/'
|
||||
}
|
||||
@@ -1,66 +0,0 @@
|
||||
# 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',
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
# 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'
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
#!/usr/bin/env ruby
|
||||
# this script verifies that keystone has
|
||||
# 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'
|
||||
|
||||
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
|
||||
@@ -1,65 +0,0 @@
|
||||
# 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.
|
||||
|
||||
#
|
||||
# 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 oslo import i18n
|
||||
|
||||
|
||||
# NOTE(dstanek): i18n.enable_lazy() must be called before
|
||||
# keystone.i18n._() is called to ensure it has the desired lazy lookup
|
||||
# behavior. This includes cases, like keystone.exceptions, where
|
||||
# keystone.i18n._() is called at import time.
|
||||
i18n.enable_lazy()
|
||||
|
||||
|
||||
from keystone import backends
|
||||
from keystone.common import dependency
|
||||
from keystone.common import environment
|
||||
from keystone.common import sql
|
||||
from keystone import config
|
||||
from keystone.openstack.common import log
|
||||
from keystone import service
|
||||
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
config.configure()
|
||||
sql.initialize()
|
||||
config.set_default_for_default_log_levels()
|
||||
|
||||
CONF(project='keystone')
|
||||
config.setup_logging()
|
||||
|
||||
environment.use_stdlib()
|
||||
name = os.path.basename(__file__)
|
||||
|
||||
if CONF.debug:
|
||||
CONF.log_opt_values(log.getLogger(CONF.prog), logging.DEBUG)
|
||||
|
||||
|
||||
drivers = backends.load_backends()
|
||||
|
||||
# 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 = service.loadapp('config:%s' % config.find_paste_config(), name)
|
||||
|
||||
dependency.resolve_future_dependencies()
|
||||
@@ -1,190 +0,0 @@
|
||||
require 'puppet/util/inifile'
|
||||
class Puppet::Provider::Keystone < Puppet::Provider
|
||||
|
||||
# retrieves the current token from keystone.conf
|
||||
def self.admin_token
|
||||
@admin_token ||= get_admin_token
|
||||
end
|
||||
|
||||
def self.get_admin_token
|
||||
if keystone_file and keystone_file['DEFAULT'] and keystone_file['DEFAULT']['admin_token']
|
||||
return "#{keystone_file['DEFAULT']['admin_token'].strip}"
|
||||
else
|
||||
raise(Puppet::Error, "File: /etc/keystone/keystone.conf does not contain a section DEFAULT with the admin_token specified. Keystone types will not work if keystone is not correctly configured")
|
||||
end
|
||||
end
|
||||
|
||||
def self.admin_endpoint
|
||||
@admin_endpoint ||= get_admin_endpoint
|
||||
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'
|
||||
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
|
||||
"#{protocol}://#{host}:#{admin_port}/v2.0/"
|
||||
end
|
||||
|
||||
def self.keystone_file
|
||||
return @keystone_file if @keystone_file
|
||||
@keystone_file = Puppet::Util::IniConfig::File.new
|
||||
@keystone_file.read('/etc/keystone/keystone.conf')
|
||||
@keystone_file
|
||||
end
|
||||
|
||||
def self.tenant_hash
|
||||
@tenant_hash = build_tenant_hash
|
||||
end
|
||||
|
||||
def tenant_hash
|
||||
self.class.tenant_hash
|
||||
end
|
||||
|
||||
def self.reset
|
||||
@admin_endpoint = nil
|
||||
@tenant_hash = nil
|
||||
@admin_token = nil
|
||||
@keystone_file = nil
|
||||
end
|
||||
|
||||
# the path to withenv changes between versions of puppet, so redefining this function here,
|
||||
# Run some code with a specific environment. Resets the environment at the end of the code.
|
||||
def self.withenv(hash, &block)
|
||||
saved = ENV.to_hash
|
||||
hash.each do |name, val|
|
||||
ENV[name.to_s] = val
|
||||
end
|
||||
block.call
|
||||
ensure
|
||||
ENV.clear
|
||||
saved.each do |name, val|
|
||||
ENV[name] = val
|
||||
end
|
||||
end
|
||||
|
||||
def self.auth_keystone(*args)
|
||||
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
|
||||
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] || []).collect do |line|
|
||||
row = line.split(/\|/)[1..-1]
|
||||
row = row.map {|x| x.strip }
|
||||
# if both checks fail then we have a mismatch between what was expected and what was received
|
||||
if (number_columns.class == Array and !number_columns.include? row.size) or (number_columns.class == Fixnum and row.size != number_columns)
|
||||
raise(Puppet::Error, "Expected #{number_columns} columns for #{type} row, found #{row.size}. Line #{line}")
|
||||
end
|
||||
row
|
||||
end
|
||||
list
|
||||
end
|
||||
|
||||
def self.get_keystone_object(type, id, attr)
|
||||
id = id.chomp
|
||||
auth_keystone("#{type}-get", id).split(/\|\n/m).each do |line|
|
||||
if line =~ /\|(\s+)?#{attr}(\s+)?\|/
|
||||
if line.kind_of?(Array)
|
||||
return line[0].split("|")[2].strip
|
||||
else
|
||||
return line.split("|")[2].strip
|
||||
end
|
||||
else
|
||||
nil
|
||||
end
|
||||
end
|
||||
raise(Puppet::Error, "Could not find colummn #{attr} when getting #{type} #{id}")
|
||||
end
|
||||
|
||||
# remove warning from the output. this is a temporary hack until
|
||||
# I refactor things to use the the rest API
|
||||
def self.remove_warnings(results)
|
||||
found_header = false
|
||||
in_warning = false
|
||||
results.split("\n").collect do |line|
|
||||
unless found_header
|
||||
if line =~ /^\+[-\+]+\+$/
|
||||
in_warning = false
|
||||
found_header = true
|
||||
line
|
||||
elsif line =~ /^WARNING/ or line =~ /UserWarning/ or in_warning
|
||||
# warnings can be multi line, we have to skip all of them
|
||||
in_warning = true
|
||||
nil
|
||||
else
|
||||
line
|
||||
end
|
||||
else
|
||||
line
|
||||
end
|
||||
end.compact.join("\n")
|
||||
end
|
||||
end
|
||||
@@ -1,27 +0,0 @@
|
||||
Puppet::Type.type(:keystone_config).provide(
|
||||
:ini_setting,
|
||||
:parent => Puppet::Type.type(:ini_setting).provider(:ruby)
|
||||
) do
|
||||
|
||||
def section
|
||||
resource[:name].split('/', 2).first
|
||||
end
|
||||
|
||||
def setting
|
||||
resource[:name].split('/', 2).last
|
||||
end
|
||||
|
||||
def separator
|
||||
'='
|
||||
end
|
||||
|
||||
def self.file_path
|
||||
'/etc/keystone/keystone.conf'
|
||||
end
|
||||
|
||||
# added for backwards compatibility with older versions of inifile
|
||||
def file_path
|
||||
self.class.file_path
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,125 +0,0 @@
|
||||
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', '..'))
|
||||
require 'puppet/provider/keystone'
|
||||
Puppet::Type.type(:keystone_endpoint).provide(
|
||||
:keystone,
|
||||
:parent => Puppet::Provider::Keystone
|
||||
) do
|
||||
|
||||
desc <<-EOT
|
||||
Provider that uses the keystone client tool to
|
||||
manage keystone endpoints
|
||||
|
||||
This provider makes a few assumptions/
|
||||
1. assumes that the admin endpoint can be accessed via localhost.
|
||||
2. Assumes that the admin token and port can be accessed from
|
||||
/etc/keystone/keystone.conf
|
||||
EOT
|
||||
|
||||
optional_commands :keystone => "keystone"
|
||||
|
||||
def initialize(resource = nil)
|
||||
super(resource)
|
||||
@property_flush = {}
|
||||
end
|
||||
|
||||
def self.prefetch(resources)
|
||||
endpoints = instances
|
||||
resources.keys.each do |name|
|
||||
if provider = endpoints.find{ |endpoint| endpoint.name == name }
|
||||
resources[name].provider = provider
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def self.instances
|
||||
list_keystone_objects('endpoint', [5,6]).collect do |endpoint|
|
||||
service_name = get_keystone_object('service', endpoint[5], 'name')
|
||||
new(
|
||||
:name => "#{endpoint[1]}/#{service_name}",
|
||||
:ensure => :present,
|
||||
:id => endpoint[0],
|
||||
:region => endpoint[1],
|
||||
:public_url => endpoint[2],
|
||||
:internal_url => endpoint[3],
|
||||
:admin_url => endpoint[4],
|
||||
:service_id => endpoint[5],
|
||||
:service_name => service_name
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
optional_opts = []
|
||||
{
|
||||
:public_url => '--publicurl',
|
||||
:internal_url => '--internalurl',
|
||||
:admin_url => '--adminurl'
|
||||
}.each do |param, opt|
|
||||
if resource[param]
|
||||
optional_opts.push(opt).push(resource[param])
|
||||
end
|
||||
end
|
||||
|
||||
(region, service_name) = resource[:name].split('/')
|
||||
resource[:region] = region
|
||||
optional_opts.push('--region').push(resource[:region])
|
||||
|
||||
service_id = self.class.list_keystone_objects('service', 4).detect do |s|
|
||||
s[1] == service_name
|
||||
end.first
|
||||
|
||||
auth_keystone('endpoint-create', '--service-id', service_id, optional_opts)
|
||||
end
|
||||
|
||||
def exists?
|
||||
@property_hash[:ensure] == :present
|
||||
end
|
||||
|
||||
def destroy
|
||||
auth_keystone('endpoint-delete', @property_hash[:id])
|
||||
end
|
||||
|
||||
def flush
|
||||
if ! @property_flush.empty?
|
||||
destroy
|
||||
create
|
||||
@property_flush.clear
|
||||
end
|
||||
@property_hash = resource.to_hash
|
||||
end
|
||||
|
||||
def id
|
||||
@property_hash[:id]
|
||||
end
|
||||
|
||||
def region
|
||||
@property_hash[:region]
|
||||
end
|
||||
|
||||
def public_url
|
||||
@property_hash[:public_url]
|
||||
end
|
||||
|
||||
def internal_url
|
||||
@property_hash[:internal_url]
|
||||
end
|
||||
|
||||
def admin_url
|
||||
@property_hash[:admin_url]
|
||||
end
|
||||
|
||||
def public_url=(value)
|
||||
@property_hash[:public_url] = value
|
||||
@property_flush[:public_url] = value
|
||||
end
|
||||
|
||||
def internal_url=(value)
|
||||
@property_hash[:internal_url] = value
|
||||
@property_flush[:internal_url] = value
|
||||
end
|
||||
|
||||
def admin_url=(value)
|
||||
@property_hash[:admin_url] = value
|
||||
@property_flush[:admin_url] = value
|
||||
end
|
||||
end
|
||||
@@ -1,65 +0,0 @@
|
||||
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', '..'))
|
||||
require 'puppet/provider/keystone'
|
||||
Puppet::Type.type(:keystone_role).provide(
|
||||
:keystone,
|
||||
:parent => Puppet::Provider::Keystone
|
||||
) do
|
||||
|
||||
desc <<-EOT
|
||||
Provider that uses the keystone client tool to
|
||||
manage keystone roles
|
||||
EOT
|
||||
|
||||
optional_commands :keystone => "keystone"
|
||||
|
||||
def self.prefetch(resource)
|
||||
# rebuild the cahce for every puppet run
|
||||
@role_hash = nil
|
||||
end
|
||||
|
||||
def self.role_hash
|
||||
@role_hash = build_role_hash
|
||||
end
|
||||
|
||||
def role_hash
|
||||
self.class.role_hash
|
||||
end
|
||||
|
||||
def self.instances
|
||||
role_hash.collect do |k, v|
|
||||
new(:name => k)
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
auth_keystone(
|
||||
'role-create',
|
||||
'--name', resource[:name]
|
||||
)
|
||||
end
|
||||
|
||||
def exists?
|
||||
role_hash[resource[:name]]
|
||||
end
|
||||
|
||||
def destroy
|
||||
auth_keystone('role-delete', role_hash[resource[:name]][:id])
|
||||
end
|
||||
|
||||
def id
|
||||
role_hash[resource[:name]][:id]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.build_role_hash
|
||||
hash = {}
|
||||
list_keystone_objects('role', 2).each do |role|
|
||||
hash[role[1]] = {
|
||||
:id => role[0],
|
||||
}
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,97 +0,0 @@
|
||||
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', '..'))
|
||||
require 'puppet/provider/keystone'
|
||||
Puppet::Type.type(:keystone_service).provide(
|
||||
:keystone,
|
||||
:parent => Puppet::Provider::Keystone
|
||||
) do
|
||||
|
||||
desc <<-EOT
|
||||
Provider that uses the keystone client tool to
|
||||
manage keystone services
|
||||
|
||||
This provider makes a few assumptions/
|
||||
1. assumes that the admin endpoint can be accessed via localhost.
|
||||
2. Assumes that the admin token and port can be accessed from
|
||||
/etc/keystone/keystone.conf
|
||||
|
||||
Does not support the ability to list all
|
||||
EOT
|
||||
|
||||
optional_commands :keystone => "keystone"
|
||||
|
||||
def self.prefetch(resource)
|
||||
# rebuild the cahce for every puppet run
|
||||
@service_hash = nil
|
||||
end
|
||||
|
||||
def self.service_hash
|
||||
@service_hash = build_service_hash
|
||||
end
|
||||
|
||||
def service_hash
|
||||
self.class.service_hash
|
||||
end
|
||||
|
||||
def self.instances
|
||||
service_hash.collect do |k, v|
|
||||
new(:name => k)
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
optional_opts = []
|
||||
raise(Puppet::Error, "Required property type not specified for KeystoneService[#{resource[:name]}]") unless resource[:type]
|
||||
if resource[:description]
|
||||
optional_opts.push('--description').push(resource[:description])
|
||||
end
|
||||
auth_keystone(
|
||||
'service-create',
|
||||
'--name', resource[:name],
|
||||
'--type', resource[:type],
|
||||
optional_opts
|
||||
)
|
||||
end
|
||||
|
||||
def exists?
|
||||
service_hash[resource[:name]]
|
||||
end
|
||||
|
||||
def destroy
|
||||
auth_keystone('service-delete', service_hash[resource[:name]][:id])
|
||||
end
|
||||
|
||||
def id
|
||||
service_hash[resource[:name]][:id]
|
||||
end
|
||||
|
||||
def type
|
||||
service_hash[resource[:name]][:type]
|
||||
end
|
||||
|
||||
def type=(value)
|
||||
raise(Puppet::Error, "service-update is not currently supported by the keystone sql driver")
|
||||
end
|
||||
|
||||
def description
|
||||
service_hash[resource[:name]][:description]
|
||||
end
|
||||
|
||||
def description=(value)
|
||||
raise(Puppet::Error, "service-update is not currently supported by the keystone sql driver")
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.build_service_hash
|
||||
hash = {}
|
||||
list_keystone_objects('service', 4).each do |user|
|
||||
hash[user[1]] = {
|
||||
:id => user[0],
|
||||
:type => user[2],
|
||||
:description => user[3]
|
||||
}
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,120 +0,0 @@
|
||||
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', '..'))
|
||||
require 'puppet/provider/keystone'
|
||||
Puppet::Type.type(:keystone_tenant).provide(
|
||||
:keystone,
|
||||
:parent => Puppet::Provider::Keystone
|
||||
) do
|
||||
|
||||
desc <<-EOT
|
||||
Provider that uses the keystone client tool to
|
||||
manage keystone tenants
|
||||
|
||||
This provider makes a few assumptions/
|
||||
1. assumes that the admin endpoint can be accessed via localhost.
|
||||
2. Assumes that the admin token and port can be accessed from
|
||||
/etc/keystone/keystone.conf
|
||||
|
||||
One string difference, is that it does not know how to change the
|
||||
name of a tenant
|
||||
EOT
|
||||
|
||||
optional_commands :keystone => "keystone"
|
||||
|
||||
def self.prefetch(resource)
|
||||
# rebuild the cahce for every puppet run
|
||||
@tenant_hash = nil
|
||||
end
|
||||
|
||||
def self.tenant_hash
|
||||
@tenant_hash = build_tenant_hash
|
||||
end
|
||||
|
||||
def tenant_hash
|
||||
self.class.tenant_hash
|
||||
end
|
||||
|
||||
def instance
|
||||
tenant_hash[resource[:name]]
|
||||
end
|
||||
|
||||
def self.instances
|
||||
tenant_hash.collect do |k, v|
|
||||
new(
|
||||
:name => k,
|
||||
:id => v[:id]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
optional_opts = []
|
||||
if resource[:description]
|
||||
optional_opts.push('--description').push(resource[:description])
|
||||
end
|
||||
results = auth_keystone(
|
||||
'tenant-create',
|
||||
'--name', resource[:name],
|
||||
'--enabled', resource[:enabled],
|
||||
optional_opts
|
||||
)
|
||||
|
||||
if results =~ /Property\s|\sValue/
|
||||
attrs = self.class.parse_keystone_object(results)
|
||||
tenant_hash[resource[:name]] = {
|
||||
:ensure => :present,
|
||||
:name => resource[:name],
|
||||
:id => attrs['id'],
|
||||
:enabled => attrs['enabled'],
|
||||
:description => attrs['description'],
|
||||
}
|
||||
else
|
||||
fail("did not get expected message on tenant creation, got #{results}")
|
||||
end
|
||||
end
|
||||
|
||||
def exists?
|
||||
instance
|
||||
end
|
||||
|
||||
def destroy
|
||||
auth_keystone('tenant-delete', instance[:id])
|
||||
instance[:ensure] = :absent
|
||||
end
|
||||
|
||||
def enabled=(value)
|
||||
Puppet.warning("I am not sure if this is supported yet")
|
||||
auth_keystone("tenant-update", '--enabled', value, instance[:id])
|
||||
instance[:enabled] = value
|
||||
end
|
||||
|
||||
def description
|
||||
self.class.get_keystone_object('tenant', instance[:id], 'description')
|
||||
end
|
||||
|
||||
def description=(value)
|
||||
auth_keystone("tenant-update", '--description', value, instance[:id])
|
||||
instance[:description] = value
|
||||
end
|
||||
|
||||
[
|
||||
:id,
|
||||
:enabled,
|
||||
].each do |attr|
|
||||
define_method(attr.to_s) do
|
||||
instance[attr] || :absent
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.build_tenant_hash
|
||||
hash = {}
|
||||
list_keystone_objects('tenant', 3).each do |tenant|
|
||||
hash[tenant[1]] = {
|
||||
:id => tenant[0],
|
||||
:enabled => tenant[2],
|
||||
}
|
||||
end
|
||||
hash
|
||||
end
|
||||
end
|
||||
@@ -1,172 +0,0 @@
|
||||
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', '..'))
|
||||
require 'puppet/provider/keystone'
|
||||
Puppet::Type.type(:keystone_user).provide(
|
||||
:keystone,
|
||||
:parent => Puppet::Provider::Keystone
|
||||
) do
|
||||
|
||||
desc <<-EOT
|
||||
Provider that uses the keystone client tool to
|
||||
manage keystone users
|
||||
|
||||
This provider makes a few assumptions/
|
||||
1. assumes that the admin endpoint can be accessed via localhost.
|
||||
2. Assumes that the admin token and port can be accessed from
|
||||
/etc/keystone/keystone.conf
|
||||
|
||||
Does not support the ability to update the user's name
|
||||
EOT
|
||||
|
||||
optional_commands :keystone => "keystone"
|
||||
|
||||
def self.prefetch(resource)
|
||||
# rebuild the cahce for every puppet run
|
||||
@user_hash = nil
|
||||
end
|
||||
|
||||
def self.user_hash
|
||||
@user_hash = build_user_hash
|
||||
end
|
||||
|
||||
def user_hash
|
||||
self.class.user_hash
|
||||
end
|
||||
|
||||
def self.instances
|
||||
user_hash.collect do |k, v|
|
||||
new(:name => k)
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
optional_opts = []
|
||||
if resource[:email]
|
||||
optional_opts.push('--email').push(resource[:email])
|
||||
end
|
||||
if resource[:password]
|
||||
optional_opts.push('--pass').push(resource[:password])
|
||||
end
|
||||
if resource[:tenant]
|
||||
tenant_id = self.class.list_keystone_objects('tenant', 3).collect {|x|
|
||||
x[0] if x[1] == resource[:tenant]
|
||||
}.compact[0]
|
||||
optional_opts.push('--tenant_id').push(tenant_id)
|
||||
end
|
||||
auth_keystone(
|
||||
'user-create',
|
||||
'--name', resource[:name],
|
||||
'--enabled', resource[:enabled],
|
||||
optional_opts
|
||||
)
|
||||
end
|
||||
|
||||
def exists?
|
||||
user_hash[resource[:name]]
|
||||
end
|
||||
|
||||
def destroy
|
||||
auth_keystone('user-delete', user_hash[resource[:name]][:id])
|
||||
end
|
||||
|
||||
def enabled
|
||||
user_hash[resource[:name]][:enabled]
|
||||
end
|
||||
|
||||
def enabled=(value)
|
||||
auth_keystone(
|
||||
"user-update",
|
||||
'--enabled', value,
|
||||
user_hash[resource[:name]][:id]
|
||||
)
|
||||
end
|
||||
|
||||
def password
|
||||
# if we don't know a password we can't test it
|
||||
return nil if resource[:password] == nil
|
||||
# we can't get the value of the password but we can test to see if the one we know
|
||||
# about works, if it doesn't then return nil, causing it to be reset
|
||||
begin
|
||||
token_out = creds_keystone(resource[:name], resource[:tenant], resource[:password], "token-get")
|
||||
rescue Exception => e
|
||||
return nil if e.message =~ /Not Authorized/ or e.message =~ /HTTP 401/
|
||||
raise e
|
||||
end
|
||||
return resource[:password]
|
||||
end
|
||||
|
||||
def password=(value)
|
||||
if resource[:manage_password] == 'True'
|
||||
auth_keystone('user-password-update', '--pass', value, user_hash[resource[:name]][:id])
|
||||
end
|
||||
end
|
||||
|
||||
def tenant
|
||||
return resource[:tenant] if resource[:ignore_default_tenant]
|
||||
user_id = user_hash[resource[:name]][:id]
|
||||
begin
|
||||
tenantId = self.class.get_keystone_object('user', user_id, 'tenantId')
|
||||
rescue
|
||||
tenantId = nil
|
||||
end
|
||||
if tenantId.nil? or tenantId == 'None' or tenantId.empty?
|
||||
tenant = 'None'
|
||||
else
|
||||
# this prevents is from failing if tenant no longer exists
|
||||
begin
|
||||
tenant = self.class.get_keystone_object('tenant', tenantId, 'name')
|
||||
rescue
|
||||
tenant = 'None'
|
||||
end
|
||||
end
|
||||
tenant
|
||||
end
|
||||
|
||||
def tenant=(value)
|
||||
fail("tenant cannot be updated. Transition requested: #{user_hash[resource[:name]][:tenant]} -> #{value}")
|
||||
end
|
||||
|
||||
def email
|
||||
user_hash[resource[:name]][:email]
|
||||
end
|
||||
|
||||
def email=(value)
|
||||
auth_keystone(
|
||||
"user-update",
|
||||
'--email', value,
|
||||
user_hash[resource[:name]][:id]
|
||||
)
|
||||
end
|
||||
|
||||
def manage_password
|
||||
user_hash[resource[:name]][:manage_password]
|
||||
end
|
||||
|
||||
def manage_password=(value)
|
||||
user_hash[resource[:name]][:manage_password]
|
||||
end
|
||||
|
||||
def id
|
||||
user_hash[resource[:name]][:id]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.build_user_hash
|
||||
hash = {}
|
||||
list_keystone_objects('user', 4).each do |user|
|
||||
password = 'nil'
|
||||
manage_password = 'True',
|
||||
hash[user[1]] = {
|
||||
:id => user[0],
|
||||
:enabled => user[2],
|
||||
:email => user[3],
|
||||
:name => user[1],
|
||||
:password => password,
|
||||
:manage_password => manage_password,
|
||||
}
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,229 +0,0 @@
|
||||
$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', '..'))
|
||||
require 'puppet/provider/keystone'
|
||||
Puppet::Type.type(:keystone_user_role).provide(
|
||||
:keystone,
|
||||
:parent => Puppet::Provider::Keystone
|
||||
) do
|
||||
|
||||
desc <<-EOT
|
||||
Provider that uses the keystone client tool to
|
||||
manage keystone role assignments to users
|
||||
EOT
|
||||
|
||||
optional_commands :keystone => "keystone"
|
||||
|
||||
|
||||
def self.prefetch(resource)
|
||||
# rebuild the cahce for every puppet run
|
||||
@user_role_hash = nil
|
||||
end
|
||||
|
||||
def self.user_role_hash
|
||||
@user_role_hash = build_user_role_hash
|
||||
end
|
||||
|
||||
def user_role_hash
|
||||
self.class.user_role_hash
|
||||
end
|
||||
|
||||
def self.instances
|
||||
user_role_hash.collect do |k, v|
|
||||
new(:name => k)
|
||||
end
|
||||
end
|
||||
|
||||
def create
|
||||
user_id, tenant_id = get_user_and_tenant
|
||||
resource[:roles].each do |role_name|
|
||||
role_id = self.class.get_role(role_name)
|
||||
auth_keystone(
|
||||
'user-role-add',
|
||||
'--user-id', user_id,
|
||||
'--tenant-id', tenant_id,
|
||||
'--role-id', role_id
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def self.get_user_and_tenant(user, tenant)
|
||||
@tenant_hash ||= {}
|
||||
@user_hash ||= {}
|
||||
@tenant_hash[tenant] = @tenant_hash[tenant] || get_tenant(tenant)
|
||||
[
|
||||
get_user(@tenant_hash[tenant], user),
|
||||
@tenant_hash[tenant]
|
||||
]
|
||||
end
|
||||
|
||||
def get_user_and_tenant
|
||||
user, tenant = resource[:name].split('@', 2)
|
||||
self.class.get_user_and_tenant(user, tenant)
|
||||
end
|
||||
|
||||
def exists?
|
||||
user_id, tenant_id = get_user_and_tenant
|
||||
get_user_tenant_hash(user_id, tenant_id)
|
||||
end
|
||||
|
||||
def destroy
|
||||
user_id, tenant_id = get_user_and_tenant
|
||||
get_user_tenant_hash(user_id, tenant_id)[:role_ids].each do |role_id|
|
||||
auth_keystone(
|
||||
'user-role-remove',
|
||||
'--user-id', user_id,
|
||||
'--tenant-id', tenant_id,
|
||||
'--role-id', role_id
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def id
|
||||
user_id, tenant_id = get_user_and_tenant
|
||||
get_user_tenant_hash(user_id, tenant_id)[:id]
|
||||
end
|
||||
|
||||
def roles
|
||||
user_id, tenant_id = get_user_and_tenant
|
||||
get_user_tenant_hash(user_id, tenant_id)[:role_names]
|
||||
end
|
||||
|
||||
def roles=(value)
|
||||
# determine the roles to be added and removed
|
||||
remove = roles - Array(value)
|
||||
add = Array(value) - roles
|
||||
|
||||
user_id, tenant_id = get_user_and_tenant
|
||||
|
||||
add.each do |role_name|
|
||||
role_id = self.class.get_role(role_name)
|
||||
auth_keystone(
|
||||
'user-role-add',
|
||||
'--user-id', user_id,
|
||||
'--tenant-id', tenant_id,
|
||||
'--role-id', role_id
|
||||
)
|
||||
end
|
||||
remove.each do |role_name|
|
||||
role_id = self.class.get_role(role_name)
|
||||
auth_keystone(
|
||||
'user-role-remove',
|
||||
'--user-id', user_id,
|
||||
'--tenant-id', tenant_id,
|
||||
'--role-id', role_id
|
||||
)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def self.build_user_role_hash
|
||||
hash = {}
|
||||
get_tenants.each do |tenant_name, tenant_id|
|
||||
get_users(tenant_id).each do |user_name, user_id|
|
||||
list_user_roles(user_id, tenant_id).sort.each do |role|
|
||||
hash["#{user_name}@#{tenant_name}"] ||= {
|
||||
:user_id => user_id,
|
||||
:tenant_id => tenant_id,
|
||||
:role_names => [],
|
||||
:role_ids => []
|
||||
}
|
||||
hash["#{user_name}@#{tenant_name}"][:role_names].push(role[1])
|
||||
hash["#{user_name}@#{tenant_name}"][:role_ids].push(role[0])
|
||||
end
|
||||
end
|
||||
end
|
||||
hash
|
||||
end
|
||||
|
||||
# lookup the roles for a single tenant/user combination
|
||||
def get_user_tenant_hash(user_id, tenant_id)
|
||||
@user_tenant_hash ||= {}
|
||||
unless @user_tenant_hash["#{user_id}@#{tenant_id}"]
|
||||
list_user_roles(user_id, tenant_id).sort.each do |role|
|
||||
@user_tenant_hash["#{user_id}@#{tenant_id}"] ||= {
|
||||
:user_id => user_id,
|
||||
:tenant_id => tenant_id,
|
||||
:role_names => [],
|
||||
:role_ids => []
|
||||
}
|
||||
@user_tenant_hash["#{user_id}@#{tenant_id}"][:role_names].push(role[1])
|
||||
@user_tenant_hash["#{user_id}@#{tenant_id}"][:role_ids].push(role[0])
|
||||
end
|
||||
end
|
||||
@user_tenant_hash["#{user_id}@#{tenant_id}"]
|
||||
end
|
||||
|
||||
|
||||
def self.list_user_roles(user_id, tenant_id)
|
||||
# this assumes that all returned objects are of the form
|
||||
# id, name, enabled_state, OTHER
|
||||
number_columns = 4
|
||||
role_output = auth_keystone('user-role-list', '--user-id', user_id, '--tenant-id', tenant_id)
|
||||
list = (role_output.split("\n")[3..-2] || []).collect do |line|
|
||||
row = line.split(/\s*\|\s*/)[1..-1]
|
||||
if row.size != number_columns
|
||||
raise(Puppet::Error, "Expected #{number_columns} columns for #{type} row, found #{row.size}. Line #{line}")
|
||||
end
|
||||
row
|
||||
end
|
||||
list
|
||||
end
|
||||
|
||||
def list_user_roles(user_id, tenant_id)
|
||||
self.class.list_user_roles(user_id, tenant_id)
|
||||
end
|
||||
|
||||
def self.get_user(tenant_id, name)
|
||||
@users ||= {}
|
||||
user_key = "#{name}@#{tenant_id}"
|
||||
unless @users[user_key]
|
||||
list_keystone_objects('user', 4, '--tenant-id', tenant_id).each do |user|
|
||||
@users["#{user[1]}@#{tenant_id}"] = user[0]
|
||||
end
|
||||
end
|
||||
@users[user_key]
|
||||
end
|
||||
|
||||
def self.get_users(tenant_id='')
|
||||
@users = {}
|
||||
list_keystone_objects('user', 4, '--tenant-id', tenant_id).each do |user|
|
||||
@users[user[1]] = user[0]
|
||||
end
|
||||
@users
|
||||
end
|
||||
|
||||
def self.get_tenants
|
||||
unless @tenants
|
||||
@tenants = {}
|
||||
list_keystone_objects('tenant', 3).each do |tenant|
|
||||
@tenants[tenant[1]] = tenant[0]
|
||||
end
|
||||
end
|
||||
@tenants
|
||||
end
|
||||
|
||||
def self.get_tenant(name)
|
||||
unless (@tenants and @tenants[name])
|
||||
@tenants = {}
|
||||
list_keystone_objects('tenant', 3).each do |tenant|
|
||||
if tenant[1] == name
|
||||
@tenants[tenant[1]] = tenant[0]
|
||||
#tenant
|
||||
end
|
||||
end
|
||||
end
|
||||
@tenants[name]
|
||||
end
|
||||
|
||||
def self.get_role(name)
|
||||
@roles ||= {}
|
||||
unless @roles[name]
|
||||
list_keystone_objects('role', 2).each do |role|
|
||||
@roles[role[1]] = role[0]
|
||||
end
|
||||
end
|
||||
@roles[name]
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,44 +0,0 @@
|
||||
Puppet::Type.newtype(:keystone_config) do
|
||||
|
||||
ensurable
|
||||
|
||||
newparam(:name, :namevar => true) do
|
||||
desc 'Section/setting name to manage from keystone.conf'
|
||||
newvalues(/\S+\/\S+/)
|
||||
end
|
||||
|
||||
newproperty(:value) do
|
||||
desc 'The value of the setting to be defined.'
|
||||
munge do |value|
|
||||
value = value.to_s.strip
|
||||
value.capitalize! if value =~ /^(true|false)$/i
|
||||
value
|
||||
end
|
||||
newvalues(/^[\S ]*$/)
|
||||
|
||||
def is_to_s( currentvalue )
|
||||
if resource.secret?
|
||||
return '[old secret redacted]'
|
||||
else
|
||||
return currentvalue
|
||||
end
|
||||
end
|
||||
|
||||
def should_to_s( newvalue )
|
||||
if resource.secret?
|
||||
return '[new secret redacted]'
|
||||
else
|
||||
return newvalue
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
newparam(:secret, :boolean => true) do
|
||||
desc 'Whether to hide the value from Puppet logs. Defaults to `false`.'
|
||||
|
||||
newvalues(:true, :false)
|
||||
|
||||
defaultto false
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,43 +0,0 @@
|
||||
Puppet::Type.newtype(:keystone_endpoint) do
|
||||
|
||||
desc <<-EOT
|
||||
This is currently used to model the management of
|
||||
keystone endpoint.
|
||||
EOT
|
||||
|
||||
ensurable
|
||||
|
||||
newparam(:name, :namevar => true) do
|
||||
newvalues(/\S+\/\S+/)
|
||||
end
|
||||
|
||||
newproperty(:id) do
|
||||
validate do |v|
|
||||
raise(Puppet::Error, 'This is a read only property')
|
||||
end
|
||||
end
|
||||
|
||||
newproperty(:region) do
|
||||
end
|
||||
|
||||
# TODO I should do some url validation
|
||||
newproperty(:public_url) do
|
||||
end
|
||||
|
||||
newproperty(:internal_url) do
|
||||
end
|
||||
|
||||
newproperty(:admin_url) do
|
||||
end
|
||||
|
||||
# we should not do anything until the keystone service is started
|
||||
autorequire(:service) do
|
||||
['keystone']
|
||||
end
|
||||
|
||||
autorequire(:keystone_service) do
|
||||
(region, service_name) = self[:name].split('/')
|
||||
[service_name]
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,25 +0,0 @@
|
||||
Puppet::Type.newtype(:keystone_role) do
|
||||
|
||||
desc <<-EOT
|
||||
This is currently used to model the creation of
|
||||
keystone roles.
|
||||
EOT
|
||||
|
||||
ensurable
|
||||
|
||||
newparam(:name, :namevar => true) do
|
||||
newvalues(/\S+/)
|
||||
end
|
||||
|
||||
newproperty(:id) do
|
||||
validate do |v|
|
||||
raise(Puppet::Error, 'This is a read only property')
|
||||
end
|
||||
end
|
||||
|
||||
# we should not do anything until the keystone service is started
|
||||
autorequire(:service) do
|
||||
['keystone']
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,31 +0,0 @@
|
||||
Puppet::Type.newtype(:keystone_service) do
|
||||
|
||||
desc <<-EOT
|
||||
This is currently used to model the management of
|
||||
keystone services.
|
||||
EOT
|
||||
|
||||
ensurable
|
||||
|
||||
newparam(:name, :namevar => true) do
|
||||
newvalues(/\S+/)
|
||||
end
|
||||
|
||||
newproperty(:id) do
|
||||
validate do |v|
|
||||
raise(Puppet::Error, 'This is a read only property')
|
||||
end
|
||||
end
|
||||
|
||||
newproperty(:type) do
|
||||
end
|
||||
|
||||
newproperty(:description) do
|
||||
end
|
||||
|
||||
# we should not do anything until the keystone service is started
|
||||
autorequire(:service) do
|
||||
['keystone']
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,38 +0,0 @@
|
||||
Puppet::Type.newtype(:keystone_tenant) do
|
||||
|
||||
desc <<-EOT
|
||||
This type can be used to manage
|
||||
keystone tenants.
|
||||
|
||||
This is assumed to be running on the same node
|
||||
as your keystone API server.
|
||||
EOT
|
||||
|
||||
ensurable
|
||||
|
||||
newparam(:name, :namevar => true) do
|
||||
newvalues(/\w+/)
|
||||
end
|
||||
|
||||
newproperty(:enabled) do
|
||||
newvalues(/(t|T)rue/, /(f|F)alse/)
|
||||
defaultto('True')
|
||||
munge do |value|
|
||||
value.to_s.capitalize
|
||||
end
|
||||
end
|
||||
|
||||
newproperty(:description)
|
||||
|
||||
newproperty(:id) do
|
||||
validate do |v|
|
||||
raise(Puppet::Error, 'This is a read only property')
|
||||
end
|
||||
end
|
||||
|
||||
# we should not do anything until the keystone service is started
|
||||
autorequire(:service) do
|
||||
['keystone']
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,82 +0,0 @@
|
||||
Puppet::Type.newtype(:keystone_user) do
|
||||
|
||||
desc <<-EOT
|
||||
This is currently used to model the creation of
|
||||
keystone users.
|
||||
|
||||
It currently requires that both the password
|
||||
as well as the tenant are specified.
|
||||
EOT
|
||||
|
||||
# TODO support description??
|
||||
|
||||
ensurable
|
||||
|
||||
newparam(:name, :namevar => true) 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')
|
||||
munge do |value|
|
||||
value.to_s.capitalize
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
newvalues(/\S+/)
|
||||
end
|
||||
|
||||
newproperty(:email) do
|
||||
newvalues(/\S+@\S+/)
|
||||
end
|
||||
|
||||
newproperty(:id) do
|
||||
validate do |v|
|
||||
raise(Puppet::Error, 'This is a read only property')
|
||||
end
|
||||
end
|
||||
|
||||
newproperty(:manage_password) do
|
||||
newvalues(/(t|T)rue/, /(f|F)alse/)
|
||||
defaultto('True')
|
||||
munge do |value|
|
||||
value.to_s.capitalize
|
||||
end
|
||||
end
|
||||
|
||||
autorequire(:keystone_tenant) do
|
||||
self[:tenant]
|
||||
end
|
||||
|
||||
# we should not do anything until the keystone service is started
|
||||
autorequire(:service) do
|
||||
['keystone']
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,51 +0,0 @@
|
||||
Puppet::Type.newtype(:keystone_user_role) do
|
||||
|
||||
desc <<-EOT
|
||||
This is currently used to model the creation of
|
||||
keystone users roles.
|
||||
|
||||
User roles are an assigment of a role to a user on
|
||||
a certain tenant. The combintation of all of these
|
||||
attributes is unique.
|
||||
EOT
|
||||
|
||||
ensurable
|
||||
|
||||
newparam(:name, :namevar => true) do
|
||||
newvalues(/^\S+@\S+$/)
|
||||
#munge do |value|
|
||||
# matchdata = /(\S+)@(\S+)/.match(value)
|
||||
# {
|
||||
# :user => matchdata[1],
|
||||
# :tenant => matchdata[2]
|
||||
# }
|
||||
#nd
|
||||
end
|
||||
|
||||
newproperty(:roles, :array_matching => :all) do
|
||||
end
|
||||
|
||||
newproperty(:id) do
|
||||
validate do |v|
|
||||
raise(Puppet::Error, 'This is a read only property')
|
||||
end
|
||||
end
|
||||
|
||||
autorequire(:keystone_user) do
|
||||
self[:name].split('@', 2).first
|
||||
end
|
||||
|
||||
autorequire(:keystone_tenant) do
|
||||
self[:name].split('@', 2).last
|
||||
end
|
||||
|
||||
autorequire(:keystone_role) do
|
||||
self[:roles]
|
||||
end
|
||||
|
||||
# we should not do anything until the keystone service is started
|
||||
autorequire(:service) do
|
||||
['keystone']
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,17 +0,0 @@
|
||||
# == 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,
|
||||
}
|
||||
}
|
||||
@@ -1,30 +0,0 @@
|
||||
# == 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)
|
||||
}
|
||||
@@ -1,93 +0,0 @@
|
||||
#
|
||||
# implements mysql backend for keystone
|
||||
#
|
||||
# This class can be used to create tables, users and grant
|
||||
# privelege for a mysql keystone database.
|
||||
#
|
||||
# == 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.
|
||||
#
|
||||
# [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']
|
||||
#
|
||||
# == Examples
|
||||
# == Authors
|
||||
#
|
||||
# Dan Bode dan@puppetlabs.com
|
||||
#
|
||||
# == Copyright
|
||||
#
|
||||
# Copyright 2012 Puppetlabs Inc, unless otherwise noted.
|
||||
#
|
||||
class keystone::db::mysql(
|
||||
$password,
|
||||
$dbname = 'keystone',
|
||||
$user = 'keystone',
|
||||
$host = '127.0.0.1',
|
||||
$charset = 'utf8',
|
||||
$collate = 'utf8_unicode_ci',
|
||||
$mysql_module = '0.9',
|
||||
$allowed_hosts = undef
|
||||
) {
|
||||
|
||||
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' |>
|
||||
|
||||
if ($mysql_module >= 2.2) {
|
||||
mysql::db { $dbname:
|
||||
user => $user,
|
||||
password => $password,
|
||||
host => $host,
|
||||
charset => $charset,
|
||||
collate => $collate,
|
||||
require => Service['mysqld'],
|
||||
}
|
||||
} else {
|
||||
require mysql::python
|
||||
|
||||
mysql::db { $dbname:
|
||||
user => $user,
|
||||
password => $password,
|
||||
host => $host,
|
||||
charset => $charset,
|
||||
require => Class['mysql::config'],
|
||||
}
|
||||
}
|
||||
|
||||
# Check allowed_hosts to avoid duplicate resource declarations
|
||||
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[$real_allowed_hosts] -> Exec<| title == 'keystone-manage db_sync' |>
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
#
|
||||
define keystone::db::mysql::host_access(
|
||||
$user,
|
||||
$password,
|
||||
$database,
|
||||
$mysql_module = '0.9'
|
||||
) {
|
||||
if ($mysql_module >= 2.2) {
|
||||
mysql_user { "${user}@${name}":
|
||||
password_hash => mysql_password($password),
|
||||
require => Mysql_database[$database],
|
||||
}
|
||||
|
||||
mysql_grant { "${user}@${name}/${database}.*":
|
||||
privileges => ['ALL'],
|
||||
options => ['GRANT'],
|
||||
table => "${database}.*",
|
||||
require => Mysql_user["${user}@${name}"],
|
||||
user => "${user}@${name}"
|
||||
}
|
||||
} else {
|
||||
database_user { "${user}@${name}":
|
||||
password_hash => mysql_password($password),
|
||||
provider => 'mysql',
|
||||
require => Database[$database],
|
||||
}
|
||||
database_grant { "${user}@${name}/${database}":
|
||||
# TODO figure out which privileges to grant.
|
||||
privileges => 'all',
|
||||
provider => 'mysql',
|
||||
require => Database_user["${user}@${name}"]
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
#
|
||||
# implements postgresql backend for keystone
|
||||
#
|
||||
# This class can be used to create tables, users and grant
|
||||
# privelege for a postgresql keystone database.
|
||||
#
|
||||
# Requires Puppetlabs Postgresql module.
|
||||
#
|
||||
# [*Parameters*]
|
||||
#
|
||||
# [password] Password that will be used for the keystone db user.
|
||||
# Optional. Defaults to: 'keystone_default_password'
|
||||
#
|
||||
# [dbname] Name of keystone database. Optional. Defaults to keystone.
|
||||
#
|
||||
# [user] Name of keystone user. Optional. Defaults to keystone.
|
||||
#
|
||||
# == Dependencies
|
||||
# Class['postgresql::server']
|
||||
#
|
||||
# == Examples
|
||||
# == Authors
|
||||
#
|
||||
# Etienne Pelletier epelletier@morphlabs.com
|
||||
#
|
||||
# == Copyright
|
||||
#
|
||||
# Copyright 2012 Etienne Pelletier, unless otherwise noted.
|
||||
#
|
||||
class keystone::db::postgresql(
|
||||
$password,
|
||||
$dbname = 'keystone',
|
||||
$user = 'keystone'
|
||||
) {
|
||||
|
||||
Class['keystone::db::postgresql'] -> Service<| title == 'keystone' |>
|
||||
|
||||
require postgresql::python
|
||||
|
||||
postgresql::db { $dbname:
|
||||
user => $user,
|
||||
password => $password,
|
||||
}
|
||||
|
||||
Postgresql::Server::Db[$dbname] ~> Exec<| title == 'keystone-manage db_sync' |>
|
||||
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
#
|
||||
# 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'],
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
#
|
||||
# Installs keystone from source. This is not yet fully implemented
|
||||
#
|
||||
# == Dependencies
|
||||
# == Examples
|
||||
# == Authors
|
||||
#
|
||||
# Dan Bode dan@puppetlabs.com
|
||||
#
|
||||
# == Copyright
|
||||
#
|
||||
# Copyright 2012 Puppetlabs Inc, unless otherwise noted.
|
||||
#
|
||||
class keystone::dev::install(
|
||||
$source_dir = '/usr/local/keystone'
|
||||
) {
|
||||
# make sure that I have python 2.7 installed
|
||||
|
||||
Class['openstack::dev'] -> Class['keystone::dev::install']
|
||||
|
||||
# there are likely conficts with other packages
|
||||
# introduced by these resources
|
||||
package { [
|
||||
'python-dev',
|
||||
'libxml2-dev',
|
||||
'libxslt1-dev',
|
||||
'libsasl2-dev',
|
||||
'libsqlite3-dev',
|
||||
'libssl-dev',
|
||||
'libldap2-dev',
|
||||
'sqlite3'
|
||||
]:
|
||||
ensure => latest,
|
||||
}
|
||||
|
||||
vcsrepo { $source_dir:
|
||||
ensure => present,
|
||||
provider => git,
|
||||
source => 'git://github.com/openstack/keystone.git',
|
||||
}
|
||||
|
||||
Exec {
|
||||
cwd => $source_dir,
|
||||
path => '/usr/bin',
|
||||
refreshonly => true,
|
||||
subscribe => Vcsrepo[$source_dir],
|
||||
logoutput => true,
|
||||
# I have disabled timeout since this seems to take forever
|
||||
# this may be a bad idea :)
|
||||
timeout => 0,
|
||||
}
|
||||
|
||||
# TODO - really, I need a way to take this file and
|
||||
# convert it into package resources
|
||||
exec { 'install_dev_deps':
|
||||
command => 'pip install -r tools/pip-requires',
|
||||
}
|
||||
|
||||
exec { 'install_keystone_source':
|
||||
command => 'python setup.py develop',
|
||||
require => Exec['install_dev_deps'],
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,169 +0,0 @@
|
||||
# == Class: keystone::endpoint
|
||||
#
|
||||
# Creates the auth endpoints for keystone
|
||||
#
|
||||
# === Parameters
|
||||
#
|
||||
# [*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 { "${region}/keystone":
|
||||
ensure => present,
|
||||
public_url => $public_url_real,
|
||||
admin_url => $admin_url_real,
|
||||
internal_url => $internal_url_real,
|
||||
region => $region,
|
||||
}
|
||||
}
|
||||
@@ -1,497 +0,0 @@
|
||||
#
|
||||
# Module for managing keystone config.
|
||||
#
|
||||
# == Parameters
|
||||
#
|
||||
# [package_ensure] Desired ensure state of packages. Optional. Defaults to present.
|
||||
# accepts latest or specific versions.
|
||||
# [bind_host] Host that keystone binds to.
|
||||
# [bind_port] Port that keystone binds to.
|
||||
# [public_port]
|
||||
# [compute_port]
|
||||
# [admin_port]
|
||||
# [admin_port] Port that can be used for admin tasks.
|
||||
# [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.
|
||||
# [debug] Rather keystone should log at debug level. Optional.
|
||||
# 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)
|
||||
# [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.
|
||||
# [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.
|
||||
# [memcache_servers] List of memcache servers/ports. Optional. Used with
|
||||
# token_driver keystone.token.persistence.backends.memcache_pool.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.
|
||||
# [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'
|
||||
#
|
||||
# [enable_pki_setup]
|
||||
# Enable call to pki_setup to generate the cert for signing pki tokens and
|
||||
# revocation lists if it doesn't already exist. This generates a cert and key
|
||||
# stored in file locations based on the signing_certfile and signing_keyfile
|
||||
# paramters below. If you are providing your own signing cert, make this false.
|
||||
#
|
||||
# [signing_certfile]
|
||||
# Location of the cert file for signing pki tokens and revocation lists.
|
||||
# Optional. Note that if this file already exists (i.e. you are providing your
|
||||
# own signing cert), the file will not be overwritten, even if enable_pki_setup
|
||||
# is set to true.
|
||||
#
|
||||
# [signing_ca_certs]
|
||||
# Use this CA certs file along with signing_certfile/signing_keyfile for
|
||||
# signing pki tokens and revocation lists.
|
||||
# Optional. Default: /etc/keystone/ssl/certs/ca.pem
|
||||
#
|
||||
# [signing_ca_key]
|
||||
# Use this CA key file along with signing_certfile/signing_keyfile for signing
|
||||
# pki tokens and revocation lists.
|
||||
# Optional. Default: /etc/keystone/ssl/private/cakey.pem
|
||||
#
|
||||
# == Dependencies
|
||||
# None
|
||||
#
|
||||
# == Examples
|
||||
#
|
||||
# class { 'keystone':
|
||||
# log_verbose => 'True',
|
||||
# admin_token => 'my_special_token',
|
||||
# }
|
||||
#
|
||||
# == Authors
|
||||
#
|
||||
# Dan Bode dan@puppetlabs.com
|
||||
#
|
||||
# == Copyright
|
||||
#
|
||||
# Copyright 2012 Puppetlabs Inc, unless otherwise noted.
|
||||
#
|
||||
class keystone(
|
||||
$admin_token,
|
||||
$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,
|
||||
$signing_certfile = '/etc/keystone/ssl/certs/signing_cert.pem',
|
||||
$signing_keyfile = '/etc/keystone/ssl/private/signing_key.pem',
|
||||
$signing_ca_certs = '/etc/keystone/ssl/certs/ca.pem',
|
||||
$signing_ca_key = '/etc/keystone/ssl/private/cakey.pem',
|
||||
$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
|
||||
) {
|
||||
|
||||
if ! $catalog_driver {
|
||||
validate_re($catalog_type, 'template|sql')
|
||||
}
|
||||
|
||||
File['/etc/keystone/keystone.conf'] -> Keystone_config<||> ~> Service['keystone']
|
||||
Keystone_config<||> ~> Exec<| title == 'keystone-manage db_sync'|>
|
||||
Keystone_config<||> ~> Exec<| title == 'keystone-manage pki_setup'|>
|
||||
|
||||
include keystone::params
|
||||
|
||||
File {
|
||||
ensure => present,
|
||||
owner => 'keystone',
|
||||
group => 'keystone',
|
||||
require => Package['keystone'],
|
||||
notify => Service['keystone'],
|
||||
}
|
||||
|
||||
package { 'keystone':
|
||||
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,
|
||||
mode => '0750',
|
||||
}
|
||||
|
||||
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 ,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+/) {
|
||||
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:\/\//) {
|
||||
|
||||
} else {
|
||||
fail("Invalid db connection ${sql_connection}")
|
||||
}
|
||||
|
||||
# memcache connection config
|
||||
if $memcache_servers {
|
||||
validate_array($memcache_servers)
|
||||
keystone_config {
|
||||
'memcache/servers': value => join($memcache_servers, ',');
|
||||
}
|
||||
} else {
|
||||
keystone_config {
|
||||
'memcache/servers': ensure => absent;
|
||||
}
|
||||
}
|
||||
|
||||
# db connection config
|
||||
keystone_config {
|
||||
'database/connection': value => $sql_connection, secret => true;
|
||||
'database/idle_timeout': value => $idle_timeout;
|
||||
}
|
||||
|
||||
# configure based on the catalog backend
|
||||
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'
|
||||
}
|
||||
|
||||
keystone_config {
|
||||
'catalog/driver': value => $catalog_driver_real;
|
||||
'catalog/template_file': value => $catalog_template_file;
|
||||
}
|
||||
|
||||
if $token_format {
|
||||
warning('token_format parameter is deprecated. Use token_provider instead.')
|
||||
}
|
||||
|
||||
# Set the signing key/cert configuration values.
|
||||
keystone_config {
|
||||
'signing/certfile': value => $signing_certfile;
|
||||
'signing/keyfile': value => $signing_keyfile;
|
||||
'signing/ca_certs': value => $signing_ca_certs;
|
||||
'signing/ca_key': value => $signing_ca_key;
|
||||
}
|
||||
|
||||
# Create cache directory used for signing.
|
||||
file { $cache_dir:
|
||||
ensure => directory,
|
||||
}
|
||||
|
||||
# Only do pki_setup if we were asked to do so. This is needed
|
||||
# regardless of the token provider since token revocation lists
|
||||
# are always signed.
|
||||
if $enable_pki_setup {
|
||||
exec { 'keystone-manage pki_setup':
|
||||
path => '/usr/bin',
|
||||
user => 'keystone',
|
||||
refreshonly => true,
|
||||
creates => $signing_keyfile,
|
||||
notify => Service['keystone'],
|
||||
subscribe => Package['keystone'],
|
||||
require => User['keystone'],
|
||||
}
|
||||
}
|
||||
|
||||
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' }
|
||||
} elsif $token_format == 'UUID' {
|
||||
keystone_config { 'token/provider': value => 'keystone.token.providers.uuid.Provider' }
|
||||
} else {
|
||||
keystone_config { 'token/provider': value => $token_provider }
|
||||
}
|
||||
|
||||
# remove the old format in case of an upgrade
|
||||
keystone_config { 'signing/token_format': ensure => absent }
|
||||
|
||||
if $notification_driver {
|
||||
keystone_config { 'DEFAULT/notification_driver': value => $notification_driver }
|
||||
} else {
|
||||
keystone_config { 'DEFAULT/notification_driver': ensure => absent }
|
||||
}
|
||||
|
||||
if $notification_topics {
|
||||
keystone_config { 'DEFAULT/notification_topics': value => $notification_topics }
|
||||
} else {
|
||||
keystone_config { 'DEFAULT/notification_topics': ensure => absent }
|
||||
}
|
||||
|
||||
if $control_exchange {
|
||||
keystone_config { 'DEFAULT/control_exchange': value => $control_exchange }
|
||||
} else {
|
||||
keystone_config { 'DEFAULT/control_exchange': ensure => absent }
|
||||
}
|
||||
|
||||
keystone_config {
|
||||
'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_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_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/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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,183 +0,0 @@
|
||||
#
|
||||
# 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;
|
||||
}
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
#
|
||||
# This class contains the platform differences for keystone
|
||||
#
|
||||
class keystone::params {
|
||||
$client_package_name = 'python-keystone'
|
||||
|
||||
case $::osfamily {
|
||||
'Debian': {
|
||||
$package_name = 'keystone'
|
||||
$service_name = 'keystone'
|
||||
$keystone_wsgi_script_path = '/usr/lib/cgi-bin/keystone'
|
||||
case $::operatingsystem {
|
||||
'Debian': {
|
||||
$service_provider = undef
|
||||
$keystone_wsgi_script_source = '/usr/share/keystone/wsgi.py'
|
||||
}
|
||||
default: {
|
||||
$service_provider = 'upstart'
|
||||
$keystone_wsgi_script_source = 'puppet:///modules/keystone/httpd/keystone.py'
|
||||
}
|
||||
}
|
||||
}
|
||||
'RedHat': {
|
||||
$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'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
#
|
||||
# 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' :
|
||||
ensure => $ensure,
|
||||
name => $client_package_name,
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
#
|
||||
# This class implements some reasonable admin defaults for keystone.
|
||||
#
|
||||
# It creates the following keystone objects:
|
||||
# * service tenant (tenant used by all service users)
|
||||
# * "admin" tenant (defaults to "openstack")
|
||||
# * admin user (that defaults to the "admin" tenant)
|
||||
# * admin role
|
||||
# * adds admin role to admin user on the "admin" tenant
|
||||
#
|
||||
# [*Parameters*]
|
||||
#
|
||||
# [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
|
||||
# == Authors
|
||||
#
|
||||
# Dan Bode dan@puppetlabs.com
|
||||
#
|
||||
# == Copyright
|
||||
#
|
||||
# Copyright 2012 Puppetlabs Inc, unless otherwise noted.
|
||||
#
|
||||
class keystone::roles::admin(
|
||||
$email,
|
||||
$password,
|
||||
$admin = 'admin',
|
||||
$admin_tenant = 'openstack',
|
||||
$service_tenant = 'services'
|
||||
) {
|
||||
|
||||
keystone_tenant { $service_tenant:
|
||||
ensure => present,
|
||||
enabled => true,
|
||||
description => 'Tenant for the openstack services',
|
||||
}
|
||||
keystone_tenant { $admin_tenant:
|
||||
ensure => present,
|
||||
enabled => true,
|
||||
description => 'admin tenant',
|
||||
}
|
||||
keystone_user { $admin:
|
||||
ensure => present,
|
||||
enabled => true,
|
||||
tenant => $admin_tenant,
|
||||
email => $email,
|
||||
password => $password,
|
||||
}
|
||||
keystone_role { 'admin':
|
||||
ensure => present,
|
||||
}
|
||||
keystone_user_role { "${admin}@${admin_tenant}":
|
||||
ensure => present,
|
||||
roles => 'admin',
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,228 +0,0 @@
|
||||
#
|
||||
# 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,
|
||||
$threads = $::processorcount,
|
||||
$priority = '10',
|
||||
$wsgi_script_ensure = 'file',
|
||||
$wsgi_script_source = 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'],
|
||||
}
|
||||
|
||||
$wsgi_files = {
|
||||
'keystone_wsgi_admin' => {
|
||||
'path' => "${::keystone::params::keystone_wsgi_script_path}/admin",
|
||||
},
|
||||
'keystone_wsgi_main' => {
|
||||
'path' => "${::keystone::params::keystone_wsgi_script_path}/main",
|
||||
},
|
||||
}
|
||||
|
||||
$wsgi_file_defaults = {
|
||||
'ensure' => $wsgi_script_ensure,
|
||||
'owner' => 'keystone',
|
||||
'group' => 'keystone',
|
||||
'mode' => '0644',
|
||||
'require' => File[$::keystone::params::keystone_wsgi_script_path],
|
||||
}
|
||||
|
||||
$wsgi_script_source_real = $wsgi_script_source ? {
|
||||
default => $wsgi_script_source,
|
||||
undef => $::keystone::params::keystone_wsgi_script_source,
|
||||
}
|
||||
|
||||
case $wsgi_script_ensure {
|
||||
default: { $wsgi_file_source = { 'source' => $wsgi_script_source_real } }
|
||||
'link': { $wsgi_file_source = { 'target' => $wsgi_script_source_real } }
|
||||
}
|
||||
|
||||
create_resources('file', $wsgi_files, merge($wsgi_file_defaults, $wsgi_file_source))
|
||||
|
||||
$wsgi_daemon_process_options = {
|
||||
user => 'keystone',
|
||||
group => 'keystone',
|
||||
processes => $workers,
|
||||
threads => $threads
|
||||
}
|
||||
$wsgi_script_aliases_main = hash([$public_path_real,"${::keystone::params::keystone_wsgi_script_path}/main"])
|
||||
$wsgi_script_aliases_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',
|
||||
priority => $priority,
|
||||
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_main',
|
||||
wsgi_daemon_process_options => $wsgi_daemon_process_options,
|
||||
wsgi_process_group => 'keystone_main',
|
||||
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',
|
||||
priority => $priority,
|
||||
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_admin',
|
||||
wsgi_daemon_process_options => $wsgi_daemon_process_options,
|
||||
wsgi_process_group => 'keystone_admin',
|
||||
wsgi_script_aliases => $wsgi_script_aliases_admin,
|
||||
require => [Class['apache::mod::wsgi'], File['keystone_wsgi_admin']],
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
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
|
||||
@@ -1,107 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'keystone::db::mysql' do
|
||||
|
||||
let :pre_condition do
|
||||
[
|
||||
'include mysql::server',
|
||||
'include keystone::db::sync'
|
||||
]
|
||||
end
|
||||
|
||||
let :facts do
|
||||
{ :osfamily => 'Debian' }
|
||||
end
|
||||
|
||||
let :param_defaults do
|
||||
{
|
||||
'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
|
||||
|
||||
[
|
||||
{},
|
||||
{
|
||||
'password' => 'password',
|
||||
'dbname' => 'not_keystone',
|
||||
'user' => 'dan',
|
||||
'host' => '127.0.0.2',
|
||||
'charset' => 'utf8'
|
||||
}
|
||||
].each do |p|
|
||||
|
||||
let :params do
|
||||
p
|
||||
end
|
||||
|
||||
let :param_values do
|
||||
param_defaults.merge(p)
|
||||
end
|
||||
|
||||
it { should contain_class('mysql::python') }
|
||||
|
||||
it { should contain_mysql__db(param_values['dbname']).with(
|
||||
'user' => param_values['user'],
|
||||
'password' => param_values['password'],
|
||||
'host' => param_values['host'],
|
||||
'charset' => param_values['charset'],
|
||||
'require' => 'Class[Mysql::Config]'
|
||||
)}
|
||||
|
||||
end
|
||||
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
|
||||
@@ -1,26 +0,0 @@
|
||||
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
|
||||
@@ -1,99 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'keystone::endpoint' do
|
||||
|
||||
it { should contain_keystone_service('keystone').with(
|
||||
:ensure => 'present',
|
||||
:type => 'identity',
|
||||
:description => 'OpenStack Identity Service'
|
||||
)}
|
||||
|
||||
describe 'with default parameters' do
|
||||
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'
|
||||
)}
|
||||
end
|
||||
|
||||
describe 'with overridden parameters' do
|
||||
|
||||
let :params do
|
||||
{ :version => 'v42.6',
|
||||
:public_url => 'https://identity.some.tld/the/main/endpoint',
|
||||
:admin_url => 'https://identity-int.some.tld/some/admin/endpoint',
|
||||
:internal_url => 'https://identity-int.some.tld/some/internal/endpoint' }
|
||||
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',
|
||||
:region => 'RegionTwo',
|
||||
:version => 'v3.0' }
|
||||
end
|
||||
|
||||
it { should contain_keystone_endpoint('RegionTwo/keystone').with(
|
||||
:ensure => 'present',
|
||||
:public_url => 'http://10.0.0.1:23456/v3.0',
|
||||
:admin_url => 'http://10.0.0.2:12345/v3.0',
|
||||
:internal_url => 'http://10.0.0.3:23456/v3.0'
|
||||
)}
|
||||
|
||||
describe 'public_address overrides public_url' do
|
||||
let :params do
|
||||
{ :public_address => '10.0.0.1',
|
||||
:public_port => '12345',
|
||||
:public_url => 'http://10.10.10.10:23456/v3.0' }
|
||||
end
|
||||
|
||||
it { should contain_keystone_endpoint('RegionOne/keystone').with(
|
||||
:ensure => 'present',
|
||||
:public_url => 'http://10.0.0.1:12345/v2.0'
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
describe 'with overridden deprecated internal_port' do
|
||||
|
||||
let :params do
|
||||
{ :internal_port => '12345' }
|
||||
end
|
||||
|
||||
it { should contain_keystone_endpoint('RegionOne/keystone').with(
|
||||
:ensure => 'present',
|
||||
:public_url => 'http://127.0.0.1:5000/v2.0',
|
||||
:admin_url => 'http://127.0.0.1:35357/v2.0',
|
||||
:internal_url => 'http://127.0.0.1:12345/v2.0'
|
||||
)}
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,156 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'keystone::python' do
|
||||
|
||||
let :facts do
|
||||
{ :osfamily => 'Debian' }
|
||||
end
|
||||
|
||||
it { should contain_package('python-keystone').with_ensure("present") }
|
||||
|
||||
describe 'override ensure' do
|
||||
let(:params) { { :ensure => "latest" } }
|
||||
|
||||
it { should contain_package('python-keystone').with_ensure("latest") }
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,75 +0,0 @@
|
||||
require 'spec_helper'
|
||||
describe 'keystone::roles::admin' do
|
||||
|
||||
describe 'with only the required params set' do
|
||||
|
||||
let :params do
|
||||
{
|
||||
:email => 'foo@bar',
|
||||
:password => 'ChangeMe',
|
||||
:service_tenant => 'services'
|
||||
}
|
||||
end
|
||||
|
||||
it { should contain_keystone_tenant('services').with(
|
||||
:ensure => 'present',
|
||||
:enabled => true,
|
||||
:description => 'Tenant for the openstack services'
|
||||
)}
|
||||
it { should contain_keystone_tenant('openstack').with(
|
||||
:ensure => 'present',
|
||||
:enabled => true,
|
||||
:description => 'admin tenant'
|
||||
)}
|
||||
it { should contain_keystone_user('admin').with(
|
||||
:ensure => 'present',
|
||||
:enabled => true,
|
||||
:tenant => 'openstack',
|
||||
:email => 'foo@bar',
|
||||
:password => 'ChangeMe'
|
||||
)}
|
||||
it { should contain_keystone_role('admin').with_ensure('present') }
|
||||
it { should contain_keystone_user_role('admin@openstack').with(
|
||||
:roles => 'admin',
|
||||
:ensure => 'present'
|
||||
)}
|
||||
|
||||
end
|
||||
|
||||
describe 'when overriding optional params' do
|
||||
|
||||
let :params do
|
||||
{
|
||||
: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,
|
||||
:description => 'admin tenant'
|
||||
)}
|
||||
it { should contain_keystone_user('admin').with(
|
||||
:ensure => 'present',
|
||||
:enabled => true,
|
||||
:tenant => 'admin',
|
||||
:email => 'foo@baz',
|
||||
:password => 'foo'
|
||||
)}
|
||||
it { should contain_keystone_user_role('admin@admin').with(
|
||||
:roles => 'admin',
|
||||
:ensure => 'present'
|
||||
)}
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,545 +0,0 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'keystone' do
|
||||
|
||||
let :facts do
|
||||
{:osfamily => 'Debian'}
|
||||
end
|
||||
|
||||
let :default_params do
|
||||
{
|
||||
'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',
|
||||
'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|
|
||||
|
||||
describe "when #{param_set == {} ? "using default" : "specifying"} class parameters" do
|
||||
let :param_hash do
|
||||
default_params.merge(param_set)
|
||||
end
|
||||
|
||||
let :params do
|
||||
param_set
|
||||
end
|
||||
|
||||
it { should contain_class('keystone::params') }
|
||||
|
||||
it { should contain_package('keystone').with(
|
||||
'ensure' => param_hash['package_ensure']
|
||||
) }
|
||||
|
||||
it { should contain_group('keystone').with(
|
||||
'ensure' => 'present',
|
||||
'system' => true
|
||||
) }
|
||||
it { should contain_user('keystone').with(
|
||||
'ensure' => 'present',
|
||||
'gid' => 'keystone',
|
||||
'system' => true
|
||||
) }
|
||||
|
||||
it 'should contain the expected directories' do
|
||||
['/etc/keystone', '/var/log/keystone', '/var/lib/keystone'].each do |d|
|
||||
should contain_file(d).with(
|
||||
'ensure' => 'directory',
|
||||
'owner' => 'keystone',
|
||||
'group' => 'keystone',
|
||||
'mode' => '0750',
|
||||
'require' => 'Package[keystone]'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
it { should contain_service('keystone').with(
|
||||
'ensure' => param_hash['enabled'] ? 'running' : 'stopped',
|
||||
'enable' => param_hash['enabled'],
|
||||
'hasstatus' => true,
|
||||
'hasrestart' => true
|
||||
) }
|
||||
|
||||
it 'should only migrate the db if $enabled is true' do
|
||||
if param_hash['enabled']
|
||||
should contain_exec('keystone-manage db_sync').with(
|
||||
:user => 'keystone',
|
||||
:refreshonly => true,
|
||||
:subscribe => ['Package[keystone]', 'Keystone_config[database/connection]'],
|
||||
:require => 'User[keystone]'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
it 'should contain correct config' do
|
||||
[
|
||||
'public_bind_host',
|
||||
'admin_bind_host',
|
||||
'public_port',
|
||||
'admin_port',
|
||||
'compute_port',
|
||||
'verbose',
|
||||
'debug'
|
||||
].each do |config|
|
||||
should contain_keystone_config("DEFAULT/#{config}").with_value(param_hash[config])
|
||||
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('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 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 '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 'when configuring PKI signing cert paths with UUID and with pki_setup disabled' do
|
||||
let :params do
|
||||
{
|
||||
'admin_token' => 'service_token',
|
||||
'token_provider' => 'keystone.token.providers.uuid.Provider',
|
||||
'enable_pki_setup' => false,
|
||||
'signing_certfile' => 'signing_certfile',
|
||||
'signing_keyfile' => 'signing_keyfile',
|
||||
'signing_ca_certs' => 'signing_ca_certs',
|
||||
'signing_ca_key' => 'signing_ca_key'
|
||||
}
|
||||
end
|
||||
|
||||
it { should_not contain_exec('keystone-manage pki_setup') }
|
||||
|
||||
it 'should contain correct PKI certfile config' do
|
||||
should contain_keystone_config('signing/certfile').with_value('signing_certfile')
|
||||
end
|
||||
|
||||
it 'should contain correct PKI keyfile config' do
|
||||
should contain_keystone_config('signing/keyfile').with_value('signing_keyfile')
|
||||
end
|
||||
|
||||
it 'should contain correct PKI ca_certs config' do
|
||||
should contain_keystone_config('signing/ca_certs').with_value('signing_ca_certs')
|
||||
end
|
||||
|
||||
it 'should contain correct PKI ca_key config' do
|
||||
should contain_keystone_config('signing/ca_key').with_value('signing_ca_key')
|
||||
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 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.persistence.backends.memcache_pool.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
|
||||
@@ -1,254 +0,0 @@
|
||||
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_admin',
|
||||
'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_main',
|
||||
'wsgi_process_group' => 'keystone_main',
|
||||
'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_admin',
|
||||
'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_main',
|
||||
'wsgi_process_group' => 'keystone_main',
|
||||
'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_main',
|
||||
'wsgi_process_group' => 'keystone_main',
|
||||
'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
|
||||
|
||||
describe 'when overriding parameters using symlink and custom file source' do
|
||||
let :params do
|
||||
{
|
||||
:wsgi_script_ensure => 'link',
|
||||
:wsgi_script_source => '/opt/keystone/httpd/keystone.py',
|
||||
}
|
||||
end
|
||||
|
||||
it { is_expected.to contain_file('keystone_wsgi_admin').with(
|
||||
'ensure' => 'link',
|
||||
'path' => "#{platform_parameters[:wsgi_script_path]}/admin",
|
||||
'target' => '/opt/keystone/httpd/keystone.py',
|
||||
'owner' => 'keystone',
|
||||
'group' => 'keystone',
|
||||
'mode' => '0644',
|
||||
'require' => "File[#{platform_parameters[:wsgi_script_path]}]"
|
||||
)}
|
||||
|
||||
it { is_expected.to contain_file('keystone_wsgi_main').with(
|
||||
'ensure' => 'link',
|
||||
'path' => "#{platform_parameters[:wsgi_script_path]}/main",
|
||||
'target' => '/opt/keystone/httpd/keystone.py',
|
||||
'owner' => 'keystone',
|
||||
'group' => 'keystone',
|
||||
'mode' => '0644',
|
||||
'require' => "File[#{platform_parameters[:wsgi_script_path]}]"
|
||||
)}
|
||||
end
|
||||
end
|
||||
|
||||
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
|
||||
@@ -1,5 +0,0 @@
|
||||
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
|
||||
@@ -1,6 +0,0 @@
|
||||
--format
|
||||
s
|
||||
--colour
|
||||
--loadby
|
||||
mtime
|
||||
--backtrace
|
||||
@@ -1,8 +0,0 @@
|
||||
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
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
require 'puppet'
|
||||
require 'spec_helper'
|
||||
require 'puppet/provider/keystone_endpoint/keystone'
|
||||
|
||||
|
||||
describe Puppet::Type.type(:keystone_endpoint).provider(:keystone) do
|
||||
|
||||
let :resource do
|
||||
Puppet::Type::Keystone_endpoint.new(
|
||||
:provider => :keystone,
|
||||
:name => 'region/foo',
|
||||
:ensure => :present,
|
||||
:public_url => 'public_url',
|
||||
:internal_url => 'internal_url',
|
||||
:admin_url => 'admin_url'
|
||||
)
|
||||
end
|
||||
|
||||
let :provider do
|
||||
described_class.new(resource)
|
||||
end
|
||||
|
||||
before :each do
|
||||
# keystone endpoint-list
|
||||
described_class.stubs(:list_keystone_objects).with('endpoint', [5,6]).returns([
|
||||
['endpoint-id', 'region', 'public_url', 'internal_url', 'admin_url', 4]
|
||||
])
|
||||
# keystone service-list
|
||||
described_class.stubs(:list_keystone_objects).with('service', 4).returns([
|
||||
[4, 'foo', 'type', 'description']
|
||||
])
|
||||
described_class.stubs(:get_keystone_object).with('service', 4, 'name').returns('foo')
|
||||
described_class.prefetch('region/foo' => resource)
|
||||
end
|
||||
|
||||
after :each do
|
||||
described_class.prefetch({})
|
||||
end
|
||||
|
||||
describe "self.instances" do
|
||||
it "should have an instances method" do
|
||||
provider.class.should respond_to(:instances)
|
||||
end
|
||||
|
||||
it "should list instances" do
|
||||
endpoints = described_class.instances
|
||||
endpoints.size.should == 1
|
||||
endpoints.map {|provider| provider.name} == ['region/foo']
|
||||
end
|
||||
end
|
||||
|
||||
describe '#create' do
|
||||
it 'should call endpoint-create' do
|
||||
provider.expects(:auth_keystone).with(
|
||||
'endpoint-create', '--service-id', 4, includes(
|
||||
'--publicurl', 'public_url', '--internalurl', 'internal_url',
|
||||
'--region', 'region')
|
||||
)
|
||||
provider.create
|
||||
end
|
||||
end
|
||||
|
||||
describe '#flush' do
|
||||
it 'should delete and create the endpoint once when any url gets updated' do
|
||||
provider.expects(:destroy).times(1)
|
||||
provider.expects(:create).times(1)
|
||||
|
||||
provider.public_url=('new-public_url')
|
||||
provider.internal_url=('new-internal_url')
|
||||
provider.admin_url=('new-admin_url')
|
||||
provider.flush
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,16 +0,0 @@
|
||||
require 'puppet'
|
||||
require 'spec_helper'
|
||||
require 'puppet/provider/keystone_role/keystone'
|
||||
|
||||
provider_class = Puppet::Type.type(:keystone_role).provider(:keystone)
|
||||
|
||||
describe provider_class do
|
||||
describe 'when query keystone objects' do
|
||||
it 'should not cache keystone objects in catalog' do
|
||||
provider_class.stubs(:build_role_hash).returns({ 'foo' => 'bar' })
|
||||
provider_class.role_hash.should == ({ 'foo' => 'bar' })
|
||||
provider_class.stubs(:build_role_hash).returns({ 'baz' => 'qux' })
|
||||
provider_class.role_hash.should == ({ 'baz' => 'qux' })
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,16 +0,0 @@
|
||||
require 'puppet'
|
||||
require 'spec_helper'
|
||||
require 'puppet/provider/keystone_service/keystone'
|
||||
|
||||
provider_class = Puppet::Type.type(:keystone_service).provider(:keystone)
|
||||
|
||||
describe provider_class do
|
||||
describe 'when query keystone objects' do
|
||||
it 'should not cache keystone objects in catalog' do
|
||||
provider_class.stubs(:build_service_hash).returns({ 'foo' => 'bar' })
|
||||
provider_class.service_hash.should == ({ 'foo' => 'bar' })
|
||||
provider_class.stubs(:build_service_hash).returns({ 'baz' => 'qux' })
|
||||
provider_class.service_hash.should == ({ 'baz' => 'qux' })
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,166 +0,0 @@
|
||||
require 'puppet'
|
||||
require 'spec_helper'
|
||||
require 'puppet/provider/keystone'
|
||||
require 'tempfile'
|
||||
|
||||
|
||||
klass = Puppet::Provider::Keystone
|
||||
|
||||
describe Puppet::Provider::Keystone do
|
||||
|
||||
after :each do
|
||||
klass.reset
|
||||
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
|
||||
t = Tempfile.new('foo')
|
||||
path = t.path
|
||||
t.unlink
|
||||
ini_file.read(path)
|
||||
expect do
|
||||
klass.get_admin_token
|
||||
end.to raise_error(Puppet::Error, /Keystone types will not work/)
|
||||
end
|
||||
|
||||
it 'should fail if the keystone config file does not have a DEFAULT section' do
|
||||
mock = {}
|
||||
Puppet::Util::IniConfig::File.expects(:new).returns(mock)
|
||||
mock.expects(:read).with('/etc/keystone/keystone.conf')
|
||||
expect do
|
||||
|
||||
klass.get_admin_token
|
||||
end.to raise_error(Puppet::Error, /Keystone types will not work/)
|
||||
end
|
||||
|
||||
it 'should fail if the keystone config file does not contain an admin token' do
|
||||
mock = {'DEFAULT' => {'not_a_token' => 'foo'}}
|
||||
Puppet::Util::IniConfig::File.expects(:new).returns(mock)
|
||||
mock.expects(:read).with('/etc/keystone/keystone.conf')
|
||||
expect do
|
||||
klass.get_admin_token
|
||||
end.to raise_error(Puppet::Error, /Keystone types will not work/)
|
||||
end
|
||||
|
||||
it 'should parse the admin token if it is in the config file' do
|
||||
mock = {'DEFAULT' => {'admin_token' => 'foo'}}
|
||||
Puppet::Util::IniConfig::File.expects(:new).returns(mock)
|
||||
mock.expects(:read).with('/etc/keystone/keystone.conf')
|
||||
klass.get_admin_token.should == 'foo'
|
||||
end
|
||||
|
||||
it 'should use the specified bind_host in the admin endpoint' do
|
||||
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' => { '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/'
|
||||
end
|
||||
|
||||
it 'should use localhost in the admin endpoint if bind_host is unspecified' do
|
||||
mock = {'DEFAULT' => { '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/'
|
||||
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 query keystone objects' do
|
||||
it 'should not cache keystone objects in catalog' do
|
||||
klass.stubs(:build_tenant_hash).returns({ 'foo' => 'bar' })
|
||||
klass.tenant_hash.should == ({ 'foo' => 'bar' })
|
||||
klass.stubs(:build_tenant_hash).returns({ 'baz' => 'qux' })
|
||||
klass.tenant_hash.should == ({ 'baz' => 'qux' })
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when parsing keystone objects' do
|
||||
it 'should parse valid output into a hash' do
|
||||
data = <<-EOT
|
||||
+-------------+----------------------------------+
|
||||
| Property | Value |
|
||||
+-------------+----------------------------------+
|
||||
| description | default tenant |
|
||||
| enabled | True |
|
||||
| id | b71040f47e144399b7f10182918b5e2f |
|
||||
| name | demo |
|
||||
+-------------+----------------------------------+
|
||||
EOT
|
||||
expected = {
|
||||
'description' => 'default tenant',
|
||||
'enabled' => 'True',
|
||||
'id' => 'b71040f47e144399b7f10182918b5e2f',
|
||||
'name' => 'demo'
|
||||
}
|
||||
klass.parse_keystone_object(data).should == expected
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,65 +0,0 @@
|
||||
require 'puppet'
|
||||
require 'spec_helper'
|
||||
require 'puppet/provider/keystone_tenant/keystone'
|
||||
|
||||
provider_class = Puppet::Type.type(:keystone_tenant).provider(:keystone)
|
||||
|
||||
describe provider_class do
|
||||
|
||||
describe 'when updating a tenant' do
|
||||
|
||||
let :tenant_name do
|
||||
'foo'
|
||||
end
|
||||
|
||||
let :tenant_attrs do
|
||||
{
|
||||
:name => tenant_name,
|
||||
:description => '',
|
||||
:ensure => 'present',
|
||||
:enabled => 'True',
|
||||
}
|
||||
end
|
||||
|
||||
let :tenant_hash do
|
||||
{ tenant_name => {
|
||||
:id => 'id',
|
||||
:name => tenant_name,
|
||||
:description => '',
|
||||
:ensure => 'present',
|
||||
:enabled => 'True',
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
let :resource do
|
||||
Puppet::Type::Keystone_tenant.new(tenant_attrs)
|
||||
end
|
||||
|
||||
let :provider do
|
||||
provider_class.new(resource)
|
||||
end
|
||||
|
||||
before :each do
|
||||
provider_class.expects(:build_tenant_hash).at_least(1).returns(tenant_hash)
|
||||
end
|
||||
|
||||
it 'should call tenant-update to set enabled' do
|
||||
provider.expects(:auth_keystone).with('tenant-update',
|
||||
'--enabled',
|
||||
'False',
|
||||
'id')
|
||||
provider.enabled=('False')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when query keystone objects' do
|
||||
it 'should not cache keystone objects in catalog' do
|
||||
provider_class.stubs(:build_tenant_hash).returns({ 'foo' => 'bar' })
|
||||
provider_class.tenant_hash.should == ({ 'foo' => 'bar' })
|
||||
provider_class.stubs(:build_tenant_hash).returns({ 'baz' => 'qux' })
|
||||
provider_class.tenant_hash.should == ({ 'baz' => 'qux' })
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,78 +0,0 @@
|
||||
require 'puppet'
|
||||
require 'spec_helper'
|
||||
require 'puppet/provider/keystone_user/keystone'
|
||||
|
||||
provider_class = Puppet::Type.type(:keystone_user).provider(:keystone)
|
||||
|
||||
describe provider_class do
|
||||
|
||||
describe 'when updating a user' do
|
||||
let :resource do
|
||||
Puppet::Type::Keystone_user.new(
|
||||
{
|
||||
:name => 'foo',
|
||||
:ensure => 'present',
|
||||
:enabled => 'True',
|
||||
:tenant => 'foo2',
|
||||
:email => 'foo@foo.com',
|
||||
:password => 'passwd'
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
let :provider do
|
||||
provider_class.new(resource)
|
||||
end
|
||||
|
||||
before :each do
|
||||
provider_class.expects(:build_user_hash).at_least(1).returns(
|
||||
'foo' => {:id => 'id', :name => 'foo', :tenant => 'foo2', :password => 'passwd'}
|
||||
)
|
||||
end
|
||||
|
||||
after :each do
|
||||
# reset global state
|
||||
provider_class.prefetch(nil)
|
||||
end
|
||||
|
||||
it 'should call user-password-update to change password' do
|
||||
provider.expects(:auth_keystone).with('user-password-update', '--pass', 'newpassword', 'id')
|
||||
provider.password=('newpassword')
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when query keystone objects' do
|
||||
it 'should not cache keystone objects in catalog' do
|
||||
provider_class.stubs(:build_user_hash).returns({ 'foo' => 'bar' })
|
||||
provider_class.user_hash.should == ({ 'foo' => 'bar' })
|
||||
provider_class.stubs(:build_user_hash).returns({ 'baz' => 'qux' })
|
||||
provider_class.user_hash.should == ({ 'baz' => 'qux' })
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when updating a user with unmanaged password' do
|
||||
let :resource do
|
||||
Puppet::Type::Keystone_user.new(
|
||||
{
|
||||
:name => 'foo',
|
||||
:ensure => 'present',
|
||||
:enabled => 'True',
|
||||
:tenant => 'foo2',
|
||||
:email => 'foo@foo.com',
|
||||
:password => 'passwd',
|
||||
:manage_password => 'False',
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
let :provider do
|
||||
provider_class.new(resource)
|
||||
end
|
||||
|
||||
it 'should not call user-password-update to change password' do
|
||||
provider.expects(:auth_keystone).with('user-password-update', '--pass', 'newpassword', 'id').times(0)
|
||||
provider.password=('newpassword')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,50 +0,0 @@
|
||||
require 'puppet'
|
||||
require 'spec_helper'
|
||||
require 'puppet/provider/keystone_user_role/keystone'
|
||||
|
||||
provider_class = Puppet::Type.type(:keystone_user_role).provider(:keystone)
|
||||
|
||||
describe provider_class do
|
||||
|
||||
describe '#get_user_and_tenant' do
|
||||
|
||||
let :user do
|
||||
'username'
|
||||
end
|
||||
|
||||
let :tenant do
|
||||
'test@example.org'
|
||||
end
|
||||
|
||||
let :resource do
|
||||
Puppet::Type::Keystone_user_role.new(
|
||||
{
|
||||
:name => "#{user}@#{tenant}",
|
||||
:roles => [ '_member_' ],
|
||||
}
|
||||
)
|
||||
end
|
||||
|
||||
let :provider do
|
||||
provider_class.new(resource)
|
||||
end
|
||||
|
||||
before :each do
|
||||
provider_class.expects(:get_user_and_tenant).with(user,tenant).returns([user,tenant])
|
||||
end
|
||||
|
||||
it 'should handle an email address as username' do
|
||||
provider.get_user_and_tenant.should == [ user, tenant ]
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when query keystone objects' do
|
||||
it 'should not cache keystone objects in catalog' do
|
||||
provider_class.stubs(:build_user_role_hash).returns({ 'foo' => 'bar' })
|
||||
provider_class.user_role_hash.should == ({ 'foo' => 'bar' })
|
||||
provider_class.stubs(:build_user_role_hash).returns({ 'baz' => 'qux' })
|
||||
provider_class.user_role_hash.should == ({ 'baz' => 'qux' })
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,9 +0,0 @@
|
||||
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
|
||||
@@ -1,68 +0,0 @@
|
||||
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}")
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
id: puppet_inifile
|
||||
handler: puppet
|
||||
puppet_module: inifile
|
||||
version: 1.0.0
|
||||
input:
|
||||
ip:
|
||||
schema: str!
|
||||
value:
|
||||
ssh_key:
|
||||
schema: str!
|
||||
value:
|
||||
ssh_user:
|
||||
schema: str!
|
||||
value:
|
||||
|
||||
tags: [resource/keystone_service, resources/keystone]
|
||||
@@ -1,177 +0,0 @@
|
||||
##2014-07-15 - Supported Release 1.1.3
|
||||
###Summary
|
||||
|
||||
This release merely updates metadata.json so the module can be uninstalled and
|
||||
upgraded via the puppet module command.
|
||||
|
||||
##2014-07-10 - Supported Release 1.1.2
|
||||
###Summary
|
||||
|
||||
This is a re-packaging release.
|
||||
|
||||
##2014-07-07 - Release 1.1.1
|
||||
###Summary
|
||||
|
||||
This supported bugfix release corrects the inifile section header detection
|
||||
regex (so you can use more characters in your section titles).
|
||||
|
||||
####Bugfixes
|
||||
- Correct section regex to allow anything other than ]
|
||||
- Correct `exists?` to return a boolean
|
||||
- Lots of test updates
|
||||
- Add missing CONTRIBUTING.md
|
||||
|
||||
##2014-06-04 - Release 1.1.0
|
||||
###Summary
|
||||
|
||||
This is a compatibility and feature release. This release adds one new
|
||||
feature, the ability to control the quote character used. This allows you to
|
||||
do things like:
|
||||
|
||||
```
|
||||
ini_subsetting { '-Xms':
|
||||
ensure => present,
|
||||
path => '/some/config/file',
|
||||
section => '',
|
||||
setting => 'JAVA_ARGS',
|
||||
quote_char => '"',
|
||||
subsetting => '-Xms'
|
||||
value => '256m',
|
||||
}
|
||||
```
|
||||
|
||||
Which builds:
|
||||
|
||||
```
|
||||
JAVA_ARGS="-Xmx256m -Xms256m"
|
||||
```
|
||||
|
||||
####Features
|
||||
- Add quote_char parameter to the ini_subsetting resource type
|
||||
|
||||
####Bugfixes
|
||||
|
||||
####Known Bugs
|
||||
* No known bugs
|
||||
|
||||
##2014-03-04 - Supported Release 1.0.3
|
||||
###Summary
|
||||
|
||||
This is a supported release. It has only test changes.
|
||||
|
||||
####Features
|
||||
|
||||
####Bugfixes
|
||||
|
||||
####Known Bugs
|
||||
* No known bugs
|
||||
|
||||
|
||||
##2014-02-26 - Version 1.0.2
|
||||
###Summary
|
||||
This release adds supported platforms to metadata.json and contains spec fixes
|
||||
|
||||
|
||||
##2014-02-12 - Version 1.0.1
|
||||
###Summary
|
||||
This release is a bugfix for handling whitespace/[]'s better, and adding a
|
||||
bunch of tests.
|
||||
|
||||
####Bugfixes
|
||||
- Handle whitespace in sections
|
||||
- Handle square brances in values
|
||||
- Add metadata.json
|
||||
- Update some travis testing
|
||||
- Tons of beaker-rspec tests
|
||||
|
||||
|
||||
##2013-07-16 - Version 1.0.0
|
||||
####Features
|
||||
- Handle empty values.
|
||||
- Handle whitespace in settings names (aka: server role = something)
|
||||
- Add mechanism for allowing ini_setting subclasses to override the
|
||||
formation of the namevar during .instances, to allow for ini_setting
|
||||
derived types that manage flat ini-file-like files and still purge
|
||||
them.
|
||||
|
||||
---
|
||||
##2013-05-28 - Chris Price <chris@puppetlabs.com> - 0.10.3
|
||||
* Fix bug in subsetting handling for new settings (cbea5dc)
|
||||
|
||||
##2013-05-22 - Chris Price <chris@puppetlabs.com> - 0.10.2
|
||||
* Better handling of quotes for subsettings (1aa7e60)
|
||||
|
||||
##2013-05-21 - Chris Price <chris@puppetlabs.com> - 0.10.1
|
||||
* Change constants to class variables to avoid ruby warnings (6b19864)
|
||||
|
||||
##2013-04-10 - Erik Dalén <dalen@spotify.com> - 0.10.1
|
||||
* Style fixes (c4af8c3)
|
||||
|
||||
##2013-04-02 - Dan Bode <dan@puppetlabs.com> - 0.10.1
|
||||
* Add travisfile and Gemfile (c2052b3)
|
||||
|
||||
##2013-04-02 - Chris Price <chris@puppetlabs.com> - 0.10.1
|
||||
* Update README.markdown (ad38a08)
|
||||
|
||||
##2013-02-15 - Karel Brezina <karel.brezina@gmail.com> - 0.10.0
|
||||
* Added 'ini_subsetting' custom resource type (4351d8b)
|
||||
|
||||
##2013-03-11 - Dan Bode <dan@puppetlabs.com> - 0.10.0
|
||||
* guard against nil indentation values (5f71d7f)
|
||||
|
||||
##2013-01-07 - Dan Bode <dan@puppetlabs.com> - 0.10.0
|
||||
* Add purging support to ini file (2f22483)
|
||||
|
||||
##2013-02-05 - James Sweeny <james.sweeny@puppetlabs.com> - 0.10.0
|
||||
* Fix test to use correct key_val_parameter (b1aff63)
|
||||
|
||||
##2012-11-06 - Chris Price <chris@puppetlabs.com> - 0.10.0
|
||||
* Added license file w/Apache 2.0 license (5e1d203)
|
||||
|
||||
##2012-11-02 - Chris Price <chris@puppetlabs.com> - 0.9.0
|
||||
* Version 0.9.0 released
|
||||
|
||||
##2012-10-26 - Chris Price <chris@puppetlabs.com> - 0.9.0
|
||||
* Add detection for commented versions of settings (a45ab65)
|
||||
|
||||
##2012-10-20 - Chris Price <chris@puppetlabs.com> - 0.9.0
|
||||
* Refactor to clarify implementation of `save` (f0d443f)
|
||||
|
||||
##2012-10-20 - Chris Price <chris@puppetlabs.com> - 0.9.0
|
||||
* Add example for `ensure=absent` (e517148)
|
||||
|
||||
##2012-10-20 - Chris Price <chris@puppetlabs.com> - 0.9.0
|
||||
* Better handling of whitespace lines at ends of sections (845fa70)
|
||||
|
||||
##2012-10-20 - Chris Price <chris@puppetlabs.com> - 0.9.0
|
||||
* Respect indentation / spacing for existing sections and settings (c2c26de)
|
||||
|
||||
##2012-10-17 - Chris Price <chris@puppetlabs.com> - 0.9.0
|
||||
* Minor tweaks to handling of removing settings (cda30a6)
|
||||
|
||||
##2012-10-10 - Dan Bode <dan@puppetlabs.com> - 0.9.0
|
||||
* Add support for removing lines (1106d70)
|
||||
|
||||
##2012-10-02 - Dan Bode <dan@puppetlabs.com> - 0.9.0
|
||||
* Make value a property (cbc90d3)
|
||||
|
||||
##2012-10-02 - Dan Bode <dan@puppetlabs.com> - 0.9.0
|
||||
* Make ruby provider a better parent. (1564c47)
|
||||
|
||||
##2012-09-29 - Reid Vandewiele <reid@puppetlabs.com> - 0.9.0
|
||||
* Allow values with spaces to be parsed and set (3829e20)
|
||||
|
||||
##2012-09-24 - Chris Price <chris@pupppetlabs.com> - 0.0.3
|
||||
* Version 0.0.3 released
|
||||
|
||||
##2012-09-20 - Chris Price <chris@puppetlabs.com> - 0.0.3
|
||||
* Add validation for key_val_separator (e527908)
|
||||
|
||||
##2012-09-19 - Chris Price <chris@puppetlabs.com> - 0.0.3
|
||||
* Allow overriding separator string between key/val pairs (8d1fdc5)
|
||||
|
||||
##2012-08-20 - Chris Price <chris@pupppetlabs.com> - 0.0.2
|
||||
* Version 0.0.2 released
|
||||
|
||||
##2012-08-17 - Chris Price <chris@pupppetlabs.com> - 0.0.2
|
||||
* Add support for "global" section at beginning of file (c57dab4)
|
||||
@@ -1,234 +0,0 @@
|
||||
Checklist (and a short version for the impatient)
|
||||
=================================================
|
||||
|
||||
* Commits:
|
||||
|
||||
- Make commits of logical units.
|
||||
|
||||
- Check for unnecessary whitespace with "git diff --check" before
|
||||
committing.
|
||||
|
||||
- Commit using Unix line endings (check the settings around "crlf" in
|
||||
git-config(1)).
|
||||
|
||||
- Do not check in commented out code or unneeded files.
|
||||
|
||||
- The first line of the commit message should be a short
|
||||
description (50 characters is the soft limit, excluding ticket
|
||||
number(s)), and should skip the full stop.
|
||||
|
||||
- Associate the issue in the message. The first line should include
|
||||
the issue number in the form "(#XXXX) Rest of message".
|
||||
|
||||
- The body should provide a meaningful commit message, which:
|
||||
|
||||
- uses the imperative, present tense: "change", not "changed" or
|
||||
"changes".
|
||||
|
||||
- includes motivation for the change, and contrasts its
|
||||
implementation with the previous behavior.
|
||||
|
||||
- Make sure that you have tests for the bug you are fixing, or
|
||||
feature you are adding.
|
||||
|
||||
- Make sure the test suites passes after your commit:
|
||||
`bundle exec rspec spec/acceptance` More information on [testing](#Testing) below
|
||||
|
||||
- When introducing a new feature, make sure it is properly
|
||||
documented in the README.md
|
||||
|
||||
* Submission:
|
||||
|
||||
* Pre-requisites:
|
||||
|
||||
- Sign the [Contributor License Agreement](https://cla.puppetlabs.com/)
|
||||
|
||||
- Make sure you have a [GitHub account](https://github.com/join)
|
||||
|
||||
- [Create a ticket](http://projects.puppetlabs.com/projects/modules/issues/new), or [watch the ticket](http://projects.puppetlabs.com/projects/modules/issues) you are patching for.
|
||||
|
||||
* Preferred method:
|
||||
|
||||
- Fork the repository on GitHub.
|
||||
|
||||
- Push your changes to a topic branch in your fork of the
|
||||
repository. (the format ticket/1234-short_description_of_change is
|
||||
usually preferred for this project).
|
||||
|
||||
- Submit a pull request to the repository in the puppetlabs
|
||||
organization.
|
||||
|
||||
The long version
|
||||
================
|
||||
|
||||
1. Make separate commits for logically separate changes.
|
||||
|
||||
Please break your commits down into logically consistent units
|
||||
which include new or changed tests relevant to the rest of the
|
||||
change. The goal of doing this is to make the diff easier to
|
||||
read for whoever is reviewing your code. In general, the easier
|
||||
your diff is to read, the more likely someone will be happy to
|
||||
review it and get it into the code base.
|
||||
|
||||
If you are going to refactor a piece of code, please do so as a
|
||||
separate commit from your feature or bug fix changes.
|
||||
|
||||
We also really appreciate changes that include tests to make
|
||||
sure the bug is not re-introduced, and that the feature is not
|
||||
accidentally broken.
|
||||
|
||||
Describe the technical detail of the change(s). If your
|
||||
description starts to get too long, that is a good sign that you
|
||||
probably need to split up your commit into more finely grained
|
||||
pieces.
|
||||
|
||||
Commits which plainly describe the things which help
|
||||
reviewers check the patch and future developers understand the
|
||||
code are much more likely to be merged in with a minimum of
|
||||
bike-shedding or requested changes. Ideally, the commit message
|
||||
would include information, and be in a form suitable for
|
||||
inclusion in the release notes for the version of Puppet that
|
||||
includes them.
|
||||
|
||||
Please also check that you are not introducing any trailing
|
||||
whitespace or other "whitespace errors". You can do this by
|
||||
running "git diff --check" on your changes before you commit.
|
||||
|
||||
2. Sign the Contributor License Agreement
|
||||
|
||||
Before we can accept your changes, we do need a signed Puppet
|
||||
Labs Contributor License Agreement (CLA).
|
||||
|
||||
You can access the CLA via the [Contributor License Agreement link](https://cla.puppetlabs.com/)
|
||||
|
||||
If you have any questions about the CLA, please feel free to
|
||||
contact Puppet Labs via email at cla-submissions@puppetlabs.com.
|
||||
|
||||
3. Sending your patches
|
||||
|
||||
To submit your changes via a GitHub pull request, we _highly_
|
||||
recommend that you have them on a topic branch, instead of
|
||||
directly on "master".
|
||||
It makes things much easier to keep track of, especially if
|
||||
you decide to work on another thing before your first change
|
||||
is merged in.
|
||||
|
||||
GitHub has some pretty good
|
||||
[general documentation](http://help.github.com/) on using
|
||||
their site. They also have documentation on
|
||||
[creating pull requests](http://help.github.com/send-pull-requests/).
|
||||
|
||||
In general, after pushing your topic branch up to your
|
||||
repository on GitHub, you can switch to the branch in the
|
||||
GitHub UI and click "Pull Request" towards the top of the page
|
||||
in order to open a pull request.
|
||||
|
||||
|
||||
4. Update the related GitHub issue.
|
||||
|
||||
If there is a GitHub issue associated with the change you
|
||||
submitted, then you should update the ticket to include the
|
||||
location of your branch, along with any other commentary you
|
||||
may wish to make.
|
||||
|
||||
Testing
|
||||
=======
|
||||
|
||||
Getting Started
|
||||
---------------
|
||||
|
||||
Our puppet modules provide [`Gemfile`](./Gemfile)s which can tell a ruby
|
||||
package manager such as [bundler](http://bundler.io/) what Ruby packages,
|
||||
or Gems, are required to build, develop, and test this software.
|
||||
|
||||
Please make sure you have [bundler installed](http://bundler.io/#getting-started)
|
||||
on your system, then use it to install all dependencies needed for this project,
|
||||
by running
|
||||
|
||||
```shell
|
||||
% bundle install
|
||||
Fetching gem metadata from https://rubygems.org/........
|
||||
Fetching gem metadata from https://rubygems.org/..
|
||||
Using rake (10.1.0)
|
||||
Using builder (3.2.2)
|
||||
-- 8><-- many more --><8 --
|
||||
Using rspec-system-puppet (2.2.0)
|
||||
Using serverspec (0.6.3)
|
||||
Using rspec-system-serverspec (1.0.0)
|
||||
Using bundler (1.3.5)
|
||||
Your bundle is complete!
|
||||
Use `bundle show [gemname]` to see where a bundled gem is installed.
|
||||
```
|
||||
|
||||
NOTE some systems may require you to run this command with sudo.
|
||||
|
||||
If you already have those gems installed, make sure they are up-to-date:
|
||||
|
||||
```shell
|
||||
% bundle update
|
||||
```
|
||||
|
||||
With all dependencies in place and up-to-date we can now run the tests:
|
||||
|
||||
```shell
|
||||
% rake spec
|
||||
```
|
||||
|
||||
This will execute all the [rspec tests](http://rspec-puppet.com/) tests
|
||||
under [spec/defines](./spec/defines), [spec/classes](./spec/classes),
|
||||
and so on. rspec tests may have the same kind of dependencies as the
|
||||
module they are testing. While the module defines in its [Modulefile](./Modulefile),
|
||||
rspec tests define them in [.fixtures.yml](./fixtures.yml).
|
||||
|
||||
Some puppet modules also come with [beaker](https://github.com/puppetlabs/beaker)
|
||||
tests. These tests spin up a virtual machine under
|
||||
[VirtualBox](https://www.virtualbox.org/)) with, controlling it with
|
||||
[Vagrant](http://www.vagrantup.com/) to actually simulate scripted test
|
||||
scenarios. In order to run these, you will need both of those tools
|
||||
installed on your system.
|
||||
|
||||
You can run them by issuing the following command
|
||||
|
||||
```shell
|
||||
% rake spec_clean
|
||||
% rspec spec/acceptance
|
||||
```
|
||||
|
||||
This will now download a pre-fabricated image configured in the [default node-set](./spec/acceptance/nodesets/default.yml),
|
||||
install puppet, copy this module and install its dependencies per [spec/spec_helper_acceptance.rb](./spec/spec_helper_acceptance.rb)
|
||||
and then run all the tests under [spec/acceptance](./spec/acceptance).
|
||||
|
||||
Writing Tests
|
||||
-------------
|
||||
|
||||
XXX getting started writing tests.
|
||||
|
||||
If you have commit access to the repository
|
||||
===========================================
|
||||
|
||||
Even if you have commit access to the repository, you will still need to
|
||||
go through the process above, and have someone else review and merge
|
||||
in your changes. The rule is that all changes must be reviewed by a
|
||||
developer on the project (that did not write the code) to ensure that
|
||||
all changes go through a code review process.
|
||||
|
||||
Having someone other than the author of the topic branch recorded as
|
||||
performing the merge is the record that they performed the code
|
||||
review.
|
||||
|
||||
|
||||
Additional Resources
|
||||
====================
|
||||
|
||||
* [Getting additional help](http://projects.puppetlabs.com/projects/puppet/wiki/Getting_Help)
|
||||
|
||||
* [Writing tests](http://projects.puppetlabs.com/projects/puppet/wiki/Development_Writing_Tests)
|
||||
|
||||
* [Patchwork](https://patchwork.puppetlabs.com)
|
||||
|
||||
* [Contributor License Agreement](https://projects.puppetlabs.com/contributor_licenses/sign)
|
||||
|
||||
* [General GitHub documentation](http://help.github.com/)
|
||||
|
||||
* [GitHub pull request documentation](http://help.github.com/send-pull-requests/)
|
||||
|
||||
@@ -1,28 +0,0 @@
|
||||
source ENV['GEM_SOURCE'] || "https://rubygems.org"
|
||||
|
||||
group :development, :test do
|
||||
gem 'rake', :require => false
|
||||
gem 'rspec', '~> 2.11', :require => false
|
||||
gem 'rspec-puppet', :require => false
|
||||
gem 'puppetlabs_spec_helper', :require => false
|
||||
gem 'serverspec', :require => false
|
||||
gem 'puppet-lint', :require => false
|
||||
gem 'beaker', :require => false
|
||||
gem 'beaker-rspec', '>= 2.2', :require => false
|
||||
gem 'pry', :require => false
|
||||
gem 'simplecov', :require => false
|
||||
end
|
||||
|
||||
if facterversion = ENV['FACTER_GEM_VERSION']
|
||||
gem 'facter', facterversion, :require => false
|
||||
else
|
||||
gem 'facter', :require => false
|
||||
end
|
||||
|
||||
if puppetversion = ENV['PUPPET_GEM_VERSION']
|
||||
gem 'puppet', puppetversion, :require => false
|
||||
else
|
||||
gem 'puppet', :require => false
|
||||
end
|
||||
|
||||
# vim:ft=ruby
|
||||
@@ -1,201 +0,0 @@
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright 2012 Chris Price
|
||||
|
||||
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.
|
||||
@@ -1,107 +0,0 @@
|
||||
[](https://travis-ci.org/puppetlabs/puppetlabs-inifile)
|
||||
|
||||
# INI-file module #
|
||||
|
||||
This module provides resource types for use in managing INI-style configuration
|
||||
files. The main resource type is `ini_setting`, which is used to manage an
|
||||
individual setting in an INI file. Here's an example usage:
|
||||
|
||||
ini_setting { "sample setting":
|
||||
ensure => present,
|
||||
path => '/tmp/foo.ini',
|
||||
section => 'foo',
|
||||
setting => 'foosetting',
|
||||
value => 'FOO!',
|
||||
}
|
||||
|
||||
A supplementary resource type is `ini_subsetting`, which is used to manage
|
||||
settings that consist of several arguments such as
|
||||
|
||||
JAVA_ARGS="-Xmx192m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/var/log/pe-puppetdb/puppetdb-oom.hprof "
|
||||
|
||||
ini_subsetting {'sample subsetting':
|
||||
ensure => present,
|
||||
section => '',
|
||||
key_val_separator => '=',
|
||||
path => '/etc/default/pe-puppetdb',
|
||||
setting => 'JAVA_ARGS',
|
||||
subsetting => '-Xmx',
|
||||
value => '512m',
|
||||
}
|
||||
|
||||
## implementing child providers:
|
||||
|
||||
|
||||
The ini_setting class can be overridden by child providers in order to implement the management of ini settings for a specific configuration file.
|
||||
|
||||
In order to implement this, you will need to specify your own Type (as shown below). This type needs to implement a namevar (name), and a property called value:
|
||||
|
||||
|
||||
example:
|
||||
|
||||
#my_module/lib/puppet/type/glance_api_config.rb
|
||||
Puppet::Type.newtype(:glance_api_config) do
|
||||
ensurable
|
||||
newparam(:name, :namevar => true) do
|
||||
desc 'Section/setting name to manage from glance-api.conf'
|
||||
# namevar should be of the form section/setting
|
||||
newvalues(/\S+\/\S+/)
|
||||
end
|
||||
newproperty(:value) do
|
||||
desc 'The value of the setting to be defined.'
|
||||
munge do |v|
|
||||
v.to_s.strip
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
This type also must have a provider that utilizes the ini_setting provider as its parent:
|
||||
|
||||
example:
|
||||
|
||||
# my_module/lib/puppet/provider/glance_api_config/ini_setting.rb
|
||||
Puppet::Type.type(:glance_api_config).provide(
|
||||
:ini_setting,
|
||||
# set ini_setting as the parent provider
|
||||
:parent => Puppet::Type.type(:ini_setting).provider(:ruby)
|
||||
) do
|
||||
# implement section as the first part of the namevar
|
||||
def section
|
||||
resource[:name].split('/', 2).first
|
||||
end
|
||||
def setting
|
||||
# implement setting as the second part of the namevar
|
||||
resource[:name].split('/', 2).last
|
||||
end
|
||||
# hard code the file path (this allows purging)
|
||||
def self.file_path
|
||||
'/etc/glance/glance-api.conf'
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Now, the individual settings of the /etc/glance/glance-api.conf file can be managed as individual resources:
|
||||
|
||||
glance_api_config { 'HEADER/important_config':
|
||||
value => 'secret_value',
|
||||
}
|
||||
|
||||
Provided that self.file_path has been implemented, you can purge with the following puppet syntax:
|
||||
|
||||
resources { 'glance_api_config'
|
||||
purge => true,
|
||||
}
|
||||
|
||||
If the above code is added, then the resulting configured file will only contain lines implemented as Puppet resources
|
||||
|
||||
|
||||
## A few noteworthy features:
|
||||
|
||||
* The module tries *hard* not to manipulate your file any more than it needs to.
|
||||
In most cases, it should leave the original whitespace, comments, ordering,
|
||||
etc. perfectly intact.
|
||||
* Supports comments starting with either '#' or ';'.
|
||||
* Will add missing sections if they don't exist.
|
||||
* Supports a "global" section (settings that go at the beginning of the file,
|
||||
before any named sections) by specifying a section name of "".
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
require 'puppetlabs_spec_helper/rake_tasks'
|
||||
require 'puppet-lint/tasks/puppet-lint'
|
||||
|
||||
PuppetLint.configuration.fail_on_warnings
|
||||
PuppetLint.configuration.send('disable_80chars')
|
||||
PuppetLint.configuration.send('disable_class_inherits_from_params_class')
|
||||
PuppetLint.configuration.send('disable_class_parameter_defaults')
|
||||
PuppetLint.configuration.send('disable_documentation')
|
||||
PuppetLint.configuration.send('disable_single_quote_string_with_variables')
|
||||
PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"]
|
||||
@@ -1,102 +0,0 @@
|
||||
require File.expand_path('../../../util/ini_file', __FILE__)
|
||||
|
||||
Puppet::Type.type(:ini_setting).provide(:ruby) do
|
||||
|
||||
def self.instances
|
||||
# this code is here to support purging and the query-all functionality of the
|
||||
# 'puppet resource' command, on a per-file basis. Users
|
||||
# can create a type for a specific config file with a provider that uses
|
||||
# this as its parent and implements the method
|
||||
# 'self.file_path', and that will provide the value for the path to the
|
||||
# ini file (rather than needing to specify it on each ini setting
|
||||
# declaration). This allows 'purging' to be used to clear out
|
||||
# all settings from a particular ini file except those included in
|
||||
# the catalog.
|
||||
if self.respond_to?(:file_path)
|
||||
# figure out what to do about the seperator
|
||||
ini_file = Puppet::Util::IniFile.new(file_path, '=')
|
||||
resources = []
|
||||
ini_file.section_names.each do |section_name|
|
||||
ini_file.get_settings(section_name).each do |setting, value|
|
||||
resources.push(
|
||||
new(
|
||||
:name => namevar(section_name, setting),
|
||||
:value => value,
|
||||
:ensure => :present
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
resources
|
||||
else
|
||||
raise(Puppet::Error, 'Ini_settings only support collecting instances when a file path is hard coded')
|
||||
end
|
||||
end
|
||||
|
||||
def self.namevar(section_name, setting)
|
||||
"#{section_name}/#{setting}"
|
||||
end
|
||||
|
||||
def exists?
|
||||
!ini_file.get_value(section, setting).nil?
|
||||
end
|
||||
|
||||
def create
|
||||
ini_file.set_value(section, setting, resource[:value])
|
||||
ini_file.save
|
||||
@ini_file = nil
|
||||
end
|
||||
|
||||
def destroy
|
||||
ini_file.remove_setting(section, setting)
|
||||
ini_file.save
|
||||
@ini_file = nil
|
||||
end
|
||||
|
||||
def value
|
||||
ini_file.get_value(section, setting)
|
||||
end
|
||||
|
||||
def value=(value)
|
||||
ini_file.set_value(section, setting, resource[:value])
|
||||
ini_file.save
|
||||
end
|
||||
|
||||
def section
|
||||
# this method is here so that it can be overridden by a child provider
|
||||
resource[:section]
|
||||
end
|
||||
|
||||
def setting
|
||||
# this method is here so that it can be overridden by a child provider
|
||||
resource[:setting]
|
||||
end
|
||||
|
||||
def file_path
|
||||
# this method is here to support purging and sub-classing.
|
||||
# if a user creates a type and subclasses our provider and provides a
|
||||
# 'file_path' method, then they don't have to specify the
|
||||
# path as a parameter for every ini_setting declaration.
|
||||
# This implementation allows us to support that while still
|
||||
# falling back to the parameter value when necessary.
|
||||
if self.class.respond_to?(:file_path)
|
||||
self.class.file_path
|
||||
else
|
||||
resource[:path]
|
||||
end
|
||||
end
|
||||
|
||||
def separator
|
||||
if resource.class.validattr?(:key_val_separator)
|
||||
resource[:key_val_separator] || '='
|
||||
else
|
||||
'='
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
def ini_file
|
||||
@ini_file ||= Puppet::Util::IniFile.new(file_path, separator)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,73 +0,0 @@
|
||||
require File.expand_path('../../../util/ini_file', __FILE__)
|
||||
require File.expand_path('../../../util/setting_value', __FILE__)
|
||||
|
||||
Puppet::Type.type(:ini_subsetting).provide(:ruby) do
|
||||
|
||||
def exists?
|
||||
setting_value.get_subsetting_value(subsetting)
|
||||
end
|
||||
|
||||
def create
|
||||
setting_value.add_subsetting(subsetting, resource[:value])
|
||||
ini_file.set_value(section, setting, setting_value.get_value)
|
||||
ini_file.save
|
||||
@ini_file = nil
|
||||
@setting_value = nil
|
||||
end
|
||||
|
||||
def destroy
|
||||
setting_value.remove_subsetting(subsetting)
|
||||
ini_file.set_value(section, setting, setting_value.get_value)
|
||||
ini_file.save
|
||||
@ini_file = nil
|
||||
@setting_value = nil
|
||||
end
|
||||
|
||||
def value
|
||||
setting_value.get_subsetting_value(subsetting)
|
||||
end
|
||||
|
||||
def value=(value)
|
||||
setting_value.add_subsetting(subsetting, resource[:value])
|
||||
ini_file.set_value(section, setting, setting_value.get_value)
|
||||
ini_file.save
|
||||
end
|
||||
|
||||
def section
|
||||
resource[:section]
|
||||
end
|
||||
|
||||
def setting
|
||||
resource[:setting]
|
||||
end
|
||||
|
||||
def subsetting
|
||||
resource[:subsetting]
|
||||
end
|
||||
|
||||
def subsetting_separator
|
||||
resource[:subsetting_separator]
|
||||
end
|
||||
|
||||
def file_path
|
||||
resource[:path]
|
||||
end
|
||||
|
||||
def separator
|
||||
resource[:key_val_separator] || '='
|
||||
end
|
||||
|
||||
def quote_char
|
||||
resource[:quote_char]
|
||||
end
|
||||
|
||||
private
|
||||
def ini_file
|
||||
@ini_file ||= Puppet::Util::IniFile.new(file_path, separator)
|
||||
end
|
||||
|
||||
def setting_value
|
||||
@setting_value ||= Puppet::Util::SettingValue.new(ini_file.get_value(section, setting), subsetting_separator, quote_char)
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,47 +0,0 @@
|
||||
Puppet::Type.newtype(:ini_setting) do
|
||||
|
||||
ensurable do
|
||||
defaultvalues
|
||||
defaultto :present
|
||||
end
|
||||
|
||||
newparam(:name, :namevar => true) do
|
||||
desc 'An arbitrary name used as the identity of the resource.'
|
||||
end
|
||||
|
||||
newparam(:section) do
|
||||
desc 'The name of the section in the ini file in which the setting should be defined.'
|
||||
end
|
||||
|
||||
newparam(:setting) do
|
||||
desc 'The name of the setting to be defined.'
|
||||
end
|
||||
|
||||
newparam(:path) do
|
||||
desc 'The ini file Puppet will ensure contains the specified setting.'
|
||||
validate do |value|
|
||||
unless (Puppet.features.posix? and value =~ /^\//) or (Puppet.features.microsoft_windows? and (value =~ /^.:\// or value =~ /^\/\/[^\/]+\/[^\/]+/))
|
||||
raise(Puppet::Error, "File paths must be fully qualified, not '#{value}'")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
newparam(:key_val_separator) do
|
||||
desc 'The separator string to use between each setting name and value. ' +
|
||||
'Defaults to " = ", but you could use this to override e.g. whether ' +
|
||||
'or not the separator should include whitespace.'
|
||||
defaultto(" = ")
|
||||
|
||||
validate do |value|
|
||||
unless value.scan('=').size == 1
|
||||
raise Puppet::Error, ":key_val_separator must contain exactly one = character."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
newproperty(:value) do
|
||||
desc 'The value of the setting to be defined.'
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
@@ -1,67 +0,0 @@
|
||||
Puppet::Type.newtype(:ini_subsetting) do
|
||||
|
||||
ensurable do
|
||||
defaultvalues
|
||||
defaultto :present
|
||||
end
|
||||
|
||||
newparam(:name, :namevar => true) do
|
||||
desc 'An arbitrary name used as the identity of the resource.'
|
||||
end
|
||||
|
||||
newparam(:section) do
|
||||
desc 'The name of the section in the ini file in which the setting should be defined.'
|
||||
end
|
||||
|
||||
newparam(:setting) do
|
||||
desc 'The name of the setting to be defined.'
|
||||
end
|
||||
|
||||
newparam(:subsetting) do
|
||||
desc 'The name of the subsetting to be defined.'
|
||||
end
|
||||
|
||||
newparam(:subsetting_separator) do
|
||||
desc 'The separator string between subsettings. Defaults to " "'
|
||||
defaultto(" ")
|
||||
end
|
||||
|
||||
newparam(:path) do
|
||||
desc 'The ini file Puppet will ensure contains the specified setting.'
|
||||
validate do |value|
|
||||
unless (Puppet.features.posix? and value =~ /^\//) or (Puppet.features.microsoft_windows? and (value =~ /^.:\// or value =~ /^\/\/[^\/]+\/[^\/]+/))
|
||||
raise(Puppet::Error, "File paths must be fully qualified, not '#{value}'")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
newparam(:key_val_separator) do
|
||||
desc 'The separator string to use between each setting name and value. ' +
|
||||
'Defaults to " = ", but you could use this to override e.g. whether ' +
|
||||
'or not the separator should include whitespace.'
|
||||
defaultto(" = ")
|
||||
|
||||
validate do |value|
|
||||
unless value.scan('=').size == 1
|
||||
raise Puppet::Error, ":key_val_separator must contain exactly one = character."
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
newparam(:quote_char) do
|
||||
desc 'The character used to quote the entire value of the setting. ' +
|
||||
%q{Valid values are '', '"' and "'". Defaults to ''.}
|
||||
defaultto('')
|
||||
|
||||
validate do |value|
|
||||
unless value =~ /^["']?$/
|
||||
raise Puppet::Error, %q{:quote_char valid values are '', '"' and "'"}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
newproperty(:value) do
|
||||
desc 'The value of the subsetting to be defined.'
|
||||
end
|
||||
|
||||
end
|
||||
@@ -1,28 +0,0 @@
|
||||
module Puppet
|
||||
module Util
|
||||
class ExternalIterator
|
||||
def initialize(coll)
|
||||
@coll = coll
|
||||
@cur_index = -1
|
||||
end
|
||||
|
||||
def next
|
||||
@cur_index = @cur_index + 1
|
||||
item_at(@cur_index)
|
||||
end
|
||||
|
||||
def peek
|
||||
item_at(@cur_index + 1)
|
||||
end
|
||||
|
||||
private
|
||||
def item_at(index)
|
||||
if @coll.length > index
|
||||
[@coll[index], index]
|
||||
else
|
||||
[nil, nil]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,300 +0,0 @@
|
||||
require File.expand_path('../external_iterator', __FILE__)
|
||||
require File.expand_path('../ini_file/section', __FILE__)
|
||||
|
||||
module Puppet
|
||||
module Util
|
||||
class IniFile
|
||||
|
||||
@@SECTION_REGEX = /^\s*\[([^\]]*)\]\s*$/
|
||||
@@SETTING_REGEX = /^(\s*)([^\[#;][\w\d\.\\\/\-\s\[\]\']*[\w\d\.\\\/\-\]])([ \t]*=[ \t]*)([\S\s]*?)\s*$/
|
||||
@@COMMENTED_SETTING_REGEX = /^(\s*)[#;]+(\s*)([^\[]*[\w\d\.\\\/\-]+[\w\d\.\\\/\-\[\]\']+)([ \t]*=[ \t]*)([\S\s]*?)\s*$/
|
||||
|
||||
def initialize(path, key_val_separator = ' = ')
|
||||
@path = path
|
||||
@key_val_separator = key_val_separator
|
||||
@section_names = []
|
||||
@sections_hash = {}
|
||||
if File.file?(@path)
|
||||
parse_file
|
||||
end
|
||||
end
|
||||
|
||||
def section_names
|
||||
@section_names
|
||||
end
|
||||
|
||||
def get_settings(section_name)
|
||||
section = @sections_hash[section_name]
|
||||
section.setting_names.inject({}) do |result, setting|
|
||||
result[setting] = section.get_value(setting)
|
||||
result
|
||||
end
|
||||
end
|
||||
|
||||
def get_value(section_name, setting)
|
||||
if (@sections_hash.has_key?(section_name))
|
||||
@sections_hash[section_name].get_value(setting)
|
||||
end
|
||||
end
|
||||
|
||||
def set_value(section_name, setting, value)
|
||||
unless (@sections_hash.has_key?(section_name))
|
||||
add_section(Section.new(section_name, nil, nil, nil, nil))
|
||||
end
|
||||
|
||||
section = @sections_hash[section_name]
|
||||
|
||||
if (section.has_existing_setting?(setting))
|
||||
update_line(section, setting, value)
|
||||
section.update_existing_setting(setting, value)
|
||||
elsif result = find_commented_setting(section, setting)
|
||||
# So, this stanza is a bit of a hack. What we're trying
|
||||
# to do here is this: for settings that don't already
|
||||
# exist, we want to take a quick peek to see if there
|
||||
# is a commented-out version of them in the section.
|
||||
# If so, we'd prefer to add the setting directly after
|
||||
# the commented line, rather than at the end of the section.
|
||||
|
||||
# If we get here then we found a commented line, so we
|
||||
# call "insert_inline_setting_line" to update the lines array
|
||||
insert_inline_setting_line(result, section, setting, value)
|
||||
|
||||
# Then, we need to tell the setting object that we hacked
|
||||
# in an inline setting
|
||||
section.insert_inline_setting(setting, value)
|
||||
|
||||
# Finally, we need to update all of the start/end line
|
||||
# numbers for all of the sections *after* the one that
|
||||
# was modified.
|
||||
section_index = @section_names.index(section_name)
|
||||
increment_section_line_numbers(section_index + 1)
|
||||
else
|
||||
section.set_additional_setting(setting, value)
|
||||
end
|
||||
end
|
||||
|
||||
def remove_setting(section_name, setting)
|
||||
section = @sections_hash[section_name]
|
||||
if (section.has_existing_setting?(setting))
|
||||
# If the setting is found, we have some work to do.
|
||||
# First, we remove the line from our array of lines:
|
||||
remove_line(section, setting)
|
||||
|
||||
# Then, we need to tell the setting object to remove
|
||||
# the setting from its state:
|
||||
section.remove_existing_setting(setting)
|
||||
|
||||
# Finally, we need to update all of the start/end line
|
||||
# numbers for all of the sections *after* the one that
|
||||
# was modified.
|
||||
section_index = @section_names.index(section_name)
|
||||
decrement_section_line_numbers(section_index + 1)
|
||||
end
|
||||
end
|
||||
|
||||
def save
|
||||
File.open(@path, 'w') do |fh|
|
||||
|
||||
@section_names.each_index do |index|
|
||||
name = @section_names[index]
|
||||
|
||||
section = @sections_hash[name]
|
||||
|
||||
# We need a buffer to cache lines that are only whitespace
|
||||
whitespace_buffer = []
|
||||
|
||||
if (section.is_new_section?) && (! section.is_global?)
|
||||
fh.puts("\n[#{section.name}]")
|
||||
end
|
||||
|
||||
if ! section.is_new_section?
|
||||
# write all of the pre-existing settings
|
||||
(section.start_line..section.end_line).each do |line_num|
|
||||
line = lines[line_num]
|
||||
|
||||
# We buffer any lines that are only whitespace so that
|
||||
# if they are at the end of a section, we can insert
|
||||
# any new settings *before* the final chunk of whitespace
|
||||
# lines.
|
||||
if (line =~ /^\s*$/)
|
||||
whitespace_buffer << line
|
||||
else
|
||||
# If we get here, we've found a non-whitespace line.
|
||||
# We'll flush any cached whitespace lines before we
|
||||
# write it.
|
||||
flush_buffer_to_file(whitespace_buffer, fh)
|
||||
fh.puts(line)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# write new settings, if there are any
|
||||
section.additional_settings.each_pair do |key, value|
|
||||
fh.puts("#{' ' * (section.indentation || 0)}#{key}#{@key_val_separator}#{value}")
|
||||
end
|
||||
|
||||
if (whitespace_buffer.length > 0)
|
||||
flush_buffer_to_file(whitespace_buffer, fh)
|
||||
else
|
||||
# We get here if there were no blank lines at the end of the
|
||||
# section.
|
||||
#
|
||||
# If we are adding a new section with a new setting,
|
||||
# and if there are more sections that come after this one,
|
||||
# we'll write one blank line just so that there is a little
|
||||
# whitespace between the sections.
|
||||
#if (section.end_line.nil? &&
|
||||
if (section.is_new_section? &&
|
||||
(section.additional_settings.length > 0) &&
|
||||
(index < @section_names.length - 1))
|
||||
fh.puts("")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
private
|
||||
def add_section(section)
|
||||
@sections_hash[section.name] = section
|
||||
@section_names << section.name
|
||||
end
|
||||
|
||||
def parse_file
|
||||
line_iter = create_line_iter
|
||||
|
||||
# We always create a "global" section at the beginning of the file, for
|
||||
# anything that appears before the first named section.
|
||||
section = read_section('', 0, line_iter)
|
||||
add_section(section)
|
||||
line, line_num = line_iter.next
|
||||
|
||||
while line
|
||||
if (match = @@SECTION_REGEX.match(line))
|
||||
section = read_section(match[1], line_num, line_iter)
|
||||
add_section(section)
|
||||
end
|
||||
line, line_num = line_iter.next
|
||||
end
|
||||
end
|
||||
|
||||
def read_section(name, start_line, line_iter)
|
||||
settings = {}
|
||||
end_line_num = nil
|
||||
min_indentation = nil
|
||||
while true
|
||||
line, line_num = line_iter.peek
|
||||
if (line_num.nil? or match = @@SECTION_REGEX.match(line))
|
||||
return Section.new(name, start_line, end_line_num, settings, min_indentation)
|
||||
elsif (match = @@SETTING_REGEX.match(line))
|
||||
settings[match[2]] = match[4]
|
||||
indentation = match[1].length
|
||||
min_indentation = [indentation, min_indentation || indentation].min
|
||||
end
|
||||
end_line_num = line_num
|
||||
line_iter.next
|
||||
end
|
||||
end
|
||||
|
||||
def update_line(section, setting, value)
|
||||
(section.start_line..section.end_line).each do |line_num|
|
||||
if (match = @@SETTING_REGEX.match(lines[line_num]))
|
||||
if (match[2] == setting)
|
||||
lines[line_num] = "#{match[1]}#{match[2]}#{match[3]}#{value}"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def remove_line(section, setting)
|
||||
(section.start_line..section.end_line).each do |line_num|
|
||||
if (match = @@SETTING_REGEX.match(lines[line_num]))
|
||||
if (match[2] == setting)
|
||||
lines.delete_at(line_num)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def create_line_iter
|
||||
ExternalIterator.new(lines)
|
||||
end
|
||||
|
||||
def lines
|
||||
@lines ||= IniFile.readlines(@path)
|
||||
end
|
||||
|
||||
# This is mostly here because it makes testing easier--we don't have
|
||||
# to try to stub any methods on File.
|
||||
def self.readlines(path)
|
||||
# If this type is ever used with very large files, we should
|
||||
# write this in a different way, using a temp
|
||||
# file; for now assuming that this type is only used on
|
||||
# small-ish config files that can fit into memory without
|
||||
# too much trouble.
|
||||
File.readlines(path)
|
||||
end
|
||||
|
||||
# This utility method scans through the lines for a section looking for
|
||||
# commented-out versions of a setting. It returns `nil` if it doesn't
|
||||
# find one. If it does find one, then it returns a hash containing
|
||||
# two keys:
|
||||
#
|
||||
# :line_num - the line number that contains the commented version
|
||||
# of the setting
|
||||
# :match - the ruby regular expression match object, which can
|
||||
# be used to mimic the whitespace from the comment line
|
||||
def find_commented_setting(section, setting)
|
||||
return nil if section.is_new_section?
|
||||
(section.start_line..section.end_line).each do |line_num|
|
||||
if (match = @@COMMENTED_SETTING_REGEX.match(lines[line_num]))
|
||||
if (match[3] == setting)
|
||||
return { :match => match, :line_num => line_num }
|
||||
end
|
||||
end
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
# This utility method is for inserting a line into the existing
|
||||
# lines array. The `result` argument is expected to be in the
|
||||
# format of the return value of `find_commented_setting`.
|
||||
def insert_inline_setting_line(result, section, setting, value)
|
||||
line_num = result[:line_num]
|
||||
match = result[:match]
|
||||
lines.insert(line_num + 1, "#{' ' * (section.indentation || 0 )}#{setting}#{match[4]}#{value}")
|
||||
end
|
||||
|
||||
# Utility method; given a section index (index into the @section_names
|
||||
# array), decrement the start/end line numbers for that section and all
|
||||
# all of the other sections that appear *after* the specified section.
|
||||
def decrement_section_line_numbers(section_index)
|
||||
@section_names[section_index..(@section_names.length - 1)].each do |name|
|
||||
section = @sections_hash[name]
|
||||
section.decrement_line_nums
|
||||
end
|
||||
end
|
||||
|
||||
# Utility method; given a section index (index into the @section_names
|
||||
# array), increment the start/end line numbers for that section and all
|
||||
# all of the other sections that appear *after* the specified section.
|
||||
def increment_section_line_numbers(section_index)
|
||||
@section_names[section_index..(@section_names.length - 1)].each do |name|
|
||||
section = @sections_hash[name]
|
||||
section.increment_line_nums
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def flush_buffer_to_file(buffer, fh)
|
||||
if buffer.length > 0
|
||||
buffer.each { |l| fh.puts(l) }
|
||||
buffer.clear
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,103 +0,0 @@
|
||||
module Puppet
|
||||
module Util
|
||||
class IniFile
|
||||
class Section
|
||||
# Some implementation details:
|
||||
#
|
||||
# * `name` will be set to the empty string for the 'global' section.
|
||||
# * there will always be a 'global' section, with a `start_line` of 0,
|
||||
# but if the file actually begins with a real section header on
|
||||
# the first line, then the 'global' section will have an
|
||||
# `end_line` of `nil`.
|
||||
# * `start_line` and `end_line` will be set to `nil` for a new non-global
|
||||
# section.
|
||||
def initialize(name, start_line, end_line, settings, indentation)
|
||||
@name = name
|
||||
@start_line = start_line
|
||||
@end_line = end_line
|
||||
@existing_settings = settings.nil? ? {} : settings
|
||||
@additional_settings = {}
|
||||
@indentation = indentation
|
||||
end
|
||||
|
||||
attr_reader :name, :start_line, :end_line, :additional_settings, :indentation
|
||||
|
||||
def is_global?()
|
||||
@name == ''
|
||||
end
|
||||
|
||||
def is_new_section?()
|
||||
# a new section (global or named) will always have `end_line`
|
||||
# set to `nil`
|
||||
@end_line.nil?
|
||||
end
|
||||
|
||||
def setting_names
|
||||
@existing_settings.keys | @additional_settings.keys
|
||||
end
|
||||
|
||||
def get_value(setting_name)
|
||||
@existing_settings[setting_name] || @additional_settings[setting_name]
|
||||
end
|
||||
|
||||
def has_existing_setting?(setting_name)
|
||||
@existing_settings.has_key?(setting_name)
|
||||
end
|
||||
|
||||
def update_existing_setting(setting_name, value)
|
||||
@existing_settings[setting_name] = value
|
||||
end
|
||||
|
||||
def remove_existing_setting(setting_name)
|
||||
if (@existing_settings.delete(setting_name))
|
||||
if @end_line
|
||||
@end_line = @end_line - 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# This is a hacky method; it's basically called when we need to insert
|
||||
# a new setting but we don't want it to appear at the very end of the
|
||||
# section. Instead we hack it into the existing settings list and
|
||||
# increment our end_line number--this assumes that the caller (`ini_file`)
|
||||
# is doing some babysitting w/rt the other sections and the actual data
|
||||
# of the lines.
|
||||
def insert_inline_setting(setting_name, value)
|
||||
@existing_settings[setting_name] = value
|
||||
if @end_line
|
||||
@end_line = @end_line + 1
|
||||
end
|
||||
end
|
||||
|
||||
def set_additional_setting(setting_name, value)
|
||||
@additional_settings[setting_name] = value
|
||||
end
|
||||
|
||||
# Decrement the start and end line numbers for the section (if they are
|
||||
# defined); this is intended to be called when a setting is removed
|
||||
# from a section that comes before this section in the ini file.
|
||||
def decrement_line_nums()
|
||||
if @start_line
|
||||
@start_line = @start_line - 1
|
||||
end
|
||||
if @end_line
|
||||
@end_line = @end_line - 1
|
||||
end
|
||||
end
|
||||
|
||||
# Increment the start and end line numbers for the section (if they are
|
||||
# defined); this is intended to be called when an inline setting is added
|
||||
# to a section that comes before this section in the ini file.
|
||||
def increment_line_nums()
|
||||
if @start_line
|
||||
@start_line = @start_line + 1
|
||||
end
|
||||
if @end_line
|
||||
@end_line = @end_line + 1
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,95 +0,0 @@
|
||||
module Puppet
|
||||
module Util
|
||||
|
||||
class SettingValue
|
||||
|
||||
def initialize(setting_value, subsetting_separator = ' ', default_quote_char = nil)
|
||||
@setting_value = setting_value
|
||||
@subsetting_separator = subsetting_separator
|
||||
|
||||
default_quote_char ||= ''
|
||||
|
||||
if @setting_value
|
||||
unquoted, @quote_char = unquote_setting_value(setting_value)
|
||||
@subsetting_items = unquoted.scan(Regexp.new("(?:(?:[^\\#{@subsetting_separator}]|\\.)+)")) # an item can contain escaped separator
|
||||
@subsetting_items.map! { |item| item.strip }
|
||||
@quote_char = default_quote_char if @quote_char.empty?
|
||||
else
|
||||
@subsetting_items = []
|
||||
@quote_char = default_quote_char
|
||||
end
|
||||
end
|
||||
|
||||
def unquote_setting_value(setting_value)
|
||||
quote_char = ""
|
||||
if (setting_value.start_with?('"') and setting_value.end_with?('"'))
|
||||
quote_char = '"'
|
||||
elsif (setting_value.start_with?("'") and setting_value.end_with?("'"))
|
||||
quote_char = "'"
|
||||
end
|
||||
|
||||
unquoted = setting_value
|
||||
|
||||
if (quote_char != "")
|
||||
unquoted = setting_value[1, setting_value.length - 2]
|
||||
end
|
||||
|
||||
[unquoted, quote_char]
|
||||
end
|
||||
|
||||
def get_value
|
||||
|
||||
result = ""
|
||||
first = true
|
||||
|
||||
@subsetting_items.each { |item|
|
||||
result << @subsetting_separator unless first
|
||||
result << item
|
||||
first = false
|
||||
}
|
||||
|
||||
@quote_char + result + @quote_char
|
||||
end
|
||||
|
||||
def get_subsetting_value(subsetting)
|
||||
|
||||
value = nil
|
||||
|
||||
@subsetting_items.each { |item|
|
||||
if(item.start_with?(subsetting))
|
||||
value = item[subsetting.length, item.length - subsetting.length]
|
||||
break
|
||||
end
|
||||
}
|
||||
|
||||
value
|
||||
end
|
||||
|
||||
def add_subsetting(subsetting, subsetting_value)
|
||||
|
||||
new_item = subsetting + (subsetting_value || '')
|
||||
found = false
|
||||
|
||||
@subsetting_items.map! { |item|
|
||||
if item.start_with?(subsetting)
|
||||
value = new_item
|
||||
found = true
|
||||
else
|
||||
value = item
|
||||
end
|
||||
|
||||
value
|
||||
}
|
||||
|
||||
unless found
|
||||
@subsetting_items.push(new_item)
|
||||
end
|
||||
end
|
||||
|
||||
def remove_subsetting(subsetting)
|
||||
@subsetting_items = @subsetting_items.map { |item| item.start_with?(subsetting) ? nil : item }.compact
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,308 +0,0 @@
|
||||
require 'spec_helper_acceptance'
|
||||
|
||||
tmpdir = default.tmpdir('tmp')
|
||||
|
||||
describe 'ini_setting resource' do
|
||||
after :all do
|
||||
shell("rm #{tmpdir}/*.ini", :acceptable_exit_codes => [0,1,2])
|
||||
end
|
||||
|
||||
shared_examples 'has_content' do |path,pp,content|
|
||||
before :all do
|
||||
shell("rm #{path}", :acceptable_exit_codes => [0,1,2])
|
||||
end
|
||||
after :all do
|
||||
shell("cat #{path}", :acceptable_exit_codes => [0,1,2])
|
||||
shell("rm #{path}", :acceptable_exit_codes => [0,1,2])
|
||||
end
|
||||
|
||||
it 'applies the manifest twice' do
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
|
||||
describe file(path) do
|
||||
it { should be_file }
|
||||
#XXX Solaris 10 doesn't support multi-line grep
|
||||
it("should contain #{content}", :unless => fact('osfamily') == 'Solaris') {
|
||||
should contain(content)
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'has_error' do |path,pp,error|
|
||||
before :all do
|
||||
shell("rm #{path}", :acceptable_exit_codes => [0,1,2])
|
||||
end
|
||||
after :all do
|
||||
shell("cat #{path}", :acceptable_exit_codes => [0,1,2])
|
||||
shell("rm #{path}", :acceptable_exit_codes => [0,1,2])
|
||||
end
|
||||
|
||||
it 'applies the manifest and gets a failure message' do
|
||||
expect(apply_manifest(pp, :expect_failures => true).stderr).to match(error)
|
||||
end
|
||||
|
||||
describe file(path) do
|
||||
it { should_not be_file }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'ensure parameter' do
|
||||
context '=> present for global and section' do
|
||||
pp = <<-EOS
|
||||
ini_setting { 'ensure => present for section':
|
||||
ensure => present,
|
||||
path => "#{tmpdir}/ini_setting.ini",
|
||||
section => 'one',
|
||||
setting => 'two',
|
||||
value => 'three',
|
||||
}
|
||||
ini_setting { 'ensure => present for global':
|
||||
ensure => present,
|
||||
path => "#{tmpdir}/ini_setting.ini",
|
||||
section => '',
|
||||
setting => 'four',
|
||||
value => 'five',
|
||||
}
|
||||
EOS
|
||||
|
||||
it 'applies the manifest twice' do
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
|
||||
describe file("#{tmpdir}/ini_setting.ini") do
|
||||
it { should be_file }
|
||||
#XXX Solaris 10 doesn't support multi-line grep
|
||||
it("should contain four = five\n[one]\ntwo = three", :unless => fact('osfamily') == 'Solaris') {
|
||||
should contain("four = five\n[one]\ntwo = three")
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
context '=> absent for key/value' do
|
||||
before :all do
|
||||
if fact('osfamily') == 'Darwin'
|
||||
shell("echo \"four = five\n[one]\ntwo = three\" > #{tmpdir}/ini_setting.ini")
|
||||
else
|
||||
shell("echo -e \"four = five\n[one]\ntwo = three\" > #{tmpdir}/ini_setting.ini")
|
||||
end
|
||||
end
|
||||
|
||||
pp = <<-EOS
|
||||
ini_setting { 'ensure => absent for key/value':
|
||||
ensure => absent,
|
||||
path => "#{tmpdir}/ini_setting.ini",
|
||||
section => 'one',
|
||||
setting => 'two',
|
||||
value => 'three',
|
||||
}
|
||||
EOS
|
||||
|
||||
it 'applies the manifest twice' do
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
|
||||
describe file("#{tmpdir}/ini_setting.ini") do
|
||||
it { should be_file }
|
||||
it { should contain('four = five') }
|
||||
it { should contain('[one]') }
|
||||
it { should_not contain('two = three') }
|
||||
end
|
||||
end
|
||||
|
||||
context '=> absent for section', :pending => "cannot ensure absent on a section" do
|
||||
before :all do
|
||||
if fact('osfamily') == 'Darwin'
|
||||
shell("echo \"four = five\n[one]\ntwo = three\" > #{tmpdir}/ini_setting.ini")
|
||||
else
|
||||
shell("echo -e \"four = five\n[one]\ntwo = three\" > #{tmpdir}/ini_setting.ini")
|
||||
end
|
||||
end
|
||||
after :all do
|
||||
shell("cat #{tmpdir}/ini_setting.ini", :acceptable_exit_codes => [0,1,2])
|
||||
shell("rm #{tmpdir}/ini_setting.ini", :acceptable_exit_codes => [0,1,2])
|
||||
end
|
||||
|
||||
pp = <<-EOS
|
||||
ini_setting { 'ensure => absent for section':
|
||||
ensure => absent,
|
||||
path => "#{tmpdir}/ini_setting.ini",
|
||||
section => 'one',
|
||||
}
|
||||
EOS
|
||||
|
||||
it 'applies the manifest twice' do
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
|
||||
describe file("#{tmpdir}/ini_setting.ini") do
|
||||
it { should be_file }
|
||||
it { should contain('four = five') }
|
||||
it { should_not contain('[one]') }
|
||||
it { should_not contain('two = three') }
|
||||
end
|
||||
end
|
||||
|
||||
context '=> absent for global' do
|
||||
before :all do
|
||||
if fact('osfamily') == 'Darwin'
|
||||
shell("echo \"four = five\n[one]\ntwo = three\" > #{tmpdir}/ini_setting.ini")
|
||||
else
|
||||
shell("echo -e \"four = five\n[one]\ntwo = three\" > #{tmpdir}/ini_setting.ini")
|
||||
end
|
||||
end
|
||||
after :all do
|
||||
shell("cat #{tmpdir}/ini_setting.ini", :acceptable_exit_codes => [0,1,2])
|
||||
shell("rm #{tmpdir}/ini_setting.ini", :acceptable_exit_codes => [0,1,2])
|
||||
end
|
||||
|
||||
pp = <<-EOS
|
||||
ini_setting { 'ensure => absent for global':
|
||||
ensure => absent,
|
||||
path => "#{tmpdir}/ini_setting.ini",
|
||||
section => '',
|
||||
setting => 'four',
|
||||
value => 'five',
|
||||
}
|
||||
EOS
|
||||
|
||||
it 'applies the manifest twice' do
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
|
||||
describe file("#{tmpdir}/ini_setting.ini") do
|
||||
it { should be_file }
|
||||
it { should_not contain('four = five') }
|
||||
it { should contain('[one]') }
|
||||
it { should contain('two = three') }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'section, setting, value parameters' do
|
||||
{
|
||||
"section => 'test', setting => 'foo', value => 'bar'," => "[test]\nfoo = bar",
|
||||
"section => 'more', setting => 'baz', value => 'quux'," => "[more]\nbaz = quux",
|
||||
"section => '', setting => 'top', value => 'level'," => "top = level",
|
||||
}.each do |parameter_list, content|
|
||||
context parameter_list do
|
||||
pp = <<-EOS
|
||||
ini_setting { "#{parameter_list}":
|
||||
ensure => present,
|
||||
path => "#{tmpdir}/ini_setting.ini",
|
||||
#{parameter_list}
|
||||
}
|
||||
EOS
|
||||
|
||||
it_behaves_like 'has_content', "#{tmpdir}/ini_setting.ini", pp, content
|
||||
end
|
||||
end
|
||||
|
||||
{
|
||||
"section => 'test'," => /setting is a required.+value is a required/,
|
||||
"setting => 'foo', value => 'bar'," => /section is a required/,
|
||||
"section => 'test', setting => 'foo'," => /value is a required/,
|
||||
"section => 'test', value => 'bar'," => /setting is a required/,
|
||||
"value => 'bar'," => /section is a required.+setting is a required/,
|
||||
"setting => 'foo'," => /section is a required.+value is a required/,
|
||||
}.each do |parameter_list, error|
|
||||
context parameter_list, :pending => 'no error checking yet' do
|
||||
pp = <<-EOS
|
||||
ini_setting { "#{parameter_list}":
|
||||
ensure => present,
|
||||
path => "#{tmpdir}/ini_setting.ini",
|
||||
#{parameter_list}
|
||||
}
|
||||
EOS
|
||||
|
||||
it_behaves_like 'has_error', "#{tmpdir}/ini_setting.ini", pp, error
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'path parameter' do
|
||||
[
|
||||
"#{tmpdir}/one.ini",
|
||||
"#{tmpdir}/two.ini",
|
||||
"#{tmpdir}/three.ini",
|
||||
].each do |path|
|
||||
context "path => #{path}" do
|
||||
pp = <<-EOS
|
||||
ini_setting { 'path => #{path}':
|
||||
ensure => present,
|
||||
section => 'one',
|
||||
setting => 'two',
|
||||
value => 'three',
|
||||
path => '#{path}',
|
||||
}
|
||||
EOS
|
||||
|
||||
it_behaves_like 'has_content', path, pp, "[one]\ntwo = three"
|
||||
end
|
||||
end
|
||||
|
||||
context "path => foo" do
|
||||
pp = <<-EOS
|
||||
ini_setting { 'path => foo':
|
||||
ensure => present,
|
||||
section => 'one',
|
||||
setting => 'two',
|
||||
value => 'three',
|
||||
path => 'foo',
|
||||
}
|
||||
EOS
|
||||
|
||||
it_behaves_like 'has_error', 'foo', pp, /must be fully qualified/
|
||||
end
|
||||
end
|
||||
|
||||
describe 'key_val_separator parameter' do
|
||||
{
|
||||
"" => "two = three",
|
||||
"key_val_separator => '='," => "two=three",
|
||||
"key_val_separator => ' = '," => "two = three",
|
||||
}.each do |parameter, content|
|
||||
context "with \"#{parameter}\" makes \"#{content}\"" do
|
||||
pp = <<-EOS
|
||||
ini_setting { "with #{parameter} makes #{content}":
|
||||
ensure => present,
|
||||
section => 'one',
|
||||
setting => 'two',
|
||||
value => 'three',
|
||||
path => "#{tmpdir}/key_val_separator.ini",
|
||||
#{parameter}
|
||||
}
|
||||
EOS
|
||||
|
||||
it_behaves_like 'has_content', "#{tmpdir}/key_val_separator.ini", pp, content
|
||||
end
|
||||
end
|
||||
|
||||
{
|
||||
"key_val_separator => ''," => /must contain exactly one/,
|
||||
"key_val_separator => ','," => /must contain exactly one/,
|
||||
"key_val_separator => ' '," => /must contain exactly one/,
|
||||
"key_val_separator => ' == '," => /must contain exactly one/,
|
||||
}.each do |parameter, error|
|
||||
context "with \"#{parameter}\" raises \"#{error}\"" do
|
||||
pp = <<-EOS
|
||||
ini_setting { "with #{parameter} raises #{error}":
|
||||
ensure => present,
|
||||
section => 'one',
|
||||
setting => 'two',
|
||||
value => 'three',
|
||||
path => "#{tmpdir}/key_val_separator.ini",
|
||||
#{parameter}
|
||||
}
|
||||
EOS
|
||||
|
||||
it_behaves_like 'has_error', "#{tmpdir}/key_val_separator.ini", pp, error
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,195 +0,0 @@
|
||||
require 'spec_helper_acceptance'
|
||||
|
||||
tmpdir = default.tmpdir('tmp')
|
||||
|
||||
describe 'ini_subsetting resource' do
|
||||
after :all do
|
||||
shell("rm #{tmpdir}/*.ini", :acceptable_exit_codes => [0,1,2])
|
||||
end
|
||||
|
||||
shared_examples 'has_content' do |path,pp,content|
|
||||
before :all do
|
||||
shell("rm #{path}", :acceptable_exit_codes => [0,1,2])
|
||||
end
|
||||
after :all do
|
||||
shell("cat #{path}", :acceptable_exit_codes => [0,1,2])
|
||||
shell("rm #{path}", :acceptable_exit_codes => [0,1,2])
|
||||
end
|
||||
|
||||
it 'applies the manifest twice' do
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
|
||||
describe file(path) do
|
||||
it { should be_file }
|
||||
it { should contain(content) }
|
||||
end
|
||||
end
|
||||
|
||||
shared_examples 'has_error' do |path,pp,error|
|
||||
before :all do
|
||||
shell("rm #{path}", :acceptable_exit_codes => [0,1,2])
|
||||
end
|
||||
after :all do
|
||||
shell("cat #{path}", :acceptable_exit_codes => [0,1,2])
|
||||
shell("rm #{path}", :acceptable_exit_codes => [0,1,2])
|
||||
end
|
||||
|
||||
it 'applies the manifest and gets a failure message' do
|
||||
expect(apply_manifest(pp, :expect_failures => true).stderr).to match(error)
|
||||
end
|
||||
|
||||
describe file(path) do
|
||||
it { should_not be_file }
|
||||
end
|
||||
end
|
||||
|
||||
describe 'ensure, section, setting, subsetting, & value parameters' do
|
||||
context '=> present with subsections' do
|
||||
pp = <<-EOS
|
||||
ini_subsetting { 'ensure => present for alpha':
|
||||
ensure => present,
|
||||
path => "#{tmpdir}/ini_subsetting.ini",
|
||||
section => 'one',
|
||||
setting => 'key',
|
||||
subsetting => 'alpha',
|
||||
value => 'bet',
|
||||
}
|
||||
ini_subsetting { 'ensure => present for beta':
|
||||
ensure => present,
|
||||
path => "#{tmpdir}/ini_subsetting.ini",
|
||||
section => 'one',
|
||||
setting => 'key',
|
||||
subsetting => 'beta',
|
||||
value => 'trons',
|
||||
}
|
||||
EOS
|
||||
|
||||
it 'applies the manifest twice' do
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
|
||||
describe file("#{tmpdir}/ini_subsetting.ini") do
|
||||
it { should be_file }
|
||||
#XXX Solaris 10 doesn't support multi-line grep
|
||||
it("should contain [one]\nkey = alphabet betatrons", :unless => fact('osfamily') == 'Solaris') {
|
||||
should contain("[one]\nkey = alphabet betatrons")
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
context 'ensure => absent' do
|
||||
before :all do
|
||||
if fact('osfamily') == 'Darwin'
|
||||
shell("echo \"[one]\nkey = alphabet betatrons\" > #{tmpdir}/ini_subsetting.ini")
|
||||
else
|
||||
shell("echo -e \"[one]\nkey = alphabet betatrons\" > #{tmpdir}/ini_subsetting.ini")
|
||||
end
|
||||
end
|
||||
|
||||
pp = <<-EOS
|
||||
ini_subsetting { 'ensure => absent for subsetting':
|
||||
ensure => absent,
|
||||
path => "#{tmpdir}/ini_subsetting.ini",
|
||||
section => 'one',
|
||||
setting => 'key',
|
||||
subsetting => 'alpha',
|
||||
}
|
||||
EOS
|
||||
|
||||
it 'applies the manifest twice' do
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
|
||||
describe file("#{tmpdir}/ini_subsetting.ini") do
|
||||
it { should be_file }
|
||||
it { should contain('[one]') }
|
||||
it { should contain('key = betatrons') }
|
||||
it { should_not contain('alphabet') }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'subsetting_separator' do
|
||||
{
|
||||
"" => "two = twinethree foobar",
|
||||
#"subsetting_separator => ''," => "two = twinethreefoobar", # breaks regex
|
||||
"subsetting_separator => ','," => "two = twinethree,foobar",
|
||||
"subsetting_separator => ' '," => "two = twinethree foobar",
|
||||
"subsetting_separator => ' == '," => "two = twinethree == foobar",
|
||||
"subsetting_separator => '='," => "two = twinethree=foobar",
|
||||
#"subsetting_separator => '---'," => "two = twinethree---foobar", # breaks regex
|
||||
}.each do |parameter, content|
|
||||
context "with \"#{parameter}\" makes \"#{content}\"" do
|
||||
pp = <<-EOS
|
||||
ini_subsetting { "with #{parameter} makes #{content}":
|
||||
ensure => present,
|
||||
section => 'one',
|
||||
setting => 'two',
|
||||
subsetting => 'twine',
|
||||
value => 'three',
|
||||
path => "#{tmpdir}/subsetting_separator.ini",
|
||||
#{parameter}
|
||||
}
|
||||
ini_subsetting { "foobar":
|
||||
ensure => present,
|
||||
section => 'one',
|
||||
setting => 'two',
|
||||
subsetting => 'foo',
|
||||
value => 'bar',
|
||||
path => "#{tmpdir}/subsetting_separator.ini",
|
||||
#{parameter}
|
||||
}
|
||||
EOS
|
||||
|
||||
it_behaves_like 'has_content', "#{tmpdir}/subsetting_separator.ini", pp, content
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'quote_char' do
|
||||
{
|
||||
['-Xmx'] => 'args=""',
|
||||
['-Xmx', '256m'] => 'args=-Xmx256m',
|
||||
['-Xmx', '512m'] => 'args="-Xmx512m"',
|
||||
['-Xms', '256m'] => 'args="-Xmx256m -Xms256m"',
|
||||
}.each do |parameter, content|
|
||||
context %Q{with '#{parameter.first}' #{parameter.length > 1 ? '=> \'' << parameter[1] << '\'' : 'absent'} makes '#{content}'} do
|
||||
path = File.join(tmpdir, 'ini_subsetting.ini')
|
||||
|
||||
before :all do
|
||||
shell(%Q{echo '[java]\nargs=-Xmx256m' > #{path}})
|
||||
end
|
||||
after :all do
|
||||
shell("cat #{path}", :acceptable_exit_codes => [0,1,2])
|
||||
shell("rm #{path}", :acceptable_exit_codes => [0,1,2])
|
||||
end
|
||||
|
||||
pp = <<-EOS
|
||||
ini_subsetting { '#{parameter.first}':
|
||||
ensure => #{parameter.length > 1 ? 'present' : 'absent'},
|
||||
path => '#{path}',
|
||||
section => 'java',
|
||||
setting => 'args',
|
||||
quote_char => '"',
|
||||
subsetting => '#{parameter.first}',
|
||||
value => '#{parameter.length > 1 ? parameter[1] : ''}'
|
||||
}
|
||||
EOS
|
||||
|
||||
it 'applies the manifest twice' do
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
|
||||
describe file("#{tmpdir}/ini_subsetting.ini") do
|
||||
it { should be_file }
|
||||
it { should contain(content) }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,10 +0,0 @@
|
||||
HOSTS:
|
||||
centos-510-x64:
|
||||
roles:
|
||||
- master
|
||||
platform: el-5-x86_64
|
||||
box : centos-510-x64-virtualbox-nocm
|
||||
box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-510-x64-virtualbox-nocm.box
|
||||
hypervisor : vagrant
|
||||
CONFIG:
|
||||
type: git
|
||||
@@ -1,10 +0,0 @@
|
||||
HOSTS:
|
||||
centos-59-x64:
|
||||
roles:
|
||||
- master
|
||||
platform: el-5-x86_64
|
||||
box : centos-59-x64-vbox4210-nocm
|
||||
box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-59-x64-vbox4210-nocm.box
|
||||
hypervisor : vagrant
|
||||
CONFIG:
|
||||
type: git
|
||||
@@ -1,12 +0,0 @@
|
||||
HOSTS:
|
||||
centos-64-x64:
|
||||
roles:
|
||||
- master
|
||||
- database
|
||||
- dashboard
|
||||
platform: el-6-x86_64
|
||||
box : centos-64-x64-vbox4210-nocm
|
||||
box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
|
||||
hypervisor : vagrant
|
||||
CONFIG:
|
||||
type: pe
|
||||
@@ -1,10 +0,0 @@
|
||||
HOSTS:
|
||||
centos-64-x64:
|
||||
roles:
|
||||
- master
|
||||
platform: el-6-x86_64
|
||||
box : centos-64-x64-vbox4210-nocm
|
||||
box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
|
||||
hypervisor : vagrant
|
||||
CONFIG:
|
||||
type: git
|
||||
@@ -1,10 +0,0 @@
|
||||
HOSTS:
|
||||
centos-65-x64:
|
||||
roles:
|
||||
- master
|
||||
platform: el-6-x86_64
|
||||
box : centos-65-x64-vbox436-nocm
|
||||
box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-65-x64-virtualbox-nocm.box
|
||||
hypervisor : vagrant
|
||||
CONFIG:
|
||||
type: foss
|
||||
@@ -1,10 +0,0 @@
|
||||
HOSTS:
|
||||
debian-607-x64:
|
||||
roles:
|
||||
- master
|
||||
platform: debian-6-amd64
|
||||
box : debian-607-x64-vbox4210-nocm
|
||||
box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-607-x64-vbox4210-nocm.box
|
||||
hypervisor : vagrant
|
||||
CONFIG:
|
||||
type: git
|
||||
@@ -1,10 +0,0 @@
|
||||
HOSTS:
|
||||
debian-73-x64:
|
||||
roles:
|
||||
- master
|
||||
platform: debian-7-amd64
|
||||
box : debian-73-x64-virtualbox-nocm
|
||||
box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-73-x64-virtualbox-nocm.box
|
||||
hypervisor : vagrant
|
||||
CONFIG:
|
||||
type: git
|
||||
@@ -1,10 +0,0 @@
|
||||
HOSTS:
|
||||
centos-64-x64:
|
||||
roles:
|
||||
- master
|
||||
platform: el-6-x86_64
|
||||
box : centos-64-x64-vbox4210-nocm
|
||||
box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box
|
||||
hypervisor : vagrant
|
||||
CONFIG:
|
||||
type: git
|
||||
@@ -1,10 +0,0 @@
|
||||
HOSTS:
|
||||
fedora-18-x64:
|
||||
roles:
|
||||
- master
|
||||
platform: fedora-18-x86_64
|
||||
box : fedora-18-x64-vbox4210-nocm
|
||||
box_url : http://puppet-vagrant-boxes.puppetlabs.com/fedora-18-x64-vbox4210-nocm.box
|
||||
hypervisor : vagrant
|
||||
CONFIG:
|
||||
type: git
|
||||
@@ -1,10 +0,0 @@
|
||||
HOSTS:
|
||||
sles-11sp1-x64:
|
||||
roles:
|
||||
- master
|
||||
platform: sles-11-x86_64
|
||||
box : sles-11sp1-x64-vbox4210-nocm
|
||||
box_url : http://puppet-vagrant-boxes.puppetlabs.com/sles-11sp1-x64-vbox4210-nocm.box
|
||||
hypervisor : vagrant
|
||||
CONFIG:
|
||||
type: git
|
||||
@@ -1,10 +0,0 @@
|
||||
HOSTS:
|
||||
ubuntu-server-10044-x64:
|
||||
roles:
|
||||
- master
|
||||
platform: ubuntu-10.04-amd64
|
||||
box : ubuntu-server-10044-x64-vbox4210-nocm
|
||||
box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-10044-x64-vbox4210-nocm.box
|
||||
hypervisor : vagrant
|
||||
CONFIG:
|
||||
type: foss
|
||||
@@ -1,10 +0,0 @@
|
||||
HOSTS:
|
||||
ubuntu-server-12042-x64:
|
||||
roles:
|
||||
- master
|
||||
platform: ubuntu-12.04-amd64
|
||||
box : ubuntu-server-12042-x64-vbox4210-nocm
|
||||
box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box
|
||||
hypervisor : vagrant
|
||||
CONFIG:
|
||||
type: foss
|
||||
@@ -1,11 +0,0 @@
|
||||
HOSTS:
|
||||
ubuntu-server-1404-x64:
|
||||
roles:
|
||||
- master
|
||||
platform: ubuntu-14.04-amd64
|
||||
box : puppetlabs/ubuntu-14.04-64-nocm
|
||||
box_url : https://vagrantcloud.com/puppetlabs/ubuntu-14.04-64-nocm
|
||||
hypervisor : vagrant
|
||||
CONFIG:
|
||||
log_level : debug
|
||||
type: git
|
||||
@@ -1,24 +0,0 @@
|
||||
HOSTS:
|
||||
ubuntu1204:
|
||||
roles:
|
||||
- master
|
||||
- database
|
||||
- dashboard
|
||||
platform: ubuntu-12.04-amd64
|
||||
template: ubuntu-1204-x86_64
|
||||
hypervisor: vcloud
|
||||
win2003_i386:
|
||||
roles:
|
||||
- agent
|
||||
- default
|
||||
platform: windows-2003-i386
|
||||
template: win-2003-i386
|
||||
hypervisor: vcloud
|
||||
CONFIG:
|
||||
nfs_server: none
|
||||
consoleport: 443
|
||||
datastore: instance0
|
||||
folder: Delivery/Quality Assurance/Enterprise/Dynamic
|
||||
resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
|
||||
pooling_api: http://vcloud.delivery.puppetlabs.net/
|
||||
pe_dir: http://neptune.puppetlabs.lan/3.2/ci-ready/
|
||||
@@ -1,24 +0,0 @@
|
||||
HOSTS:
|
||||
ubuntu1204:
|
||||
roles:
|
||||
- master
|
||||
- database
|
||||
- dashboard
|
||||
platform: ubuntu-12.04-amd64
|
||||
template: ubuntu-1204-x86_64
|
||||
hypervisor: vcloud
|
||||
win2003r2_x86_64:
|
||||
roles:
|
||||
- agent
|
||||
- default
|
||||
platform: windows-2003r2-x86_64
|
||||
template: win-2003r2-x86_64
|
||||
hypervisor: vcloud
|
||||
CONFIG:
|
||||
nfs_server: none
|
||||
consoleport: 443
|
||||
datastore: instance0
|
||||
folder: Delivery/Quality Assurance/Enterprise/Dynamic
|
||||
resourcepool: delivery/Quality Assurance/Enterprise/Dynamic
|
||||
pooling_api: http://vcloud.delivery.puppetlabs.net/
|
||||
pe_dir: http://neptune.puppetlabs.lan/3.3/ci-ready/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user