From 252969895a4836e5edcb6dae2233e0450c3bca5b Mon Sep 17 00:00:00 2001 From: vsaienko Date: Mon, 22 Jun 2015 18:50:19 +0300 Subject: [PATCH] sync keystone with upstream master de419015bb96d83135b306d9fb34e77e033c26cb sources https://github.com/openstack/puppet-keystone Partially Implements: blueprint upgrade-openstack-puppet-modules Fuel-CI: disable Change-Id: Idedef32288e214486d05225b09147b5b1c30cdab --- deployment/puppet/keystone/.fixtures.yml | 15 +- deployment/puppet/keystone/.gitreview | 4 - deployment/puppet/keystone/Gemfile | 19 +- deployment/puppet/keystone/LICENSE | 6 +- deployment/puppet/keystone/Modulefile | 13 - deployment/puppet/keystone/README.md | 102 +- .../puppet/keystone/examples/apache_dropin.pp | 26 +- .../keystone/examples/apache_with_paths.pp | 31 +- .../puppet/keystone/examples/ldap_full.pp | 106 ++- .../puppet/keystone/examples/ldap_identity.pp | 30 +- .../puppet/keystone/files/httpd/keystone.py | 1 + .../keystone/lib/puppet/provider/keystone.rb | 250 ++--- .../provider/keystone_endpoint/keystone.rb | 125 --- .../provider/keystone_endpoint/openstack.rb | 112 +++ .../keystone_paste_ini/ini_setting.rb | 27 + .../puppet/provider/keystone_role/keystone.rb | 65 -- .../provider/keystone_role/openstack.rb | 54 ++ .../provider/keystone_service/keystone.rb | 97 -- .../provider/keystone_service/openstack.rb | 88 ++ .../provider/keystone_tenant/keystone.rb | 120 --- .../provider/keystone_tenant/openstack.rb | 99 ++ .../puppet/provider/keystone_user/keystone.rb | 172 ---- .../provider/keystone_user/openstack.rb | 204 ++++ .../provider/keystone_user_role/keystone.rb | 229 ----- .../provider/keystone_user_role/openstack.rb | 131 +++ .../lib/puppet/type/keystone_endpoint.rb | 11 +- .../lib/puppet/type/keystone_paste_ini.rb | 43 + .../keystone/lib/puppet/type/keystone_role.rb | 5 +- .../lib/puppet/type/keystone_service.rb | 22 +- .../lib/puppet/type/keystone_tenant.rb | 32 +- .../keystone/lib/puppet/type/keystone_user.rb | 40 +- .../lib/puppet/type/keystone_user_role.rb | 30 +- .../puppet/keystone/manifests/client.pp | 4 +- .../keystone/manifests/cron/token_flush.pp | 75 ++ .../puppet/keystone/manifests/db/mysql.pp | 99 +- .../manifests/db/mysql/host_access.pp | 34 - .../keystone/manifests/db/postgresql.pp | 64 +- .../puppet/keystone/manifests/db/sync.pp | 2 + .../puppet/keystone/manifests/dev/install.pp | 6 + .../puppet/keystone/manifests/endpoint.pp | 146 +-- deployment/puppet/keystone/manifests/init.pp | 845 +++++++++++++---- deployment/puppet/keystone/manifests/ldap.pp | 772 +++++++++++++-- .../puppet/keystone/manifests/logging.pp | 211 +++++ .../puppet/keystone/manifests/params.pp | 23 +- .../puppet/keystone/manifests/policy.pp | 39 + .../puppet/keystone/manifests/python.pp | 10 + .../manifests/resource/service_identity.pp | 164 ++++ .../puppet/keystone/manifests/roles/admin.pp | 91 +- .../puppet/keystone/manifests/service.pp | 123 +++ .../puppet/keystone/manifests/wsgi/apache.pp | 144 +-- deployment/puppet/keystone/metadata.json | 39 + .../spec/acceptance/basic_keystone_spec.rb | 92 ++ .../spec/acceptance/nodesets/default.yml | 9 + .../acceptance/nodesets/nodepool-centos7.yml | 10 + .../acceptance/nodesets/nodepool-trusty.yml | 10 + .../spec/classes/keystone_client_spec.rb | 10 +- .../classes/keystone_cron_token_flush_spec.rb | 68 ++ .../spec/classes/keystone_db_mysql_spec.rb | 67 +- .../classes/keystone_db_postgresql_spec.rb | 58 +- .../spec/classes/keystone_endpoint_spec.rb | 56 +- .../spec/classes/keystone_ldap_spec.rb | 264 ++++-- .../spec/classes/keystone_logging_spec.rb | 107 +++ .../spec/classes/keystone_policy_spec.rb | 41 + .../spec/classes/keystone_python_spec.rb | 4 +- .../spec/classes/keystone_roles_admin_spec.rb | 89 +- .../spec/classes/keystone_service_spec.rb | 31 + .../keystone/spec/classes/keystone_spec.rb | 891 ++++++++++++------ .../spec/classes/keystone_wsgi_apache_spec.rb | 137 ++- ...keystone_resource_service_identity_spec.rb | 89 ++ .../puppet/keystone/spec/shared_examples.rb | 2 +- .../puppet/keystone/spec/spec_helper.rb | 7 +- .../keystone/spec/spec_helper_acceptance.rb | 46 + .../keystone_endpoint/keystone_spec.rb | 74 -- .../keystone_endpoint/openstack_spec.rb | 100 ++ .../keystone_paste_ini/ini_setting_spec.rb | 29 + .../provider/keystone_role/keystone_spec.rb | 16 - .../provider/keystone_role/openstack_spec.rb | 86 ++ .../keystone_service/keystone_spec.rb | 16 - .../keystone_service/openstack_spec.rb | 93 ++ .../spec/unit/provider/keystone_spec.rb | 137 +-- .../provider/keystone_tenant/keystone_spec.rb | 65 -- .../keystone_tenant/openstack_spec.rb | 90 ++ .../provider/keystone_user/keystone_spec.rb | 78 -- .../provider/keystone_user/openstack_spec.rb | 277 ++++++ .../keystone_user_role/keystone_spec.rb | 50 - .../keystone_user_role/openstack_spec.rb | 89 ++ .../spec/unit/type/keystone_paste_ini_spec.rb | 23 + .../spec/unit/type/keystone_user_role_spec.rb | 28 + deployment/puppet/keystone/tests/site.pp | 44 +- 89 files changed, 5785 insertions(+), 2798 deletions(-) delete mode 100644 deployment/puppet/keystone/.gitreview delete mode 100644 deployment/puppet/keystone/Modulefile delete mode 100644 deployment/puppet/keystone/lib/puppet/provider/keystone_endpoint/keystone.rb create mode 100644 deployment/puppet/keystone/lib/puppet/provider/keystone_endpoint/openstack.rb create mode 100644 deployment/puppet/keystone/lib/puppet/provider/keystone_paste_ini/ini_setting.rb delete mode 100644 deployment/puppet/keystone/lib/puppet/provider/keystone_role/keystone.rb create mode 100644 deployment/puppet/keystone/lib/puppet/provider/keystone_role/openstack.rb delete mode 100644 deployment/puppet/keystone/lib/puppet/provider/keystone_service/keystone.rb create mode 100644 deployment/puppet/keystone/lib/puppet/provider/keystone_service/openstack.rb delete mode 100644 deployment/puppet/keystone/lib/puppet/provider/keystone_tenant/keystone.rb create mode 100644 deployment/puppet/keystone/lib/puppet/provider/keystone_tenant/openstack.rb delete mode 100644 deployment/puppet/keystone/lib/puppet/provider/keystone_user/keystone.rb create mode 100644 deployment/puppet/keystone/lib/puppet/provider/keystone_user/openstack.rb delete mode 100644 deployment/puppet/keystone/lib/puppet/provider/keystone_user_role/keystone.rb create mode 100644 deployment/puppet/keystone/lib/puppet/provider/keystone_user_role/openstack.rb create mode 100644 deployment/puppet/keystone/lib/puppet/type/keystone_paste_ini.rb create mode 100644 deployment/puppet/keystone/manifests/cron/token_flush.pp delete mode 100644 deployment/puppet/keystone/manifests/db/mysql/host_access.pp create mode 100644 deployment/puppet/keystone/manifests/logging.pp create mode 100644 deployment/puppet/keystone/manifests/policy.pp create mode 100644 deployment/puppet/keystone/manifests/resource/service_identity.pp create mode 100644 deployment/puppet/keystone/manifests/service.pp create mode 100644 deployment/puppet/keystone/metadata.json create mode 100644 deployment/puppet/keystone/spec/acceptance/basic_keystone_spec.rb create mode 100644 deployment/puppet/keystone/spec/acceptance/nodesets/default.yml create mode 100644 deployment/puppet/keystone/spec/acceptance/nodesets/nodepool-centos7.yml create mode 100644 deployment/puppet/keystone/spec/acceptance/nodesets/nodepool-trusty.yml create mode 100644 deployment/puppet/keystone/spec/classes/keystone_cron_token_flush_spec.rb create mode 100644 deployment/puppet/keystone/spec/classes/keystone_logging_spec.rb create mode 100644 deployment/puppet/keystone/spec/classes/keystone_policy_spec.rb create mode 100644 deployment/puppet/keystone/spec/classes/keystone_service_spec.rb create mode 100644 deployment/puppet/keystone/spec/defines/keystone_resource_service_identity_spec.rb create mode 100644 deployment/puppet/keystone/spec/spec_helper_acceptance.rb delete mode 100644 deployment/puppet/keystone/spec/unit/provider/keystone_endpoint/keystone_spec.rb create mode 100644 deployment/puppet/keystone/spec/unit/provider/keystone_endpoint/openstack_spec.rb create mode 100644 deployment/puppet/keystone/spec/unit/provider/keystone_paste_ini/ini_setting_spec.rb delete mode 100644 deployment/puppet/keystone/spec/unit/provider/keystone_role/keystone_spec.rb create mode 100644 deployment/puppet/keystone/spec/unit/provider/keystone_role/openstack_spec.rb delete mode 100644 deployment/puppet/keystone/spec/unit/provider/keystone_service/keystone_spec.rb create mode 100644 deployment/puppet/keystone/spec/unit/provider/keystone_service/openstack_spec.rb delete mode 100644 deployment/puppet/keystone/spec/unit/provider/keystone_tenant/keystone_spec.rb create mode 100644 deployment/puppet/keystone/spec/unit/provider/keystone_tenant/openstack_spec.rb delete mode 100644 deployment/puppet/keystone/spec/unit/provider/keystone_user/keystone_spec.rb create mode 100644 deployment/puppet/keystone/spec/unit/provider/keystone_user/openstack_spec.rb delete mode 100644 deployment/puppet/keystone/spec/unit/provider/keystone_user_role/keystone_spec.rb create mode 100644 deployment/puppet/keystone/spec/unit/provider/keystone_user_role/openstack_spec.rb create mode 100644 deployment/puppet/keystone/spec/unit/type/keystone_paste_ini_spec.rb create mode 100644 deployment/puppet/keystone/spec/unit/type/keystone_user_role_spec.rb diff --git a/deployment/puppet/keystone/.fixtures.yml b/deployment/puppet/keystone/.fixtures.yml index 8ced34484a..73f11ff6c4 100644 --- a/deployment/puppet/keystone/.fixtures.yml +++ b/deployment/puppet/keystone/.fixtures.yml @@ -1,17 +1,14 @@ fixtures: repositories: 'apache': 'git://github.com/puppetlabs/puppetlabs-apache.git' - 'apt': 'git://github.com/puppetlabs/puppetlabs-apt.git' - 'mysql': - repo: 'git://github.com/puppetlabs/puppetlabs-mysql.git' - ref: 'origin/0.x' - 'stdlib': 'git://github.com/puppetlabs/puppetlabs-stdlib.git' - 'inifile': 'git://github.com/puppetlabs/puppetlabs-inifile' - 'postgresql': - repo: 'git://github.com/puppetlabs/puppetlabs-postgresql.git' - ref: '2.5.0' 'concat': 'repo': 'git://github.com/puppetlabs/puppetlabs-concat.git' 'ref': '1.2.1' + 'apt': 'git://github.com/puppetlabs/puppetlabs-apt.git' + 'mysql': 'git://github.com/puppetlabs/puppetlabs-mysql.git' + 'openstacklib': 'git://github.com/stackforge/puppet-openstacklib.git' + 'stdlib': 'git://github.com/puppetlabs/puppetlabs-stdlib.git' + 'inifile': 'git://github.com/puppetlabs/puppetlabs-inifile' + 'postgresql': 'git://github.com/puppetlabs/puppetlabs-postgresql.git' symlinks: 'keystone': "#{source_dir}" diff --git a/deployment/puppet/keystone/.gitreview b/deployment/puppet/keystone/.gitreview deleted file mode 100644 index 23429b7286..0000000000 --- a/deployment/puppet/keystone/.gitreview +++ /dev/null @@ -1,4 +0,0 @@ -[gerrit] -host=review.openstack.org -port=29418 -project=stackforge/puppet-keystone.git diff --git a/deployment/puppet/keystone/Gemfile b/deployment/puppet/keystone/Gemfile index 0d35201b4d..4d9cab8af9 100644 --- a/deployment/puppet/keystone/Gemfile +++ b/deployment/puppet/keystone/Gemfile @@ -2,8 +2,23 @@ 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' + gem 'rspec-puppet', '~> 2.1.0', :require => false + + gem 'metadata-json-lint' + gem 'puppet-lint-param-docs' + gem 'puppet-lint-absolute_classname-check' + gem 'puppet-lint-absolute_template_path' + gem 'puppet-lint-trailing_newline-check' + + # Puppet 4.x related lint checks + gem 'puppet-lint-unquoted_string-check' + gem 'puppet-lint-leading_zero-check' + gem 'puppet-lint-variable_contains_upcase' + gem 'puppet-lint-numericvariable' + + gem 'json' + gem 'webmock' + gem 'beaker-rspec', :require => false end if puppetversion = ENV['PUPPET_GEM_VERSION'] diff --git a/deployment/puppet/keystone/LICENSE b/deployment/puppet/keystone/LICENSE index 0bc44c17d2..88a11a0e77 100644 --- a/deployment/puppet/keystone/LICENSE +++ b/deployment/puppet/keystone/LICENSE @@ -1,8 +1,4 @@ -Puppet Labs Keystone Module - Puppet module for managing Keystone - -Copyright (C) 2012 Puppet Labs Inc - -Puppet Labs can be contacted at: info@puppetlabs.com +Copyright 2012 OpenStack Foundation Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/deployment/puppet/keystone/Modulefile b/deployment/puppet/keystone/Modulefile deleted file mode 100644 index a520e7d3c7..0000000000 --- a/deployment/puppet/keystone/Modulefile +++ /dev/null @@ -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' diff --git a/deployment/puppet/keystone/README.md b/deployment/puppet/keystone/README.md index eb35f4cac3..1f9ec2b244 100644 --- a/deployment/puppet/keystone/README.md +++ b/deployment/puppet/keystone/README.md @@ -1,7 +1,7 @@ keystone ======= -4.0.0 - 2014.1.0 - Icehouse +5.1.0 - 2014.2 - Juno #### Table of Contents @@ -45,10 +45,10 @@ To utilize the keystone module's functionality you will need to declare multiple ```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', + verbose => True, + catalog_type => 'sql', + admin_token => 'random_uuid', + database_connection => 'mysql://keystone_admin:super_secret_db_password@openstack-controller.example.com/keystone', } # Adds the admin credential to keystone. @@ -59,10 +59,10 @@ class { 'keystone::roles::admin': # 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', + public_url => 'http://10.16.0.101:5000/v2.0', + admin_url => 'http://10.16.1.101:35357/v2.0', + internal_url => 'http://10.16.2.101:5000/v2.0', + region => 'example-1', } ``` @@ -148,7 +148,17 @@ Limitations * If you've setup Openstack using previous versions of this module you need to be aware that it used UUID as the dedault to the token_format parameter but now defaults to PKI. If you're using this module to manage a Grizzly Openstack deployment that was set up using a development release of the modules or are attempting an upgrade from Folsom then you'll need to make sure you set the token_format to UUID at classification time. -* The Keystone Openstack service depends on a sqlalchemy database. If you are using puppetlabs-mysql to achieve this, there is a parameter called mysql_module that can be used to swap between the two supported versions: 0.9 and 2.2. This is needed because the puppetlabs-mysql module was rewritten and the custom type names have changed between versions. +Beaker-Rspec +------------ + +This module has beaker-rspec tests + +To run: + +``shell +bundle install +bundle exec rspec spec/acceptance +`` Development ----------- @@ -165,6 +175,78 @@ Contributors Release Notes ------------- +**5.1.0** + +* Allow disabling or delaying the token_flush cron +* crontab: ensure the script is run with shell +* Use openstackclient for keystone_* providers +* Add lib directories to $LOAD_PATH if not present +* Remove keystone.rb provider for keystone_endpoint +* Add timeout to API requests +* Test keystone_user password with Net::HTTP +* service_identity: add user/role ordering +* Fix password check for SSL endpoints +* add require json for to_json dependency +* spec: pin rspec-puppet to 1.0.1 +* Switch to TLSv1 +* handle missing project/tenant when using ldap backend +* Add support for LDAP connection pools +* Sync keystone.py with upstream to function with Juno +* Create resource cache upon creation +* Implement caching lookup for keystone_user_role +* Remove warnings from openstack responses +* Properly handle embedded newlines in csv +* support the ldap user_enabled_invert parameter +* Shorten HTTP request timeout length +* Tag packages with 'openstack' +* Allow Keystone to be queried when using IPv6 ::0 +* Add ::keystone::policy class for policy management +* New option replace_password for keystone_user +* Pin puppetlabs-concat to 1.2.1 in fixtures +* Set WSGI process display-name +* Rename resource instance variable +* Add native types for keystone paste configuration +* Update .gitreview file for project rename + +**5.0.0** + +* Stable Juno release +* Updated token driver, logging, and ldap config parameters for Juno +* Changed admin_roles parameter to accept an array in order to configure multiple admin roles +* Installs python-ldappool package for ldap +* Added new parameters to keystone class to configure pki signing +* Changed keystone class to inherit from keystone::params +* Changed pki_setup to run regardless of token provider +* Made UUID the default token provider +* Made keystone_user_role idempotent +* Added parameters to control whether to configure users +* Stopped managing _member_ role since it is created automatically +* Stopped overriding token_flush log file +* Changed the usage of admin_endpoint to not include the API version +* Allowed keystone_user_role to accept email as username +* Added ability to set up keystone using Apache mod_wsgi +* Migrated the keystone::db::mysql class to use openstacklib::db::mysql and deprecated the mysql_module parameter +* Installs python-memcache when using token driver memcache +* Enabled setting cert and key paths for PKI token signing +* Added parameters for SSL communication between keystone and rabbitmq +* Added parameter ignore_default_tenant to keystone::role::admin +* Added parameter service_provider to keystone class +* Added parameters for service validation to keystone class + +**4.2.0** + +* Added class for extended logging options +* Fixed rabbit password leaking +* Added parameters to set tenant descriptions +* Fixed keystone user authorization error handling + +**4.1.0** + +* Added token flushing with cron. +* Updated database api for consistency with other projects. +* Fixed admin_token with secret parameter. +* Fixed deprecated catalog driver. + **4.0.0** * Stable Icehouse release. diff --git a/deployment/puppet/keystone/examples/apache_dropin.pp b/deployment/puppet/keystone/examples/apache_dropin.pp index 310f0a3fd6..5ed29264fe 100644 --- a/deployment/puppet/keystone/examples/apache_dropin.pp +++ b/deployment/puppet/keystone/examples/apache_dropin.pp @@ -20,30 +20,30 @@ Exec { logoutput => 'on_failure' } -class { 'mysql::server': } -class { 'keystone::db::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', - enabled => false, +class { '::keystone': + verbose => true, + debug => true, + database_connection => 'mysql://keystone:keystone@127.0.0.1/keystone', + catalog_type => 'sql', + admin_token => 'admin_token', + enabled => false, } -class { 'keystone::roles::admin': +class { '::keystone::roles::admin': email => 'test@puppetlabs.com', password => 'ChangeMe', } -class { 'keystone::endpoint': +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': +include ::apache +class { '::keystone::wsgi::apache': ssl => true } diff --git a/deployment/puppet/keystone/examples/apache_with_paths.pp b/deployment/puppet/keystone/examples/apache_with_paths.pp index b616071a89..8b0fc699c0 100644 --- a/deployment/puppet/keystone/examples/apache_with_paths.pp +++ b/deployment/puppet/keystone/examples/apache_with_paths.pp @@ -20,31 +20,32 @@ Exec { logoutput => 'on_failure' } -class { 'mysql::server': } -class { 'keystone::db::mysql': +class { '::mysql::server': } +class { '::keystone::db::mysql': password => 'keystone', } -class { 'keystone': - verbose => true, - debug => true, - sql_connection => 'mysql://keystone_admin:keystone@127.0.0.1/keystone', - catalog_type => 'sql', - admin_token => 'admin_token', - enabled => true, +class { '::keystone': + verbose => true, + debug => true, + database_connection => 'mysql://keystone_admin:keystone@127.0.0.1/keystone', + catalog_type => 'sql', + admin_token => 'admin_token', + enabled => true, } -class { 'keystone::roles::admin': +class { '::keystone::cron::token_flush': } +class { '::keystone::roles::admin': email => 'test@puppetlabs.com', password => 'ChangeMe', } -class { 'keystone::endpoint': - public_url => "https://${::fqdn}:443/main/", - admin_address => "https://${::fqdn}:443/admin/", +class { '::keystone::endpoint': + public_url => "https://${::fqdn}:443/main/", + admin_url => "https://${::fqdn}:443/admin/", } keystone_config { 'ssl/enable': ensure => absent } -include apache -class { 'keystone::wsgi::apache': +include ::apache +class { '::keystone::wsgi::apache': ssl => true, public_port => 443, admin_port => 443, diff --git a/deployment/puppet/keystone/examples/ldap_full.pp b/deployment/puppet/keystone/examples/ldap_full.pp index d8f1d41135..09ce7c8eff 100644 --- a/deployment/puppet/keystone/examples/ldap_full.pp +++ b/deployment/puppet/keystone/examples/ldap_full.pp @@ -3,7 +3,7 @@ # Ensure this matches what is in LDAP or keystone will try to recreate # the admin user -class { 'keystone::roles::admin': +class { '::keystone::roles::admin': email => 'test@example.com', password => 'ChangeMe', } @@ -12,55 +12,61 @@ class { 'keystone::roles::admin': # 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 \ +# ldapsearch -v -x -H 'ldap://example.com: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', +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', + project_tree_dn => 'ou=projects,ou=openstack,dc=example,dc=com', + project_objectclass => 'organizationalUnit', + project_id_attribute => 'ou', + project_member_attribute => 'member', + project_name_attribute => 'ou', + project_desc_attribute => 'description', + project_allow_create => 'True', + project_allow_update => 'True', + project_allow_delete => 'True', + project_enabled_emulation => 'True', + project_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', + use_pool => 'True', + use_auth_pool => 'True', + pool_size => 5, + auth_pool_size => 5, + pool_retry_max => 3, + pool_connection_timeout => 120, } diff --git a/deployment/puppet/keystone/examples/ldap_identity.pp b/deployment/puppet/keystone/examples/ldap_identity.pp index 41272c52f1..f3a578cae2 100644 --- a/deployment/puppet/keystone/examples/ldap_identity.pp +++ b/deployment/puppet/keystone/examples/ldap_identity.pp @@ -3,7 +3,7 @@ # Ensure this matches what is in LDAP or keystone will try to recreate # the admin user -class { 'keystone::roles::admin': +class { '::keystone::roles::admin': email => 'test@example.com', password => 'ChangeMe', } @@ -11,18 +11,18 @@ class { 'keystone::roles::admin': # 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' +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' } diff --git a/deployment/puppet/keystone/files/httpd/keystone.py b/deployment/puppet/keystone/files/httpd/keystone.py index 2e7f3a913b..04efb2ab80 100644 --- a/deployment/puppet/keystone/files/httpd/keystone.py +++ b/deployment/puppet/keystone/files/httpd/keystone.py @@ -13,6 +13,7 @@ # under the License. # +# This file was copied from https://github.com/openstack/keystone/raw/0b676730347c76c7f64a67c1ad0135663e99c4fc/httpd/keystone.py # It's only required for platforms on which it is not packaged yet. # It should be removed when available everywhere in a package. # diff --git a/deployment/puppet/keystone/lib/puppet/provider/keystone.rb b/deployment/puppet/keystone/lib/puppet/provider/keystone.rb index ead9f47283..4e7815abf7 100644 --- a/deployment/puppet/keystone/lib/puppet/provider/keystone.rb +++ b/deployment/puppet/keystone/lib/puppet/provider/keystone.rb @@ -1,7 +1,35 @@ require 'puppet/util/inifile' -class Puppet::Provider::Keystone < Puppet::Provider +require 'puppet/provider/openstack' +require 'puppet/provider/openstack/auth' +require 'puppet/provider/openstack/credentials' + +class Puppet::Provider::Keystone < Puppet::Provider::Openstack + + extend Puppet::Provider::Openstack::Auth + + INI_FILENAME = '/etc/keystone/keystone.conf' + + def self.get_endpoint + endpoint = nil + if ENV['OS_AUTH_URL'] + endpoint = ENV['OS_AUTH_URL'] + else + endpoint = get_os_vars_from_rcfile(rc_filename)['OS_AUTH_URL'] + unless endpoint + # This is from legacy but seems wrong, we want auth_url not url! + endpoint = get_admin_endpoint + end + end + unless endpoint + raise(Puppet::Error::OpenstackAuthInputError, 'Could not find auth url to check user password.') + end + endpoint + end + + def self.admin_endpoint + @admin_endpoint ||= get_admin_endpoint + end - # retrieves the current token from keystone.conf def self.admin_token @admin_token ||= get_admin_token end @@ -10,181 +38,79 @@ class Puppet::Provider::Keystone < Puppet::Provider 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") + return nil 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 + if keystone_file + if keystone_file['DEFAULT'] + if keystone_file['DEFAULT']['admin_endpoint'] + auth_url = keystone_file['DEFAULT']['admin_endpoint'].strip.chomp('/') + return "#{auth_url}/v#{@credentials.version}/" + end - admin_port = keystone_file['DEFAULT']['admin_port'] ? keystone_file['DEFAULT']['admin_port'].strip : '35357' - 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" + if keystone_file['DEFAULT']['admin_port'] + admin_port = keystone_file['DEFAULT']['admin_port'].strip + else + admin_port = '35357' + end + + if keystone_file['DEFAULT']['admin_bind_host'] + host = keystone_file['DEFAULT']['admin_bind_host'].strip + if host == "0.0.0.0" + host = "127.0.0.1" + elsif host == '::0' + host = '[::1]' + end + else + host = "127.0.0.1" + end + end + + if keystone_file['ssl'] && keystone_file['ssl']['enable'] && keystone_file['ssl']['enable'].strip.downcase == 'true' + protocol = 'https' + else + protocol = 'http' end - else - host = "127.0.0.1" end - "#{protocol}://#{host}:#{admin_port}/v2.0/" + + "#{protocol}://#{host}:#{admin_port}/v#{@credentials.version}/" + end + + def self.request(service, action, properties=nil) + super + rescue Puppet::Error::OpenstackAuthInputError => error + request_by_service_token(service, action, error, properties) + end + + def self.request_by_service_token(service, action, error, properties=nil) + properties ||= [] + @credentials.token = get_admin_token + @credentials.url = get_admin_endpoint + raise error unless @credentials.service_token_set? + Puppet::Provider::Openstack.request(service, action, properties, @credentials) + end + + def self.ini_filename + INI_FILENAME end 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 + if File.exists?(ini_filename) + @keystone_file = Puppet::Util::IniConfig::File.new + @keystone_file.read(ini_filename) + @keystone_file 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 + # Helper functions to use on the pre-validated enabled field + def bool_to_sym(bool) + bool == true ? :true : :false end - def auth_keystone(*args) - self.class.auth_keystone(args) + def sym_to_bool(sym) + sym == :true ? true : false 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 diff --git a/deployment/puppet/keystone/lib/puppet/provider/keystone_endpoint/keystone.rb b/deployment/puppet/keystone/lib/puppet/provider/keystone_endpoint/keystone.rb deleted file mode 100644 index c7696c8a60..0000000000 --- a/deployment/puppet/keystone/lib/puppet/provider/keystone_endpoint/keystone.rb +++ /dev/null @@ -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 diff --git a/deployment/puppet/keystone/lib/puppet/provider/keystone_endpoint/openstack.rb b/deployment/puppet/keystone/lib/puppet/provider/keystone_endpoint/openstack.rb new file mode 100644 index 0000000000..97de693d86 --- /dev/null +++ b/deployment/puppet/keystone/lib/puppet/provider/keystone_endpoint/openstack.rb @@ -0,0 +1,112 @@ +require 'puppet/provider/keystone' + +Puppet::Type.type(:keystone_endpoint).provide( + :openstack, + :parent => Puppet::Provider::Keystone +) do + + desc "Provider to manage keystone endpoints." + + @credentials = Puppet::Provider::Openstack::CredentialsV2_0.new + + def initialize(value={}) + super(value) + @property_flush = {} + end + + def create + properties = [] + # The region property is just ignored. We should fix this in kilo. + region, name = resource[:name].split('/') + properties << name + properties << '--region' + properties << region + if resource[:public_url] + properties << '--publicurl' + properties << resource[:public_url] + end + if resource[:internal_url] + properties << '--internalurl' + properties << resource[:internal_url] + end + if resource[:admin_url] + properties << '--adminurl' + properties << resource[:admin_url] + end + self.class.request('endpoint', 'create', properties) + @property_hash[:ensure] = :present + end + + def destroy + self.class.request('endpoint', 'delete', @property_hash[:id]) + @property_hash.clear + end + + def exists? + @property_hash[:ensure] == :present + end + + def region + @property_hash[:region] + end + + def public_url=(value) + @property_flush[:public_url] = value + end + + def public_url + @property_hash[:public_url] + end + + def internal_url=(value) + @property_flush[:internal_url] = value + end + + def internal_url + @property_hash[:internal_url] + end + + def admin_url=(value) + @property_flush[:admin_url] = value + end + + def admin_url + @property_hash[:admin_url] + end + + def id + @property_hash[:id] + end + + def self.instances + list = request('endpoint', 'list', '--long') + list.collect do |endpoint| + new( + :name => "#{endpoint[:region]}/#{endpoint[:service_name]}", + :ensure => :present, + :id => endpoint[:id], + :region => endpoint[:region], + :public_url => endpoint[:publicurl], + :internal_url => endpoint[:internalurl], + :admin_url => endpoint[:adminurl] + ) + end + end + + def self.prefetch(resources) + endpoints = instances + resources.keys.each do |name| + if provider = endpoints.find{ |endpoint| endpoint.name == name } + resources[name].provider = provider + end + end + end + + def flush + if ! @property_flush.empty? + destroy + create + @property_flush.clear + end + end +end diff --git a/deployment/puppet/keystone/lib/puppet/provider/keystone_paste_ini/ini_setting.rb b/deployment/puppet/keystone/lib/puppet/provider/keystone_paste_ini/ini_setting.rb new file mode 100644 index 0000000000..23a47af659 --- /dev/null +++ b/deployment/puppet/keystone/lib/puppet/provider/keystone_paste_ini/ini_setting.rb @@ -0,0 +1,27 @@ +Puppet::Type.type(:keystone_paste_ini).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def self.file_path + '/etc/keystone/keystone-paste.ini' + end + + # this needs to be removed. This has been replaced with the class method + def file_path + self.class.file_path + end + +end diff --git a/deployment/puppet/keystone/lib/puppet/provider/keystone_role/keystone.rb b/deployment/puppet/keystone/lib/puppet/provider/keystone_role/keystone.rb deleted file mode 100644 index 82ec84908d..0000000000 --- a/deployment/puppet/keystone/lib/puppet/provider/keystone_role/keystone.rb +++ /dev/null @@ -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 diff --git a/deployment/puppet/keystone/lib/puppet/provider/keystone_role/openstack.rb b/deployment/puppet/keystone/lib/puppet/provider/keystone_role/openstack.rb new file mode 100644 index 0000000000..b15462047d --- /dev/null +++ b/deployment/puppet/keystone/lib/puppet/provider/keystone_role/openstack.rb @@ -0,0 +1,54 @@ +require 'puppet/provider/keystone' + +Puppet::Type.type(:keystone_role).provide( + :openstack, + :parent => Puppet::Provider::Keystone +) do + + desc 'Provider for keystone roles.' + + @credentials = Puppet::Provider::Openstack::CredentialsV2_0.new + + def initialize(value={}) + super(value) + @property_flush = {} + end + + def create + self.class.request('role', 'create', name) + @property_hash[:ensure] = :present + end + + def destroy + self.class.request('role', 'delete', @property_hash[:id]) + @property_hash.clear + end + + def exists? + @property_hash[:ensure] == :present + end + + def id + @property_hash[:id] + end + + def self.instances + list = request('role', 'list') + list.collect do |role| + new( + :name => role[:name], + :ensure => :present, + :id => role[:id] + ) + end + end + + def self.prefetch(resources) + roles = instances + resources.keys.each do |name| + if provider = roles.find{ |role| role.name == name } + resources[name].provider = provider + end + end + end +end diff --git a/deployment/puppet/keystone/lib/puppet/provider/keystone_service/keystone.rb b/deployment/puppet/keystone/lib/puppet/provider/keystone_service/keystone.rb deleted file mode 100644 index 4cec32772c..0000000000 --- a/deployment/puppet/keystone/lib/puppet/provider/keystone_service/keystone.rb +++ /dev/null @@ -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 diff --git a/deployment/puppet/keystone/lib/puppet/provider/keystone_service/openstack.rb b/deployment/puppet/keystone/lib/puppet/provider/keystone_service/openstack.rb new file mode 100644 index 0000000000..4853b7d272 --- /dev/null +++ b/deployment/puppet/keystone/lib/puppet/provider/keystone_service/openstack.rb @@ -0,0 +1,88 @@ +require 'puppet/provider/keystone' + +Puppet::Type.type(:keystone_service).provide( + :openstack, + :parent => Puppet::Provider::Keystone +) do + + desc "Provider to manage keystone services." + + @credentials = Puppet::Provider::Openstack::CredentialsV2_0.new + + def initialize(value={}) + super(value) + @property_flush = {} + end + + def create + properties = ['--name'] + properties << resource[:name] + if resource[:description] + properties << '--description' + properties << resource[:description] + end + raise(Puppet::Error, 'The service type is mandatory') unless resource[:type] + properties << resource[:type] + self.class.request('service', 'create', properties) + @property_hash[:ensure] = :present + end + + def exists? + @property_hash[:ensure] == :present + end + + def destroy + self.class.request('service', 'delete', @property_hash[:id]) + @property_hash.clear + end + + def description=(value) + @property_flush[:description] = value + end + + def description + @property_hash[:description] + end + + def type=(value) + @property_flush[:type] = value + end + + def type + @property_hash[:type] + end + + def id + @property_hash[:id] + end + + def self.instances + list = request('service', 'list', '--long') + list.collect do |service| + new( + :name => service[:name], + :ensure => :present, + :type => service[:type], + :description => service[:description], + :id => service[:id] + ) + end + end + + def self.prefetch(resources) + services = instances + resources.keys.each do |name| + if provider = services.find{ |service| service.name == name } + resources[name].provider = provider + end + end + end + + def flush + if ! @property_flush.empty? + destroy + create + @property_flush.clear + end + end +end diff --git a/deployment/puppet/keystone/lib/puppet/provider/keystone_tenant/keystone.rb b/deployment/puppet/keystone/lib/puppet/provider/keystone_tenant/keystone.rb deleted file mode 100644 index 59501f0542..0000000000 --- a/deployment/puppet/keystone/lib/puppet/provider/keystone_tenant/keystone.rb +++ /dev/null @@ -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 diff --git a/deployment/puppet/keystone/lib/puppet/provider/keystone_tenant/openstack.rb b/deployment/puppet/keystone/lib/puppet/provider/keystone_tenant/openstack.rb new file mode 100644 index 0000000000..198798477d --- /dev/null +++ b/deployment/puppet/keystone/lib/puppet/provider/keystone_tenant/openstack.rb @@ -0,0 +1,99 @@ +require 'puppet/provider/keystone' + +Puppet::Type.type(:keystone_tenant).provide( + :openstack, + :parent => Puppet::Provider::Keystone +) do + + desc "Provider to manage keystone tenants/projects." + + @credentials = Puppet::Provider::Openstack::CredentialsV2_0.new + + def initialize(value={}) + super(value) + @property_flush = {} + end + + def create + properties = [resource[:name]] + if resource[:enabled] == :true + properties << '--enable' + elsif resource[:enabled] == :false + properties << '--disable' + end + if resource[:description] + properties << '--description' + properties << resource[:description] + end + self.class.request('project', 'create', properties) + @property_hash[:ensure] = :present + end + + def exists? + @property_hash[:ensure] == :present + end + + def destroy + self.class.request('project', 'delete', @property_hash[:id]) + @property_hash.clear + end + + def enabled=(value) + @property_flush[:enabled] = value + end + + def enabled + bool_to_sym(@property_hash[:enabled]) + end + + def description=(value) + @property_flush[:description] = value + end + + def description + @property_hash[:description] + end + + def id + @property_hash[:id] + end + + def self.instances + list = request('project', 'list', '--long') + list.collect do |project| + new( + :name => project[:name], + :ensure => :present, + :enabled => project[:enabled].downcase.chomp == 'true' ? true : false, + :description => project[:description], + :id => project[:id] + ) + end + end + + def self.prefetch(resources) + tenants = instances + resources.keys.each do |name| + if provider = tenants.find{ |tenant| tenant.name == name } + resources[name].provider = provider + end + end + end + + def flush + options = [] + if @property_flush && !@property_flush.empty? + case @property_flush[:enabled] + when :true + options << '--enable' + when :false + options << '--disable' + end + (options << "--description=#{resource[:description]}") if @property_flush[:description] + options << @property_hash[:id] + self.class.request('project', 'set', options) unless options.empty? + @property_flush.clear + end + end + +end diff --git a/deployment/puppet/keystone/lib/puppet/provider/keystone_user/keystone.rb b/deployment/puppet/keystone/lib/puppet/provider/keystone_user/keystone.rb deleted file mode 100644 index 3004097b30..0000000000 --- a/deployment/puppet/keystone/lib/puppet/provider/keystone_user/keystone.rb +++ /dev/null @@ -1,172 +0,0 @@ -$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', '..')) -require 'puppet/provider/keystone' -Puppet::Type.type(:keystone_user).provide( - :keystone, - :parent => Puppet::Provider::Keystone -) do - - desc <<-EOT - Provider that uses the keystone client tool to - manage keystone users - - This provider makes a few assumptions/ - 1. assumes that the admin endpoint can be accessed via localhost. - 2. Assumes that the admin token and port can be accessed from - /etc/keystone/keystone.conf - - Does not support the ability to update the user's name - EOT - - optional_commands :keystone => "keystone" - - def self.prefetch(resource) - # rebuild the cahce for every puppet run - @user_hash = nil - end - - def self.user_hash - @user_hash = build_user_hash - end - - def user_hash - self.class.user_hash - end - - def self.instances - user_hash.collect do |k, v| - new(:name => k) - end - end - - def create - optional_opts = [] - if resource[:email] - optional_opts.push('--email').push(resource[:email]) - end - if resource[:password] - optional_opts.push('--pass').push(resource[:password]) - end - if resource[:tenant] - tenant_id = self.class.list_keystone_objects('tenant', 3).collect {|x| - x[0] if x[1] == resource[:tenant] - }.compact[0] - optional_opts.push('--tenant_id').push(tenant_id) - end - auth_keystone( - 'user-create', - '--name', resource[:name], - '--enabled', resource[:enabled], - optional_opts - ) - end - - def exists? - user_hash[resource[:name]] - end - - def destroy - auth_keystone('user-delete', user_hash[resource[:name]][:id]) - end - - def enabled - user_hash[resource[:name]][:enabled] - end - - def enabled=(value) - auth_keystone( - "user-update", - '--enabled', value, - user_hash[resource[:name]][:id] - ) - end - - def password - # if we don't know a password we can't test it - return nil if resource[:password] == nil - # we can't get the value of the password but we can test to see if the one we know - # about works, if it doesn't then return nil, causing it to be reset - begin - token_out = creds_keystone(resource[:name], resource[:tenant], resource[:password], "token-get") - rescue Exception => e - return nil if e.message =~ /Not Authorized/ or e.message =~ /HTTP 401/ - raise e - end - return resource[:password] - end - - def password=(value) - if resource[:replace_password] == 'True' - auth_keystone('user-password-update', '--pass', value, user_hash[resource[:name]][:id]) - end - end - - def tenant - return resource[:tenant] if resource[:ignore_default_tenant] - user_id = user_hash[resource[:name]][:id] - begin - tenantId = self.class.get_keystone_object('user', user_id, 'tenantId') - rescue - tenantId = nil - end - if tenantId.nil? or tenantId == 'None' or tenantId.empty? - tenant = 'None' - else - # this prevents is from failing if tenant no longer exists - begin - tenant = self.class.get_keystone_object('tenant', tenantId, 'name') - rescue - tenant = 'None' - end - end - tenant - end - - def tenant=(value) - fail("tenant cannot be updated. Transition requested: #{user_hash[resource[:name]][:tenant]} -> #{value}") - end - - def email - user_hash[resource[:name]][:email] - end - - def email=(value) - auth_keystone( - "user-update", - '--email', value, - user_hash[resource[:name]][:id] - ) - end - - def replace_password - user_hash[resource[:name]][:replace_password] - end - - def replace_password=(value) - user_hash[resource[:name]][:replace_password] - end - - def id - user_hash[resource[:name]][:id] - end - - private - - def self.build_user_hash - hash = {} - list_keystone_objects('user', 4).each do |user| - password = 'nil' - replace_password = 'True', - hash[user[1]] = { - :id => user[0], - :enabled => user[2], - :email => user[3], - :name => user[1], - :password => password, - :replace_password => replace_password, - } - end - hash - end - -end - diff --git a/deployment/puppet/keystone/lib/puppet/provider/keystone_user/openstack.rb b/deployment/puppet/keystone/lib/puppet/provider/keystone_user/openstack.rb new file mode 100644 index 0000000000..98a34cd3cd --- /dev/null +++ b/deployment/puppet/keystone/lib/puppet/provider/keystone_user/openstack.rb @@ -0,0 +1,204 @@ +require 'puppet/provider/keystone' + +Puppet::Type.type(:keystone_user).provide( + :openstack, + :parent => Puppet::Provider::Keystone +) do + + desc "Provider to manage keystone users." + + @credentials = Puppet::Provider::Openstack::CredentialsV2_0.new + + def initialize(value={}) + super(value) + @property_flush = {} + end + + def create + properties = [resource[:name]] + if resource[:enabled] == :true + properties << '--enable' + elsif resource[:enabled] == :false + properties << '--disable' + end + if resource[:password] + properties << '--password' << resource[:password] + end + if resource[:tenant] + properties << '--project' << resource[:tenant] + end + if resource[:email] + properties << '--email' << resource[:email] + end + self.class.request('user', 'create', properties) + @property_hash[:ensure] = :present + end + + def destroy + self.class.request('user', 'delete', @property_hash[:id]) + @property_hash.clear + end + + def flush + options = [] + if @property_flush && !@property_flush.empty? + options << '--enable' if @property_flush[:enabled] == :true + options << '--disable' if @property_flush[:enabled] == :false + # There is a --description flag for the set command, but it does not work if the value is empty + options << '--password' << resource[:password] if @property_flush[:password] + options << '--email' << resource[:email] if @property_flush[:email] + # project handled in tenant= separately + unless options.empty? + options << @property_hash[:id] + self.class.request('user', 'set', options) + end + @property_flush.clear + end + end + + def exists? + @property_hash[:ensure] == :present + end + + # Types properties + def enabled + bool_to_sym(@property_hash[:enabled]) + end + + def enabled=(value) + @property_flush[:enabled] = value + end + + def email + @property_hash[:email] + end + + def email=(value) + @property_flush[:email] = value + end + + def id + @property_hash[:id] + end + + def password + res = nil + return res if resource[:password] == nil + if resource[:enabled] == :false || resource[:replace_password] == :false + # Unchanged password + res = resource[:password] + else + # Password validation + credentials = Puppet::Provider::Openstack::CredentialsV2_0.new + credentials.auth_url = self.class.get_endpoint + credentials.password = resource[:password] + credentials.project_name = resource[:tenant] + credentials.username = resource[:name] + begin + token = Puppet::Provider::Openstack.request('token', 'issue', ['--format', 'value'], credentials) + rescue Puppet::Error::OpenstackUnauthorizedError + # password is invalid + else + res = resource[:password] unless token.empty? + end + end + return res + end + + def password=(value) + @property_flush[:password] = value + end + + def replace_password + @property_hash[:replace_password] + end + + def replace_password=(value) + @property_flush[:replace_password] = value + end + + def tenant + return resource[:tenant] if sym_to_bool(resource[:ignore_default_tenant]) + # use the one returned from instances + tenant_name = @property_hash[:project] + if tenant_name.nil? or tenant_name.empty? + # if none (i.e. ldap backend) use the given one + tenant_name = resource[:tenant] + else + return tenant_name + end + if tenant_name.nil? or tenant_name.empty? + return nil # nothing found, nothing given + end + # If the user list command doesn't report the project, it might still be there + # We don't need to know exactly what it is, we just need to know whether it's + # the one we're trying to set. + roles = self.class.request('user role', 'list', [resource[:name], '--project', tenant_name]) + if roles.empty? + return nil + else + return tenant_name + end + end + + def tenant=(value) + self.class.request('user', 'set', [resource[:name], '--project', value]) + rescue Puppet::ExecutionFailure => e + if e.message =~ /You are not authorized to perform the requested action: LDAP user update/ + # read-only LDAP identity backend - just fall through + else + raise e + end + # note: read-write ldap will silently fail, not raise an exception + else + @property_hash[:tenant] = self.class.set_project(value, resource[:name]) + end + + def self.instances + list = request('user', 'list', '--long') + list.collect do |user| + new( + :name => user[:name], + :ensure => :present, + :enabled => user[:enabled].downcase.chomp == 'true' ? true : false, + :password => user[:password], + :project => user[:project], + :email => user[:email], + :id => user[:id] + ) + end + end + + def self.prefetch(resources) + users = instances + resources.keys.each do |name| + if provider = users.find{ |user| user.name == name } + resources[name].provider = provider + end + end + end + + def self.set_project(newproject, name) + # some backends do not store the project/tenant in the user object, so we have to + # to modify the project/tenant instead + # First, see if the project actually needs to change + roles = request('user role', 'list', [name, '--project', newproject]) + unless roles.empty? + return # if already set, just skip + end + # Currently the only way to assign a user to a tenant not using user-create + # is to use user-role-add - this means we also need a role - there is usual + # a default role called _member_ which can be used for this purpose. What + # usually happens in a puppet module is that immediately after calling + # keystone_user, the module will then assign a role to that user. It is + # ok for a user to have the _member_ role and another role. + default_role = "_member_" + begin + request('role', 'show', [default_role]) + rescue + debug("Keystone role #{default_role} does not exist - creating") + request('role', 'create', [default_role]) + end + request('role', 'add', [default_role, '--project', newproject, '--user', name]) + end +end diff --git a/deployment/puppet/keystone/lib/puppet/provider/keystone_user_role/keystone.rb b/deployment/puppet/keystone/lib/puppet/provider/keystone_user_role/keystone.rb deleted file mode 100644 index 84f7452f5f..0000000000 --- a/deployment/puppet/keystone/lib/puppet/provider/keystone_user_role/keystone.rb +++ /dev/null @@ -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 diff --git a/deployment/puppet/keystone/lib/puppet/provider/keystone_user_role/openstack.rb b/deployment/puppet/keystone/lib/puppet/provider/keystone_user_role/openstack.rb new file mode 100644 index 0000000000..da2b87044b --- /dev/null +++ b/deployment/puppet/keystone/lib/puppet/provider/keystone_user_role/openstack.rb @@ -0,0 +1,131 @@ +require 'puppet/provider/keystone' + +Puppet::Type.type(:keystone_user_role).provide( + :openstack, + :parent => Puppet::Provider::Keystone +) do + + desc "Provider to manage keystone role assignments to users." + + @credentials = Puppet::Provider::Openstack::CredentialsV2_0.new + + def initialize(value={}) + super(value) + @property_flush = {} + end + + def create + properties = [] + properties << '--project' << get_project + properties << '--user' << get_user + if resource[:roles] + resource[:roles].each do |role| + self.class.request('role', 'add', [role] + properties) + end + end + end + + def destroy + properties = [] + properties << '--project' << get_project + properties << '--user' << get_user + if @property_hash[:roles] + @property_hash[:roles].each do |role| + self.class.request('role', 'remove', [role] + properties) + end + end + @property_hash[:ensure] = :absent + end + + def exists? + if @user_role_hash + return ! @property_hash[:name].empty? + else + roles = self.class.request('user role', 'list', [get_user, '--project', get_project]) + # Since requesting every combination of users, roles, and + # projects is so expensive, construct the property hash here + # instead of in self.instances so it can be used in the role + # and destroy methods + @property_hash[:name] = resource[:name] + if roles.empty? + @property_hash[:ensure] = :absent + else + @property_hash[:ensure] = :present + @property_hash[:roles] = roles.collect do |role| + role[:name] + end + end + return @property_hash[:ensure] == :present + end + end + + def roles + @property_hash[:roles] + end + + def roles=(value) + current_roles = roles + # determine the roles to be added and removed + remove = current_roles - Array(value) + add = Array(value) - current_roles + user = get_user + project = get_project + add.each do |role_name| + self.class.request('role', 'add', [role_name, '--project', project, '--user', user]) + end + remove.each do |role_name| + self.class.request('role', 'remove', [role_name, '--project', project, '--user', user]) + end + end + + def self.instances + instances = build_user_role_hash + instances.collect do |title, roles| + new( + :name => title, + :ensure => :present, + :roles => roles + ) + end + end + + private + + def get_user + resource[:name].rpartition('@').first + end + + def get_project + resource[:name].rpartition('@').last + end + + def self.get_projects + request('project', 'list').collect { |project| project[:name] } + end + + def self.get_users(project) + request('user', 'list', ['--project', project]).collect { |user| user[:name] } + end + + def self.set_user_role_hash(user_role_hash) + @user_role_hash = user_role_hash + end + + def self.build_user_role_hash + hash = @user_role_hash || {} + return hash unless hash.empty? + projects = get_projects + projects.each do |project| + users = get_users(project) + users.each do |user| + user_roles = request('user role', 'list', [user, '--project', project]) + hash["#{user}@#{project}"] = [] + user_roles.each do |role| + hash["#{user}@#{project}"] << role[:name] + end + end + end + set_user_role_hash(hash) + hash + end +end diff --git a/deployment/puppet/keystone/lib/puppet/type/keystone_endpoint.rb b/deployment/puppet/keystone/lib/puppet/type/keystone_endpoint.rb index 3b461b5bc7..43c5eb2ea8 100644 --- a/deployment/puppet/keystone/lib/puppet/type/keystone_endpoint.rb +++ b/deployment/puppet/keystone/lib/puppet/type/keystone_endpoint.rb @@ -1,9 +1,10 @@ +# LP#1408531 +File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) } +File.expand_path('../../../../openstacklib/lib', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) } + Puppet::Type.newtype(:keystone_endpoint) do - desc <<-EOT - This is currently used to model the management of - keystone endpoint. - EOT + desc 'Type for managing keystone endpoints.' ensurable @@ -20,7 +21,6 @@ Puppet::Type.newtype(:keystone_endpoint) do newproperty(:region) do end - # TODO I should do some url validation newproperty(:public_url) do end @@ -39,5 +39,4 @@ Puppet::Type.newtype(:keystone_endpoint) do (region, service_name) = self[:name].split('/') [service_name] end - end diff --git a/deployment/puppet/keystone/lib/puppet/type/keystone_paste_ini.rb b/deployment/puppet/keystone/lib/puppet/type/keystone_paste_ini.rb new file mode 100644 index 0000000000..e315a95706 --- /dev/null +++ b/deployment/puppet/keystone/lib/puppet/type/keystone_paste_ini.rb @@ -0,0 +1,43 @@ +Puppet::Type.newtype(:keystone_paste_ini) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from keystone/keystone-paste.ini' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end + +end diff --git a/deployment/puppet/keystone/lib/puppet/type/keystone_role.rb b/deployment/puppet/keystone/lib/puppet/type/keystone_role.rb index 7893250ba3..3636afb279 100644 --- a/deployment/puppet/keystone/lib/puppet/type/keystone_role.rb +++ b/deployment/puppet/keystone/lib/puppet/type/keystone_role.rb @@ -1,3 +1,7 @@ +# LP#1408531 +File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) } +File.expand_path('../../../../openstacklib/lib', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) } + Puppet::Type.newtype(:keystone_role) do desc <<-EOT @@ -21,5 +25,4 @@ Puppet::Type.newtype(:keystone_role) do autorequire(:service) do ['keystone'] end - end diff --git a/deployment/puppet/keystone/lib/puppet/type/keystone_service.rb b/deployment/puppet/keystone/lib/puppet/type/keystone_service.rb index 124deba1bc..a4be4edae8 100644 --- a/deployment/puppet/keystone/lib/puppet/type/keystone_service.rb +++ b/deployment/puppet/keystone/lib/puppet/type/keystone_service.rb @@ -1,13 +1,15 @@ +# LP#1408531 +File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) } +File.expand_path('../../../../openstacklib/lib', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) } + Puppet::Type.newtype(:keystone_service) do - desc <<-EOT - This is currently used to model the management of - keystone services. - EOT + desc 'This type can be used to manage keystone services.' ensurable newparam(:name, :namevar => true) do + desc 'The name of the service.' newvalues(/\S+/) end @@ -18,14 +20,22 @@ Puppet::Type.newtype(:keystone_service) do end newproperty(:type) do + desc 'The type of service' + validate do |value| + fail('The service type is required.') unless value + end end newproperty(:description) do + desc 'A description of the service.' + defaultto('') end - # we should not do anything until the keystone service is started + # This ensures the service is started and therefore the keystone + # config is configured IF we need them for authentication. + # If there is no keystone config, authentication credentials + # need to come from another source. autorequire(:service) do ['keystone'] end - end diff --git a/deployment/puppet/keystone/lib/puppet/type/keystone_tenant.rb b/deployment/puppet/keystone/lib/puppet/type/keystone_tenant.rb index 513430878d..6195d23f90 100644 --- a/deployment/puppet/keystone/lib/puppet/type/keystone_tenant.rb +++ b/deployment/puppet/keystone/lib/puppet/type/keystone_tenant.rb @@ -1,38 +1,44 @@ +# LP#1408531 +File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) } +File.expand_path('../../../../openstacklib/lib', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) } + Puppet::Type.newtype(:keystone_tenant) do - 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 + desc 'This type can be used to manage keystone tenants.' ensurable newparam(:name, :namevar => true) do + desc 'The name of the tenant.' newvalues(/\w+/) end newproperty(:enabled) do - newvalues(/(t|T)rue/, /(f|F)alse/) - defaultto('True') + desc 'Whether the tenant should be enabled. Defaults to true.' + newvalues(/(t|T)rue/, /(f|F)alse/, true, false ) + defaultto(true) munge do |value| - value.to_s.capitalize + value.to_s.downcase.to_sym end end - newproperty(:description) + newproperty(:description) do + desc 'A description of the tenant.' + defaultto('') + end newproperty(:id) do + desc 'Read-only property of the tenant.' 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 + # This ensures the service is started and therefore the keystone + # config is configured IF we need them for authentication. + # If there is no keystone config, authentication credentials + # need to come from another source. autorequire(:service) do ['keystone'] end - end diff --git a/deployment/puppet/keystone/lib/puppet/type/keystone_user.rb b/deployment/puppet/keystone/lib/puppet/type/keystone_user.rb index 7691c2cd67..b484e7c5fd 100644 --- a/deployment/puppet/keystone/lib/puppet/type/keystone_user.rb +++ b/deployment/puppet/keystone/lib/puppet/type/keystone_user.rb @@ -1,14 +1,10 @@ +# LP#1408531 +File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) } +File.expand_path('../../../../openstacklib/lib', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) } + Puppet::Type.newtype(:keystone_user) do - 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?? + desc 'Type for managing keystone users.' ensurable @@ -16,16 +12,19 @@ Puppet::Type.newtype(:keystone_user) do newvalues(/\S+/) end - newparam(:ignore_default_tenant, :boolean => true) do - newvalues(:true, :false) - defaultto false + newparam(:ignore_default_tenant) do + newvalues(/(t|T)rue/, /(f|F)alse/, true, false) + defaultto(false) + munge do |value| + value.to_s.downcase.to_sym + end end newproperty(:enabled) do - newvalues(/(t|T)rue/, /(f|F)alse/) - defaultto('True') + newvalues(/(t|T)rue/, /(f|F)alse/, true, false) + defaultto(true) munge do |value| - value.to_s.capitalize + value.to_s.downcase.to_sym end end @@ -53,7 +52,7 @@ Puppet::Type.newtype(:keystone_user) do end newproperty(:email) do - newvalues(/\S+@\S+/) + newvalues(/^(\S+@\S+)|$/) end newproperty(:id) do @@ -62,11 +61,11 @@ Puppet::Type.newtype(:keystone_user) do end end - newproperty(:replace_password) do - newvalues(/(t|T)rue/, /(f|F)alse/) - defaultto('True') + newparam(:replace_password) do + newvalues(/(t|T)rue/, /(f|F)alse/, true, false) + defaultto(true) munge do |value| - value.to_s.capitalize + value.to_s.downcase.to_sym end end @@ -78,5 +77,4 @@ Puppet::Type.newtype(:keystone_user) do autorequire(:service) do ['keystone'] end - end diff --git a/deployment/puppet/keystone/lib/puppet/type/keystone_user_role.rb b/deployment/puppet/keystone/lib/puppet/type/keystone_user_role.rb index 0198cc2994..502dc39761 100644 --- a/deployment/puppet/keystone/lib/puppet/type/keystone_user_role.rb +++ b/deployment/puppet/keystone/lib/puppet/type/keystone_user_role.rb @@ -1,42 +1,37 @@ +# LP#1408531 +File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) } +File.expand_path('../../../../openstacklib/lib', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) } + Puppet::Type.newtype(:keystone_user_role) do 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 + User roles are an assignment of a role to a user on + a certain tenant. The combination 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') + def insync?(is) + return false unless is.is_a? Array + # order of roles does not matter + is.sort == self.should.sort end end autorequire(:keystone_user) do - self[:name].split('@', 2).first + self[:name].rpartition('@').first end autorequire(:keystone_tenant) do - self[:name].split('@', 2).last + self[:name].rpartition('@').last end autorequire(:keystone_role) do @@ -47,5 +42,4 @@ Puppet::Type.newtype(:keystone_user_role) do autorequire(:service) do ['keystone'] end - end diff --git a/deployment/puppet/keystone/manifests/client.pp b/deployment/puppet/keystone/manifests/client.pp index 453503d663..84a6e08ce7 100644 --- a/deployment/puppet/keystone/manifests/client.pp +++ b/deployment/puppet/keystone/manifests/client.pp @@ -5,7 +5,8 @@ # === Parameters # # [*ensure*] -# (optional) Ensure state of the package. Defaults to 'present'. +# (optional) Ensure state of the package. +# Defaults to 'present'. # class keystone::client ( $ensure = 'present' @@ -13,5 +14,6 @@ class keystone::client ( package { 'python-keystoneclient': ensure => $ensure, + tag => 'openstack', } } diff --git a/deployment/puppet/keystone/manifests/cron/token_flush.pp b/deployment/puppet/keystone/manifests/cron/token_flush.pp new file mode 100644 index 0000000000..331eeba563 --- /dev/null +++ b/deployment/puppet/keystone/manifests/cron/token_flush.pp @@ -0,0 +1,75 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Class: keystone::cron::token_flush +# +# Installs a cron job to purge expired tokens. +# +# === Parameters +# +# [*ensure*] +# (optional) Defaults to present. +# Valid values are present, absent. +# +# [*minute*] +# (optional) Defaults to '1'. +# +# [*hour*] +# (optional) Defaults to '0'. +# +# [*monthday*] +# (optional) Defaults to '*'. +# +# [*month*] +# (optional) Defaults to '*'. +# +# [*weekday*] +# (optional) Defaults to '*'. +# +# [*maxdelay*] +# (optional) Seconds. Defaults to 0. Should be a positive integer. +# Induces a random delay before running the cronjob to avoid running all +# cron jobs at the same time on all hosts this job is configured. +# +class keystone::cron::token_flush ( + $ensure = present, + $minute = 1, + $hour = 0, + $monthday = '*', + $month = '*', + $weekday = '*', + $maxdelay = 0, +) { + + if $maxdelay == 0 { + $sleep = '' + } else { + $sleep = "sleep `expr \${RANDOM} \\% ${maxdelay}`; " + } + + cron { 'keystone-manage token_flush': + ensure => $ensure, + command => "${sleep}keystone-manage token_flush >>/var/log/keystone/keystone-tokenflush.log 2>&1", + environment => 'PATH=/bin:/usr/bin:/usr/sbin SHELL=/bin/sh', + user => 'keystone', + minute => $minute, + hour => $hour, + monthday => $monthday, + month => $month, + weekday => $weekday + } +} diff --git a/deployment/puppet/keystone/manifests/db/mysql.pp b/deployment/puppet/keystone/manifests/db/mysql.pp index d7719435f3..dc94896cdc 100644 --- a/deployment/puppet/keystone/manifests/db/mysql.pp +++ b/deployment/puppet/keystone/manifests/db/mysql.pp @@ -1,27 +1,43 @@ -# -# implements mysql backend for keystone +# The keystone::db::mysql class 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' +# [*password*] +# (Mandatory) Password to connect to the database. +# Defaults to 'false'. # -# [dbname] Name of keystone database. Optional. Defaults to keystone. +# [*dbname*] +# (Optional) Name of the database. +# Defaults to 'keystone'. # -# [user] Name of keystone user. Optional. Defaults to keystone. +# [*user*] +# (Optional) User to connect to the database. +# Defaults to 'keystone'. # -# [host] Host where user should be allowed all priveleges for database. -# Optional. Defaults to 127.0.0.1. +# [*host*] +# (Optional) The default source host user is allowed to connect from. +# Defaults to '127.0.0.1' # -# [allowed_hosts] Hosts allowed to use the database +# [*allowed_hosts*] +# (Optional) Other hosts the user is allowed to connect from. +# Defaults to 'undef'. # -# [*mysql_module*] -# (optional) The mysql puppet module version to use -# Tested versions include 0.9 and 2.2 -# Default to '0.9' +# [*charset*] +# (Optional) The database charset. +# Defaults to 'utf8' +# +# [*collate*] +# (Optional) The database collate. +# Only used with mysql modules >= 2.2. +# Defaults to 'utf8_general_ci' +# +# === Deprecated Parameters +# +# [*mysql_module*] +# (Optional) Does nothing. # # == Dependencies # Class['mysql::server'] @@ -41,53 +57,26 @@ class keystone::db::mysql( $user = 'keystone', $host = '127.0.0.1', $charset = 'utf8', - $collate = 'utf8_unicode_ci', - $mysql_module = '0.9', + $collate = 'utf8_general_ci', + $mysql_module = undef, $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'], - } + if $mysql_module { + warning('The mysql_module parameter is deprecated. The latest 2.x mysql module will be used.') } - # 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' |> - + validate_string($password) + + ::openstacklib::db::mysql { 'keystone': + user => $user, + password_hash => mysql_password($password), + dbname => $dbname, + host => $host, + charset => $charset, + collate => $collate, + allowed_hosts => $allowed_hosts, } + ::Openstacklib::Db::Mysql['keystone'] ~> Exec<| title == 'keystone-manage db_sync' |> } diff --git a/deployment/puppet/keystone/manifests/db/mysql/host_access.pp b/deployment/puppet/keystone/manifests/db/mysql/host_access.pp deleted file mode 100644 index a016067a4f..0000000000 --- a/deployment/puppet/keystone/manifests/db/mysql/host_access.pp +++ /dev/null @@ -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}"] - } - } -} diff --git a/deployment/puppet/keystone/manifests/db/postgresql.pp b/deployment/puppet/keystone/manifests/db/postgresql.pp index efe1422b50..4bf5a6a755 100644 --- a/deployment/puppet/keystone/manifests/db/postgresql.pp +++ b/deployment/puppet/keystone/manifests/db/postgresql.pp @@ -1,47 +1,57 @@ +# == Class: keystone::db::postgresql # -# implements postgresql backend for keystone +# Class that configures postgresql for keystone +# Requires the Puppetlabs postgresql module. # -# This class can be used to create tables, users and grant -# privelege for a postgresql keystone database. -# -# Requires Puppetlabs Postgresql module. -# -# [*Parameters*] -# -# [password] Password that will be used for the keystone db user. -# Optional. Defaults to: 'keystone_default_password' -# -# [dbname] Name of keystone database. Optional. Defaults to keystone. -# -# [user] Name of keystone user. Optional. Defaults to keystone. -# -# == Dependencies -# Class['postgresql::server'] -# -# == Examples # == Authors # +# Stackforge Contributors puppet-openstack@puppetlabs.com # Etienne Pelletier epelletier@morphlabs.com # # == Copyright # +# Copyright 2013-2014 Stackforge Contributors # Copyright 2012 Etienne Pelletier, unless otherwise noted. # +# === Parameters +# +# [*password*] +# (Required) Password to connect to the database. +# +# [*dbname*] +# (Optional) Name of the database. +# Defaults to 'keystone'. +# +# [*user*] +# (Optional) User to connect to the database. +# Defaults to 'keystone'. +# +# [*encoding*] +# (Optional) The charset to use for the database. +# Default to undef. +# +# [*privileges*] +# (Optional) Privileges given to the database user. +# Default to 'ALL' +# class keystone::db::postgresql( $password, - $dbname = 'keystone', - $user = 'keystone' + $dbname = 'keystone', + $user = 'keystone', + $encoding = undef, + $privileges = 'ALL', ) { Class['keystone::db::postgresql'] -> Service<| title == 'keystone' |> - require postgresql::python - - postgresql::db { $dbname: - user => $user, - password => $password, + ::openstacklib::db::postgresql { 'keystone': + password_hash => postgresql_password($user, $password), + dbname => $dbname, + user => $user, + encoding => $encoding, + privileges => $privileges, } - Postgresql::Server::Db[$dbname] ~> Exec<| title == 'keystone-manage db_sync' |> + ::Openstacklib::Db::Postgresql['keystone'] ~> Exec<| title == 'keystone-manage db_sync' |> } diff --git a/deployment/puppet/keystone/manifests/db/sync.pp b/deployment/puppet/keystone/manifests/db/sync.pp index 7de731fbc2..5984a03a15 100644 --- a/deployment/puppet/keystone/manifests/db/sync.pp +++ b/deployment/puppet/keystone/manifests/db/sync.pp @@ -9,4 +9,6 @@ class keystone::db::sync { subscribe => [Package['keystone'], Keystone_config['database/connection']], require => User['keystone'], } + + Exec['keystone-manage db_sync'] ~> Service<| title == 'keystone' |> } diff --git a/deployment/puppet/keystone/manifests/dev/install.pp b/deployment/puppet/keystone/manifests/dev/install.pp index 3e68113c2c..f52800f23b 100644 --- a/deployment/puppet/keystone/manifests/dev/install.pp +++ b/deployment/puppet/keystone/manifests/dev/install.pp @@ -1,6 +1,12 @@ # # Installs keystone from source. This is not yet fully implemented # +# == Parameters +# +# [*source_dir*] +# (optional) The source dire for dev installation +# Defaults to '/usr/local/keystone' +# # == Dependencies # == Examples # == Authors diff --git a/deployment/puppet/keystone/manifests/endpoint.pp b/deployment/puppet/keystone/manifests/endpoint.pp index 96f2ec1591..6c821f4755 100644 --- a/deployment/puppet/keystone/manifests/endpoint.pp +++ b/deployment/puppet/keystone/manifests/endpoint.pp @@ -6,12 +6,15 @@ # # [*public_url*] # (optional) Public url for keystone endpoint. (Defaults to 'http://127.0.0.1:5000') +# This url should *not* contain any version or trailing '/'. # # [*internal_url*] # (optional) Internal url for keystone endpoint. (Defaults to $public_url) +# This url should *not* contain any version or trailing '/'. # # [*admin_url*] # (optional) Admin url for keystone endpoint. (Defaults to 'http://127.0.0.1:35357') +# This url should *not* contain any version or trailing '/'. # # [*region*] # (optional) Region for endpoint. (Defaults to 'RegionOne') @@ -19,58 +22,6 @@ # [*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': @@ -85,85 +36,26 @@ class keystone::endpoint ( $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.') + $public_url_real = "${public_url}/${version}" + $admin_url_real = "${admin_url}/${version}" + + if $internal_url { + $internal_url_real = "${internal_url}/${version}" + } else { + $internal_url_real = "${public_url}/${version}" } - if $public_protocol { - warning('The public_protocol parameter is deprecated, use public_url instead.') + keystone::resource::service_identity { 'keystone': + configure_user => false, + configure_user_role => false, + service_type => 'identity', + service_description => 'OpenStack Identity Service', + public_url => $public_url_real, + admin_url => $admin_url_real, + internal_url => $internal_url_real, + region => $region, } - 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, - } } diff --git a/deployment/puppet/keystone/manifests/init.pp b/deployment/puppet/keystone/manifests/init.pp index af0bb42f72..20c2011e31 100644 --- a/deployment/puppet/keystone/manifests/init.pp +++ b/deployment/puppet/keystone/manifests/init.pp @@ -3,141 +3,365 @@ # # == 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 +# [*package_ensure*] +# (optional) Desired ensure state of packages. +# accepts latest or specific versions. +# Defaults to present. # -# [*public_bind_host*] +# [*client_package_ensure*] +# (optional) Desired ensure state of the client package. +# accepts latest or specific versions. +# Defaults to present. +# +# [*public_port*] +# (optional) Port that keystone binds to. +# Defaults to '5000' +# +# [*compute_port*] +# (optional) DEPRECATED The port for compute servie. +# Defaults to '8774' +# +# [*admin_port*] +# (optional) Port that can be used for admin tasks. +# Defaults to '35357' +# +# [*admin_token*] +# Admin token that can be used to authenticate as a keystone +# admin. Required. +# +# [*verbose*] +# (optional) Rather keystone should log at verbose level. +# Defaults to false. +# +# [*debug*] +# (optional) Rather keystone should log at debug level. +# Defaults to False. +# +# [*use_syslog*] +# (optional) Use syslog for logging. +# Defaults to false. +# +# [*log_facility*] +# (optional) Syslog facility to receive log lines. +# Defaults to 'LOG_USER'. +# +# [*catalog_type*] +# (optional) Type of catalog that keystone uses to store endpoints,services. +# Defaults to sql. (Also accepts template) +# +# [*catalog_driver*] +# (optional) Catalog driver used by Keystone to store endpoints and services. +# Setting this value will override and ignore catalog_type. +# Defaults to false. +# +# [*catalog_template_file*] +# (optional) Path to the catalog used if catalog_type equals 'template'. +# Defaults to '/etc/keystone/default_catalog.templates' +# +# [*token_provider*] +# (optional) Format keystone uses for tokens. +# Defaults to 'keystone.token.providers.uuid.Provider' +# Supports PKI, PKIZ, Fernet, and UUID. +# +# [*token_driver*] +# (optional) Driver to use for managing tokens. +# Defaults to 'keystone.token.persistence.backends.sql.Token' +# +# [*token_expiration*] +# (optional) Amount of time a token should remain valid (seconds). +# Defaults to 3600 (1 hour). +# +# [*revoke_driver*] +# (optional) Driver for token revocation. +# Defaults to 'keystone.contrib.revoke.backends.sql.Revoke' +# +# [*cache_dir*] +# (optional) Directory created when token_provider is pki. +# Defaults to /var/cache/keystone. +# +# [*memcache_servers*] +# (optional) List of memcache servers in format of server:port. +# Used with token_driver 'keystone.token.backends.memcache.Token'. +# Defaults to false. Example: ['localhost:11211'] +# +# [*cache_backend*] +# (optional) Dogpile.cache backend module. It is recommended that Memcache with pooling +# (keystone.cache.memcache_pool) or Redis (dogpile.cache.redis) be used in production. +# This has no effects unless 'memcache_servers' is set. +# Defaults to 'keystone.common.cache.noop' +# +# [*cache_backend_argument*] +# (optional) List of arguments in format of argname:value supplied to the backend module. +# Specify this option once per argument to be passed to the dogpile.cache backend. +# This has no effects unless 'memcache_servers' is set. +# Default to undef. +# +# [*debug_cache_backend*] +# (optional) Extra debugging from the cache backend (cache keys, get/set/delete calls). +# This has no effects unless 'memcache_servers' is set. +# Default to false. +# +# [*token_caching*] +# (optional) Toggle for token system caching. This has no effects unless 'memcache_servers' is set. +# Default to true. +# +# [*manage_service*] +# (Optional) If Puppet should manage service startup / shutdown. +# Defaults to true. +# +# [*enabled*] +# (optional) If the keystone services should be enabled. +# Default to true. +# +# [*database_connection*] +# (optional) Url used to connect to database. +# Defaults to sqlite:////var/lib/keystone/keystone.db +# +# [*database_idle_timeout*] +# (optional) Timeout when db connections should be reaped. +# Defaults to 200. +# +# [*enable_pki_setup*] +# (optional) 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. +# Default to true. +# +# [*signing_certfile*] +# (optional) Location of the cert file for signing pki tokens and revocation lists. +# 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. +# Default: /etc/keystone/ssl/certs/signing_cert.pem +# +# [*signing_keyfile*] +# (optional) Location of the key file for signing pki tokens and revocation lists. +# 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. +# Default: /etc/keystone/ssl/private/signing_key.pem +# +# [*signing_ca_certs*] +# (optional) Use this CA certs file along with signing_certfile/signing_keyfile for +# signing pki tokens and revocation lists. +# Default: /etc/keystone/ssl/certs/ca.pem +# +# [*signing_ca_key*] +# (optional) Use this CA key file along with signing_certfile/signing_keyfile for signing +# pki tokens and revocation lists. +# Default: /etc/keystone/ssl/private/cakey.pem +# +# [*signing_cert_subject*] +# (optional) Certificate subject (auto generated certificate) for token signing. +# Defaults to '/C=US/ST=Unset/L=Unset/O=Unset/CN=www.example.com' +# +# [*signing_key_size*] +# (optional) Key size (in bits) for token signing cert (auto generated certificate) +# Defaults to 2048 +# +# [*rabbit_host*] +# (optional) Location of rabbitmq installation. +# Defaults to localhost. +# +# [*rabbit_port*] +# (optional) Port for rabbitmq instance. +# Defaults to 5672. +# +# [*rabbit_hosts*] +# (optional) Location of rabbitmq installation. +# Defaults to undef. +# +# [*rabbit_password*] +# (optional) Password used to connect to rabbitmq. +# Defaults to guest. +# +# [*rabbit_userid*] +# (optional) User used to connect to rabbitmq. +# Defaults to guest. +# +# [*rabbit_virtual_host*] +# (optional) The RabbitMQ virtual host. +# Defaults to /. +# +# [*rabbit_use_ssl*] +# (optional) Connect over SSL for RabbitMQ +# Defaults to false +# +# [*kombu_ssl_ca_certs*] +# (optional) SSL certification authority file (valid only if SSL enabled). +# Defaults to undef +# +# [*kombu_ssl_certfile*] +# (optional) SSL cert file (valid only if SSL enabled). +# Defaults to undef +# +# [*kombu_ssl_keyfile*] +# (optional) SSL key file (valid only if SSL enabled). +# Defaults to undef +# +# [*kombu_ssl_version*] +# (optional) SSL version to use (valid only if SSL enabled). +# Valid values are TLSv1, SSLv23 and SSLv3. SSLv2 may be +# available on some distributions. +# Defaults to 'TLSv1' +# +# [*notification_driver*] +# RPC driver. Not enabled by default +# +# [*notification_topics*] +# (optional) AMQP topics to publish to when using the RPC notification driver. +# Default to false. +# +# [*notification_format*] +# Format for the notifications. Valid values are 'basic' and 'cadf'. +# Default to undef +# +# [*control_exchange*] +# (optional) AMQP exchange to connect to if using RabbitMQ or Qpid +# Default to false. +# +# [*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*] +# [*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*] +# [*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*] +# [*log_file*] # (optional) Where to log # Defaults to false # -# [*public_endpoint*] +# [*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/' +# Sample value: 'http://localhost:5000/' # Defaults to false # -# [*admin_endpoint*] +# [*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/' +# Sample value: 'http://localhost:35357/' # Defaults to false # -# [*enable_ssl*] +# [*enable_ssl*] # (optional) Toggle for SSL support on the keystone eventlet servers. # (boolean value) # Defaults to false # -# [*ssl_certfile*] +# [*ssl_certfile*] # (optional) Path of the certfile for SSL. (string value) # Defaults to '/etc/keystone/ssl/certs/keystone.pem' # -# [*ssl_keyfile*] +# [*ssl_keyfile*] # (optional) Path of the keyfile for SSL. (string value) # Defaults to '/etc/keystone/ssl/private/keystonekey.pem' # -# [*ssl_ca_certs*] +# [*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*] +# [*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*] +# [*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' +# [*mysql_module*] +# (optional) Deprecated. Does nothing. # -# [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. +# [*validate_service*] +# (optional) Whether to validate keystone connections after +# the service is started. +# Defaults to 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. +# [*validate_insecure*] +# (optional) Whether to validate keystone connections +# using the --insecure option with keystone client. +# Defaults to false # -# [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 +# [*validate_cacert*] +# (optional) Whether to validate keystone connections +# using the specified argument with the --os-cacert option +# with keystone client. +# Defaults to undef # -# [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 +# [*validate_auth_url*] +# (optional) The url to validate keystone against +# Defaults to undef +# +# [*service_provider*] +# (optional) Provider, that can be used for keystone service. +# Default value defined in keystone::params for given operation system. +# If you use Pacemaker or another Cluster Resource Manager, you can make +# custom service provider for changing start/stop/status behavior of service, +# and set it here. +# +# [*service_name*] +# (optional) Name of the service that will be providing the +# server functionality of keystone. For example, the default +# is just 'keystone', which means keystone will be run as a +# standalone eventlet service, and will able to be managed +# separately by the operating system's service manager. For +# example, you will be able to use +# service openstack-keystone restart +# to restart the service. +# If the value is 'httpd', this means keystone will be a web +# service, and you must use another class to configure that +# web service. For example, after calling class {'keystone'...} +# use class { 'keystone::wsgi::apache'...} to make keystone be +# a web app using apache mod_wsgi. +# Defaults to '$::keystone::params::service_name' +# NOTE: validate_service only applies if the default value is used. +# +# [*paste_config*] +# (optional) Name of the paste configuration file that defines the +# available pipelines. (string value) +# Defaults to '/usr/share/keystone/keystone-dist-paste.ini' on RedHat and +# undef on other platforms. +# +# [*max_token_size*] +# (optional) maximum allowable Keystone token size +# Defaults to undef +# +# [*admin_workers*] +# (optional) The number of worker processes to serve the admin WSGI application. +# Defaults to max($::processorcount, 2) +# +# [*public_workers*] +# (optional) The number of worker processes to serve the public WSGI application. +# Defaults to max($::processorcount, 2) +# +# [*sync_db*] +# (Optional) Run db sync on the node. +# Defaults to true +# +# [*enable_fernet_setup*] +# (Optional) Setup keystone for fernet tokens. This is typically only +# run on a single node, then the keys are replicated to the other nodes +# in a cluster. You would typically also pair this with a fernet token +# provider setting. +# Defaults to false +# +# [*fernet_key_repository*] +# (Optional) Location for the fernet key repository. This value must +# be set if enable_fernet_setup is set to true. +# Defaults to '/etc/keystone/fernet-keys' +# +# [*fernet_max_active_keys*] +# (Optional) Number of maximum active Fernet keys. Integer > 0. +# Defaults to undef # # == Dependencies # None @@ -149,6 +373,17 @@ # admin_token => 'my_special_token', # } # +# OR +# +# class { 'keystone': +# ... +# service_name => 'httpd', +# ... +# } +# class { 'keystone::wsgi::apache': +# ... +# } +# # == Authors # # Dan Bode dan@puppetlabs.com @@ -159,77 +394,130 @@ # 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 -) { + $package_ensure = 'present', + $client_package_ensure = 'present', + $public_bind_host = '0.0.0.0', + $admin_bind_host = '0.0.0.0', + $public_port = '5000', + $admin_port = '35357', + $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_provider = 'keystone.token.providers.uuid.Provider', + $token_driver = 'keystone.token.persistence.backends.sql.Token', + $token_expiration = 3600, + $revoke_driver = 'keystone.contrib.revoke.backends.sql.Revoke', + $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, + $manage_service = true, + $cache_backend = 'keystone.common.cache.noop', + $cache_backend_argument = undef, + $debug_cache_backend = false, + $token_caching = true, + $enabled = true, + $database_connection = 'sqlite:////var/lib/keystone/keystone.db', + $database_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', + $signing_cert_subject = '/C=US/ST=Unset/L=Unset/O=Unset/CN=www.example.com', + $signing_key_size = 2048, + $rabbit_host = 'localhost', + $rabbit_hosts = false, + $rabbit_password = 'guest', + $rabbit_port = '5672', + $rabbit_userid = 'guest', + $rabbit_virtual_host = '/', + $rabbit_use_ssl = false, + $kombu_ssl_ca_certs = undef, + $kombu_ssl_certfile = undef, + $kombu_ssl_keyfile = undef, + $kombu_ssl_version = 'TLSv1', + $notification_driver = false, + $notification_topics = false, + $notification_format = undef, + $control_exchange = false, + $validate_service = false, + $validate_insecure = false, + $validate_auth_url = false, + $validate_cacert = undef, + $paste_config = $::keystone::params::paste_config, + $service_provider = $::keystone::params::service_provider, + $service_name = $::keystone::params::service_name, + $max_token_size = undef, + $admin_workers = max($::processorcount, 2), + $public_workers = max($::processorcount, 2), + $sync_db = true, + $enable_fernet_setup = false, + $fernet_key_repository = '/etc/keystone/fernet-keys', + $fernet_max_active_keys = undef, + # DEPRECATED PARAMETERS + $mysql_module = undef, + $compute_port = undef, +) inherits keystone::params { if ! $catalog_driver { validate_re($catalog_type, 'template|sql') } - File['/etc/keystone/keystone.conf'] -> Keystone_config<||> ~> Service['keystone'] + if $mysql_module { + warning('The mysql_module parameter is deprecated. The latest 2.x mysql module will be used.') + } + + if ($admin_endpoint and 'v2.0' in $admin_endpoint) { + warning('Version string /v2.0/ should not be included in keystone::admin_endpoint') + } + + if ($public_endpoint and 'v2.0' in $public_endpoint) { + warning('Version string /v2.0/ should not be included in keystone::public_endpoint') + } + + if $rabbit_use_ssl { + if !$kombu_ssl_ca_certs { + fail('The kombu_ssl_ca_certs parameter is required when rabbit_use_ssl is set to true') + } + if !$kombu_ssl_certfile { + fail('The kombu_ssl_certfile parameter is required when rabbit_use_ssl is set to true') + } + if !$kombu_ssl_keyfile { + fail('The kombu_ssl_keyfile parameter is required when rabbit_use_ssl is set to true') + } + } + + File['/etc/keystone/keystone.conf'] -> Keystone_config<||> ~> Service[$service_name] Keystone_config<||> ~> Exec<| title == 'keystone-manage db_sync'|> Keystone_config<||> ~> Exec<| title == 'keystone-manage pki_setup'|> + Keystone_config<||> ~> Exec<| title == 'keystone-manage fernet_setup'|> - include keystone::params - - File { - ensure => present, - owner => 'keystone', - group => 'keystone', - require => Package['keystone'], - notify => Service['keystone'], - } + include ::keystone::params package { 'keystone': ensure => $package_ensure, name => $::keystone::params::package_name, + tag => 'openstack', + } + if $client_package_ensure == 'present' { + include '::openstacklib::openstackclient' + } else { + class { '::openstacklib::openstackclient': + package_ensure => $client_package_ensure, + } } group { 'keystone': @@ -248,33 +536,42 @@ class keystone( file { ['/etc/keystone', '/var/log/keystone', '/var/lib/keystone']: ensure => directory, mode => '0750', + owner => 'keystone', + group => 'keystone', + require => Package['keystone'], + notify => Service[$service_name], } file { '/etc/keystone/keystone.conf': + ensure => present, mode => '0600', + owner => 'keystone', + group => 'keystone', + require => Package['keystone'], + notify => Service[$service_name], } - 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/admin_token': value => $admin_token, secret => true; + 'DEFAULT/public_bind_host': value => $public_bind_host; + 'DEFAULT/admin_bind_host': value => $admin_bind_host; '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; } + if $compute_port { + warning('The compute_port parameter is deprecated and will be removed in L') + keystone_config { + 'DEFAULT/compute_port': value => $compute_port; + } + } else { + keystone_config { + 'DEFAULT/compute_port': ensure => absent; + } + } + # Endpoint configuration if $public_endpoint { keystone_config { @@ -294,6 +591,13 @@ class keystone( 'DEFAULT/admin_endpoint': ensure => absent; } } + # requirements for memcache token driver + if ($token_driver =~ /memcache/ ) { + package { 'python-memcache': + ensure => present, + name => $::keystone::params::python_memcache_package_name, + } + } # token driver config keystone_config { @@ -301,6 +605,16 @@ class keystone( 'token/expiration': value => $token_expiration; } + if $revoke_driver { + keystone_config { + 'revoke/driver': value => $revoke_driver; + } + } else { + keystone_config { + 'revoke/driver': ensure => absent; + } + } + # ssl config if ($enable_ssl) { keystone_config { @@ -317,37 +631,53 @@ class keystone( } } - 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+/) { + if($database_connection =~ /mysql:\/\/\S+:\S+@\S+\/\S+/) { + require 'mysql::bindings' + require 'mysql::bindings::python' + } elsif($database_connection =~ /postgresql:\/\/\S+:\S+@\S+\/\S+/) { - } elsif($sql_connection =~ /sqlite:\/\//) { + } elsif($database_connection =~ /sqlite:\/\//) { } else { - fail("Invalid db connection ${sql_connection}") + fail("Invalid db connection ${database_connection}") } # memcache connection config if $memcache_servers { validate_array($memcache_servers) + Service<| title == 'memcached' |> -> Service['keystone'] keystone_config { - 'memcache/servers': value => join($memcache_servers, ','); + 'cache/enabled': value => true; + 'cache/backend': value => $cache_backend; + 'cache/debug_cache_backend': value => $debug_cache_backend; + 'token/caching': value => $token_caching; + 'memcache/servers': value => join($memcache_servers, ','); + } + if $cache_backend_argument { + validate_array($cache_backend_argument) + keystone_config { + 'cache/backend_argument': value => join($cache_backend_argument, ','); + } + } else { + keystone_config { + 'cache/backend_argument': ensure => absent; + } } } else { keystone_config { - 'memcache/servers': ensure => absent; + 'cache/enabled': ensure => absent; + 'cache/backend': ensure => absent; + 'cache/backend_argument': ensure => absent; + 'cache/debug_cache_backend': ensure => absent; + 'token/caching': ensure => absent; + 'memcache/servers': ensure => absent; } } # db connection config keystone_config { - 'database/connection': value => $sql_connection, secret => true; - 'database/idle_timeout': value => $idle_timeout; + 'database/connection': value => $database_connection, secret => true; + 'database/idle_timeout': value => $database_idle_timeout; } # configure based on the catalog backend @@ -366,16 +696,14 @@ class keystone( '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; + 'signing/certfile': value => $signing_certfile; + 'signing/keyfile': value => $signing_keyfile; + 'signing/ca_certs': value => $signing_ca_certs; + 'signing/ca_key': value => $signing_ca_key; + 'signing/cert_subject': value => $signing_cert_subject; + 'signing/key_size': value => $signing_key_size; } # Create cache directory used for signing. @@ -392,35 +720,35 @@ class keystone( user => 'keystone', refreshonly => true, creates => $signing_keyfile, - notify => Service['keystone'], + notify => Service[$service_name], 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 } - } + keystone_config { 'token/provider': value => $token_provider } - # remove the old format in case of an upgrade - keystone_config { 'signing/token_format': ensure => absent } + if $max_token_size { + keystone_config { 'DEFAULT/max_token_size': value => $max_token_size } + } else { + keystone_config { 'DEFAULT/max_token_size': 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 $notification_format { + keystone_config { 'DEFAULT/notification_format': value => $notification_format } + } else { + keystone_config { 'DEFAULT/notification_format': ensure => absent } + } if $control_exchange { keystone_config { 'DEFAULT/control_exchange': value => $control_exchange } } else { @@ -428,7 +756,7 @@ class keystone( } keystone_config { - 'DEFAULT/rabbit_password': value => $rabbit_password; + 'DEFAULT/rabbit_password': value => $rabbit_password, secret => true; 'DEFAULT/rabbit_userid': value => $rabbit_userid; 'DEFAULT/rabbit_virtual_host': value => $rabbit_virtual_host; } @@ -443,24 +771,85 @@ class keystone( keystone_config { 'DEFAULT/rabbit_ha_queues': value => false } } - if $enabled { - $service_ensure = 'running' + keystone_config { 'DEFAULT/rabbit_use_ssl': value => $rabbit_use_ssl } + if $rabbit_use_ssl { + keystone_config { + 'DEFAULT/kombu_ssl_ca_certs': value => $kombu_ssl_ca_certs; + 'DEFAULT/kombu_ssl_certfile': value => $kombu_ssl_certfile; + 'DEFAULT/kombu_ssl_keyfile': value => $kombu_ssl_keyfile; + 'DEFAULT/kombu_ssl_version': value => $kombu_ssl_version; + } } else { - $service_ensure = 'stopped' + keystone_config { + 'DEFAULT/kombu_ssl_ca_certs': ensure => absent; + 'DEFAULT/kombu_ssl_certfile': ensure => absent; + 'DEFAULT/kombu_ssl_keyfile': ensure => absent; + 'DEFAULT/kombu_ssl_version': ensure => absent; + } } - service { 'keystone': - ensure => $service_ensure, - name => $::keystone::params::service_name, - enable => $enabled, - hasstatus => true, - hasrestart => true, - provider => $::keystone::params::service_provider, + keystone_config { + 'DEFAULT/admin_workers': value => $admin_workers; + 'DEFAULT/public_workers': value => $public_workers; } - if $enabled { - include keystone::db::sync - Class['keystone::db::sync'] ~> Service['keystone'] + if $manage_service { + if $enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + } else { + warning('Execution of db_sync does not depend on $enabled anymore. Please use sync_db instead.') + } + + if $service_name == $::keystone::params::service_name { + if $validate_service { + if $validate_auth_url { + $v_auth_url = $validate_auth_url + } else { + $v_auth_url = $admin_endpoint + } + + class { '::keystone::service': + ensure => $service_ensure, + service_name => $service_name, + enable => $enabled, + hasstatus => true, + hasrestart => true, + provider => $service_provider, + validate => true, + admin_endpoint => $v_auth_url, + admin_token => $admin_token, + insecure => $validate_insecure, + cacert => $validate_cacert, + } + } else { + class { '::keystone::service': + ensure => $service_ensure, + service_name => $service_name, + enable => $enabled, + hasstatus => true, + hasrestart => true, + provider => $service_provider, + validate => false, + } + } + } elsif $service_name == 'httpd' { + class { '::keystone::service': + ensure => 'stopped', + service_name => $::keystone::params::service_name, + enable => false, + provider => $service_provider, + validate => false, + } + } else { + fail('Invalid service_name. Either keystone/openstack-keystone for running as a standalone service, or httpd for being run by a httpd server') + } + + if $sync_db { + include ::keystone::db::sync + Class['::keystone::db::sync'] ~> Service[$service_name] } # Syslog configuration @@ -494,4 +883,48 @@ class keystone( } } + if $paste_config { + keystone_config { + 'paste_deploy/config_file': value => $paste_config; + } + } else { + keystone_config { + 'paste_deploy/config_file': ensure => absent; + } + } + + # Fernet tokens support + if $enable_fernet_setup { + validate_string($fernet_key_repository) + + exec { 'keystone-manage fernet_setup': + path => '/usr/bin', + user => 'keystone', + refreshonly => true, + creates => "${fernet_key_repository}/0", + notify => Service[$service_name], + subscribe => [Package['keystone'], Keystone_config['fernet_tokens/key_repository']], + } + } + + if $fernet_key_repository { + keystone_config { + 'fernet_tokens/key_repository': value => $fernet_key_repository; + } + } else { + keystone_config { + 'fernet_tokens/key_repository': ensure => absent; + } + } + + if $fernet_max_active_keys { + keystone_config { + 'fernet_tokens/max_active_keys': value => $fernet_max_active_keys; + } + } else { + keystone_config { + 'fernet_tokens/max_active_keys': ensure => absent; + } + } + } diff --git a/deployment/puppet/keystone/manifests/ldap.pp b/deployment/puppet/keystone/manifests/ldap.pp index f65a798b08..05428e971b 100644 --- a/deployment/puppet/keystone/manifests/ldap.pp +++ b/deployment/puppet/keystone/manifests/ldap.pp @@ -1,6 +1,380 @@ +# == class: keystone::ldap # # Implements ldap configuration for keystone. # +# === parameters: +# +# [*url*] +# URL for connecting to the LDAP server. (string value) +# Defaults to 'undef' +# +# [*user*] +# User BindDN to query the LDAP server. (string value) +# Defaults to 'undef' +# +# [*password*] +# Password for the BindDN to query the LDAP server. (string value) +# Defaults to 'undef' +# +# [*suffix*] +# LDAP server suffix (string value) +# Defaults to 'undef' +# +# [*query_scope*] +# The LDAP scope for queries, this can be either "one" +# (onelevel/singleLevel) or "sub" (subtree/wholeSubtree). (string value) +# Defaults to 'undef' +# +# [*page_size*] +# Maximum results per page; a value of zero ("0") disables paging. (integer value) +# Defaults to 'undef' +# +# [*user_tree_dn*] +# Search base for users. (string value) +# Defaults to 'undef' +# +# [*user_filter*] +# LDAP search filter for users. (string value) +# Defaults to 'undef' +# +# [*user_objectclass*] +# LDAP objectclass for users. (string value) +# Defaults to 'undef' +# +# [*user_id_attribute*] +# LDAP attribute mapped to user id. WARNING: must not be a multivalued attribute. (string value) +# Defaults to 'undef' +# +# [*user_name_attribute*] +# LDAP attribute mapped to user name. (string value) +# Defaults to 'undef' +# +# [*user_mail_attribute*] +# LDAP attribute mapped to user email. (string value) +# +# [*user_enabled_attribute*] +# LDAP attribute mapped to user enabled flag. (string value) +# Defaults to 'undef' +# +# [*user_enabled_mask*] +# Bitmask integer to indicate the bit that the enabled value is stored in if +# the LDAP server represents "enabled" as a bit on an integer rather than a +# boolean. A value of "0" indicates the mask is not used. If this is not set +# to "0" the typical value is "2". This is typically used when +# "user_enabled_attribute = userAccountControl". (integer value) +# Defaults to 'undef' +# +# [*user_enabled_default*] +# Default value to enable users. This should match an appropriate int value +# if the LDAP server uses non-boolean (bitmask) values to indicate if a user +# is enabled or disabled. If this is not set to "True" the typical value is +# "512". This is typically used when "user_enabled_attribute = +# userAccountControl". (string value) +# Defaults to 'undef' +# +# [*user_enabled_invert*] +# Invert the meaning of the boolean enabled values. Some LDAP servers use a +# boolean lock attribute where "true" means an account is disabled. Setting +# "user_enabled_invert = true" will allow these lock attributes to be used. +# This setting will have no effect if "user_enabled_mask" or +# "user_enabled_emulation" settings are in use. (boolean value) +# Defaults to 'undef' +# +# [*user_attribute_ignore*] +# List of attributes stripped off the user on update. (list value) +# Defaults to 'undef' +# +# [*user_default_project_id_attribute*] +# LDAP attribute mapped to default_project_id for users. (string value) +# Defaults to 'undef' +# +# [*user_allow_create*] +# Allow user creation in LDAP backend. (boolean value) +# Defaults to 'undef' +# +# [*user_allow_update*] +# Allow user updates in LDAP backend. (boolean value) +# Defaults to 'undef' +# +# [*user_allow_delete*] +# Allow user deletion in LDAP backend. (boolean value) +# Defaults to 'undef' +# +# [*user_pass_attribute*] +# LDAP attribute mapped to password. (string value) +# Defaults to 'undef' +# +# [*user_enabled_emulation*] +# If true, Keystone uses an alternative method to determine if +# a user is enabled or not by checking if they are a member of +# the "user_enabled_emulation_dn" group. (boolean value) +# Defaults to 'undef' +# +# [*user_enabled_emulation_dn*] +# DN of the group entry to hold enabled users when using enabled emulation. +# (string value) +# Defaults to 'undef' +# +# [*user_additional_attribute_mapping*] +# List of additional LDAP attributes used for mapping +# additional attribute mappings for users. Attribute mapping +# format is :, where ldap_attr is the +# attribute in the LDAP entry and user_attr is the Identity +# API attribute. (list value) +# Defaults to 'undef' +# +# [*project_tree_dn*] +# Search base for projects (string value) +# Defaults to 'undef' +# +# [*project_filter*] +# LDAP search filter for projects. (string value) +# Defaults to 'undef' +# +# [*project_objectclass*] +# LDAP objectclass for projects. (string value) +# Defaults to 'undef' +# +# [*project_id_attribute*] +# LDAP attribute mapped to project id. (string value) +# Defaults to 'undef' +# +# [*project_member_attribute*] +# LDAP attribute mapped to project membership for user. (string value) +# Defaults to 'undef' +# +# [*project_name_attribute*] +# LDAP attribute mapped to project name. (string value) +# Defaults to 'undef' +# +# [*project_desc_attribute*] +# LDAP attribute mapped to project description. (string value) +# Defaults to 'undef' +# +# [*project_enabled_attribute*] +# LDAP attribute mapped to project enabled. (string value) +# Defaults to 'undef' +# +# [*project_domain_id_attribute*] +# LDAP attribute mapped to project domain_id. (string value) +# Defaults to 'undef' +# +# [*project_attribute_ignore*] +# List of attributes stripped off the project on update. (list value) +# Defaults to 'undef' +# +# [*project_allow_create*] +# Allow project creation in LDAP backend. (boolean value) +# Defaults to 'undef' +# +# [*project_allow_update*] +# Allow project update in LDAP backend. (boolean value) +# Defaults to 'undef' +# +# [*project_allow_delete*] +# Allow project deletion in LDAP backend. (boolean value) +# Defaults to 'undef' +# +# [*project_enabled_emulation*] +# If true, Keystone uses an alternative method to determine if +# a project is enabled or not by checking if they are a member +# of the "project_enabled_emulation_dn" group. (boolean value) +# Defaults to 'undef' +# +# [*project_enabled_emulation_dn*] +# DN of the group entry to hold enabled projects when using +# enabled emulation. (string value) +# Defaults to 'undef' +# +# [*project_additional_attribute_mapping*] +# Additional attribute mappings for projects. Attribute +# mapping format is :, where ldap_attr +# is the attribute in the LDAP entry and user_attr is the +# Identity API attribute. (list value) +# Defaults to 'undef' +# +# [*role_tree_dn*] +# Search base for roles. (string value) +# Defaults to 'undef' +# +# [*role_filter*] +# LDAP search filter for roles. (string value) +# Defaults to 'undef' +# +# [*role_objectclass*] +# LDAP objectclass for roles. (string value) +# Defaults to 'undef' +# +# [*role_id_attribute*] +# LDAP attribute mapped to role id. (string value) +# Defaults to 'undef' +# +# [*role_name_attribute*] +# LDAP attribute mapped to role name. (string value) +# Defaults to 'undef' +# +# [*role_member_attribute*] +# LDAP attribute mapped to role membership. (string value) +# Defaults to 'undef' +# +# [*role_attribute_ignore*] +# List of attributes stripped off the role on update. (list value) +# Defaults to 'undef' +# +# [*role_allow_create*] +# Allow role creation in LDAP backend. (boolean value) +# Defaults to 'undef' +# +# [*role_allow_update*] +# Allow role update in LDAP backend. (boolean value) +# Defaults to 'undef' +# +# [*role_allow_delete*] +# Allow role deletion in LDAP backend. (boolean value) +# Defaults to 'undef' +# +# [*role_additional_attribute_mapping*] +# Additional attribute mappings for roles. Attribute mapping +# format is :, where ldap_attr is the +# attribute in the LDAP entry and user_attr is the Identity +# API attribute. (list value) +# Defaults to 'undef' +# +# [*group_tree_dn*] +# Search base for groups. (string value) +# Defaults to 'undef' +# +# [*group_filter*] +# LDAP search filter for groups. (string value) +# Defaults to 'undef' +# +# [*group_objectclass*] +# LDAP objectclass for groups. (string value) +# Defaults to 'undef' +# +# [*group_id_attribute*] +# LDAP attribute mapped to group id. (string value) +# Defaults to 'undef' +# +# [*group_name_attribute*] +# LDAP attribute mapped to group name. (string value) +# Defaults to 'undef' +# +# [*group_member_attribute*] +# LDAP attribute mapped to show group membership. (string value) +# Defaults to 'undef' +# +# [*group_desc_attribute*] +# LDAP attribute mapped to group description. (string value) +# Defaults to 'undef' +# +# [*group_attribute_ignore*] +# List of attributes stripped off the group on update. (list value) +# Defaults to 'undef' +# +# [*group_allow_create*] +# Allow group creation in LDAP backend. (boolean value) +# Defaults to 'undef' +# +# [*group_allow_update*] +# Allow group update in LDAP backend. (boolean value) +# Defaults to 'undef' +# +# [*group_allow_delete*] +# Allow group deletion in LDAP backend. (boolean value) +# Defaults to 'undef' +# +# [*group_additional_attribute_mapping*] +# Additional attribute mappings for groups. Attribute mapping +# format is :, where ldap_attr is the +# attribute in the LDAP entry and user_attr is the Identity +# API attribute. (list value) +# Defaults to 'undef' +# +# [*use_tls*] +# Enable TLS for communicating with LDAP servers. (boolean value) +# Defaults to 'undef' +# +# [*tls_cacertfile*] +# CA certificate file path for communicating with LDAP servers. (string value) +# Defaults to 'undef' +# +# [*tls_cacertdir*] +# CA certificate directory path for communicating with LDAP servers. (string value) +# Defaults to 'undef' +# +# [*tls_req_cert*] +# Valid options for tls_req_cert are demand, never, and allow. (string value) +# Defaults to 'undef' +# +# [*identity_driver*] +# Identity backend driver. (string value) +# Defaults to 'undef' +# +# [*credential_driver*] +# Credential backend driver. (string value) +# Defaults to 'undef' +# +# [*assignment_driver*] +# Assignment backend driver. (string value) +# Defaults to 'undef' +# +# [*use_pool*] +# Enable LDAP connection pooling. (boolean value) +# Defaults to false +# +# [*pool_size*] +# Connection pool size. (integer value) +# Defaults to '10' +# +# [*pool_retry_max*] +# Maximum count of reconnect trials. (integer value) +# Defaults to '3' +# +# [*pool_retry_delay*] +# Time span in seconds to wait between two reconnect trials. (floating point value) +# Defaults to '0.1' +# +# [*pool_connection_timeout*] +# Connector timeout in seconds. Value -1 indicates indefinite wait for response. (integer value) +# Defaults to '-1' +# +# [*pool_connection_lifetime*] +# Connection lifetime in seconds. (integer value) +# Defaults to '600' +# +# [*use_auth_pool*] +# Enable LDAP connection pooling for end user authentication. +# If use_pool is disabled, then this setting is meaningless and is not used at all. (boolean value) +# Defaults to false +# +# [*auth_pool_size*] +# End user auth connection pool size. (integer value) +# Defaults to '100' +# +# [*auth_pool_connection_lifetime*] +# End user auth connection lifetime in seconds. (integer value) +# Defaults to '60' +# +# === DEPRECATED group/name +# +# [*tenant_tree_dn*] +# [*tenant_filter*] +# [*tenant_objectclass*] +# [*tenant_id_attribute*] +# [*tenant_member_attribute*] +# [*tenant_name_attribute*] +# [*tenant_desc_attribute*] +# [*tenant_enabled_attribute*] +# [*tenant_domain_id_attribute*] +# [*tenant_attribute_ignore*] +# [*tenant_allow_create*] +# [*tenant_allow_update*] +# [*tenant_enabled_emulation*] +# [*tenant_enabled_emulation_dn*] +# [*tenant_additional_attribute_mapping*] +# [*tenant_allow_delete*] +# # == Dependencies # == Examples # == Authors @@ -28,6 +402,7 @@ class keystone::ldap( $user_enabled_attribute = undef, $user_enabled_mask = undef, $user_enabled_default = undef, + $user_enabled_invert = undef, $user_attribute_ignore = undef, $user_default_project_id_attribute = undef, $user_allow_create = undef, @@ -37,22 +412,38 @@ class keystone::ldap( $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, + $tenant_tree_dn = undef, #DEPRECATED + $project_tree_dn = undef, + $tenant_filter = undef, #DEPRECATED + $project_filter = undef, + $tenant_objectclass = undef, #DEPRECATED + $project_objectclass = undef, + $tenant_id_attribute = undef, #DEPRECATED + $project_id_attribute = undef, + $tenant_member_attribute = undef, #DEPRECATED + $project_member_attribute = undef, + $tenant_desc_attribute = undef, #DEPRECATED + $project_desc_attribute = undef, + $tenant_name_attribute = undef, #DEPRECATED + $project_name_attribute = undef, + $tenant_enabled_attribute = undef, #DEPRECATED + $project_enabled_attribute = undef, + $tenant_domain_id_attribute = undef, #DEPRECATED + $project_domain_id_attribute = undef, + $tenant_attribute_ignore = undef, #DEPRECATED + $project_attribute_ignore = undef, + $tenant_allow_create = undef, #DEPRECATED + $project_allow_create = undef, + $tenant_allow_update = undef, #DEPRECATED + $project_allow_update = undef, + $tenant_allow_delete = undef, #DEPRECATED + $project_allow_delete = undef, + $tenant_enabled_emulation = undef, #DEPRECATED + $project_enabled_emulation = undef, + $tenant_enabled_emulation_dn = undef, #DEPRECATED + $project_enabled_emulation_dn = undef, + $tenant_additional_attribute_mapping = undef, #DEPRECATED + $project_additional_attribute_mapping= undef, $role_tree_dn = undef, $role_filter = undef, $role_objectclass = undef, @@ -76,17 +467,205 @@ class keystone::ldap( $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, + $credential_driver = undef, + $use_pool = false, + $pool_size = 10, + $pool_retry_max = 3, + $pool_retry_delay = 0.1, + $pool_connection_timeout = -1, + $pool_connection_lifetime = 600, + $use_auth_pool = false, + $auth_pool_size = 100, + $auth_pool_connection_lifetime = 60, ) { - package { 'python-ldap': + # In Juno the term "tenant" was deprecated in the config in favor of "project" + # Let's assume project_ is being used and warning otherwise. If both are set we will + # fail, because having both set may cause unexpected results in Keystone. + if ($tenant_tree_dn) { + $project_tree_dn_real = $tenant_tree_dn + warning ('tenant_tree_dn is deprecated in Juno. switch to project_tree_dn') + if ($project_tree_dn) { + fail ('tenant_tree_dn and project_tree_dn are both set. results may be unexpected') + } + } + else { + $project_tree_dn_real = $project_tree_dn + } + + if ($tenant_filter) { + $project_filter_real = $tenant_filter + warning ('tenant_filter is deprecated in Juno. switch to project_filter') + if ($project_filter) { + fail ('tenant_filter and project_filter are both set. results may be unexpected') + } + } + else { + $project_filter_real = $project_filter + } + + if ($tenant_objectclass) { + $project_objectclass_real = $tenant_objectclass + warning ('tenant_objectclass is deprecated in Juno. switch to project_objectclass') + if ($project_objectclass) { + fail ('tenant_objectclass and project_objectclass are both set. results may be unexpected') + } + } + else { + $project_objectclass_real = $project_objectclass + } + + if ($tenant_id_attribute) { + $project_id_attribute_real = $tenant_id_attribute + warning ('tenant_id_attribute is deprecated in Juno. switch to project_id_attribute') + if ($project_id_attribute) { + fail ('tenant_id_attribute and project_id_attribute are both set. results may be unexpected') + } + } + else { + $project_id_attribute_real = $project_id_attribute + } + + if ($tenant_member_attribute) { + $project_member_attribute_real = $tenant_member_attribute + warning ('tenant_member_attribute is deprecated in Juno. switch to project_member_attribute') + if ($project_member_attribute) { + fail ('tenant_member_attribute and project_member_attribute are both set. results may be unexpected') + } + } + else { + $project_member_attribute_real = $project_member_attribute + } + + if ($tenant_desc_attribute) { + $project_desc_attribute_real = $tenant_desc_attribute + warning ('tenant_desc_attribute is deprecated in Juno. switch to project_desc_attribute') + if ($project_desc_attribute) { + fail ('tenant_desc_attribute and project_desc_attribute are both set. results may be unexpected') + } + } + else { + $project_desc_attribute_real = $project_desc_attribute + } + + if ($tenant_name_attribute) { + $project_name_attribute_real = $tenant_name_attribute + warning ('tenant_name_attribute is deprecated in Juno. switch to project_name_attribute') + if ($project_name_attribute) { + fail ('tenant_name_attribute and project_name_attribute are both set. results may be unexpected') + } + } + else { + $project_name_attribute_real = $project_name_attribute + } + + if ($tenant_enabled_attribute) { + $project_enabled_attribute_real = $tenant_enabled_attribute + warning ('tenant_enabled_attribute is deprecated in Juno. switch to project_enabled_attribute') + if ($project_enabled_attribute) { + fail ('tenant_enabled_attribute and project_enabled_attribute are both set. results may be unexpected') + } + } + else { + $project_enabled_attribute_real = $project_enabled_attribute + } + + if ($tenant_attribute_ignore) { + $project_attribute_ignore_real = $tenant_attribute_ignore + warning ('tenant_attribute_ignore is deprecated in Juno. switch to project_attribute_ignore') + if ($project_attribute_ignore) { + fail ('tenant_attribute_ignore and project_attribute_ignore are both set. results may be unexpected') + } + } + else { + $project_attribute_ignore_real = $project_attribute_ignore + } + + if ($tenant_domain_id_attribute) { + $project_domain_id_attribute_real = $tenant_domain_id_attribute + warning ('tenant_domain_id_attribute is deprecated in Juno. switch to project_domain_id_attribute') + if ($project_domain_id_attribute) { + fail ('tenant_domain_id_attribute and project_domain_id_attribute are both set. results may be unexpected') + } + } + else { + $project_domain_id_attribute_real = $project_domain_id_attribute + } + + if ($tenant_allow_create) { + $project_allow_create_real = $tenant_allow_create + warning ('tenant_allow_create is deprecated in Juno. switch to project_allow_create') + if ($project_allow_create) { + fail ('tenant_allow_create and project_allow_create are both set. results may be unexpected') + } + } + else { + $project_allow_create_real = $project_allow_create + } + + if ($tenant_allow_update) { + $project_allow_update_real = $tenant_allow_update + warning ('tenant_allow_update is deprecated in Juno. switch to project_allow_update') + if ($project_allow_update) { + fail ('tenant_allow_update and project_allow_update are both set. results may be unexpected') + } + } + else { + $project_allow_update_real = $project_allow_update + } + + if ($tenant_allow_delete) { + $project_allow_delete_real = $tenant_allow_delete + warning ('tenant_allow_delete is deprecated in Juno. switch to project_allow_delete') + if ($project_allow_delete) { + fail ('tenant_allow_delete and project_allow_delete are both set. results may be unexpected') + } + } + else { + $project_allow_delete_real = $project_allow_delete + } + + if ($tenant_enabled_emulation) { + $project_enabled_emulation_real = $tenant_enabled_emulation + warning ('tenant_enabled_emulation is deprecated in Juno. switch to project_enabled_emulation') + if ($project_enabled_emulation) { + fail ('tenant_enabled_emulation and project_enabled_emulation are both set. results may be unexpected') + } + } + else { + $project_enabled_emulation_real = $project_enabled_emulation + } + + if ($tenant_enabled_emulation_dn) { + $project_enabled_emulation_dn_real = $tenant_enabled_emulation_dn + warning ('tenant_enabled_emulation_dn is deprecated in Juno. switch to project_enabled_emulation_dn') + if ($project_enabled_emulation_dn) { + fail ('tenant_enabled_emulation_dn and project_enabled_emulation_dn are both set. results may be unexpected') + } + } + else { + $project_enabled_emulation_dn_real = $project_enabled_emulation_dn + } + + if ($tenant_additional_attribute_mapping) { + $project_additional_attribute_mapping_real = $tenant_additional_attribute_mapping + warning ('tenant_additional_attribute_mapping is deprecated in Juno. switch to project_additional_attribute_mapping') + if ($project_additional_attribute_mapping) { + fail ('tenant_additional_attribute_mapping and project_additional_attribute_mapping are both set. results may be unexpected') + } + } + else { + $project_additional_attribute_mapping_real = $project_additional_attribute_mapping + } + + $ldap_packages = ['python-ldap', 'python-ldappool'] + package { $ldap_packages: ensure => present, } @@ -103,6 +682,12 @@ class keystone::ldap( } } + if ($credential_driver != undef) { + if ! ($credential_driver =~ /^keystone.credential.backends.*Credential$/) { + fail('credential driver should be of the form \'keystone.credential.backends.*Credential\'') + } + } + if ($tls_cacertdir != undef) { file { $tls_cacertdir: ensure => directory @@ -110,74 +695,85 @@ class keystone::ldap( } 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; + '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_enabled_invert': value => $user_enabled_invert; + '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/project_tree_dn': value => $project_tree_dn_real; + 'ldap/project_filter': value => $project_filter_real; + 'ldap/project_objectclass': value => $project_objectclass_real; + 'ldap/project_id_attribute': value => $project_id_attribute_real; + 'ldap/project_member_attribute': value => $project_member_attribute_real; + 'ldap/project_desc_attribute': value => $project_desc_attribute_real; + 'ldap/project_name_attribute': value => $project_name_attribute_real; + 'ldap/project_enabled_attribute': value => $project_enabled_attribute_real; + 'ldap/project_attribute_ignore': value => $project_attribute_ignore_real; + 'ldap/project_domain_id_attribute': value => $project_domain_id_attribute_real; + 'ldap/project_allow_create': value => $project_allow_create_real; + 'ldap/project_allow_update': value => $project_allow_update_real; + 'ldap/project_allow_delete': value => $project_allow_delete_real; + 'ldap/project_enabled_emulation': value => $project_enabled_emulation_real; + 'ldap/project_enabled_emulation_dn': value => $project_enabled_emulation_dn_real; + 'ldap/project_additional_attribute_mapping': value => $project_additional_attribute_mapping_real; + '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; + 'ldap/use_pool': value => $use_pool; + 'ldap/pool_size': value => $pool_size; + 'ldap/pool_retry_max': value => $pool_retry_max; + 'ldap/pool_retry_delay': value => $pool_retry_delay; + 'ldap/pool_connection_timeout': value => $pool_connection_timeout; + 'ldap/pool_connection_lifetime': value => $pool_connection_lifetime; + 'ldap/use_auth_pool': value => $use_auth_pool; + 'ldap/auth_pool_size': value => $auth_pool_size; + 'ldap/auth_pool_connection_lifetime': value => $auth_pool_connection_lifetime; + 'identity/driver': value => $identity_driver; + 'credential/driver': value => $credential_driver; + 'assignment/driver': value => $assignment_driver; } } diff --git a/deployment/puppet/keystone/manifests/logging.pp b/deployment/puppet/keystone/manifests/logging.pp new file mode 100644 index 0000000000..dade7df735 --- /dev/null +++ b/deployment/puppet/keystone/manifests/logging.pp @@ -0,0 +1,211 @@ +# Class keystone::logging +# +# keystone extended logging configuration +# +# == parameters +# +# [*logging_context_format_string*] +# (optional) Format string to use for log messages with context. +# Defaults to undef. +# Example: '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s\ +# [%(request_id)s %(user_identity)s] %(instance)s%(message)s' +# +# [*logging_default_format_string*] +# (optional) Format string to use for log messages without context. +# Defaults to undef. +# Example: '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s\ +# [-] %(instance)s%(message)s' +# +# [*logging_debug_format_suffix*] +# (optional) Formatted data to append to log format when level is DEBUG. +# Defaults to undef. +# Example: '%(funcName)s %(pathname)s:%(lineno)d' +# +# [*logging_exception_prefix*] +# (optional) Prefix each line of exception output with this format. +# Defaults to undef. +# Example: '%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s' +# +# [*log_config_append*] +# The name of an additional logging configuration file. +# Defaults to undef. +# See https://docs.python.org/2/howto/logging.html +# +# [*default_log_levels*] +# (optional) Hash of logger (keys) and level (values) pairs. +# Defaults to undef. +# Example: +# { 'amqp' => 'WARN', 'amqplib' => 'WARN', 'boto' => 'WARN', +# 'qpid' => 'WARN', 'sqlalchemy' => 'WARN', 'suds' => 'INFO', +# 'oslo.messaging' => 'INFO', 'iso8601' => 'WARN', +# 'requests.packages.urllib3.connectionpool' => 'WARN', +# 'urllib3.connectionpool' => 'WARN', +# 'websocket' => 'WARN', 'keystonemiddleware' => 'WARN', +# 'routes.middleware' => 'WARN', stevedore => 'WARN' } +# +# [*publish_errors*] +# (optional) Publish error events (boolean value). +# Defaults to undef (false if unconfigured). +# +# [*fatal_deprecations*] +# (optional) Make deprecations fatal (boolean value) +# Defaults to undef (false if unconfigured). +# +# [*instance_format*] +# (optional) If an instance is passed with the log message, format it +# like this (string value). +# Defaults to undef. +# Example: '[instance: %(uuid)s] ' +# +# [*instance_uuid_format*] +# (optional) If an instance UUID is passed with the log message, format +# it like this (string value). +# Defaults to undef. +# Example: instance_uuid_format='[instance: %(uuid)s] ' + +# [*log_date_format*] +# (optional) Format string for %%(asctime)s in log records. +# Defaults to undef. +# Example: 'Y-%m-%d %H:%M:%S' + +class keystone::logging( + $logging_context_format_string = undef, + $logging_default_format_string = undef, + $logging_debug_format_suffix = undef, + $logging_exception_prefix = undef, + $log_config_append = undef, + $default_log_levels = undef, + $publish_errors = undef, + $fatal_deprecations = undef, + $instance_format = undef, + $instance_uuid_format = undef, + $log_date_format = undef, +) { + + if $logging_context_format_string { + keystone_config { + 'DEFAULT/logging_context_format_string' : + value => $logging_context_format_string; + } + } + else { + keystone_config { + 'DEFAULT/logging_context_format_string' : ensure => absent; + } + } + + if $logging_default_format_string { + keystone_config { + 'DEFAULT/logging_default_format_string' : + value => $logging_default_format_string; + } + } + else { + keystone_config { + 'DEFAULT/logging_default_format_string' : ensure => absent; + } + } + + if $logging_debug_format_suffix { + keystone_config { + 'DEFAULT/logging_debug_format_suffix' : + value => $logging_debug_format_suffix; + } + } + else { + keystone_config { + 'DEFAULT/logging_debug_format_suffix' : ensure => absent; + } + } + + if $logging_exception_prefix { + keystone_config { + 'DEFAULT/logging_exception_prefix' : value => $logging_exception_prefix; + } + } + else { + keystone_config { + 'DEFAULT/logging_exception_prefix' : ensure => absent; + } + } + + if $log_config_append { + keystone_config { + 'DEFAULT/log_config_append' : value => $log_config_append; + } + } + else { + keystone_config { + 'DEFAULT/log_config_append' : ensure => absent; + } + } + + if $default_log_levels { + keystone_config { + 'DEFAULT/default_log_levels' : + value => join(sort(join_keys_to_values($default_log_levels, '=')), ','); + } + } + else { + keystone_config { + 'DEFAULT/default_log_levels' : ensure => absent; + } + } + + if $publish_errors { + keystone_config { + 'DEFAULT/publish_errors' : value => $publish_errors; + } + } + else { + keystone_config { + 'DEFAULT/publish_errors' : ensure => absent; + } + } + + if $fatal_deprecations { + keystone_config { + 'DEFAULT/fatal_deprecations' : value => $fatal_deprecations; + } + } + else { + keystone_config { + 'DEFAULT/fatal_deprecations' : ensure => absent; + } + } + + if $instance_format { + keystone_config { + 'DEFAULT/instance_format' : value => $instance_format; + } + } + else { + keystone_config { + 'DEFAULT/instance_format' : ensure => absent; + } + } + + if $instance_uuid_format { + keystone_config { + 'DEFAULT/instance_uuid_format' : value => $instance_uuid_format; + } + } + else { + keystone_config { + 'DEFAULT/instance_uuid_format' : ensure => absent; + } + } + + if $log_date_format { + keystone_config { + 'DEFAULT/log_date_format' : value => $log_date_format; + } + } + else { + keystone_config { + 'DEFAULT/log_date_format' : ensure => absent; + } + } + + +} diff --git a/deployment/puppet/keystone/manifests/params.pp b/deployment/puppet/keystone/manifests/params.pp index 8127036ef1..12660caee0 100644 --- a/deployment/puppet/keystone/manifests/params.pp +++ b/deployment/puppet/keystone/manifests/params.pp @@ -6,26 +6,33 @@ class keystone::params { case $::osfamily { 'Debian': { - $package_name = 'keystone' - $service_name = 'keystone' - $keystone_wsgi_script_path = '/usr/lib/cgi-bin/keystone' + $package_name = 'keystone' + $service_name = 'keystone' + $keystone_wsgi_script_path = '/usr/lib/cgi-bin/keystone' + $python_memcache_package_name = 'python-memcache' + $paste_config = undef case $::operatingsystem { 'Debian': { $service_provider = undef $keystone_wsgi_script_source = '/usr/share/keystone/wsgi.py' } default: { + # NOTE: Ubuntu does not currently provide the keystone wsgi script in the + # keystone packages. When Ubuntu does provide the script, change this + # to use the correct path (which I'm assuming will be the same as Debian). $service_provider = 'upstart' $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' + $package_name = 'openstack-keystone' + $service_name = 'openstack-keystone' + $keystone_wsgi_script_path = '/var/www/cgi-bin/keystone' + $python_memcache_package_name = 'python-memcached' + $service_provider = undef + $keystone_wsgi_script_source = '/usr/share/keystone/keystone.wsgi' + $paste_config = '/usr/share/keystone/keystone-dist-paste.ini' } } } diff --git a/deployment/puppet/keystone/manifests/policy.pp b/deployment/puppet/keystone/manifests/policy.pp new file mode 100644 index 0000000000..13be064b08 --- /dev/null +++ b/deployment/puppet/keystone/manifests/policy.pp @@ -0,0 +1,39 @@ +# == Class: keystone::policy +# +# Configure the keystone policies +# +# === Parameters +# +# [*policies*] +# (optional) Set of policies to configure for keystone +# Example : +# { +# 'keystone-context_is_admin' => { +# 'key' => 'context_is_admin', +# 'value' => 'true' +# }, +# 'keystone-default' => { +# 'key' => 'default', +# 'value' => 'rule:admin_or_owner' +# } +# } +# Defaults to empty hash. +# +# [*policy_path*] +# (optional) Path to the nova policy.json file +# Defaults to /etc/keystone/policy.json +# +class keystone::policy ( + $policies = {}, + $policy_path = '/etc/keystone/policy.json', +) { + + validate_hash($policies) + + Openstacklib::Policy::Base { + file_path => $policy_path, + } + + create_resources('openstacklib::policy::base', $policies) + +} diff --git a/deployment/puppet/keystone/manifests/python.pp b/deployment/puppet/keystone/manifests/python.pp index 858fd65042..32adc63f43 100644 --- a/deployment/puppet/keystone/manifests/python.pp +++ b/deployment/puppet/keystone/manifests/python.pp @@ -1,6 +1,16 @@ +# == Class keystone::python # # installs client python libraries for keystone # +# === Parameters: +# +# [*client_package_name*] +# (optional) The name of python keystone client package +# Defaults to $keystone::params::client_package_name +# +# [*ensure*] +# (optional) The state for the keystone client package +# Defaults to 'present' # class keystone::python ( $client_package_name = $keystone::params::client_package_name, diff --git a/deployment/puppet/keystone/manifests/resource/service_identity.pp b/deployment/puppet/keystone/manifests/resource/service_identity.pp new file mode 100644 index 0000000000..9bbd1b13ae --- /dev/null +++ b/deployment/puppet/keystone/manifests/resource/service_identity.pp @@ -0,0 +1,164 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Definition: keystone::resource::service_identity +# +# This resource configures Keystone resources for an OpenStack service. +# +# == Parameters: +# +# [*password*] +# Password to create for the service user; +# string; required +# +# [*auth_name*] +# The name of the service user; +# string; optional; default to the $title of the resource, i.e. 'nova' +# +# [*service_name*] +# Name of the service; +# string; required +# +# [*service_type*] +# Type of the service; +# string; required +# +# [*service_description*] +# Description of the service; +# string; optional: default to '$name service' +# +# [*public_url*] +# Public endpoint URL; +# string; required +# +# [*internal_url*] +# Internal endpoint URL; +# string; required +# +# [*admin_url*] +# Admin endpoint URL; +# string; required +# +# [*region*] +# Endpoint region; +# string; optional: default to 'RegionOne' +# +# [*tenant*] +# Service tenant; +# string; optional: default to 'services' +# +# [*ignore_default_tenant*] +# Ignore setting the default tenant value when the user is created. +# string; optional: default to false +# +# [*roles*] +# List of roles; +# string; optional: default to ['admin'] +# +# [*domain*] +# User domain (keystone v3), not implemented yet. +# string; optional: default to undef +# +# [*email*] +# Service email; +# string; optional: default to '$auth_name@localhost' +# +# [*configure_endpoint*] +# Whether to create the endpoint. +# string; optional: default to True +# +# [*configure_user*] +# Whether to create the user. +# string; optional: default to True +# +# [*configure_user_role*] +# Whether to create the user role. +# string; optional: default to True +# +# [*configure_service*] +# Whether to create the service. +# string; optional: default to True +# +define keystone::resource::service_identity( + $admin_url = false, + $internal_url = false, + $password = false, + $public_url = false, + $service_type = false, + $auth_name = $name, + $configure_endpoint = true, + $configure_user = true, + $configure_user_role = true, + $configure_service = true, + $domain = undef, + $email = "${name}@localhost", + $region = 'RegionOne', + $service_name = undef, + $service_description = "${name} service", + $tenant = 'services', + $ignore_default_tenant = false, + $roles = ['admin'], +) { + + if $domain { + warning('Keystone domains are not yet managed by puppet-keystone.') + } + + if $service_name == undef { + $service_name_real = $auth_name + } else { + $service_name_real = $service_name + } + + if $configure_user { + ensure_resource('keystone_user', $auth_name, { + 'ensure' => 'present', + 'enabled' => true, + 'password' => $password, + 'email' => $email, + 'tenant' => $tenant, + 'ignore_default_tenant' => $ignore_default_tenant, + }) + } + + if $configure_user_role { + ensure_resource('keystone_user_role', "${auth_name}@${tenant}", { + 'ensure' => 'present', + 'roles' => $roles, + }) + if $configure_user { + Keystone_user[$auth_name] -> Keystone_user_role["${auth_name}@${tenant}"] + } + } + + if $configure_service { + ensure_resource('keystone_service', $service_name_real, { + 'ensure' => 'present', + 'type' => $service_type, + 'description' => $service_description, + }) + } + + if $configure_endpoint { + ensure_resource('keystone_endpoint', "${region}/${service_name_real}", { + 'ensure' => 'present', + 'public_url' => $public_url, + 'admin_url' => $admin_url, + 'internal_url' => $internal_url, + }) + } +} diff --git a/deployment/puppet/keystone/manifests/roles/admin.pp b/deployment/puppet/keystone/manifests/roles/admin.pp index 499cc13361..aa5abd72fa 100644 --- a/deployment/puppet/keystone/manifests/roles/admin.pp +++ b/deployment/puppet/keystone/manifests/roles/admin.pp @@ -1,3 +1,4 @@ +# == Class: keystone::roles::admin # # This class implements some reasonable admin defaults for keystone. # @@ -8,12 +9,49 @@ # * admin role # * adds admin role to admin user on the "admin" tenant # -# [*Parameters*] +# === 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. +# [*email*] +# The email address for the admin. Required. +# +# [*password*] +# The admin password. Required. +# +# [*admin_roles*] +# The list of the roles with admin privileges. Optional. +# Defaults to ['admin']. +# +# [*admin_tenant*] +# The name of the tenant to be used for admin privileges. Optional. +# Defaults to openstack. +# +# [*service_tenant*] +# The name of service keystone tenant. Optional. +# Defaults to 'services'. +# +# [*admin*] +# Admin user. Optional. +# Defaults to admin. +# +# [*ignore_default_tenant*] +# Ignore setting the default tenant value when the user is created. Optional. +# Defaults to false. +# +# [*admin_tenant_desc*] +# Optional. Description for admin tenant, +# Defaults to 'admin tenant' +# +# [*service_tenant_desc*] +# Optional. Description for admin tenant, +# Defaults to 'Tenant for the openstack services' +# +# [*configure_user*] +# Optional. Should the admin user be created? +# Defaults to 'true'. +# +# [*configure_user_role*] +# Optional. Should the admin role be configured for the admin user? +# Defaulst to 'true'. # # == Dependencies # == Examples @@ -28,34 +66,47 @@ class keystone::roles::admin( $email, $password, - $admin = 'admin', - $admin_tenant = 'openstack', - $service_tenant = 'services' + $admin = 'admin', + $admin_tenant = 'openstack', + $admin_roles = ['admin'], + $service_tenant = 'services', + $ignore_default_tenant = false, + $admin_tenant_desc = 'admin tenant', + $service_tenant_desc = 'Tenant for the openstack services', + $configure_user = true, + $configure_user_role = true, ) { keystone_tenant { $service_tenant: ensure => present, enabled => true, - description => 'Tenant for the openstack services', + description => $service_tenant_desc, } 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, + description => $admin_tenant_desc, } keystone_role { 'admin': ensure => present, } - keystone_user_role { "${admin}@${admin_tenant}": - ensure => present, - roles => 'admin', + + if $configure_user { + keystone_user { $admin: + ensure => present, + enabled => true, + tenant => $admin_tenant, + email => $email, + password => $password, + ignore_default_tenant => $ignore_default_tenant, + } + } + + if $configure_user_role { + keystone_user_role { "${admin}@${admin_tenant}": + ensure => present, + roles => $admin_roles, + } } } diff --git a/deployment/puppet/keystone/manifests/service.pp b/deployment/puppet/keystone/manifests/service.pp new file mode 100644 index 0000000000..46312144ab --- /dev/null +++ b/deployment/puppet/keystone/manifests/service.pp @@ -0,0 +1,123 @@ +# == Class keystone::service +# +# Encapsulates the keystone service to a class. +# This allows resources that require keystone to +# require this class, which can optionally +# validate that the service can actually accept +# connections. +# +# === Parameters +# +# [*ensure*] +# (optional) The desired state of the keystone service +# Defaults to undef +# +# [*service_name*] +# (optional) The name of the keystone service +# Defaults to $::keystone::params::service_name +# +# [*enable*] +# (optional) Whether to enable the keystone service +# Defaults to true +# +# [*hasstatus*] +# (optional) Whether the keystone service has status +# Defaults to true +# +# [*hasrestart*] +# (optional) Whether the keystone service has restart +# Defaults to true +# +# [*provider*] +# (optional) Provider for keystone service +# Defaults to $::keystone::params::service_provider +# +# [*validate*] +# (optional) Whether to validate the service is working after any service refreshes +# Defaults to false +# +# [*admin_token*] +# (optional) The admin token to use for validation +# Defaults to undef +# +# [*admin_endpoint*] +# (optional) The admin endpont to use for validation +# Defaults to 'http://localhost:35357/v2.0' +# +# [*retries*] +# (optional) Number of times to retry validation +# Defaults to 10 +# +# [*delay*] +# (optional) Number of seconds between validation attempts +# Defaults to 2 +# +# [*insecure*] +# (optional) Whether to validate keystone connections +# using the --insecure option with keystone client. +# Defaults to false +# +# [*cacert*] +# (optional) Whether to validate keystone connections +# using the specified argument with the --os-cacert option +# with keystone client. +# Defaults to undef +# +class keystone::service( + $ensure = undef, + $service_name = $::keystone::params::service_name, + $enable = true, + $hasstatus = true, + $hasrestart = true, + $provider = $::keystone::params::service_provider, + $validate = false, + $admin_token = undef, + $admin_endpoint = 'http://localhost:35357/v2.0', + $retries = 10, + $delay = 2, + $insecure = false, + $cacert = undef, +) { + include ::keystone::params + + service { 'keystone': + ensure => $ensure, + name => $service_name, + enable => $enable, + hasstatus => $hasstatus, + hasrestart => $hasrestart, + provider => $provider + } + + if $insecure { + $insecure_s = '--insecure' + } else { + $insecure_s = '' + } + + if $cacert { + $cacert_s = "--os-cacert ${cacert}" + } else { + $cacert_s = '' + } + + if $validate and $admin_token and $admin_endpoint { + $cmd = "openstack --os-auth-url ${admin_endpoint} --os-token ${admin_token} ${insecure_s} ${cacert_s} user list" + $catch = 'name' + exec { 'validate_keystone_connection': + path => '/usr/bin:/bin:/usr/sbin:/sbin', + provider => shell, + command => $cmd, + subscribe => Service['keystone'], + refreshonly => true, + tries => $retries, + try_sleep => $delay + } + + Exec['validate_keystone_connection'] -> Keystone_user<||> + Exec['validate_keystone_connection'] -> Keystone_role<||> + Exec['validate_keystone_connection'] -> Keystone_tenant<||> + Exec['validate_keystone_connection'] -> Keystone_service<||> + Exec['validate_keystone_connection'] -> Keystone_endpoint<||> + } +} diff --git a/deployment/puppet/keystone/manifests/wsgi/apache.pp b/deployment/puppet/keystone/manifests/wsgi/apache.pp index 903b6af418..165e399e96 100644 --- a/deployment/puppet/keystone/manifests/wsgi/apache.pp +++ b/deployment/puppet/keystone/manifests/wsgi/apache.pp @@ -46,15 +46,41 @@ # Optional. Defaults to 1 # # [*ssl_cert*] +# (optional) Path to SSL certificate +# Default to apache::vhost 'ssl_*' defaults. +# # [*ssl_key*] +# (optional) Path to SSL key +# Default to apache::vhost 'ssl_*' defaults. +# # [*ssl_chain*] +# (optional) SSL chain +# Default to apache::vhost 'ssl_*' defaults. +# # [*ssl_ca*] +# (optional) Path to SSL certificate authority +# Default to apache::vhost 'ssl_*' defaults. +# # [*ssl_crl_path*] +# (optional) Path to SSL certificate revocation list +# Default to apache::vhost 'ssl_*' defaults. +# # [*ssl_crl*] +# (optional) SSL certificate revocation list name +# Default to apache::vhost 'ssl_*' defaults. +# # [*ssl_certs_dir*] # apache::vhost ssl parameters. # Optional. Default to apache::vhost 'ssl_*' defaults. # +# [*priority*] +# (optional) The priority for the vhost. +# Defaults to '10' +# +# [*threads*] +# (optional) The number of threads for the vhost. +# Defaults to $::processorcount +# # == Dependencies # # requires Class['apache'] & Class['keystone'] @@ -72,41 +98,40 @@ # # == Authors # -# François Charlier +# Francois Charlier # # == Copyright # # Copyright 2013 eNovance # 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, + $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', ) { - include keystone::params + include ::keystone::params include ::apache include ::apache::mod::wsgi - include keystone::db::sync + if $ssl { + include ::apache::mod::ssl + } - Exec <| title == 'keystone-manage pki_setup' |> ~> Service['httpd'] - Exec <| title == 'keystone-manage db_sync' |> ~> Service['httpd'] + Package['keystone'] -> Package['httpd'] Package['keystone'] ~> Service['httpd'] Keystone_config <| |> ~> Service['httpd'] Service['httpd'] -> Keystone_endpoint <| |> @@ -134,41 +159,44 @@ class keystone::wsgi::apache ( 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", - }, + file { 'keystone_wsgi_admin': + ensure => file, + path => "${::keystone::params::keystone_wsgi_script_path}/admin", + source => $::keystone::params::keystone_wsgi_script_source, + owner => 'keystone', + group => 'keystone', + mode => '0644', + # source file provided by keystone package + require => [File[$::keystone::params::keystone_wsgi_script_path], Package['keystone']], } - $wsgi_file_defaults = { - 'ensure' => $wsgi_script_ensure, - 'owner' => 'keystone', - 'group' => 'keystone', - 'mode' => '0644', - 'require' => File[$::keystone::params::keystone_wsgi_script_path], + file { 'keystone_wsgi_main': + ensure => file, + path => "${::keystone::params::keystone_wsgi_script_path}/main", + source => $::keystone::params::keystone_wsgi_script_source, + owner => 'keystone', + group => 'keystone', + mode => '0644', + # source file provided by keystone package + require => [File[$::keystone::params::keystone_wsgi_script_path], Package['keystone']], } - $wsgi_script_source_real = $wsgi_script_source ? { - default => $wsgi_script_source, - undef => $::keystone::params::keystone_wsgi_script_source, + $wsgi_daemon_process_options_main = { + user => 'keystone', + group => 'keystone', + processes => $workers, + threads => $threads, + display-name => 'keystone-main', } - case $wsgi_script_ensure { - default: { $wsgi_file_source = { 'source' => $wsgi_script_source_real } } - 'link': { $wsgi_file_source = { 'target' => $wsgi_script_source_real } } + $wsgi_daemon_process_options_admin = { + user => 'keystone', + group => 'keystone', + processes => $workers, + threads => $threads, + display-name => 'keystone-admin', } - create_resources('file', $wsgi_files, merge($wsgi_file_defaults, $wsgi_file_source)) - - $wsgi_daemon_process_options = { - user => 'keystone', - group => 'keystone', - processes => $workers, - threads => $threads - } $wsgi_script_aliases_main = hash([$public_path_real,"${::keystone::params::keystone_wsgi_script_path}/main"]) $wsgi_script_aliases_admin = hash([$admin_path_real, "${::keystone::params::keystone_wsgi_script_path}/admin"]) @@ -178,7 +206,8 @@ class keystone::wsgi::apache ( $wsgi_script_aliases_main_real = $wsgi_script_aliases_main } - apache::vhost { 'keystone_wsgi_main': + ::apache::vhost { 'keystone_wsgi_main': + ensure => 'present', servername => $servername, ip => $bind_host, port => $public_port, @@ -195,14 +224,15 @@ class keystone::wsgi::apache ( ssl_crl => $ssl_crl, ssl_certs_dir => $ssl_certs_dir, wsgi_daemon_process => 'keystone_main', - wsgi_daemon_process_options => $wsgi_daemon_process_options, + wsgi_daemon_process_options => $wsgi_daemon_process_options_main, wsgi_process_group => 'keystone_main', wsgi_script_aliases => $wsgi_script_aliases_main_real, - require => [Class['apache::mod::wsgi'], File['keystone_wsgi_main']], + require => File['keystone_wsgi_main'], } if $public_port != $admin_port { - apache::vhost { 'keystone_wsgi_admin': + ::apache::vhost { 'keystone_wsgi_admin': + ensure => 'present', servername => $servername, ip => $bind_host, port => $admin_port, @@ -219,10 +249,10 @@ class keystone::wsgi::apache ( ssl_crl => $ssl_crl, ssl_certs_dir => $ssl_certs_dir, wsgi_daemon_process => 'keystone_admin', - wsgi_daemon_process_options => $wsgi_daemon_process_options, + wsgi_daemon_process_options => $wsgi_daemon_process_options_admin, wsgi_process_group => 'keystone_admin', wsgi_script_aliases => $wsgi_script_aliases_admin, - require => [Class['apache::mod::wsgi'], File['keystone_wsgi_admin']], + require => File['keystone_wsgi_admin'], } } } diff --git a/deployment/puppet/keystone/metadata.json b/deployment/puppet/keystone/metadata.json new file mode 100644 index 0000000000..77e23afd4e --- /dev/null +++ b/deployment/puppet/keystone/metadata.json @@ -0,0 +1,39 @@ +{ + "name": "stackforge-keystone", + "version": "5.1.0", + "author": "Puppet Labs and OpenStack Contributors", + "summary": "Puppet module for OpenStack Keystone", + "license": "Apache-2.0", + "source": "git://github.com/openstack/puppet-keystone.git", + "project_page": "https://launchpad.net/puppet-keystone", + "issues_url": "https://bugs.launchpad.net/puppet-keystone", + "requirements": [ + { "name": "pe","version_requirement": "3.x" }, + { "name": "puppet","version_requirement": "3.x" } + ], + "operatingsystem_support": [ + { + "operatingsystem": "Debian", + "operatingsystemrelease": ["7"] + }, + { + "operatingsystem": "Fedora", + "operatingsystemrelease": ["20"] + }, + { + "operatingsystem": "RedHat", + "operatingsystemrelease": ["6.5","7"] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": ["12.04","14.04"] + } + ], + "description": "Installs and configures OpenStack Keystone (Identity).", + "dependencies": [ + { "name": "puppetlabs/apache", "version_requirement": ">=1.0.0 <2.0.0" }, + { "name": "puppetlabs/inifile", "version_requirement": ">=1.0.0 <2.0.0" }, + { "name": "puppetlabs/stdlib", "version_requirement": ">=4.0.0 <5.0.0" }, + { "name": "stackforge/openstacklib", "version_requirement": ">=5.0.0 <6.0.0" } + ] +} diff --git a/deployment/puppet/keystone/spec/acceptance/basic_keystone_spec.rb b/deployment/puppet/keystone/spec/acceptance/basic_keystone_spec.rb new file mode 100644 index 0000000000..93a81cc26a --- /dev/null +++ b/deployment/puppet/keystone/spec/acceptance/basic_keystone_spec.rb @@ -0,0 +1,92 @@ +require 'spec_helper_acceptance' + +describe 'basic keystone server with resources' do + + context 'default parameters' do + + it 'should work with no errors' do + pp= <<-EOS + Exec { logoutput => 'on_failure' } + + # Common resources + case $::osfamily { + 'Debian': { + include ::apt + class { '::openstack_extras::repo::debian::ubuntu': + release => 'kilo', + package_require => true, + } + } + 'RedHat': { + class { '::openstack_extras::repo::redhat::redhat': + # Kilo is not GA yet, so let's use the testing repo + manage_rdo => false, + repo_hash => { + 'rdo-kilo-testing' => { + 'baseurl' => 'https://repos.fedorapeople.org/repos/openstack/openstack-kilo/testing/el7/', + # packages are not GA so not signed + 'gpgcheck' => '0', + 'priority' => 97, + }, + }, + } + } + default: { + fail("Unsupported osfamily (${::osfamily})") + } + } + + class { '::mysql::server': } + + # Keystone resources + class { '::keystone::client': } + class { '::keystone::cron::token_flush': } + class { '::keystone::db::mysql': + password => 'keystone', + } + class { '::keystone': + verbose => true, + debug => true, + database_connection => 'mysql://keystone:keystone@127.0.0.1/keystone', + admin_token => 'admin_token', + enabled => true, + } + class { '::keystone::roles::admin': + email => 'test@example.tld', + password => 'a_big_secret', + } + class { '::keystone::endpoint': + public_url => "https://${::fqdn}:5000/", + admin_url => "https://${::fqdn}:35357/", + } + ::keystone::resource::service_identity { 'beaker-ci': + service_type => 'beaker', + service_description => 'beaker service', + service_name => 'beaker', + password => 'secret', + public_url => 'http://127.0.0.1:1234', + admin_url => 'http://127.0.0.1:1234', + internal_url => 'http://127.0.0.1:1234', + } + EOS + + + # Run it twice and test for idempotency + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe port(5000) do + it { is_expected.to be_listening.with('tcp') } + end + + describe port(35357) do + it { is_expected.to be_listening.with('tcp') } + end + + describe cron do + it { should have_entry('1 0 * * * keystone-manage token_flush >>/var/log/keystone/keystone-tokenflush.log 2>&1').with_user('keystone') } + end + + end +end diff --git a/deployment/puppet/keystone/spec/acceptance/nodesets/default.yml b/deployment/puppet/keystone/spec/acceptance/nodesets/default.yml new file mode 100644 index 0000000000..a2c1ecc63d --- /dev/null +++ b/deployment/puppet/keystone/spec/acceptance/nodesets/default.yml @@ -0,0 +1,9 @@ +HOSTS: + ubuntu-14.04-amd64: + roles: + - master + platform: ubuntu-14.04-amd64 + hypervisor : none + ip: 127.0.0.1 +CONFIG: + type: foss diff --git a/deployment/puppet/keystone/spec/acceptance/nodesets/nodepool-centos7.yml b/deployment/puppet/keystone/spec/acceptance/nodesets/nodepool-centos7.yml new file mode 100644 index 0000000000..575ae6732b --- /dev/null +++ b/deployment/puppet/keystone/spec/acceptance/nodesets/nodepool-centos7.yml @@ -0,0 +1,10 @@ +HOSTS: + centos-70-x64: + roles: + - master + platform: el-7-x86_64 + hypervisor : none + ip: 127.0.0.1 +CONFIG: + type: foss + set_env: false diff --git a/deployment/puppet/keystone/spec/acceptance/nodesets/nodepool-trusty.yml b/deployment/puppet/keystone/spec/acceptance/nodesets/nodepool-trusty.yml new file mode 100644 index 0000000000..a95d9f38db --- /dev/null +++ b/deployment/puppet/keystone/spec/acceptance/nodesets/nodepool-trusty.yml @@ -0,0 +1,10 @@ +HOSTS: + ubuntu-14.04-amd64: + roles: + - master + platform: ubuntu-14.04-amd64 + hypervisor : none + ip: 127.0.0.1 +CONFIG: + type: foss + set_env: false diff --git a/deployment/puppet/keystone/spec/classes/keystone_client_spec.rb b/deployment/puppet/keystone/spec/classes/keystone_client_spec.rb index 8e13655a90..2e58fad52a 100644 --- a/deployment/puppet/keystone/spec/classes/keystone_client_spec.rb +++ b/deployment/puppet/keystone/spec/classes/keystone_client_spec.rb @@ -3,7 +3,10 @@ require 'spec_helper' describe 'keystone::client' do describe "with default parameters" do - it { should contain_package('python-keystoneclient').with_ensure('present') } + it { is_expected.to contain_package('python-keystoneclient').with( + 'ensure' => 'present', + 'tag' => 'openstack' + ) } end describe "with specified version" do @@ -11,6 +14,9 @@ describe 'keystone::client' do {:ensure => '2013.1'} end - it { should contain_package('python-keystoneclient').with_ensure('2013.1') } + it { is_expected.to contain_package('python-keystoneclient').with( + 'ensure' => '2013.1', + 'tag' => 'openstack' + ) } end end diff --git a/deployment/puppet/keystone/spec/classes/keystone_cron_token_flush_spec.rb b/deployment/puppet/keystone/spec/classes/keystone_cron_token_flush_spec.rb new file mode 100644 index 0000000000..88e1fd5193 --- /dev/null +++ b/deployment/puppet/keystone/spec/classes/keystone_cron_token_flush_spec.rb @@ -0,0 +1,68 @@ +require 'spec_helper' + +describe 'keystone::cron::token_flush' do + + let :facts do + { :osfamily => 'Debian' } + end + + describe 'with default parameters' do + it 'configures a cron' do + is_expected.to contain_cron('keystone-manage token_flush').with( + :ensure => 'present', + :command => 'keystone-manage token_flush >>/var/log/keystone/keystone-tokenflush.log 2>&1', + :environment => 'PATH=/bin:/usr/bin:/usr/sbin SHELL=/bin/sh', + :user => 'keystone', + :minute => 1, + :hour => 0, + :monthday => '*', + :month => '*', + :weekday => '*' + ) + end + end + + describe 'when specifying a maxdelay param' do + let :params do + { + :maxdelay => 600 + } + end + + it 'configures a cron with delay' do + is_expected.to contain_cron('keystone-manage token_flush').with( + :ensure => 'present', + :command => 'sleep `expr ${RANDOM} \\% 600`; keystone-manage token_flush >>/var/log/keystone/keystone-tokenflush.log 2>&1', + :environment => 'PATH=/bin:/usr/bin:/usr/sbin SHELL=/bin/sh', + :user => 'keystone', + :minute => 1, + :hour => 0, + :monthday => '*', + :month => '*', + :weekday => '*' + ) + end + end + + describe 'when specifying a maxdelay param' do + let :params do + { + :ensure => 'absent' + } + end + + it 'configures a cron with delay' do + is_expected.to contain_cron('keystone-manage token_flush').with( + :ensure => 'absent', + :command => 'keystone-manage token_flush >>/var/log/keystone/keystone-tokenflush.log 2>&1', + :environment => 'PATH=/bin:/usr/bin:/usr/sbin SHELL=/bin/sh', + :user => 'keystone', + :minute => 1, + :hour => 0, + :monthday => '*', + :month => '*', + :weekday => '*' + ) + end + end +end diff --git a/deployment/puppet/keystone/spec/classes/keystone_db_mysql_spec.rb b/deployment/puppet/keystone/spec/classes/keystone_db_mysql_spec.rb index f41346620d..f032aa99f6 100644 --- a/deployment/puppet/keystone/spec/classes/keystone_db_mysql_spec.rb +++ b/deployment/puppet/keystone/spec/classes/keystone_db_mysql_spec.rb @@ -13,48 +13,23 @@ describe 'keystone::db::mysql' do { :osfamily => 'Debian' } end - let :param_defaults do + let :params do { 'password' => 'keystone_default_password', - 'dbname' => 'keystone', + } + end + + describe 'with only required params' do + it { is_expected.to contain_openstacklib__db__mysql('keystone').with( 'user' => 'keystone', - 'charset' => 'utf8', - 'collate' => 'utf8_unicode_ci', + 'password_hash' => '*B552157B14BCEDDCEAA06767A012F31BDAA9CE3D', + 'dbname' => 'keystone', '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]' + 'charset' => 'utf8', + :collate => 'utf8_general_ci', )} - end + describe "overriding allowed_hosts param to array" do let :params do { @@ -63,16 +38,6 @@ describe 'keystone::db::mysql' do } 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 @@ -82,11 +47,6 @@ describe 'keystone::db::mysql' do } 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 @@ -97,11 +57,6 @@ describe 'keystone::db::mysql' do } end - it {should_not contain_keystone__db__mysql__host_access("127.0.0.1").with( - :user => 'keystone', - :password => 'keystonepass2', - :database => 'keystone' - )} end end diff --git a/deployment/puppet/keystone/spec/classes/keystone_db_postgresql_spec.rb b/deployment/puppet/keystone/spec/classes/keystone_db_postgresql_spec.rb index 7efe94619d..ecdad5a28f 100644 --- a/deployment/puppet/keystone/spec/classes/keystone_db_postgresql_spec.rb +++ b/deployment/puppet/keystone/spec/classes/keystone_db_postgresql_spec.rb @@ -3,24 +3,56 @@ require 'spec_helper' describe 'keystone::db::postgresql' do let :req_params do - {:password => 'pw'} + { :password => 'pw' } end - let :facts do - { - :postgres_default_version => '8.4', - :osfamily => 'RedHat', - } + let :pre_condition do + 'include postgresql::server' end - describe 'with only required params' do - let :params do - req_params + context 'on a RedHat osfamily' do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '7.0', + :concat_basedir => '/var/lib/puppet/concat' + } end - it { should contain_postgresql__db('keystone').with( - :user => 'keystone', - :password => 'pw' - ) } + + context 'with only required parameters' do + let :params do + req_params + end + + it { is_expected.to contain_postgresql__server__db('keystone').with( + :user => 'keystone', + :password => 'md5c530c33636c58ae83ca933f39319273e' + )} + end + + end + + context 'on a Debian osfamily' do + let :facts do + { + :operatingsystemrelease => '7.8', + :operatingsystem => 'Debian', + :osfamily => 'Debian', + :concat_basedir => '/var/lib/puppet/concat' + } + end + + context 'with only required parameters' do + let :params do + req_params + end + + it { is_expected.to contain_postgresql__server__db('keystone').with( + :user => 'keystone', + :password => 'md5c530c33636c58ae83ca933f39319273e' + )} + end + end end diff --git a/deployment/puppet/keystone/spec/classes/keystone_endpoint_spec.rb b/deployment/puppet/keystone/spec/classes/keystone_endpoint_spec.rb index 61b596abd4..217d791f9d 100644 --- a/deployment/puppet/keystone/spec/classes/keystone_endpoint_spec.rb +++ b/deployment/puppet/keystone/spec/classes/keystone_endpoint_spec.rb @@ -2,14 +2,14 @@ require 'spec_helper' describe 'keystone::endpoint' do - it { should contain_keystone_service('keystone').with( + it { is_expected.to 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( + it { is_expected.to 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', @@ -26,7 +26,7 @@ describe 'keystone::endpoint' do :internal_url => 'https://identity-int.some.tld/some/internal/endpoint' } end - it { should contain_keystone_endpoint('RegionOne/keystone').with( + it { is_expected.to 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', @@ -41,59 +41,11 @@ describe 'keystone::endpoint' do end it 'internal_url should default to public_url' do - should contain_keystone_endpoint('RegionOne/keystone').with( + is_expected.to contain_keystone_endpoint('RegionOne/keystone').with( :ensure => 'present', :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 diff --git a/deployment/puppet/keystone/spec/classes/keystone_ldap_spec.rb b/deployment/puppet/keystone/spec/classes/keystone_ldap_spec.rb index 6d62f56f4c..0d36624c45 100644 --- a/deployment/puppet/keystone/spec/classes/keystone_ldap_spec.rb +++ b/deployment/puppet/keystone/spec/classes/keystone_ldap_spec.rb @@ -2,7 +2,7 @@ require 'spec_helper' describe 'keystone::ldap' do describe 'with basic params' do - let :params do + let :params do { :url => 'ldap://foo', :user => 'cn=foo,dc=example,dc=com', @@ -19,6 +19,7 @@ describe 'keystone::ldap' do :user_enabled_attribute => 'UserAccountControl', :user_enabled_mask => '2', :user_enabled_default => '512', + :user_enabled_invert => 'False', :user_attribute_ignore => '', :user_default_project_id_attribute => 'defaultProject', :user_allow_create => 'False', @@ -28,22 +29,22 @@ describe 'keystone::ldap' do :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', + :project_tree_dn => 'ou=projects,ou=openstack,dc=example,dc=com', + :project_filter => '', + :project_objectclass => 'organizationalUnit', + :project_id_attribute => 'ou', + :project_member_attribute => 'member', + :project_desc_attribute => 'description', + :project_name_attribute => 'ou', + :project_enabled_attribute => 'enabled', + :project_domain_id_attribute => 'businessCategory', + :project_attribute_ignore => '', + :project_allow_create => 'True', + :project_allow_update => 'True', + :project_allow_delete => 'True', + :project_enabled_emulation => 'False', + :project_enabled_emulation_dn => 'True', + :project_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', @@ -72,85 +73,170 @@ describe 'keystone::ldap' do :tls_cacertfile => '/etc/ssl/certs/ca-certificates.crt', :tls_req_cert => 'demand', :identity_driver => 'keystone.identity.backends.ldap.Identity', + :credential_driver => 'keystone.credential.backends.ldap.Credential', :assignment_driver => 'keystone.assignment.backends.ldap.Assignment', + :use_pool => 'True', + :pool_size => 20, + :pool_retry_max => 2, + :pool_retry_delay => 0.2, + :pool_connection_timeout => 222, + :pool_connection_lifetime => 222, + :use_auth_pool => 'True', + :auth_pool_size => 20, + :auth_pool_connection_lifetime => 200, } end - it { should contain_package('python-ldap') } + it { is_expected.to contain_package('python-ldap') } + it { is_expected.to contain_package('python-ldappool') } it 'should have basic params' do - 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') + # basic params + is_expected.to contain_keystone_config('ldap/url').with_value('ldap://foo') + is_expected.to contain_keystone_config('ldap/user').with_value('cn=foo,dc=example,dc=com') + is_expected.to contain_keystone_config('ldap/password').with_value('abcdefg').with_secret(true) + is_expected.to contain_keystone_config('ldap/suffix').with_value('dc=example,dc=com') + is_expected.to contain_keystone_config('ldap/query_scope').with_value('sub') + is_expected.to contain_keystone_config('ldap/page_size').with_value('50') - should contain_keystone_config('ldap/user_tree_dn').with_value('cn=users,dc=example,dc=com') - 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') + # users + is_expected.to contain_keystone_config('ldap/user_tree_dn').with_value('cn=users,dc=example,dc=com') + is_expected.to contain_keystone_config('ldap/user_filter').with_value('(memberOf=cn=openstack,cn=groups,cn=accounts,dc=example,dc=com)') + is_expected.to contain_keystone_config('ldap/user_objectclass').with_value('inetUser') + is_expected.to contain_keystone_config('ldap/user_id_attribute').with_value('uid') + is_expected.to contain_keystone_config('ldap/user_name_attribute').with_value('cn') + is_expected.to contain_keystone_config('ldap/user_mail_attribute').with_value('mail') + is_expected.to contain_keystone_config('ldap/user_enabled_attribute').with_value('UserAccountControl') + is_expected.to contain_keystone_config('ldap/user_enabled_mask').with_value('2') + is_expected.to contain_keystone_config('ldap/user_enabled_default').with_value('512') + is_expected.to contain_keystone_config('ldap/user_enabled_invert').with_value('False') + is_expected.to contain_keystone_config('ldap/user_attribute_ignore').with_value('') + is_expected.to contain_keystone_config('ldap/user_default_project_id_attribute').with_value('defaultProject') + is_expected.to contain_keystone_config('ldap/user_tree_dn').with_value('cn=users,dc=example,dc=com') + is_expected.to contain_keystone_config('ldap/user_allow_create').with_value('False') + is_expected.to contain_keystone_config('ldap/user_allow_update').with_value('False') + is_expected.to contain_keystone_config('ldap/user_allow_delete').with_value('False') + is_expected.to contain_keystone_config('ldap/user_pass_attribute').with_value('krbPassword') + is_expected.to contain_keystone_config('ldap/user_enabled_emulation').with_value('True') + is_expected.to contain_keystone_config('ldap/user_enabled_emulation_dn').with_value('cn=openstack-enabled,cn=groups,cn=accounts,dc=example,dc=com') + is_expected.to contain_keystone_config('ldap/user_additional_attribute_mapping').with_value('description:name, gecos:name') - should contain_keystone_config('ldap/tenant_tree_dn').with_value('ou=projects,ou=openstack,dc=example,dc=com') - 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('') + # projects/tenants + is_expected.to contain_keystone_config('ldap/project_tree_dn').with_value('ou=projects,ou=openstack,dc=example,dc=com') + is_expected.to contain_keystone_config('ldap/project_filter').with_value('') + is_expected.to contain_keystone_config('ldap/project_objectclass').with_value('organizationalUnit') + is_expected.to contain_keystone_config('ldap/project_id_attribute').with_value('ou') + is_expected.to contain_keystone_config('ldap/project_member_attribute').with_value('member') + is_expected.to contain_keystone_config('ldap/project_desc_attribute').with_value('description') + is_expected.to contain_keystone_config('ldap/project_name_attribute').with_value('ou') + is_expected.to contain_keystone_config('ldap/project_enabled_attribute').with_value('enabled') + is_expected.to contain_keystone_config('ldap/project_domain_id_attribute').with_value('businessCategory') + is_expected.to contain_keystone_config('ldap/project_attribute_ignore').with_value('') + is_expected.to contain_keystone_config('ldap/project_allow_create').with_value('True') + is_expected.to contain_keystone_config('ldap/project_allow_update').with_value('True') + is_expected.to contain_keystone_config('ldap/project_allow_delete').with_value('True') + is_expected.to contain_keystone_config('ldap/project_enabled_emulation').with_value('False') + is_expected.to contain_keystone_config('ldap/project_enabled_emulation_dn').with_value('True') + is_expected.to contain_keystone_config('ldap/project_additional_attribute_mapping').with_value('cn=enabled,ou=openstack,dc=example,dc=com') - 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') + # roles + is_expected.to contain_keystone_config('ldap/role_tree_dn').with_value('ou=roles,ou=openstack,dc=example,dc=com') + is_expected.to contain_keystone_config('ldap/role_filter').with_value('') + is_expected.to contain_keystone_config('ldap/role_objectclass').with_value('organizationalRole') + is_expected.to contain_keystone_config('ldap/role_id_attribute').with_value('cn') + is_expected.to contain_keystone_config('ldap/role_name_attribute').with_value('ou') + is_expected.to contain_keystone_config('ldap/role_member_attribute').with_value('roleOccupant') + is_expected.to contain_keystone_config('ldap/role_attribute_ignore').with_value('description') + is_expected.to contain_keystone_config('ldap/role_allow_create').with_value('True') + is_expected.to contain_keystone_config('ldap/role_allow_update').with_value('True') + is_expected.to contain_keystone_config('ldap/role_allow_delete').with_value('True') + is_expected.to contain_keystone_config('ldap/role_additional_attribute_mapping').with_value('') + + # groups + is_expected.to contain_keystone_config('ldap/group_tree_dn').with_value('ou=groups,ou=openstack,dc=example,dc=com') + is_expected.to contain_keystone_config('ldap/group_filter').with_value('cn=enabled-groups,cn=groups,cn=accounts,dc=example,dc=com') + is_expected.to contain_keystone_config('ldap/group_objectclass').with_value('organizationalRole') + is_expected.to contain_keystone_config('ldap/group_id_attribute').with_value('cn') + is_expected.to contain_keystone_config('ldap/group_member_attribute').with_value('roleOccupant') + is_expected.to contain_keystone_config('ldap/group_desc_attribute').with_value('description') + is_expected.to contain_keystone_config('ldap/group_name_attribute').with_value('cn') + is_expected.to contain_keystone_config('ldap/group_attribute_ignore').with_value('') + is_expected.to contain_keystone_config('ldap/group_allow_create').with_value('False') + is_expected.to contain_keystone_config('ldap/group_allow_update').with_value('False') + is_expected.to contain_keystone_config('ldap/group_allow_delete').with_value('False') + is_expected.to contain_keystone_config('ldap/group_additional_attribute_mapping').with_value('') + + # tls + is_expected.to contain_keystone_config('ldap/use_tls').with_value('False') + is_expected.to contain_keystone_config('ldap/tls_cacertdir').with_value('/etc/ssl/certs/') + is_expected.to contain_keystone_config('ldap/tls_cacertfile').with_value('/etc/ssl/certs/ca-certificates.crt') + is_expected.to contain_keystone_config('ldap/tls_req_cert').with_value('demand') + + # ldap pooling + is_expected.to contain_keystone_config('ldap/use_pool').with_value('True') + is_expected.to contain_keystone_config('ldap/pool_size').with_value('20') + is_expected.to contain_keystone_config('ldap/pool_retry_max').with_value('2') + is_expected.to contain_keystone_config('ldap/pool_retry_delay').with_value('0.2') + is_expected.to contain_keystone_config('ldap/pool_connection_timeout').with_value('222') + is_expected.to contain_keystone_config('ldap/pool_connection_lifetime').with_value('222') + is_expected.to contain_keystone_config('ldap/use_auth_pool').with_value('True') + is_expected.to contain_keystone_config('ldap/auth_pool_size').with_value('20') + is_expected.to contain_keystone_config('ldap/auth_pool_connection_lifetime').with_value('200') + + # drivers + is_expected.to contain_keystone_config('identity/driver').with_value('keystone.identity.backends.ldap.Identity') + is_expected.to contain_keystone_config('credential/driver').with_value('keystone.credential.backends.ldap.Credential') + is_expected.to contain_keystone_config('assignment/driver').with_value('keystone.assignment.backends.ldap.Assignment') end end -end + describe 'with deprecated params' do + let :params do + { + :tenant_tree_dn => 'ou=projects,ou=openstack,dc=example,dc=com', + :tenant_filter => '', + :tenant_objectclass => 'organizationalUnit', + :tenant_id_attribute => 'ou', + :tenant_member_attribute => 'member', + :tenant_desc_attribute => 'description', + :tenant_name_attribute => 'ou', + :tenant_enabled_attribute => 'enabled', + :tenant_domain_id_attribute => 'businessCategory', + :tenant_attribute_ignore => '', + :tenant_allow_create => 'True', + :tenant_allow_update => 'True', + :tenant_allow_delete => 'True', + :tenant_enabled_emulation => 'False', + :tenant_enabled_emulation_dn => 'True', + :tenant_additional_attribute_mapping => 'cn=enabled,ou=openstack,dc=example,dc=com', + } + end + it 'should work with deprecated params' do + is_expected.to contain_keystone_config('ldap/project_tree_dn').with_value('ou=projects,ou=openstack,dc=example,dc=com') + is_expected.to contain_keystone_config('ldap/project_filter') + is_expected.to contain_keystone_config('ldap/project_objectclass').with_value('organizationalUnit') + is_expected.to contain_keystone_config('ldap/project_id_attribute').with_value('ou') + is_expected.to contain_keystone_config('ldap/project_member_attribute').with_value('member') + is_expected.to contain_keystone_config('ldap/project_desc_attribute').with_value('description') + is_expected.to contain_keystone_config('ldap/project_name_attribute').with_value('ou') + is_expected.to contain_keystone_config('ldap/project_enabled_attribute').with_value('enabled') + is_expected.to contain_keystone_config('ldap/project_domain_id_attribute').with_value('businessCategory') + is_expected.to contain_keystone_config('ldap/project_attribute_ignore') + is_expected.to contain_keystone_config('ldap/project_allow_create').with_value('True') + is_expected.to contain_keystone_config('ldap/project_allow_update').with_value('True') + is_expected.to contain_keystone_config('ldap/project_allow_delete').with_value('True') + is_expected.to contain_keystone_config('ldap/project_enabled_emulation').with_value('False') + is_expected.to contain_keystone_config('ldap/project_enabled_emulation_dn').with_value('True') + is_expected.to contain_keystone_config('ldap/project_additional_attribute_mapping').with_value('cn=enabled,ou=openstack,dc=example,dc=com') + end + end + + describe 'with deprecated and new params both set' do + let :params do + { + :tenant_tree_dn => 'ou=projects,ou=old-openstack,dc=example,dc=com', + :project_tree_dn => 'ou=projects,ou=new-openstack,dc=example,dc=com', + } + end + + it_raises 'a Puppet::Error', /tenant_tree_dn and project_tree_dn are both set. results may be unexpected/ + end +end diff --git a/deployment/puppet/keystone/spec/classes/keystone_logging_spec.rb b/deployment/puppet/keystone/spec/classes/keystone_logging_spec.rb new file mode 100644 index 0000000000..f0ac50d7c5 --- /dev/null +++ b/deployment/puppet/keystone/spec/classes/keystone_logging_spec.rb @@ -0,0 +1,107 @@ +require 'spec_helper' + +describe 'keystone::logging' do + + let :params do + { + } + end + + let :log_params do + { + :logging_context_format_string => '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s', + :logging_default_format_string => '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s', + :logging_debug_format_suffix => '%(funcName)s %(pathname)s:%(lineno)d', + :logging_exception_prefix => '%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s', + :log_config_append => '/etc/keystone/logging.conf', + :publish_errors => true, + :default_log_levels => { + 'amqp' => 'WARN', 'amqplib' => 'WARN', 'boto' => 'WARN', + 'qpid' => 'WARN', 'sqlalchemy' => 'WARN', 'suds' => 'INFO', + 'iso8601' => 'WARN', + 'requests.packages.urllib3.connectionpool' => 'WARN' }, + :fatal_deprecations => true, + :instance_format => '[instance: %(uuid)s] ', + :instance_uuid_format => '[instance: %(uuid)s] ', + :log_date_format => '%Y-%m-%d %H:%M:%S', + } + end + + shared_examples_for 'keystone-logging' do + + context 'with extended logging options' do + before { params.merge!( log_params ) } + it_configures 'logging params set' + end + + context 'without extended logging options' do + it_configures 'logging params unset' + end + + end + + shared_examples_for 'logging params set' do + it 'enables logging params' do + is_expected.to contain_keystone_config('DEFAULT/logging_context_format_string').with_value( + '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s') + + is_expected.to contain_keystone_config('DEFAULT/logging_default_format_string').with_value( + '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s') + + is_expected.to contain_keystone_config('DEFAULT/logging_debug_format_suffix').with_value( + '%(funcName)s %(pathname)s:%(lineno)d') + + is_expected.to contain_keystone_config('DEFAULT/logging_exception_prefix').with_value( + '%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s') + + is_expected.to contain_keystone_config('DEFAULT/log_config_append').with_value( + '/etc/keystone/logging.conf') + is_expected.to contain_keystone_config('DEFAULT/publish_errors').with_value( + true) + + is_expected.to contain_keystone_config('DEFAULT/default_log_levels').with_value( + 'amqp=WARN,amqplib=WARN,boto=WARN,iso8601=WARN,qpid=WARN,requests.packages.urllib3.connectionpool=WARN,sqlalchemy=WARN,suds=INFO') + + is_expected.to contain_keystone_config('DEFAULT/fatal_deprecations').with_value( + true) + + is_expected.to contain_keystone_config('DEFAULT/instance_format').with_value( + '[instance: %(uuid)s] ') + + is_expected.to contain_keystone_config('DEFAULT/instance_uuid_format').with_value( + '[instance: %(uuid)s] ') + + is_expected.to contain_keystone_config('DEFAULT/log_date_format').with_value( + '%Y-%m-%d %H:%M:%S') + end + end + + + shared_examples_for 'logging params unset' do + [ :logging_context_format_string, :logging_default_format_string, + :logging_debug_format_suffix, :logging_exception_prefix, + :log_config_append, :publish_errors, + :default_log_levels, :fatal_deprecations, + :instance_format, :instance_uuid_format, + :log_date_format, ].each { |param| + it { is_expected.to contain_keystone_config("DEFAULT/#{param}").with_ensure('absent') } + } + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'keystone-logging' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'keystone-logging' + end + +end diff --git a/deployment/puppet/keystone/spec/classes/keystone_policy_spec.rb b/deployment/puppet/keystone/spec/classes/keystone_policy_spec.rb new file mode 100644 index 0000000000..56c8f8bc41 --- /dev/null +++ b/deployment/puppet/keystone/spec/classes/keystone_policy_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +describe 'keystone::policy' do + + shared_examples_for 'keystone policies' do + let :params do + { + :policy_path => '/etc/keystone/policy.json', + :policies => { + 'context_is_admin' => { + 'key' => 'context_is_admin', + 'value' => 'foo:bar' + } + } + } + end + + it 'set up the policies' do + is_expected.to contain_openstacklib__policy__base('context_is_admin').with({ + :key => 'context_is_admin', + :value => 'foo:bar' + }) + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'keystone policies' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'keystone policies' + end +end diff --git a/deployment/puppet/keystone/spec/classes/keystone_python_spec.rb b/deployment/puppet/keystone/spec/classes/keystone_python_spec.rb index 1324fb2f67..500413e961 100644 --- a/deployment/puppet/keystone/spec/classes/keystone_python_spec.rb +++ b/deployment/puppet/keystone/spec/classes/keystone_python_spec.rb @@ -6,12 +6,12 @@ describe 'keystone::python' do { :osfamily => 'Debian' } end - it { should contain_package('python-keystone').with_ensure("present") } + it { is_expected.to contain_package('python-keystone').with_ensure("present") } describe 'override ensure' do let(:params) { { :ensure => "latest" } } - it { should contain_package('python-keystone').with_ensure("latest") } + it { is_expected.to contain_package('python-keystone').with_ensure("latest") } end end diff --git a/deployment/puppet/keystone/spec/classes/keystone_roles_admin_spec.rb b/deployment/puppet/keystone/spec/classes/keystone_roles_admin_spec.rb index 99db80f772..bbd6d953b8 100644 --- a/deployment/puppet/keystone/spec/classes/keystone_roles_admin_spec.rb +++ b/deployment/puppet/keystone/spec/classes/keystone_roles_admin_spec.rb @@ -11,26 +11,27 @@ describe 'keystone::roles::admin' do } end - it { should contain_keystone_tenant('services').with( + it { is_expected.to contain_keystone_tenant('services').with( :ensure => 'present', :enabled => true, :description => 'Tenant for the openstack services' )} - it { should contain_keystone_tenant('openstack').with( + it { is_expected.to 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 { is_expected.to contain_keystone_user('admin').with( + :ensure => 'present', + :enabled => true, + :tenant => 'openstack', + :email => 'foo@bar', + :password => 'ChangeMe', + :ignore_default_tenant => 'false' )} - it { should contain_keystone_role('admin').with_ensure('present') } - it { should contain_keystone_user_role('admin@openstack').with( - :roles => 'admin', + it { is_expected.to contain_keystone_role('admin').with_ensure('present') } + it { is_expected.to contain_keystone_user_role('admin@openstack').with( + :roles => ['admin'], :ensure => 'present' )} @@ -40,36 +41,68 @@ describe 'keystone::roles::admin' do let :params do { - :admin => 'admin', - :email => 'foo@baz', - :password => 'foo', - :admin_tenant => 'admin', - :service_tenant => 'foobar' + :admin => 'admin', + :email => 'foo@baz', + :password => 'foo', + :admin_tenant => 'admin', + :admin_roles => ['admin', 'heat_stack_owner'], + :service_tenant => 'foobar', + :ignore_default_tenant => 'true', + :admin_tenant_desc => 'admin something else', + :service_tenant_desc => 'foobar description', } end - it { should contain_keystone_tenant('foobar').with( + it { is_expected.to contain_keystone_tenant('foobar').with( :ensure => 'present', :enabled => true, - :description => 'Tenant for the openstack services' + :description => 'foobar description' )} - it { should contain_keystone_tenant('admin').with( + it { is_expected.to contain_keystone_tenant('admin').with( :ensure => 'present', :enabled => true, - :description => 'admin tenant' + :description => 'admin something else' )} - it { should contain_keystone_user('admin').with( - :ensure => 'present', - :enabled => true, - :tenant => 'admin', - :email => 'foo@baz', - :password => 'foo' + it { is_expected.to contain_keystone_user('admin').with( + :ensure => 'present', + :enabled => true, + :tenant => 'admin', + :email => 'foo@baz', + :password => 'foo', + :ignore_default_tenant => 'true' )} - it { should contain_keystone_user_role('admin@admin').with( - :roles => 'admin', + it { is_expected.to contain_keystone_user_role('admin@admin').with( + :roles => ['admin', 'heat_stack_owner'], :ensure => 'present' )} end + describe 'when disabling user configuration' do + before do + let :params do + { + :configure_user => false + } + end + + it { is_expected.to_not contain_keystone_user('keystone') } + it { is_expected.to contain_keystone_user_role('keystone@openstack') } + end + end + + describe 'when disabling user and role configuration' do + before do + let :params do + { + :configure_user => false, + :configure_user_role => false + } + end + + it { is_expected.to_not contain_keystone_user('keystone') } + it { is_expected.to_not contain_keystone_user_role('keystone@openstack') } + end + end + end diff --git a/deployment/puppet/keystone/spec/classes/keystone_service_spec.rb b/deployment/puppet/keystone/spec/classes/keystone_service_spec.rb new file mode 100644 index 0000000000..3aa302d631 --- /dev/null +++ b/deployment/puppet/keystone/spec/classes/keystone_service_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' + +describe 'keystone::service' do + + describe "with default parameters" do + it { is_expected.to contain_service('keystone').with( + :ensure => nil, + :enable => true, + :hasstatus => true, + :hasrestart => true + ) } + it { is_expected.to_not contain_exec('validate_keystone_connection') } + end + + describe "with validation on" do + let :params do + { + :validate => 'true', + :admin_token => 'admintoken' + } + end + + it { is_expected.to contain_service('keystone').with( + :ensure => nil, + :enable => true, + :hasstatus => true, + :hasrestart => true + ) } + it { is_expected.to contain_exec('validate_keystone_connection') } + end +end diff --git a/deployment/puppet/keystone/spec/classes/keystone_spec.rb b/deployment/puppet/keystone/spec/classes/keystone_spec.rb index a0478370ca..89c4fc55e5 100644 --- a/deployment/puppet/keystone/spec/classes/keystone_spec.rb +++ b/deployment/puppet/keystone/spec/classes/keystone_spec.rb @@ -2,174 +2,282 @@ require 'spec_helper' describe 'keystone' do - let :facts do - {:osfamily => 'Debian'} - end - - let :default_params do + let :global_facts 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', + :processorcount => 42, + :concat_basedir => '/var/lib/puppet/concat', + :fqdn => 'some.host.tld' } 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| + let :facts do + global_facts.merge({ + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => '7.0', + :processorcount => '1' + }) + end - describe "when #{param_set == {} ? "using default" : "specifying"} class parameters" do - let :param_hash do - default_params.merge(param_set) + default_params = { + 'admin_token' => 'service_token', + 'package_ensure' => 'present', + 'client_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', + 'verbose' => false, + 'debug' => false, + 'catalog_type' => 'sql', + 'catalog_driver' => false, + 'token_provider' => 'keystone.token.providers.uuid.Provider', + 'token_driver' => 'keystone.token.persistence.backends.sql.Token', + 'revoke_driver' => 'keystone.contrib.revoke.backends.sql.Revoke', + '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, + 'manage_service' => true, + 'database_connection' => 'sqlite:////var/lib/keystone/keystone.db', + 'database_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', + 'rabbit_host' => 'localhost', + 'rabbit_password' => 'guest', + 'rabbit_userid' => 'guest', + 'admin_workers' => 20, + 'public_workers' => 20, + 'sync_db' => true, + } + + override_params = { + 'package_ensure' => 'latest', + 'client_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', + 'verbose' => true, + 'debug' => true, + 'catalog_type' => 'template', + 'token_provider' => 'keystone.token.providers.uuid.Provider', + 'token_driver' => 'keystone.token.backends.kvs.Token', + 'revoke_driver' => 'keystone.contrib.revoke.backends.kvs.Revoke', + '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, + 'manage_service' => true, + 'database_connection' => 'mysql://a:b@c/d', + 'database_idle_timeout' => '300', + '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', + 'rabbit_host' => '127.0.0.1', + 'rabbit_password' => 'openstack', + 'rabbit_userid' => 'admin', + } + + httpd_params = {'service_name' => 'httpd'}.merge(default_params) + + shared_examples_for 'core keystone examples' do |param_hash| + it { is_expected.to contain_class('keystone::params') } + + it { is_expected.to contain_package('keystone').with( + 'ensure' => param_hash['package_ensure'], + 'tag' => 'openstack' + ) } + + it { is_expected.to contain_package('python-openstackclient').with( + 'ensure' => param_hash['client_package_ensure'], + 'tag' => 'openstack' + ) } + + it { is_expected.to contain_group('keystone').with( + 'ensure' => 'present', + 'system' => true + ) } + + it { is_expected.to 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| + is_expected.to contain_file(d).with( + 'ensure' => 'directory', + 'owner' => 'keystone', + 'group' => 'keystone', + 'mode' => '0750', + 'require' => 'Package[keystone]' + ) end + end + + it 'should synchronize the db if $sync_db is true' do + if param_hash['sync_db'] + is_expected.to 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', + 'verbose', + 'debug' + ].each do |config| + is_expected.to contain_keystone_config("DEFAULT/#{config}").with_value(param_hash[config]) + end + end + + it 'should contain correct admin_token config' do + is_expected.to contain_keystone_config('DEFAULT/admin_token').with_value(param_hash['admin_token']).with_secret(true) + end + + it 'should contain correct mysql config' do + is_expected.to contain_keystone_config('database/idle_timeout').with_value(param_hash['database_idle_timeout']) + is_expected.to contain_keystone_config('database/connection').with_value(param_hash['database_connection']).with_secret(true) + end + + it { is_expected.to contain_keystone_config('token/provider').with_value( + param_hash['token_provider'] + ) } + + it 'should contain correct token driver' do + is_expected.to contain_keystone_config('token/driver').with_value(param_hash['token_driver']) + end + + it 'should contain correct revoke driver' do + should contain_keystone_config('revoke/driver').with_value(param_hash['revoke_driver']) + end + + it 'should ensure proper setting of admin_endpoint and public_endpoint' do + if param_hash['admin_endpoint'] + is_expected.to contain_keystone_config('DEFAULT/admin_endpoint').with_value(param_hash['admin_endpoint']) + else + is_expected.to contain_keystone_config('DEFAULT/admin_endpoint').with_ensure('absent') + end + if param_hash['public_endpoint'] + is_expected.to contain_keystone_config('DEFAULT/public_endpoint').with_value(param_hash['public_endpoint']) + else + is_expected.to contain_keystone_config('DEFAULT/public_endpoint').with_ensure('absent') + end + end + + it 'should contain correct rabbit_password' do + is_expected.to contain_keystone_config('DEFAULT/rabbit_password').with_value(param_hash['rabbit_password']).with_secret(true) + end + + it 'should remove max_token_size param by default' do + is_expected.to contain_keystone_config('DEFAULT/max_token_size').with_ensure('absent') + end + + it 'should ensure proper setting of admin_workers and public_workers' do + if param_hash['admin_workers'] + is_expected.to contain_keystone_config('DEFAULT/admin_workers').with_value(param_hash['admin_workers']) + else + is_expected.to contain_keystone_config('DEFAULT/admin_workers').with_value('2') + end + if param_hash['public_workers'] + is_expected.to contain_keystone_config('DEFAULT/public_workers').with_value(param_hash['public_workers']) + else + is_expected.to contain_keystone_config('DEFAULT/public_workers').with_value('2') + end + end + end + + [default_params, override_params].each do |param_hash| + describe "when #{param_hash == default_params ? "using default" : "specifying"} class parameters for service" do let :params do - param_set + param_hash end - it { should contain_class('keystone::params') } + it_configures 'core keystone examples', param_hash - 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', + it { is_expected.to contain_service('keystone').with( + 'ensure' => (param_hash['manage_service'] && 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 + shared_examples_for "when using default class parameters for httpd" do + let :params do + httpd_params + end + + let :pre_condition do + 'include ::apache' + end + + it_configures 'core keystone examples', httpd_params + + it do + expect { + should contain_service(platform_parameters[:service_name]).with('ensure' => 'running') + }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected that the catalogue would contain Service\[#{platform_parameters[:service_name]}\]/) + end + + it { should contain_class('keystone::service').with( + 'ensure' => 'stopped', + 'service_name' => platform_parameters[:service_name], + 'enable' => false, + 'validate' => false + )} + end + + describe 'when using invalid service name for keystone' do + let (:params) { {'service_name' => 'foo'}.merge(default_params) } + + it_raises 'a Puppet::Error', /Invalid service_name/ + end + + describe 'with disabled service managing' do + let :params do + { :admin_token => 'service_token', + :manage_service => false, + :enabled => false } + end + + it { is_expected.to contain_service('keystone').with( + 'ensure' => nil, + 'enable' => false, + 'hasstatus' => true, + 'hasrestart' => true + ) } + end + describe 'when configuring signing token provider' do describe 'when configuring as UUID' do @@ -179,23 +287,23 @@ describe 'keystone' do 'token_provider' => 'keystone.token.providers.uuid.Provider' } end - it { should contain_exec('keystone-manage pki_setup').with( + it { is_expected.to 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') } + it { is_expected.to 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') } + it { is_expected.to 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') } + it { is_expected.to_not contain_exec('keystone-manage pki_setup') } end end @@ -206,55 +314,107 @@ describe 'keystone' do 'token_provider' => 'keystone.token.providers.pki.Provider' } end - it { should contain_exec('keystone-manage pki_setup').with( + it { is_expected.to 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') } + it { is_expected.to 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') } + it { is_expected.to 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') } + it { is_expected.to_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' + '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', + 'signing_cert_subject' => 'signing_cert_subject', + 'signing_key_size' => 2048 } end - it { should_not contain_exec('keystone-manage pki_setup') } + it { is_expected.to_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') + is_expected.to 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') + is_expected.to 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') + is_expected.to 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') + is_expected.to contain_keystone_config('signing/ca_key').with_value('signing_ca_key') + end + + it 'should contain correct PKI cert_subject config' do + is_expected.to contain_keystone_config('signing/cert_subject').with_value('signing_cert_subject') + end + + it 'should contain correct PKI key_size config' do + is_expected.to contain_keystone_config('signing/key_size').with_value('2048') + end + end + + describe 'when configuring PKI signing cert paths with pki_setup disabled' do + let :params do + { + 'admin_token' => 'service_token', + 'token_provider' => 'keystone.token.providers.pki.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', + 'signing_cert_subject' => 'signing_cert_subject', + 'signing_key_size' => 2048 + } + end + + it { is_expected.to_not contain_exec('keystone-manage pki_setup') } + + it 'should contain correct PKI certfile config' do + is_expected.to contain_keystone_config('signing/certfile').with_value('signing_certfile') + end + + it 'should contain correct PKI keyfile config' do + is_expected.to contain_keystone_config('signing/keyfile').with_value('signing_keyfile') + end + + it 'should contain correct PKI ca_certs config' do + is_expected.to contain_keystone_config('signing/ca_certs').with_value('signing_ca_certs') + end + + it 'should contain correct PKI ca_key config' do + is_expected.to contain_keystone_config('signing/ca_key').with_value('signing_ca_key') + end + + it 'should contain correct PKI cert_subject config' do + is_expected.to contain_keystone_config('signing/cert_subject').with_value('signing_cert_subject') + end + + it 'should contain correct PKI key_size config' do + is_expected.to contain_keystone_config('signing/key_size').with_value('2048') end end @@ -273,42 +433,8 @@ describe 'keystone' do :catalog_driver => 'keystone.catalog.backends.alien.AlienCatalog' } end - it { should contain_keystone_config('catalog/driver').with_value(params[:catalog_driver]) } + it { is_expected.to 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 @@ -319,7 +445,7 @@ describe 'keystone' do } end - it { should contain_keystone_config("token/expiration").with_value('42') } + it { is_expected.to contain_keystone_config("token/expiration").with_value('42') } end describe 'when not configuring token expiration' do @@ -329,19 +455,40 @@ describe 'keystone' do } end - it { should contain_keystone_config("token/expiration").with_value('3600') } + it { is_expected.to contain_keystone_config("token/expiration").with_value('3600') } + end + + describe 'when sync_db is set to false' do + let :params do + { + 'admin_token' => 'service_token', + 'sync_db' => false, + } + end + + it { is_expected.not_to contain_exec('keystone-manage db_sync') } 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' + 'admin_token' => 'service_token', + 'memcache_servers' => [ 'SERVER1:11211', 'SERVER2:11211' ], + 'token_driver' => 'keystone.token.backends.memcache.Token', + 'cache_backend' => 'dogpile.cache.memcached', + 'cache_backend_argument' => ['url:SERVER1:12211'], } end - it { should contain_keystone_config("memcache/servers").with_value('SERVER1:11211,SERVER2:11211') } + it { is_expected.to contain_keystone_config("memcache/servers").with_value('SERVER1:11211,SERVER2:11211') } + it { is_expected.to contain_keystone_config('cache/enabled').with_value(true) } + it { is_expected.to contain_keystone_config('token/caching').with_value(true) } + it { is_expected.to contain_keystone_config('cache/backend').with_value('dogpile.cache.memcached') } + it { is_expected.to contain_keystone_config('cache/backend_argument').with_value('url:SERVER1:12211') } + it { is_expected.to contain_package('python-memcache').with( + :name => 'python-memcache', + :ensure => 'present' + ) } end describe 'do not configure memcache servers when not set' do @@ -349,7 +496,12 @@ describe 'keystone' do default_params end - it { should contain_keystone_config("memcache/servers").with_ensure('absent') } + it { is_expected.to contain_keystone_config("cache/enabled").with_ensure('absent') } + it { is_expected.to contain_keystone_config("token/caching").with_ensure('absent') } + it { is_expected.to contain_keystone_config("cache/backend").with_ensure('absent') } + it { is_expected.to contain_keystone_config("cache/backend_argument").with_ensure('absent') } + it { is_expected.to contain_keystone_config("cache/debug_cache_backend").with_ensure('absent') } + it { is_expected.to contain_keystone_config("memcache/servers").with_ensure('absent') } end describe 'raise error if memcache_servers is not an array' do @@ -360,7 +512,7 @@ describe 'keystone' do } end - it { expect { should contain_class('keystone::params') }.to \ + it { expect { is_expected.to contain_class('keystone::params') }.to \ raise_error(Puppet::Error, /is not an Array/) } end @@ -369,8 +521,8 @@ describe 'keystone' 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') } + it { is_expected.to contain_keystone_config('DEFAULT/use_syslog').with_value(false) } + it { is_expected.to_not contain_keystone_config('DEFAULT/syslog_log_facility') } end describe 'with syslog enabled' do @@ -380,8 +532,8 @@ describe 'keystone' do }) 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') } + it { is_expected.to contain_keystone_config('DEFAULT/use_syslog').with_value(true) } + it { is_expected.to contain_keystone_config('DEFAULT/syslog_log_facility').with_value('LOG_USER') } end describe 'with syslog enabled and custom settings' do @@ -392,15 +544,15 @@ describe 'keystone' do }) 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') } + it { is_expected.to contain_keystone_config('DEFAULT/use_syslog').with_value(true) } + it { is_expected.to 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') } + it { is_expected.to contain_keystone_config('DEFAULT/log_file').with_ensure('absent') } end describe 'with log_file and log_dir enabled' do @@ -410,8 +562,8 @@ describe 'keystone' do :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') } + it { is_expected.to contain_keystone_config('DEFAULT/log_file').with_value('keystone.log') } + it { is_expected.to contain_keystone_config('DEFAULT/log_dir').with_value('/var/lib/keystone') } end describe 'with log_file and log_dir disabled' do @@ -421,42 +573,10 @@ describe 'keystone' do :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') } + it { is_expected.to contain_keystone_config('DEFAULT/log_file').with_ensure('absent') } + it { is_expected.to 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 { @@ -466,14 +586,14 @@ describe 'keystone' do '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/')} + it {is_expected.to contain_keystone_config('ssl/enable').with_value(true)} + it {is_expected.to contain_keystone_config('ssl/certfile').with_value('/etc/keystone/ssl/certs/keystone.pem')} + it {is_expected.to contain_keystone_config('ssl/keyfile').with_value('/etc/keystone/ssl/private/keystonekey.pem')} + it {is_expected.to contain_keystone_config('ssl/ca_certs').with_value('/etc/keystone/ssl/certs/ca.pem')} + it {is_expected.to contain_keystone_config('ssl/ca_key').with_value('/etc/keystone/ssl/private/cakey.pem')} + it {is_expected.to contain_keystone_config('ssl/cert_subject').with_value('/C=US/ST=Unset/L=Unset/O=Unset/CN=localhost')} + it {is_expected.to contain_keystone_config('DEFAULT/public_endpoint').with_value('https://localhost:5000/v2.0/')} + it {is_expected.to contain_keystone_config('DEFAULT/admin_endpoint').with_value('https://localhost:35357/v2.0/')} end describe 'when disabling SSL' do let :params do @@ -482,18 +602,67 @@ describe 'keystone' do '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')} + it {is_expected.to contain_keystone_config('ssl/enable').with_value(false)} + it {is_expected.to contain_keystone_config('DEFAULT/public_endpoint').with_ensure('absent')} + it {is_expected.to 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) } + it { is_expected.to contain_keystone_config('DEFAULT/notification_driver').with_value(nil) } + it { is_expected.to contain_keystone_config('DEFAULT/notification_topics').with_value(nil) } + it { is_expected.to contain_keystone_config('DEFAULT/notification_format').with_value(nil) } + it { is_expected.to contain_keystone_config('DEFAULT/control_exchange').with_value(nil) } + end + + describe 'with RabbitMQ communication SSLed' do + let :params do + default_params.merge!({ + :rabbit_use_ssl => true, + :kombu_ssl_ca_certs => '/path/to/ssl/ca/certs', + :kombu_ssl_certfile => '/path/to/ssl/cert/file', + :kombu_ssl_keyfile => '/path/to/ssl/keyfile', + :kombu_ssl_version => 'TLSv1' + }) + end + + it do + is_expected.to contain_keystone_config('DEFAULT/rabbit_use_ssl').with_value('true') + is_expected.to contain_keystone_config('DEFAULT/kombu_ssl_ca_certs').with_value('/path/to/ssl/ca/certs') + is_expected.to contain_keystone_config('DEFAULT/kombu_ssl_certfile').with_value('/path/to/ssl/cert/file') + is_expected.to contain_keystone_config('DEFAULT/kombu_ssl_keyfile').with_value('/path/to/ssl/keyfile') + is_expected.to contain_keystone_config('DEFAULT/kombu_ssl_version').with_value('TLSv1') + end + end + + describe 'with RabbitMQ communication not SSLed' do + let :params do + default_params.merge!({ + :rabbit_use_ssl => false, + :kombu_ssl_ca_certs => 'undef', + :kombu_ssl_certfile => 'undef', + :kombu_ssl_keyfile => 'undef', + :kombu_ssl_version => 'TLSv1' + }) + end + + it do + is_expected.to contain_keystone_config('DEFAULT/rabbit_use_ssl').with_value('false') + is_expected.to contain_keystone_config('DEFAULT/kombu_ssl_ca_certs').with_ensure('absent') + is_expected.to contain_keystone_config('DEFAULT/kombu_ssl_certfile').with_ensure('absent') + is_expected.to contain_keystone_config('DEFAULT/kombu_ssl_keyfile').with_ensure('absent') + is_expected.to contain_keystone_config('DEFAULT/kombu_ssl_version').with_ensure('absent') + end + end + + describe 'when configuring max_token_size' do + let :params do + default_params.merge({:max_token_size => '16384' }) + end + + it { is_expected.to contain_keystone_config('DEFAULT/max_token_size').with_value(params[:max_token_size]) } end describe 'setting notification settings' do @@ -501,13 +670,15 @@ describe 'keystone' do default_params.merge({ :notification_driver => 'keystone.openstack.common.notifier.rpc_notifier', :notification_topics => 'notifications', + :notification_format => 'cadf', :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') } + it { is_expected.to contain_keystone_config('DEFAULT/notification_driver').with_value('keystone.openstack.common.notifier.rpc_notifier') } + it { is_expected.to contain_keystone_config('DEFAULT/notification_topics').with_value('notifications') } + it { is_expected.to contain_keystone_config('DEFAULT/notification_format').with_value('cadf') } + it { is_expected.to contain_keystone_config('DEFAULT/control_exchange').with_value('keystone') } end describe 'setting sql (default) catalog' do @@ -515,7 +686,7 @@ describe 'keystone' do default_params end - it { should contain_keystone_config('catalog/driver').with_value('keystone.catalog.backends.sql.Catalog') } + it { is_expected.to contain_keystone_config('catalog/driver').with_value('keystone.catalog.backends.sql.Catalog') } end describe 'setting default template catalog' do @@ -526,8 +697,40 @@ describe 'keystone' do } 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') } + it { is_expected.to contain_keystone_config('catalog/driver').with_value('keystone.catalog.backends.templated.Catalog') } + it { is_expected.to contain_keystone_config('catalog/template_file').with_value('/etc/keystone/default_catalog.templates') } + end + + describe 'with overridden validation_auth_url' do + let :params do + { + :admin_token => 'service_token', + :validate_service => true, + :validate_auth_url => 'http://some.host:35357/v2.0', + :admin_endpoint => 'http://some.host:35357' + } + end + + it { is_expected.to contain_keystone_config('DEFAULT/admin_endpoint').with_value('http://some.host:35357') } + it { is_expected.to contain_class('keystone::service').with( + 'validate' => true, + 'admin_endpoint' => 'http://some.host:35357/v2.0' + )} + end + + describe 'with service validation' do + let :params do + { + :admin_token => 'service_token', + :validate_service => true, + :admin_endpoint => 'http://some.host:35357' + } + end + + it { is_expected.to contain_class('keystone::service').with( + 'validate' => true, + 'admin_endpoint' => 'http://some.host:35357' + )} end describe 'setting another template catalog' do @@ -539,7 +742,141 @@ describe 'keystone' do } 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') } + it { is_expected.to contain_keystone_config('catalog/driver').with_value('keystone.catalog.backends.templated.Catalog') } + it { is_expected.to contain_keystone_config('catalog/template_file').with_value('/some/template_file') } + end + + describe 'setting service_provider' do + let :facts do + global_facts.merge({ + :osfamily => 'RedHat', + :operatingsystemrelease => '6.0' + }) + end + + describe 'with default service_provider' do + let :params do + { 'admin_token' => 'service_token' } + end + + it { is_expected.to contain_service('keystone').with( + :provider => nil + )} + end + + describe 'with overrided service_provider' do + let :params do + { + 'admin_token' => 'service_token', + 'service_provider' => 'pacemaker' + } + end + + it { is_expected.to contain_service('keystone').with( + :provider => 'pacemaker' + )} + end + end + + describe 'when using fernet tokens' do + describe 'when enabling fernet_setup' do + let :params do + default_params.merge({ + 'enable_fernet_setup' => true, + 'fernet_max_active_keys' => 5, + }) + end + + it { is_expected.to contain_exec('keystone-manage fernet_setup').with( + :creates => '/etc/keystone/fernet-keys/0' + ) } + it { is_expected.to contain_keystone_config('fernet_tokens/max_active_keys').with_value(5)} + end + + describe 'when overriding the fernet key directory' do + let :params do + default_params.merge({ + 'enable_fernet_setup' => true, + 'fernet_key_repository' => '/var/lib/fernet-keys', + }) + end + it { is_expected.to contain_exec('keystone-manage fernet_setup').with( + :creates => '/var/lib/fernet-keys/0' + ) } + + end + end + + describe 'when configuring paste_deploy' do + describe 'with default paste config on Debian' do + let :params do + default_params + end + + it { is_expected.to contain_keystone_config('paste_deploy/config_file').with_ensure('absent')} + end + + describe 'with default paste config on RedHat' do + let :facts do + global_facts.merge({ + :osfamily => 'RedHat', + :operatingsystemrelease => '6.0' + }) + end + let :params do + default_params + end + + it { is_expected.to contain_keystone_config('paste_deploy/config_file').with_value( + '/usr/share/keystone/keystone-dist-paste.ini' + )} + end + + describe 'with overrided paste_deploy' do + let :params do + default_params.merge({ + 'paste_config' => '/usr/share/keystone/keystone-paste.ini', + }) + end + + it { is_expected.to contain_keystone_config('paste_deploy/config_file').with_value( + '/usr/share/keystone/keystone-paste.ini' + )} + end + end + + context 'on RedHat platforms' do + let :facts do + global_facts.merge({ + :osfamily => 'RedHat', + :operatingsystemrelease => '7.0' + }) + end + + let :platform_parameters do + { + :service_name => 'openstack-keystone' + } + end + + it_configures 'when using default class parameters for httpd' + end + + context 'on Debian platforms' do + let :facts do + global_facts.merge({ + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => '7.0' + }) + end + + let :platform_parameters do + { + :service_name => 'keystone' + } + end + + it_configures 'when using default class parameters for httpd' end end diff --git a/deployment/puppet/keystone/spec/classes/keystone_wsgi_apache_spec.rb b/deployment/puppet/keystone/spec/classes/keystone_wsgi_apache_spec.rb index a8ed509792..0612b9424d 100644 --- a/deployment/puppet/keystone/spec/classes/keystone_wsgi_apache_spec.rb +++ b/deployment/puppet/keystone/spec/classes/keystone_wsgi_apache_spec.rb @@ -11,47 +11,48 @@ describe 'keystone::wsgi::apache' do end let :pre_condition do - 'include apache - class { keystone: admin_token => "dummy" }' + [ + 'class { keystone: admin_token => "dummy", service_name => "httpd", enable_ssl => true }' + ] 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') } + it { is_expected.to contain_service('httpd').with_name(platform_parameters[:httpd_service_name]) } + it { is_expected.to contain_class('keystone::params') } + it { is_expected.to contain_class('apache') } + it { is_expected.to contain_class('apache::mod::wsgi') } + it { is_expected.to contain_class('keystone::db::sync') } describe 'with default parameters' do - it { should contain_file("#{platform_parameters[:wsgi_script_path]}").with( + it { is_expected.to contain_file("#{platform_parameters[:wsgi_script_path]}").with( 'ensure' => 'directory', 'owner' => 'keystone', 'group' => 'keystone', 'require' => 'Package[httpd]' )} - it { should contain_file('keystone_wsgi_admin').with( + it { is_expected.to 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]}]" + 'require' => ["File[#{platform_parameters[:wsgi_script_path]}]", "Package[keystone]"] )} - it { should contain_file('keystone_wsgi_main').with( + it { is_expected.to contain_file('keystone_wsgi_main').with( 'ensure' => 'file', '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]}]" + 'require' => ["File[#{platform_parameters[:wsgi_script_path]}]", "Package[keystone]"] )} - it { should contain_apache__vhost('keystone_wsgi_admin').with( + it { is_expected.to contain_apache__vhost('keystone_wsgi_admin').with( 'servername' => 'some.host.tld', 'ip' => nil, 'port' => '35357', @@ -59,12 +60,20 @@ describe 'keystone::wsgi::apache' do 'docroot_owner' => 'keystone', 'docroot_group' => 'keystone', 'ssl' => 'true', + 'wsgi_daemon_process' => 'keystone_admin', + 'wsgi_daemon_process_options' => { + 'user' => 'keystone', + 'group' => 'keystone', + 'processes' => '1', + 'threads' => '42', + 'display-name' => 'keystone-admin', + }, 'wsgi_process_group' => 'keystone_admin', 'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/admin" }, - 'require' => ['Class[Apache::Mod::Wsgi]', 'File[keystone_wsgi_admin]'] + 'require' => 'File[keystone_wsgi_admin]' )} - it { should contain_apache__vhost('keystone_wsgi_main').with( + it { is_expected.to contain_apache__vhost('keystone_wsgi_main').with( 'servername' => 'some.host.tld', 'ip' => nil, 'port' => '5000', @@ -73,15 +82,18 @@ describe 'keystone::wsgi::apache' do 'docroot_group' => 'keystone', 'ssl' => 'true', 'wsgi_daemon_process' => 'keystone_main', + 'wsgi_daemon_process_options' => { + 'user' => 'keystone', + 'group' => 'keystone', + 'processes' => '1', + 'threads' => '42', + 'display-name' => 'keystone-main', + }, 'wsgi_process_group' => 'keystone_main', 'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/main" }, - 'require' => ['Class[Apache::Mod::Wsgi]', 'File[keystone_wsgi_main]'] + 'require' => 'File[keystone_wsgi_main]' )} - it "should set keystone wsgi options" do - contain_file('25-keystone_wsgi_main.conf').with_content( - /^ WSGIDaemonProcess keystone group=keystone processes=1 threads=1 user=keystone$/ - ) - end + it { is_expected.to contain_file("#{platform_parameters[:httpd_ports_file]}") } end describe 'when overriding parameters using different ports' do @@ -96,7 +108,7 @@ describe 'keystone::wsgi::apache' do } end - it { should contain_apache__vhost('keystone_wsgi_admin').with( + it { is_expected.to contain_apache__vhost('keystone_wsgi_admin').with( 'servername' => 'dummy.host', 'ip' => '10.42.51.1', 'port' => '4142', @@ -104,12 +116,20 @@ describe 'keystone::wsgi::apache' do 'docroot_owner' => 'keystone', 'docroot_group' => 'keystone', 'ssl' => 'false', + 'wsgi_daemon_process' => 'keystone_admin', + 'wsgi_daemon_process_options' => { + 'user' => 'keystone', + 'group' => 'keystone', + 'processes' => '37', + 'threads' => '42', + 'display-name' => 'keystone-admin', + }, 'wsgi_process_group' => 'keystone_admin', 'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/admin" }, - 'require' => ['Class[Apache::Mod::Wsgi]', 'File[keystone_wsgi_admin]'] + 'require' => 'File[keystone_wsgi_admin]' )} - it { should contain_apache__vhost('keystone_wsgi_main').with( + it { is_expected.to contain_apache__vhost('keystone_wsgi_main').with( 'servername' => 'dummy.host', 'ip' => '10.42.51.1', 'port' => '12345', @@ -118,15 +138,19 @@ describe 'keystone::wsgi::apache' do 'docroot_group' => 'keystone', 'ssl' => 'false', 'wsgi_daemon_process' => 'keystone_main', + 'wsgi_daemon_process_options' => { + 'user' => 'keystone', + 'group' => 'keystone', + 'processes' => '37', + 'threads' => '42', + 'display-name' => 'keystone-main', + }, 'wsgi_process_group' => 'keystone_main', 'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/main" }, - 'require' => ['Class[Apache::Mod::Wsgi]', 'File[keystone_wsgi_main]'] + 'require' => 'File[keystone_wsgi_main]' )} - it "should set keystone wsgi options" do - contain_file('25-keystone_wsgi_main.conf').with_content( - /^ WSGIDaemonProcess keystone group=keystone processes=37 threads=1 user=keystone$/ - ) - end + + it { is_expected.to contain_file("#{platform_parameters[:httpd_ports_file]}") } end describe 'when overriding parameters using same port' do @@ -142,9 +166,9 @@ describe 'keystone::wsgi::apache' do } end - it { should_not contain_apache__vhost('keystone_wsgi_admin') } + it { is_expected.to_not contain_apache__vhost('keystone_wsgi_admin') } - it { should contain_apache__vhost('keystone_wsgi_main').with( + it { is_expected.to contain_apache__vhost('keystone_wsgi_main').with( 'servername' => 'dummy.host', 'ip' => nil, 'port' => '4242', @@ -153,18 +177,20 @@ describe 'keystone::wsgi::apache' do 'docroot_group' => 'keystone', 'ssl' => 'true', 'wsgi_daemon_process' => 'keystone_main', + 'wsgi_daemon_process_options' => { + 'user' => 'keystone', + 'group' => 'keystone', + 'processes' => '37', + 'threads' => '42', + 'display-name' => 'keystone-main', + }, 'wsgi_process_group' => 'keystone_main', 'wsgi_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]'] + }, + 'require' => 'File[keystone_wsgi_main]' )} - it "should set keystone wsgi options" do - contain_file('25-keystone_wsgi_main.conf').with_content( - /^ WSGIDaemonProcess keystone group=keystone processes=37 threads=1 user=keystone$/ - ) - end end describe 'when overriding parameters using same port and same path' do @@ -182,35 +208,6 @@ describe 'keystone::wsgi::apache' do it_raises 'a Puppet::Error', /When using the same port for public & private endpoints, public_path and admin_path should be different\./ 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 @@ -224,8 +221,9 @@ describe 'keystone::wsgi::apache' do let :platform_parameters do { :httpd_service_name => 'httpd', + :httpd_ports_file => '/etc/httpd/conf/ports.conf', :wsgi_script_path => '/var/www/cgi-bin/keystone', - :wsgi_script_source => 'puppet:///modules/keystone/httpd/keystone.py' + :wsgi_script_source => '/usr/share/keystone/keystone.wsgi' } end @@ -244,6 +242,7 @@ describe 'keystone::wsgi::apache' do let :platform_parameters do { :httpd_service_name => 'apache2', + :httpd_ports_file => '/etc/apache2/ports.conf', :wsgi_script_path => '/usr/lib/cgi-bin/keystone', :wsgi_script_source => '/usr/share/keystone/wsgi.py' } diff --git a/deployment/puppet/keystone/spec/defines/keystone_resource_service_identity_spec.rb b/deployment/puppet/keystone/spec/defines/keystone_resource_service_identity_spec.rb new file mode 100644 index 0000000000..18979635eb --- /dev/null +++ b/deployment/puppet/keystone/spec/defines/keystone_resource_service_identity_spec.rb @@ -0,0 +1,89 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +require 'spec_helper' + +describe 'keystone::resource::service_identity' do + + let (:title) { 'neutron' } + + let :required_params do + { :password => 'secrete', + :service_type => 'network', + :admin_url => 'http://192.168.0.1:9696', + :internal_url => 'http://10.0.0.1:9696', + :public_url => 'http://7.7.7.7:9696' } + end + + shared_examples 'keystone::resource::service_identity examples' do + + context 'with only required parameters' do + let :params do + required_params + end + + it { is_expected.to contain_keystone_user(title).with( + :ensure => 'present', + :password => 'secrete', + :email => 'neutron@localhost', + :tenant => 'services', + )} + + it { is_expected.to contain_keystone_user_role("#{title}@services").with( + :ensure => 'present', + :roles => ['admin'], + )} + + it { is_expected.to contain_keystone_service(title).with( + :ensure => 'present', + :type => 'network', + :description => 'neutron service', + )} + + it { is_expected.to contain_keystone_endpoint("RegionOne/#{title}").with( + :ensure => 'present', + :public_url => 'http://7.7.7.7:9696', + :internal_url => 'http://10.0.0.1:9696', + :admin_url => 'http://192.168.0.1:9696', + )} + end + + context 'when omitting a required parameter password' do + let :params do + required_params.delete(:password) + end + it { expect { is_expected.to raise_error(Puppet::Error) } } + end + + end + + context 'on a Debian osfamily' do + let :facts do + { :osfamily => "Debian" } + end + + include_examples 'keystone::resource::service_identity examples' + end + + context 'on a RedHat osfamily' do + let :facts do + { :osfamily => 'RedHat' } + end + + include_examples 'keystone::resource::service_identity examples' + end +end diff --git a/deployment/puppet/keystone/spec/shared_examples.rb b/deployment/puppet/keystone/spec/shared_examples.rb index d92156a361..fec0eacc98 100644 --- a/deployment/puppet/keystone/spec/shared_examples.rb +++ b/deployment/puppet/keystone/spec/shared_examples.rb @@ -1,5 +1,5 @@ shared_examples_for "a Puppet::Error" do |description| it "with message matching #{description.inspect}" do - expect { should have_class_count(1) }.to raise_error(Puppet::Error, description) + expect { is_expected.to have_class_count(1) }.to raise_error(Puppet::Error, description) end end diff --git a/deployment/puppet/keystone/spec/spec_helper.rb b/deployment/puppet/keystone/spec/spec_helper.rb index 92560eb2bd..78594f8ae7 100644 --- a/deployment/puppet/keystone/spec/spec_helper.rb +++ b/deployment/puppet/keystone/spec/spec_helper.rb @@ -1,8 +1,9 @@ +# Load libraries from openstacklib here to simulate how they live together in a real puppet run (for provider unit tests) +$LOAD_PATH.push(File.join(File.dirname(__FILE__), 'fixtures', 'modules', 'openstacklib', 'lib')) require 'puppetlabs_spec_helper/module_spec_helper' require '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' + c.alias_it_should_behave_like_to :it_configures, 'configures' + c.alias_it_should_behave_like_to :it_raises, 'raises' end - diff --git a/deployment/puppet/keystone/spec/spec_helper_acceptance.rb b/deployment/puppet/keystone/spec/spec_helper_acceptance.rb new file mode 100644 index 0000000000..ffcb47a516 --- /dev/null +++ b/deployment/puppet/keystone/spec/spec_helper_acceptance.rb @@ -0,0 +1,46 @@ +require 'beaker-rspec' + +hosts.each do |host| + + install_puppet + + on host, "mkdir -p #{host['distmoduledir']}" +end + +RSpec.configure do |c| + # Project root + proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) + + # Readable test descriptions + c.formatter = :documentation + + # Configure all nodes in nodeset + c.before :suite do + # Install module and dependencies + hosts.each do |host| + + # install git + install_package host, 'git' + + # clean out any module cruft + shell('rm -fr /etc/puppet/modules/*') + + # install library modules from the forge + on host, puppet('module','install','puppetlabs-mysql'), { :acceptable_exit_codes => 0 } + on host, puppet('module','install','dprince/qpid'), { :acceptable_exit_codes => 0 } + on host, puppet('module','install','duritong/sysctl'), { :acceptable_exit_codes => 0 } + on host, puppet('module','install','puppetlabs-inifile'), { :acceptable_exit_codes => 0 } + on host, puppet('module','install','puppetlabs-rabbitmq'), { :acceptable_exit_codes => 0 } + on host, puppet('module','install','puppetlabs-apache'), { :acceptable_exit_codes => 0 } + + # install puppet modules from git, use master + shell('git clone https://git.openstack.org/openstack/puppet-openstacklib /etc/puppet/modules/openstacklib') + shell('git clone https://git.openstack.org/openstack/puppet-openstack_extras /etc/puppet/modules/openstack_extras') + + # Install the module being tested + puppet_module_install(:source => proj_root, :module_name => 'keystone') + # List modules installed to help with debugging + on hosts[0], puppet('module','list'), { :acceptable_exit_codes => 0 } + end + end +end diff --git a/deployment/puppet/keystone/spec/unit/provider/keystone_endpoint/keystone_spec.rb b/deployment/puppet/keystone/spec/unit/provider/keystone_endpoint/keystone_spec.rb deleted file mode 100644 index 41ccefc23c..0000000000 --- a/deployment/puppet/keystone/spec/unit/provider/keystone_endpoint/keystone_spec.rb +++ /dev/null @@ -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 diff --git a/deployment/puppet/keystone/spec/unit/provider/keystone_endpoint/openstack_spec.rb b/deployment/puppet/keystone/spec/unit/provider/keystone_endpoint/openstack_spec.rb new file mode 100644 index 0000000000..9ca5b436f3 --- /dev/null +++ b/deployment/puppet/keystone/spec/unit/provider/keystone_endpoint/openstack_spec.rb @@ -0,0 +1,100 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/keystone_endpoint/openstack' + +provider_class = Puppet::Type.type(:keystone_endpoint).provider(:openstack) + +describe provider_class do + + shared_examples 'authenticated with environment variables' do + ENV['OS_USERNAME'] = 'test' + ENV['OS_PASSWORD'] = 'abc123' + ENV['OS_PROJECT_NAME'] = 'test' + ENV['OS_AUTH_URL'] = 'http://127.0.0.1:35357/v2.0' + end + + describe 'when managing an endpoint' do + + let(:endpoint_attrs) do + { + :name => 'foo/bar', + :ensure => 'present', + :public_url => 'http://127.0.0.1:5000/v2.0', + :internal_url => 'http://127.0.0.1:5001/v2.0', + :admin_url => 'http://127.0.0.1:5002/v2.0', + } + end + + let(:resource) do + Puppet::Type::Keystone_endpoint.new(endpoint_attrs) + end + + let(:provider) do + provider_class.new(resource) + end + + it_behaves_like 'authenticated with environment variables' do + describe '#create' do + it 'creates an endpoint' do + provider.class.stubs(:openstack) + .with('endpoint', 'list', '--quiet', '--format', 'csv', '--long') + .returns('"ID","Region","Service Name","Service Type","PublicURL","AdminURL","InternalURL" +"1cb05cfed7c24279be884ba4f6520262","foo","bar","","http://127.0.0.1:5000/v2.0","http://127.0.0.1:5001/v2.0","http://127.0.0.1:5002/v2.0" +') + provider.class.stubs(:openstack) + .with('endpoint', 'create', '--format', 'shell', ['bar', '--region', 'foo', '--publicurl', 'http://127.0.0.1:5000/v2.0', '--internalurl', 'http://127.0.0.1:5001/v2.0', '--adminurl', 'http://127.0.0.1:5002/v2.0']) + .returns('adminurl="http://127.0.0.1:5002/v2.0" +id="3a5c4378981e4112a0d44902a43e16ef" +internalurl="http://127.0.0.1:5001/v2.0" +publicurl="http://127.0.0.1:5000/v2.0" +region="foo" +service_id="8137d72980fd462192f276585a002426" +service_name="bar" +service_type="test" +') + provider.create + expect(provider.exists?).to be_truthy + end + end + + describe '#destroy' do + it 'destroys an endpoint' do + provider.class.stubs(:openstack) + .with('endpoint', 'list', '--quiet', '--format', 'csv', '--long') + .returns('"ID","Region","Service Name","Service Type","PublicURL","AdminURL","InternalURL" +"1cb05cfed7c24279be884ba4f6520262","foo","bar","test","http://127.0.0.1:5000/v2.0","http://127.0.0.1:5001/v2.0","http://127.0.0.1:5002/v2.0" +') + provider.class.stubs(:openstack) + .with('endpoint', 'delete', []) + provider.destroy + expect(provider.exists?).to be_falsey + end + end + + describe '#exists' do + context 'when tenant does not exist' do + subject(:response) do + provider.class.stubs(:openstack) + .with('endpoint', 'list', '--quiet', '--format', 'csv', '--long') + .returns('"ID","Region","Service Name","Service Type","PublicURL","AdminURL","InternalURL"') + response = provider.exists? + end + + it { is_expected.to be_falsey } + end + end + + describe '#instances' do + it 'finds every tenant' do + provider.class.stubs(:openstack) + .with('endpoint', 'list', '--quiet', '--format', 'csv', '--long') + .returns('"ID","Region","Service Name","Service Type","PublicURL","AdminURL","InternalURL" +"3a5c4378981e4112a0d44902a43e16ef","foo","bar","test","http://127.0.0.1:5000/v2.0","http://127.0.0.1:5001/v2.0","http://127.0.0.1:5002/v2.0" +') + instances = Puppet::Type::Keystone_endpoint::ProviderOpenstack.instances + expect(instances.count).to eq(1) + end + end + end + end +end diff --git a/deployment/puppet/keystone/spec/unit/provider/keystone_paste_ini/ini_setting_spec.rb b/deployment/puppet/keystone/spec/unit/provider/keystone_paste_ini/ini_setting_spec.rb new file mode 100644 index 0000000000..2eff5d63fe --- /dev/null +++ b/deployment/puppet/keystone/spec/unit/provider/keystone_paste_ini/ini_setting_spec.rb @@ -0,0 +1,29 @@ +# +# these tests are a little concerning b/c they are hacking around the +# modulepath, so these tests will not catch issues that may eventually arise +# related to loading these plugins. +# I could not, for the life of me, figure out how to programatcally set the modulepath +$LOAD_PATH.push( + File.join( + File.dirname(__FILE__), + '..', + '..', + '..', + 'fixtures', + 'modules', + 'inifile', + 'lib') +) +require 'spec_helper' +provider_class = Puppet::Type.type(:keystone_paste_ini).provider(:ini_setting) +describe provider_class do + + it 'should allow setting to be set explicitly' do + resource = Puppet::Type::Keystone_paste_ini.new( + {:name => 'dude/foo', :value => 'bar'} + ) + provider = provider_class.new(resource) + provider.section.should == 'dude' + provider.setting.should == 'foo' + end +end diff --git a/deployment/puppet/keystone/spec/unit/provider/keystone_role/keystone_spec.rb b/deployment/puppet/keystone/spec/unit/provider/keystone_role/keystone_spec.rb deleted file mode 100644 index c367c95b83..0000000000 --- a/deployment/puppet/keystone/spec/unit/provider/keystone_role/keystone_spec.rb +++ /dev/null @@ -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 diff --git a/deployment/puppet/keystone/spec/unit/provider/keystone_role/openstack_spec.rb b/deployment/puppet/keystone/spec/unit/provider/keystone_role/openstack_spec.rb new file mode 100644 index 0000000000..09e229b82f --- /dev/null +++ b/deployment/puppet/keystone/spec/unit/provider/keystone_role/openstack_spec.rb @@ -0,0 +1,86 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/keystone_role/openstack' + +provider_class = Puppet::Type.type(:keystone_role).provider(:openstack) + +describe provider_class do + + shared_examples 'authenticated with environment variables' do + ENV['OS_USERNAME'] = 'test' + ENV['OS_PASSWORD'] = 'abc123' + ENV['OS_PROJECT_NAME'] = 'test' + ENV['OS_AUTH_URL'] = 'http://127.0.0.1:5000' + end + + describe 'when creating a role' do + it_behaves_like 'authenticated with environment variables' do + let(:role_attrs) do + { + :name => 'foo', + :ensure => 'present', + } + end + + let(:resource) do + Puppet::Type::Keystone_role.new(role_attrs) + end + + let(:provider) do + provider_class.new(resource) + end + + describe '#create' do + it 'creates a role' do + provider.class.stubs(:openstack) + .with('role', 'list', '--quiet', '--format', 'csv', []) + .returns('"ID","Name" +"1cb05cfed7c24279be884ba4f6520262","foo" +') + provider.class.stubs(:openstack) + .with('role', 'create', '--format', 'shell', 'foo') + .returns('name="foo"') + provider.create + expect(provider.exists?).to be_truthy + end + end + + describe '#destroy' do + it 'destroys a role' do + provider.class.stubs(:openstack) + .with('role', 'list', '--quiet', '--format', 'csv', []) + .returns('"ID","Name"') + provider.class.stubs(:openstack) + .with('role', 'delete', []) + provider.destroy + expect(provider.exists?).to be_falsey + end + + end + + describe '#exists' do + context 'when role does not exist' do + subject(:response) do + provider.class.stubs(:openstack) + .with('role', 'list', '--quiet', '--format', 'csv', []) + .returns('"ID","Name"') + response = provider.exists? + end + it { is_expected.to be_falsey } + end + end + + describe '#instances' do + it 'finds every role' do + provider.class.stubs(:openstack) + .with('role', 'list', '--quiet', '--format', 'csv', []) + .returns('"ID","Name" +"1cb05cfed7c24279be884ba4f6520262","foo" +') + instances = Puppet::Type::Keystone_role::ProviderOpenstack.instances + expect(instances.count).to eq(1) + end + end + end + end +end diff --git a/deployment/puppet/keystone/spec/unit/provider/keystone_service/keystone_spec.rb b/deployment/puppet/keystone/spec/unit/provider/keystone_service/keystone_spec.rb deleted file mode 100644 index b22d330676..0000000000 --- a/deployment/puppet/keystone/spec/unit/provider/keystone_service/keystone_spec.rb +++ /dev/null @@ -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 diff --git a/deployment/puppet/keystone/spec/unit/provider/keystone_service/openstack_spec.rb b/deployment/puppet/keystone/spec/unit/provider/keystone_service/openstack_spec.rb new file mode 100644 index 0000000000..b627ec1fad --- /dev/null +++ b/deployment/puppet/keystone/spec/unit/provider/keystone_service/openstack_spec.rb @@ -0,0 +1,93 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/keystone_service/openstack' + +provider_class = Puppet::Type.type(:keystone_service).provider(:openstack) + +describe provider_class do + + shared_examples 'authenticated with environment variables' do + ENV['OS_USERNAME'] = 'test' + ENV['OS_PASSWORD'] = 'abc123' + ENV['OS_PROJECT_NAME'] = 'test' + ENV['OS_AUTH_URL'] = 'http://127.0.0.1:35357/v2.0' + end + + describe 'when managing a service' do + + let(:service_attrs) do + { + :name => 'foo', + :description => 'foo', + :ensure => 'present', + :type => 'foo', + } + end + + let(:resource) do + Puppet::Type::Keystone_service.new(service_attrs) + end + + let(:provider) do + provider_class.new(resource) + end + + it_behaves_like 'authenticated with environment variables' do + describe '#create' do + it 'creates a service' do + provider.class.stubs(:openstack) + .with('service', 'list', '--quiet', '--format', 'csv', '--long') + .returns('"ID","Name","Type","Description" +"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo" +') + provider.class.stubs(:openstack) + .with('service', 'create', '--format', 'shell', ['--name', 'foo', '--description', 'foo', 'foo']) + .returns('description="foo" +enabled="True" +id="8f0dd4c0abc44240998fbb3f5089ecbf" +name="foo" +type="foo" +') + provider.create + expect(provider.exists?).to be_truthy + end + end + + describe '#destroy' do + it 'destroys a service' do + provider.class.stubs(:openstack) + .with('service', 'list', '--quiet', '--format', 'csv', '--long') + .returns('"ID","Name","Type","Description" +"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo" +') + provider.class.stubs(:openstack) + .with('service', 'delete', []) + provider.destroy + expect(provider.exists?).to be_falsey + end + + context 'when service does not exist' do + subject(:response) do + provider.class.stubs(:openstack) + .with('service', 'list', '--quiet', '--format', 'csv', '--long') + .returns('"ID","Name","Type","Description"') + response = provider.exists? + end + it { is_expected.to be_falsey } + end + end + + describe '#instances' do + it 'finds every service' do + provider.class.stubs(:openstack) + .with('service', 'list', '--quiet', '--format', 'csv', '--long') + .returns('"ID","Name","Type","Description" +"8f0dd4c0abc44240998fbb3f5089ecbf","foo","foo","foo" +') + instances = Puppet::Type::Keystone_service::ProviderOpenstack.instances + expect(instances.count).to eq(1) + end + end + end + end +end diff --git a/deployment/puppet/keystone/spec/unit/provider/keystone_spec.rb b/deployment/puppet/keystone/spec/unit/provider/keystone_spec.rb index 50357bf572..4981f1e5ce 100644 --- a/deployment/puppet/keystone/spec/unit/provider/keystone_spec.rb +++ b/deployment/puppet/keystone/spec/unit/provider/keystone_spec.rb @@ -3,164 +3,119 @@ require 'spec_helper' require 'puppet/provider/keystone' require 'tempfile' - klass = Puppet::Provider::Keystone +class Puppet::Provider::Keystone + @credentials = Puppet::Provider::Openstack::CredentialsV2_0.new + + def self.reset + @admin_endpoint = nil + @tenant_hash = nil + @admin_token = nil + @keystone_file = nil + end +end + describe Puppet::Provider::Keystone do 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/) + it 'should return nothing if there is no keystone config file' do + File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(false) + expect(klass.get_admin_token).to be_nil end - it 'should fail if the keystone config file does not have a DEFAULT section' do + it 'should return nothing if the keystone config file does not have a DEFAULT section' do mock = {} + File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true) Puppet::Util::IniConfig::File.expects(:new).returns(mock) mock.expects(:read).with('/etc/keystone/keystone.conf') - expect do - - klass.get_admin_token - end.to raise_error(Puppet::Error, /Keystone types will not work/) + expect(klass.get_admin_token).to be_nil end it 'should fail if the keystone config file does not contain an admin token' do mock = {'DEFAULT' => {'not_a_token' => 'foo'}} + File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true) Puppet::Util::IniConfig::File.expects(:new).returns(mock) mock.expects(:read).with('/etc/keystone/keystone.conf') - expect do - klass.get_admin_token - end.to raise_error(Puppet::Error, /Keystone types will not work/) + expect(klass.get_admin_token).to be_nil end it 'should parse the admin token if it is in the config file' do mock = {'DEFAULT' => {'admin_token' => 'foo'}} + File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true) Puppet::Util::IniConfig::File.expects(:new).returns(mock) mock.expects(:read).with('/etc/keystone/keystone.conf') - klass.get_admin_token.should == 'foo' + expect(klass.get_admin_token).to eq('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' }} + File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true) Puppet::Util::IniConfig::File.expects(:new).returns(mock) mock.expects(:read).with('/etc/keystone/keystone.conf') - klass.get_admin_endpoint.should == 'http://192.168.56.210:35357/v2.0/' + expect(klass.get_admin_endpoint).to eq('http://192.168.56.210:35357/v2.0/') end 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' }} + File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true) Puppet::Util::IniConfig::File.expects(:new).returns(mock) mock.expects(:read).with('/etc/keystone/keystone.conf') - klass.get_admin_endpoint.should == 'http://127.0.0.1:35357/v2.0/' + expect(klass.get_admin_endpoint).to eq('http://127.0.0.1:35357/v2.0/') + end + + it 'should use [::1] in the admin endpoint if bind_host is ::0' do + mock = {'DEFAULT' => { 'admin_bind_host' => '::0', 'admin_port' => '35357' }} + File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true) + Puppet::Util::IniConfig::File.expects(:new).returns(mock) + mock.expects(:read).with('/etc/keystone/keystone.conf') + expect(klass.get_admin_endpoint).to eq('http://[::1]:35357/v2.0/') end it 'should use localhost in the admin endpoint if bind_host is unspecified' do mock = {'DEFAULT' => { 'admin_port' => '35357' }} + File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true) Puppet::Util::IniConfig::File.expects(:new).returns(mock) mock.expects(:read).with('/etc/keystone/keystone.conf') - klass.get_admin_endpoint.should == 'http://127.0.0.1:35357/v2.0/' + expect(klass.get_admin_endpoint).to eq('http://127.0.0.1:35357/v2.0/') end it 'should use https if ssl is enabled' do mock = {'DEFAULT' => {'admin_bind_host' => '192.168.56.210', 'admin_port' => '35357' }, 'ssl' => {'enable' => 'True'}} + File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true) Puppet::Util::IniConfig::File.expects(:new).returns(mock) mock.expects(:read).with('/etc/keystone/keystone.conf') - klass.get_admin_endpoint.should == 'https://192.168.56.210:35357/v2.0/' + expect(klass.get_admin_endpoint).to eq('https://192.168.56.210:35357/v2.0/') end it 'should use http if ssl is disabled' do mock = {'DEFAULT' => {'admin_bind_host' => '192.168.56.210', 'admin_port' => '35357' }, 'ssl' => {'enable' => 'False'}} + File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true) Puppet::Util::IniConfig::File.expects(:new).returns(mock) mock.expects(:read).with('/etc/keystone/keystone.conf') - klass.get_admin_endpoint.should == 'http://192.168.56.210:35357/v2.0/' + expect(klass.get_admin_endpoint).to eq('http://192.168.56.210:35357/v2.0/') end it 'should use the defined admin_endpoint if available' do - mock = {'DEFAULT' => {'admin_endpoint' => 'https://keystone.example.com/v2.0/' }, 'ssl' => {'enable' => 'False'}} + mock = {'DEFAULT' => {'admin_endpoint' => 'https://keystone.example.com' }, 'ssl' => {'enable' => 'False'}} + File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true) Puppet::Util::IniConfig::File.expects(:new).returns(mock) mock.expects(:read).with('/etc/keystone/keystone.conf') - klass.get_admin_endpoint.should == 'https://keystone.example.com/v2.0/' + expect(klass.get_admin_endpoint).to eq('https://keystone.example.com/v2.0/') end - 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'}} + it 'should handle an admin_endpoint with a trailing slash' do + mock = {'DEFAULT' => {'admin_endpoint' => 'https://keystone.example.com/' }, 'ssl' => {'enable' => 'False'}} + File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(true) Puppet::Util::IniConfig::File.expects(:new).returns(mock) 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" + expect(klass.get_admin_endpoint).to eq('https://keystone.example.com/v2.0/') 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 diff --git a/deployment/puppet/keystone/spec/unit/provider/keystone_tenant/keystone_spec.rb b/deployment/puppet/keystone/spec/unit/provider/keystone_tenant/keystone_spec.rb deleted file mode 100644 index b6ba73aad9..0000000000 --- a/deployment/puppet/keystone/spec/unit/provider/keystone_tenant/keystone_spec.rb +++ /dev/null @@ -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 diff --git a/deployment/puppet/keystone/spec/unit/provider/keystone_tenant/openstack_spec.rb b/deployment/puppet/keystone/spec/unit/provider/keystone_tenant/openstack_spec.rb new file mode 100644 index 0000000000..1dec49e060 --- /dev/null +++ b/deployment/puppet/keystone/spec/unit/provider/keystone_tenant/openstack_spec.rb @@ -0,0 +1,90 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/keystone_tenant/openstack' + +provider_class = Puppet::Type.type(:keystone_tenant).provider(:openstack) + +describe provider_class do + + shared_examples 'authenticated with environment variables' do + ENV['OS_USERNAME'] = 'test' + ENV['OS_PASSWORD'] = 'abc123' + ENV['OS_PROJECT_NAME'] = 'test' + ENV['OS_AUTH_URL'] = 'http://127.0.0.1:35357/v2.0' + end + + describe 'when managing a tenant' do + + let(:tenant_attrs) do + { + :name => 'foo', + :description => 'foo', + :ensure => 'present', + :enabled => 'True', + } + end + + let(:resource) do + Puppet::Type::Keystone_tenant.new(tenant_attrs) + end + + let(:provider) do + provider_class.new(resource) + end + + it_behaves_like 'authenticated with environment variables' do + describe '#create' do + it 'creates a tenant' do + provider.class.stubs(:openstack) + .with('project', 'list', '--quiet', '--format', 'csv', '--long') + .returns('"ID","Name","Description","Enabled" +"1cb05cfed7c24279be884ba4f6520262","foo","foo",True +') + provider.class.stubs(:openstack) + .with('project', 'create', '--format', 'shell', ['foo', '--enable', '--description', 'foo']) + .returns('description="foo" +enabled="True" +name="foo" +') + provider.create + expect(provider.exists?).to be_truthy + end + end + + describe '#destroy' do + it 'destroys a tenant' do + provider.class.stubs(:openstack) + .with('project', 'list', '--quiet', '--format', 'csv', '--long') + .returns('"ID","Name","Description","Enabled"') + provider.class.stubs(:openstack) + .with('project', 'delete', []) + provider.destroy + expect(provider.exists?).to be_falsey + end + end + + context 'when tenant does not exist' do + subject(:response) do + provider.class.stubs(:openstack) + .with('project', 'list', '--quiet', '--format', 'csv', '--long') + .returns('"ID","Name","Description","Enabled"') + response = provider.exists? + end + + it { is_expected.to be_falsey } + end + + describe '#instances' do + it 'finds every tenant' do + provider.class.stubs(:openstack) + .with('project', 'list', '--quiet', '--format', 'csv', '--long') + .returns('"ID","Name","Description","Enabled" +"1cb05cfed7c24279be884ba4f6520262","foo","foo",True +') + instances = Puppet::Type::Keystone_tenant::ProviderOpenstack.instances + expect(instances.count).to eq(1) + end + end + end + end +end diff --git a/deployment/puppet/keystone/spec/unit/provider/keystone_user/keystone_spec.rb b/deployment/puppet/keystone/spec/unit/provider/keystone_user/keystone_spec.rb deleted file mode 100644 index 4a2b2d69d7..0000000000 --- a/deployment/puppet/keystone/spec/unit/provider/keystone_user/keystone_spec.rb +++ /dev/null @@ -1,78 +0,0 @@ -require 'puppet' -require 'spec_helper' -require 'puppet/provider/keystone_user/keystone' - -provider_class = Puppet::Type.type(:keystone_user).provider(:keystone) - -describe provider_class do - - describe 'when updating a user' do - let :resource do - Puppet::Type::Keystone_user.new( - { - :name => 'foo', - :ensure => 'present', - :enabled => 'True', - :tenant => 'foo2', - :email => 'foo@foo.com', - :password => 'passwd' - } - ) - end - - let :provider do - provider_class.new(resource) - end - - before :each do - provider_class.expects(:build_user_hash).at_least(1).returns( - 'foo' => {:id => 'id', :name => 'foo', :tenant => 'foo2', :password => 'passwd'} - ) - end - - after :each do - # reset global state - provider_class.prefetch(nil) - end - - it 'should call user-password-update to change password' do - provider.expects(:auth_keystone).with('user-password-update', '--pass', 'newpassword', 'id') - provider.password=('newpassword') - end - end - - describe 'when query keystone objects' do - it 'should not cache keystone objects in catalog' do - provider_class.stubs(:build_user_hash).returns({ 'foo' => 'bar' }) - provider_class.user_hash.should == ({ 'foo' => 'bar' }) - provider_class.stubs(:build_user_hash).returns({ 'baz' => 'qux' }) - provider_class.user_hash.should == ({ 'baz' => 'qux' }) - end - end - - describe 'when updating a user with unmanaged password' do - let :resource do - Puppet::Type::Keystone_user.new( - { - :name => 'foo', - :ensure => 'present', - :enabled => 'True', - :tenant => 'foo2', - :email => 'foo@foo.com', - :password => 'passwd', - :replace_password => 'False', - } - ) - end - - let :provider do - provider_class.new(resource) - end - - it 'should not call user-password-update to change password' do - provider.expects(:auth_keystone).with('user-password-update', '--pass', 'newpassword', 'id').times(0) - provider.password=('newpassword') - end - end - -end diff --git a/deployment/puppet/keystone/spec/unit/provider/keystone_user/openstack_spec.rb b/deployment/puppet/keystone/spec/unit/provider/keystone_user/openstack_spec.rb new file mode 100644 index 0000000000..3f545d0cf1 --- /dev/null +++ b/deployment/puppet/keystone/spec/unit/provider/keystone_user/openstack_spec.rb @@ -0,0 +1,277 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/keystone_user/openstack' + +provider_class = Puppet::Type.type(:keystone_user).provider(:openstack) + +describe provider_class do + + shared_examples 'authenticated with environment variables' do + ENV['OS_USERNAME'] = 'test' + ENV['OS_PASSWORD'] = 'abc123' + ENV['OS_PROJECT_NAME'] = 'test' + ENV['OS_AUTH_URL'] = 'http://127.0.0.1:5000' + end + + let(:user_attrs) do + { + :name => 'foo', + :ensure => :present, + :enabled => 'True', + :password => 'foo', + :tenant => 'foo', + :email => 'foo@example.com', + } + end + + let(:resource) do + Puppet::Type::Keystone_user.new(user_attrs) + end + + let(:provider) do + provider_class.new(resource) + end + + describe 'when managing a user' do + it_behaves_like 'authenticated with environment variables' do + describe '#create' do + it 'creates a user' do + provider.class.stubs(:openstack) + .with('user', 'list', '--quiet', '--format', 'csv', '--long') + .returns('"ID","Name","Project","Email","Enabled" +"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo@example.com",True +') + provider.class.stubs(:openstack) + .with('user', 'create', '--format', 'shell', ['foo', '--enable', '--password', 'foo', '--project', 'foo', '--email', 'foo@example.com']) + .returns('email="foo@example.com" +enabled="True" +id="12b23f07d4a3448d8189521ab09610b0" +name="foo" +project_id="5e2001b2248540f191ff22627dc0c2d7" +username="foo" +') + provider.create + expect(provider.exists?).to be_truthy + end + end + + describe '#destroy' do + it 'destroys a user' do + provider.class.stubs(:openstack) + .with('user', 'list', '--quiet', '--format', 'csv', '--long') + .returns('"ID","Name","Project","Email","Enabled"') + provider.class.stubs(:openstack) + .with('user', 'delete', []) + provider.destroy + expect(provider.exists?).to be_falsey + end + + end + + describe '#exists' do + context 'when user does not exist' do + subject(:response) do + provider.class.stubs(:openstack) + .with('user', 'list', '--quiet', '--format', 'csv', '--long') + .returns('"ID","Name","Project","Email","Enabled"') + response = provider.exists? + end + + it { is_expected.to be_falsey } + end + end + + describe '#instances' do + it 'finds every user' do + provider.class.stubs(:openstack) + .with('user', 'list', '--quiet', '--format', 'csv', '--long') + .returns('"ID","Name","Project","Email","Enabled" +"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo@example.com",True +') + instances = Puppet::Type::Keystone_user::ProviderOpenstack.instances + expect(instances.count).to eq(1) + end + end + + describe '#tenant' do + it 'gets the tenant with default backend' do + provider.class.stubs(:openstack) + .with('user', 'list', '--quiet', '--format', 'csv', '--long') + .returns('"ID","Name","Project","Email","Enabled" +"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo@example.com",True +') + provider.class.stubs(:openstack) + .with('user role', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'foo']) + .returns('"ID","Name","Project","User" +"9fe2ff9ee4384b1894a90878d3e92bab","_member_","foo","foo" +') + tenant = provider.tenant + expect(tenant).to eq('foo') + end + + it 'gets the tenant with LDAP backend' do + provider.class.stubs(:openstack) + .with('user', 'list', '--quiet', '--format', 'csv', '--long') + .returns('"ID","Name","Project","Email","Enabled" +"1cb05cfed7c24279be884ba4f6520262","foo","","foo@example.com",True +') + provider.class.expects(:openstack) + .with('user role', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'foo']) + .returns('"ID","Name","Project","User" +"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo" +') + tenant = provider.tenant + expect(tenant).to eq('foo') + end + end + + describe '#tenant=' do + context 'when using default backend' do + it 'sets the tenant' do + provider.class.expects(:openstack) + .with('user', 'set', ['foo', '--project', 'bar']) + provider.class.expects(:openstack) + .with('user role', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'bar']) + .returns('"ID","Name","Project","User" +"9fe2ff9ee4384b1894a90878d3e92bab","_member_","bar","foo" +') + provider.tenant=('bar') + end + end + + context 'when using LDAP read-write backend' do + it 'sets the tenant when _member_ role exists' do + provider.class.expects(:openstack) + .with('user', 'set', ['foo', '--project', 'bar']) + provider.class.expects(:openstack) + .with('user role', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'bar']) + .returns('') + provider.class.expects(:openstack) + .with('role', 'show', '--format', 'shell', ['_member_']) + .returns('id="9fe2ff9ee4384b1894a90878d3e92bab" +name="_member_" +') + provider.class.expects(:openstack) + .with('role', 'add', ['_member_', '--project', 'bar', '--user', 'foo']) + provider.tenant=('bar') + end + it 'sets the tenant when _member_ role does not exist' do + provider.class.expects(:openstack) + .with('user', 'set', ['foo', '--project', 'bar']) + provider.class.expects(:openstack) + .with('user role', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'bar']) + .returns('') + provider.class.expects(:openstack) + .with('role', 'show', '--format', 'shell', ['_member_']) + .raises(Puppet::ExecutionFailure, 'no such role _member_') + provider.class.expects(:openstack) + .with('role', 'create', '--format', 'shell', ['_member_']) + .returns('name="_member_"') + provider.class.expects(:openstack) + .with('role', 'add', ['_member_', '--project', 'bar', '--user', 'foo']) + .returns('id="8wr2ff9ee4384b1894a90878d3e92bab" +name="_member_" +') + provider.tenant=('bar') + end + end + +# This doesn't make sense, need to clarify what's happening with LDAP mock +=begin + context 'when using LDAP read-only backend' do + it 'sets the tenant when _member_ role exists' do + provider.class.expects(:openstack) + .with('user', 'set', [['foo', '--project', 'bar']]) + .raises(Puppet::ExecutionFailure, 'You are not authorized to perform the requested action: LDAP user update') + provider.class.expects(:openstack) + .with('user role', 'list', '--quiet', '--format', 'csv', [['foo', '--project', 'bar']]) + .returns('') + provider.class.expects(:openstack) + .with('role', 'show', '--format', 'shell', [['_member_']]) + .returns('id="9fe2ff9ee4384b1894a90878d3e92bab" +name="_member_" +') + provider.class.expects(:openstack) + .with('role', 'add', [['_member_', '--project', 'bar', '--user', 'foo']]) + provider.tenant=('bar') + end + + it 'sets the tenant and gets an unexpected exception message' do + provider.class.expects(:openstack) + .with('user', 'set', [['foo', '--project', 'bar']]) + .raises(Puppet::ExecutionFailure, 'unknown error message') + expect{ provider.tenant=('bar') }.to raise_error(Puppet::ExecutionFailure, /unknown error message/) + end + end +=end + end + end + end + + describe "#password" do + let(:user_attrs) do + { + :name => 'foo', + :ensure => 'present', + :enabled => 'True', + :password => 'foo', + :tenant => 'foo', + :email => 'foo@example.com', + } + end + + let(:resource) do + Puppet::Type::Keystone_user.new(user_attrs) + end + + let :provider do + provider_class.new(resource) + end + + shared_examples 'with auth-url environment variable' do + ENV['OS_AUTH_URL'] = 'http://localhost:5000' + end + + it_behaves_like 'with auth-url environment variable' do + it 'checks the password' do + Puppet::Provider::Openstack.stubs(:openstack) + .with('token', 'issue', ['--format', 'value']) + .returns('2015-05-14T04:06:05Z +e664a386befa4a30878dcef20e79f167 +8dce2ae9ecd34c199d2877bf319a3d06 +ac43ec53d5a74a0b9f51523ae41a29f0 +') + password = provider.password + expect(password).to eq('foo') + end + + it 'fails the password check' do + Puppet::Provider::Openstack.stubs(:openstack) + .with('token', 'issue', ['--format', 'value']) + .raises(Puppet::ExecutionFailure, 'HTTP 401 invalid authentication') + password = provider.password + expect(password).to eq(nil) + end + end + + describe 'when updating a user with unmanaged password' do + + let(:user_attrs) do + { + :name => 'foo', + :ensure => 'present', + :enabled => 'True', + :password => 'foo', + :replace_password => 'False', + :tenant => 'foo', + :email => 'foo@example.com', + } + end + + it 'should not try to check password' do + expect(provider.password).to eq('foo') + end + end + + end +end diff --git a/deployment/puppet/keystone/spec/unit/provider/keystone_user_role/keystone_spec.rb b/deployment/puppet/keystone/spec/unit/provider/keystone_user_role/keystone_spec.rb deleted file mode 100644 index 95532fb03c..0000000000 --- a/deployment/puppet/keystone/spec/unit/provider/keystone_user_role/keystone_spec.rb +++ /dev/null @@ -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 diff --git a/deployment/puppet/keystone/spec/unit/provider/keystone_user_role/openstack_spec.rb b/deployment/puppet/keystone/spec/unit/provider/keystone_user_role/openstack_spec.rb new file mode 100644 index 0000000000..2490adc52b --- /dev/null +++ b/deployment/puppet/keystone/spec/unit/provider/keystone_user_role/openstack_spec.rb @@ -0,0 +1,89 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/keystone_user_role/openstack' + +provider_class = Puppet::Type.type(:keystone_user_role).provider(:openstack) + +describe provider_class do + + shared_examples 'authenticated with environment variables' do + ENV['OS_USERNAME'] = 'test' + ENV['OS_PASSWORD'] = 'abc123' + ENV['OS_PROJECT_NAME'] = 'test' + ENV['OS_AUTH_URL'] = 'http://127.0.0.1:5000' + end + + describe 'when updating a user\'s role' do + it_behaves_like 'authenticated with environment variables' do + let(:user_role_attrs) do + { + :name => 'foo@foo', + :ensure => 'present', + :roles => ['foo', 'bar'], + } + end + + let(:resource) do + Puppet::Type::Keystone_user_role.new(user_role_attrs) + end + + let(:provider) do + provider_class.new(resource) + end + + before(:each) do + provider.class.stubs(:openstack) + .with('user', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'foo']) + .returns('"ID","Name","Project","User" +"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo" +') + end + + describe '#create' do + it 'adds all the roles to the user' do + provider.class.stubs(:openstack) + .with('role', 'add', ['foo', '--project', 'foo', '--user', 'foo']) + provider.class.stubs(:openstack) + .with('role', 'add', ['bar', '--project', 'foo', '--user', 'foo']) + provider.class.stubs(:openstack) + .with('user role', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'foo']) + .returns('"ID","Name","Project","User" +"1cb05ed7c24279be884ba4f6520262","foo","foo","foo" +"2cb05ed7c24279be884ba4f6520262","bar","foo","foo" +') + provider.create + expect(provider.exists?).to be_truthy + end + end + + describe '#destroy' do + it 'removes all the roles from a user' do + provider.class.stubs(:openstack) + .with('user role', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'foo']) + .returns('"ID","Name","Project","User"') + provider.class.stubs(:openstack) + .with('role', 'remove', ['foo', '--project', 'foo', '--user', 'foo']) + provider.class.stubs(:openstack) + .with('role', 'remove', ['bar', '--project', 'foo', '--user', 'foo']) + provider.destroy + expect(provider.exists?).to be_falsey + end + + end + + describe '#exists' do + subject(:response) do + provider.class.stubs(:openstack) + .with('user role', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'foo']) + .returns('"ID","Name","Project","User" +"1cb05ed7c24279be884ba4f6520262","foo","foo","foo" +') + response = provider.exists? + end + + it { is_expected.to be_truthy } + + end + end + end +end diff --git a/deployment/puppet/keystone/spec/unit/type/keystone_paste_ini_spec.rb b/deployment/puppet/keystone/spec/unit/type/keystone_paste_ini_spec.rb new file mode 100644 index 0000000000..98f7157b67 --- /dev/null +++ b/deployment/puppet/keystone/spec/unit/type/keystone_paste_ini_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' +# this hack is required for now to ensure that the path is set up correctly +# to retrive the parent provider +$LOAD_PATH.push( + File.join( + File.dirname(__FILE__), + '..', + '..', + 'fixtures', + 'modules', + 'inifile', + 'lib') +) +require 'puppet/type/keystone_paste_ini' +describe 'Puppet::Type.type(:keystone_paste_ini)' do + before :each do + @keystone_paste_ini = Puppet::Type.type(:keystone_paste_ini).new(:name => 'DEFAULT/foo', :value => 'bar') + end + it 'should accept a valid value' do + @keystone_paste_ini[:value] = 'bar' + @keystone_paste_ini[:value].should == 'bar' + end +end diff --git a/deployment/puppet/keystone/spec/unit/type/keystone_user_role_spec.rb b/deployment/puppet/keystone/spec/unit/type/keystone_user_role_spec.rb new file mode 100644 index 0000000000..82c32688f2 --- /dev/null +++ b/deployment/puppet/keystone/spec/unit/type/keystone_user_role_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' +require 'puppet' +require 'puppet/type/keystone_user_role' + +describe Puppet::Type.type(:keystone_user_role) do + + before :each do + @user_roles = Puppet::Type.type(:keystone_user_role).new( + :name => 'foo@bar', + :roles => ['a', 'b'] + ) + + @roles = @user_roles.parameter('roles') + end + + it 'should not be in sync for' do + expect(@roles.insync?(['a', 'b', 'c'])).to be false + expect(@roles.insync?('a')).to be false + expect(@roles.insync?(['a'])).to be false + expect(@roles.insync?(nil)).to be false + end + + it 'should be in sync for' do + expect(@roles.insync?(['a', 'b'])).to be true + expect(@roles.insync?(['b', 'a'])).to be true + end + +end diff --git a/deployment/puppet/keystone/tests/site.pp b/deployment/puppet/keystone/tests/site.pp index ddd3355903..c3a3fbb905 100644 --- a/deployment/puppet/keystone/tests/site.pp +++ b/deployment/puppet/keystone/tests/site.pp @@ -5,36 +5,36 @@ 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': +node 'keystone_sqlite' { + class { '::keystone': verbose => true, debug => true, catalog_type => 'sql', admin_token => 'admin_token', } - class { 'keystone::roles::admin': + class { '::keystone::roles::admin': email => 'example@abc.com', password => 'ChangeMe', } - class { 'keystone::endpoint': + class { '::keystone::endpoint': public_url => "http://${::fqdn}:5000/", admin_url => "http://${::fqdn}:35357/", } } node keystone_mysql { - class { 'mysql::server': } - class { 'keystone::db::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': + verbose => true, + debug => true, + database_connection => 'mysql://keystone:keystone@127.0.0.1/keystone', + catalog_type => 'sql', + admin_token => 'admin_token', } - class { 'keystone::roles::admin': + class { '::keystone::roles::admin': email => 'test@puppetlabs.com', password => 'ChangeMe', } @@ -43,21 +43,21 @@ node keystone_mysql { # 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': + verbose => true, + debug => true, + database_connection => 'mysql://keystone:password@127.0.0.1/keystone', + catalog_type => 'sql', + admin_token => 'admin_token', } - class { 'keystone::db::mysql': + class { '::keystone::db::mysql': password => 'keystone', } - class { 'keystone::roles::admin': + class { '::keystone::roles::admin': email => 'example@abc.com', password => 'ChangeMe', } - class { 'keystone::endpoint': + class { '::keystone::endpoint': public_url => "http://${::fqdn}:5000/", admin_url => "http://${::fqdn}:35357/", }