Move Puppet resources to outside repos

This commit is contained in:
Przemyslaw Kaminski
2015-06-24 14:20:07 +02:00
parent 711bdb6c1b
commit 65c4e75580
566 changed files with 9 additions and 32418 deletions

View File

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

View File

@@ -1,4 +0,0 @@
class {'keystone':
admin_token => '{{ admin_token }}',
package_ensure => 'absent'
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,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.

View File

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

View File

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

View File

@@ -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/'
}

View File

@@ -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',
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,47 +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' |>
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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',
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,6 +0,0 @@
--format
s
--colour
--loadby
mtime
--backtrace

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -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}")
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -1,107 +0,0 @@
[![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-inifile.png?branch=master)](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 "".

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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