try with modules from master
authorMartin Zobel-Helas <zobel@debian.org>
Fri, 3 Jul 2015 15:16:07 +0000 (15:16 +0000)
committerMartin Zobel-Helas <zobel@debian.org>
Fri, 3 Jul 2015 15:16:07 +0000 (15:16 +0000)
Signed-off-by: Martin Zobel-Helas <zobel@debian.org>
109 files changed:
3rdparty/modules/keystone/CHANGELOG.md [new file with mode: 0644]
3rdparty/modules/keystone/Gemfile
3rdparty/modules/keystone/LICENSE
3rdparty/modules/keystone/README.md
3rdparty/modules/keystone/checksums.json [deleted file]
3rdparty/modules/keystone/examples/apache_dropin.pp
3rdparty/modules/keystone/examples/apache_with_paths.pp
3rdparty/modules/keystone/examples/ldap_full.pp
3rdparty/modules/keystone/examples/ldap_identity.pp
3rdparty/modules/keystone/files/httpd/keystone.py
3rdparty/modules/keystone/lib/puppet/provider/keystone.rb
3rdparty/modules/keystone/lib/puppet/provider/keystone_endpoint/openstack.rb
3rdparty/modules/keystone/lib/puppet/provider/keystone_role/openstack.rb
3rdparty/modules/keystone/lib/puppet/provider/keystone_service/openstack.rb
3rdparty/modules/keystone/lib/puppet/provider/keystone_tenant/openstack.rb
3rdparty/modules/keystone/lib/puppet/provider/keystone_user/openstack.rb
3rdparty/modules/keystone/lib/puppet/provider/keystone_user_role/openstack.rb
3rdparty/modules/keystone/lib/puppet/provider/openstack.rb [deleted file]
3rdparty/modules/keystone/lib/puppet/type/keystone_endpoint.rb
3rdparty/modules/keystone/lib/puppet/type/keystone_role.rb
3rdparty/modules/keystone/lib/puppet/type/keystone_service.rb
3rdparty/modules/keystone/lib/puppet/type/keystone_tenant.rb
3rdparty/modules/keystone/lib/puppet/type/keystone_user.rb
3rdparty/modules/keystone/lib/puppet/type/keystone_user_role.rb
3rdparty/modules/keystone/lib/puppet/util/openstack.rb [deleted file]
3rdparty/modules/keystone/manifests/client.pp
3rdparty/modules/keystone/manifests/db/mysql.pp
3rdparty/modules/keystone/manifests/db/postgresql.pp
3rdparty/modules/keystone/manifests/dev/install.pp
3rdparty/modules/keystone/manifests/endpoint.pp
3rdparty/modules/keystone/manifests/init.pp
3rdparty/modules/keystone/manifests/ldap.pp
3rdparty/modules/keystone/manifests/params.pp
3rdparty/modules/keystone/manifests/python.pp
3rdparty/modules/keystone/manifests/resource/service_identity.pp
3rdparty/modules/keystone/manifests/roles/admin.pp
3rdparty/modules/keystone/manifests/service.pp
3rdparty/modules/keystone/manifests/wsgi/apache.pp
3rdparty/modules/keystone/metadata.json
3rdparty/modules/keystone/spec/acceptance/basic_keystone_spec.rb [new file with mode: 0644]
3rdparty/modules/keystone/spec/acceptance/nodesets/default.yml [new file with mode: 0644]
3rdparty/modules/keystone/spec/acceptance/nodesets/nodepool-centos7.yml [new file with mode: 0644]
3rdparty/modules/keystone/spec/acceptance/nodesets/nodepool-trusty.yml [new file with mode: 0644]
3rdparty/modules/keystone/spec/classes/keystone_client_spec.rb
3rdparty/modules/keystone/spec/classes/keystone_cron_token_flush_spec.rb
3rdparty/modules/keystone/spec/classes/keystone_db_mysql_spec.rb
3rdparty/modules/keystone/spec/classes/keystone_db_postgresql_spec.rb
3rdparty/modules/keystone/spec/classes/keystone_endpoint_spec.rb
3rdparty/modules/keystone/spec/classes/keystone_ldap_spec.rb
3rdparty/modules/keystone/spec/classes/keystone_logging_spec.rb
3rdparty/modules/keystone/spec/classes/keystone_policy_spec.rb
3rdparty/modules/keystone/spec/classes/keystone_python_spec.rb
3rdparty/modules/keystone/spec/classes/keystone_roles_admin_spec.rb
3rdparty/modules/keystone/spec/classes/keystone_service_spec.rb
3rdparty/modules/keystone/spec/classes/keystone_spec.rb
3rdparty/modules/keystone/spec/classes/keystone_wsgi_apache_spec.rb
3rdparty/modules/keystone/spec/defines/keystone_resource_service_identity_spec.rb
3rdparty/modules/keystone/spec/shared_examples.rb
3rdparty/modules/keystone/spec/spec_helper.rb
3rdparty/modules/keystone/spec/spec_helper_acceptance.rb [new file with mode: 0644]
3rdparty/modules/keystone/spec/unit/provider/keystone_endpoint/openstack_spec.rb
3rdparty/modules/keystone/spec/unit/provider/keystone_role/openstack_spec.rb
3rdparty/modules/keystone/spec/unit/provider/keystone_service/openstack_spec.rb
3rdparty/modules/keystone/spec/unit/provider/keystone_spec.rb
3rdparty/modules/keystone/spec/unit/provider/keystone_tenant/openstack_spec.rb
3rdparty/modules/keystone/spec/unit/provider/keystone_user/openstack_spec.rb
3rdparty/modules/keystone/spec/unit/provider/keystone_user_role/openstack_spec.rb
3rdparty/modules/keystone/spec/unit/provider/openstack_spec.rb [deleted file]
3rdparty/modules/keystone/tests/site.pp
3rdparty/modules/openstacklib/CHANGELOG.md [new file with mode: 0644]
3rdparty/modules/openstacklib/Gemfile
3rdparty/modules/openstacklib/LICENSE
3rdparty/modules/openstacklib/README.md
3rdparty/modules/openstacklib/checksums.json [deleted file]
3rdparty/modules/openstacklib/lib/puppet/provider/aviator.rb [deleted file]
3rdparty/modules/openstacklib/lib/puppet/provider/openstack.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/lib/puppet/provider/openstack/auth.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/lib/puppet/provider/openstack/credentials.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/lib/puppet/util/aviator.rb [deleted file]
3rdparty/modules/openstacklib/manifests/db/postgresql.pp [new file with mode: 0644]
3rdparty/modules/openstacklib/manifests/openstackclient.pp [new file with mode: 0644]
3rdparty/modules/openstacklib/manifests/policy/base.pp
3rdparty/modules/openstacklib/manifests/wsgi/apache.pp [new file with mode: 0644]
3rdparty/modules/openstacklib/metadata.json
3rdparty/modules/openstacklib/spec/acceptance/mysql_spec.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/acceptance/nodesets/default.yml [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/acceptance/nodesets/nodepool-centos7.yml [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/acceptance/nodesets/nodepool-trusty.yml [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/acceptance/rabbitmq_spec.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/classes/openstacklib_policy_spec.rb
3rdparty/modules/openstacklib/spec/defines/openstacklib_db_mysql_host_access_spec.rb
3rdparty/modules/openstacklib/spec/defines/openstacklib_db_mysql_spec.rb
3rdparty/modules/openstacklib/spec/defines/openstacklib_db_postgresql_spec.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/defines/openstacklib_messaging_rabbitmq_spec.rb
3rdparty/modules/openstacklib/spec/defines/openstacklib_policy_spec.rb
3rdparty/modules/openstacklib/spec/defines/openstacklib_service_validation_spec.rb
3rdparty/modules/openstacklib/spec/defines/openstacklib_wsgi_apache_spec.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/request/with_session.yml [deleted file]
3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/request/without_session.yml [deleted file]
3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/session/with_password.yml [deleted file]
3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/session/with_token.yml [deleted file]
3rdparty/modules/openstacklib/spec/functions/os_database_connection_spec.rb
3rdparty/modules/openstacklib/spec/shared_examples.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/spec_helper.rb
3rdparty/modules/openstacklib/spec/spec_helper_acceptance.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/unit/provider/aviator_spec.rb [deleted file]
3rdparty/modules/openstacklib/spec/unit/provider/openstack/auth_spec.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/unit/provider/openstack/credentials_spec.rb [new file with mode: 0644]
3rdparty/modules/openstacklib/spec/unit/provider/openstack_spec.rb [new file with mode: 0644]

diff --git a/3rdparty/modules/keystone/CHANGELOG.md b/3rdparty/modules/keystone/CHANGELOG.md
new file mode 100644 (file)
index 0000000..973da8f
--- /dev/null
@@ -0,0 +1,209 @@
+##2015-06-17 - 5.1.0
+###Summary
+
+This is a features and bugfixes release in the Juno series.
+
+####Features
+- Allow disabling or delaying the token_flush cron
+- Use openstackclient for keystone_* providers
+- Switch to TLSv1
+- Handle missing project/tenant when using ldap backend
+- Add support for LDAP connection pools
+- Support the ldap user_enabled_invert parameter
+- Tag packages with 'openstack'
+- Add ::keystone::policy class for policy management
+- New option replace_password for keystone_user
+- Set WSGI process display-name
+- Add native types for keystone paste configuration
+
+####Bugfixes
+- crontab: ensure the script is run with shell
+- service_identity: add user/role ordering
+- Fix password check for SSL endpoints
+- Add require json for to_json dependency
+- Sync keystone.py with upstream to function with Juno
+- Allow Keystone to be queried when using IPv6 ::0
+
+####Maintenance
+* spec: pin rspec-puppet to 1.0.1
+* Pin puppetlabs-concat to 1.2.1 in fixtures
+* Update .gitreview file for project rename
+
+##2014-11-24 - 5.0.0
+###Summary
+
+This is a backwards-incompatible major release for OpenStack Juno.
+
+####Backwards-incompatible changes
+- Update token driver, logging, and ldap config parameters for Juno
+- Make UUID the default token provider
+- Migrate the keystone::db::mysql class to use openstacklib::db::mysql, adding
+  dependency on openstacklib
+
+####Features
+- Change admin_roles parameter to accept an array in order to configure
+  multiple admin roles
+- Add new parameters to keystone class to configure pki signing
+- Add parameters to control whether to configure users
+- Deprecate the mysql_module parameter
+- Enable setting cert and key paths for PKI token signing
+- Add parameters for SSL communication between keystone and rabbitmq
+- Add parameter ignore_default_tenant to keystone::role::admin
+- Add parameter service_provider to keystone class
+- Add parameters for service validation to keystone class
+
+####Bugfixes
+- Install python-ldappool package for ldap
+- Change keystone class to inherit from keystone::params
+- Change pki_setup to run regardless of token provider
+- Stop managing _member_ role since it is created automatically
+- Stop overriding token_flush log file
+- Change the usage of admin_endpoint to not include the API version
+- Allow keystone_user_role to accept email as username
+- Add ability to set up keystone using Apache mod_wsgi
+- Make keystone_user_role idempotent
+- Install python-memcache when using token driver memcache
+
+##2014-10-16 - 4.2.0
+###Summary
+
+This is a feature and bugfix release in the Icehouse series.
+
+####Features
+- Add class for extended logging options
+- Add parameters to set tenant descriptions
+
+####Bugfixes
+- Fix rabbit password leaking
+- Fix keystone user authorization error handling
+
+##2014-06-19 - 4.1.0
+###Summary
+
+This is a feature and bugfix release in the Icehouse series.
+
+####Features
+- Add token flushing with cron
+
+####Bugfixes
+- Update database api for consistency with other projects
+- Fix admin_token with secret parameter
+- Fix deprecated catalog driver
+
+##2014-05-05 - 4.0.0
+###Summary
+
+This is a major release for OpenStack Icehouse but contains no API-breaking
+changes.
+
+####Features
+* Add template_file parameter to specify catalog
+* Add keystone::config to handle additional custom options
+* Add notification parameters
+* Add support for puppetlabs-mysql 2.2 and greater
+
+####Bugfixes
+- Fix deprecated sql section header in keystone.conf
+- Fix deprecated bind_host parameter
+- Fix example for native type keystone_service
+- Fix LDAP module bugs
+- Fix variable for host_access dependency
+- Reduce default token duration to one hour
+
+##2014-04-15 - 3.2.0
+###Summary
+
+This is a feature and bugfix release in the Havana series.
+
+####Features
+- Add ability to configure any catalog driver
+
+####Bugfixes
+- Ensure log_file is absent when using syslog
+
+##2014-03-28 - 3.1.1
+###Summary
+
+This is a bugfix release in the Havana series.
+
+####Bugfixes
+- Fix inconsistent variable for mysql allowed hosts
+
+##2014-03-26 - 3.1.0
+###Summary
+
+This is a feature and bugfix release in the Havana series.
+
+####Features
+- Add ability to disable pki_setup
+- Add log_dir param, with option to disable
+- Add support to enable SSL
+
+####Bugfixes
+- Load tenant un-lazily if needed
+- Update endpoint argument
+- Remove setting of Keystone endpoint by default
+- Relax regex when keystone refuses connections
+
+##2014-01-16 - 3.0.0
+###Summary
+
+This is a backwards-incompatible major release for OpenStack Havana.
+
+####Backwards-incompatible changes
+- Move db_sync to its own class
+- Remove creation of Member role
+- Switch from signing/format to token/provider
+
+####Features
+- Create memcache_servers option to allow for multiple cache servers
+- Enable serving Keystone from Apache mod_wsgi
+- Improve performance of Keystone providers
+- Update endpoints to support paths and ssl
+- Add support for token expiration parameter
+
+####Bugfixes
+- Fix duplicated keystone endpoints
+- Refactor keystone_endpoint to use prefetch and flush paradigm
+
+##2013-10-07 - 2.2.0
+###Summary
+
+This is a feature and bugfix release in the Grizzly series.
+
+####Features
+- Optimized tenant and user queries
+- Added syslog support
+- Added support for token driver backend
+
+####Bugfixes
+- Various bug and lint fixes
+
+##2013-08-06 - 2.1.0
+###Summary
+
+This is a bugfix release in the Grizzly series.
+
+####Bugfixes
+- Fix allowed_hosts contitional statement
+- Select keystone endpoint based on SSL setting
+- Improve tenant_hash usage in keystone_tenant
+- Various cleanup and bug fixes
+
+####Maintenance
+- Pin dependencies
+
+##2013-06-18 - 2.0.0
+###Summary
+
+Initial release on StackForge.
+
+####Backwards-incompatible changes
+
+####Features
+- keystone_user can be used to change passwords
+- service tenant name now configurable
+- keystone_user is now idempotent
+
+####Bugfixes
+- Various cleanups and bug fixes
index e757d38..23c74a8 100644 (file)
@@ -2,10 +2,24 @@ source 'https://rubygems.org'
 
 group :development, :test do
   gem 'puppetlabs_spec_helper', :require => false
-  gem 'puppet-lint', '~> 0.3.2'
+  gem 'rspec-puppet', '~> 2.1.0', :require => false
+
   gem 'metadata-json-lint'
-  gem 'rspec-puppet', '~> 1.0.1'
-  gem 'rake', '10.1.1'
+  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
+  gem 'beaker-puppet_install_helper', :require => false
 end
 
 if puppetversion = ENV['PUPPET_GEM_VERSION']
index 0bc44c1..88a11a0 100644 (file)
@@ -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.
index 2f5b155..df60237 100644 (file)
@@ -12,12 +12,11 @@ keystone
 5. [Limitations - OS compatibility, etc.](#limitations)
 6. [Development - Guide for contributing to the module](#development)
 7. [Contributors - Those with commits](#contributors)
-8. [Release Notes - Notes on the most recent updates to the module](#release-notes)
 
 Overview
 --------
 
-The keystone module is a part of [Stackforge](https://github.com/stackfoge), an effort by the Openstack infrastructure team to provide continuous integration testing and code review for Openstack and Openstack community projects not part of the core software.  The module its self is used to flexibly configure and manage the identify service for Openstack.
+The keystone module is a part of [OpenStack](https://github.com/openstack), an effort by the Openstack infrastructure team to provide continuous integration testing and code review for Openstack and Openstack community projects as part of the core software.  The module its self is used to flexibly configure and manage the identify service for Openstack.
 
 Module Description
 ------------------
@@ -45,10 +44,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 +58,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,6 +147,18 @@ 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.
 
+Beaker-Rspec
+------------
+
+This module has beaker-rspec tests
+
+To run:
+
+``shell
+bundle install
+bundle exec rspec spec/acceptance
+``
+
 Development
 -----------
 
@@ -158,150 +169,4 @@ Developer documentation for the entire puppet-openstack project.
 Contributors
 ------------
 
-* https://github.com/stackforge/puppet-keystone/graphs/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.
-* Added template_file parameter to specify catalog.
-* Added keystone::config to handle additional custom options.
-* Added notification parameters.
-* Added support for puppetlabs-mysql 2.2 and greater.
-* Fixed deprecated sql section header in keystone.conf.
-* Fixed deprecated bind_host parameter.
-* Fixed example for native type keystone_service.
-* Fixed LDAP module bugs.
-* Fixed variable for host_access dependency.
-* Reduced default token duration to one hour.
-
-**3.2.0**
-
-* Added ability to configure any catalog driver.
-* Ensures log_file is absent when using syslog.
-
-**3.1.1**
-
-* Fixed inconsistent variable for mysql allowed hosts.
-
-**3.1.0**
-
-* Added ability to disable pki_setup.
-* Load tenant un-lazily if needed.
-* Add log_dir param, with option to disable.
-* Updated endpoint argument.
-* Added support to enable SSL.
-* Removes setting of Keystone endpoint by default.
-* Relaxed regex when keystone refuses connections.
-
-**3.0.0**
-
-* Major release for OpenStack Havana.
-* Fixed duplicated keystone endpoints.
-* Refactored keystone_endpoint to use prefetch and flush paradigm.
-* Switched from signing/format to token/provider.
-* Created memcache_servers option to allow for multiple cache servers.
-* Enabled serving Keystone from Apache mod_wsgi.
-* Moved db_sync to its own class.
-* Removed creation of Member role.
-* Improved performance of Keystone providers.
-* Updated endpoints to support paths and ssl.
-* Added support for token expiration parameter.
-
-**2.2.0**
-
-* Optimized tenant and user queries.
-* Added syslog support.
-* Added support for token driver backend.
-* Various bug and lint fixes.
-
-**2.1.0**
-
-* Tracks release of puppet-quantum
-* Fixed allowed_hosts contitional statement
-* Pinned depedencies
-* Select keystone endpoint based on SSL setting
-* Improved tenant_hash usage in keystone_tenant
-* Various cleanup and bug fixes.
-
-**2.0.0**
-
-* Upstream is now part of stackfoge.
-* keystone_user can be used to change passwords.
-* service tenant name now configurable.
-* keystone_user is now idempotent.
-* Various cleanups and bug fixes.
+* https://github.com/openstack/puppet-keystone/graphs/contributors
diff --git a/3rdparty/modules/keystone/checksums.json b/3rdparty/modules/keystone/checksums.json
deleted file mode 100644 (file)
index 7f46630..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-{
-  "Gemfile": "bda594bd6e3cc9ee1db4c29e55220505",
-  "LICENSE": "88c9def20bf88cdd1cf474cfb53f16ab",
-  "README.md": "d150d6dc30f3dd54b319317b681e1e14",
-  "Rakefile": "68e2a46cd546eeb34bab6dc1512b549d",
-  "examples/apache_dropin.pp": "c40c6fe26b4211c85fe2c55926d10bb2",
-  "examples/apache_with_paths.pp": "3113e40e01bb70b391b52b7e17509678",
-  "examples/ldap_full.pp": "284fd9fd95fc7091b924177a4e3f5c76",
-  "examples/ldap_identity.pp": "63f00b0a413163542e348d96a87c9f68",
-  "ext/keystone_test.rb": "d403c8c80616f94d0cac9ff12c327b9a",
-  "files/httpd/keystone.py": "a359685b85254d738c13b167c7e84e6b",
-  "lib/puppet/provider/keystone.rb": "c754d86f1ef111030c17b3690c063a6c",
-  "lib/puppet/provider/keystone_config/ini_setting.rb": "b3c3813be1c155f49fedf0a1178fe905",
-  "lib/puppet/provider/keystone_endpoint/openstack.rb": "1864e99269b8f707cb16dbf501bc5587",
-  "lib/puppet/provider/keystone_paste_ini/ini_setting.rb": "df7e671676104f090a07942f774844e3",
-  "lib/puppet/provider/keystone_role/openstack.rb": "54d3dda0ac3427bd1180df9190a5166f",
-  "lib/puppet/provider/keystone_service/openstack.rb": "279e16db49cf59734ef98ce6cbf581f8",
-  "lib/puppet/provider/keystone_tenant/openstack.rb": "9f443449581c23e54cd5bf0b1d62172a",
-  "lib/puppet/provider/keystone_user/openstack.rb": "032358692dae948d29d9464c97793f78",
-  "lib/puppet/provider/keystone_user_role/openstack.rb": "a9a3ba9b455c7cb6d630d7b6235ebd14",
-  "lib/puppet/provider/openstack.rb": "86e27a181394e3e8630c5a3934ba320b",
-  "lib/puppet/type/keystone_config.rb": "01069a89da581af00fed130fc373c2c3",
-  "lib/puppet/type/keystone_endpoint.rb": "78ee04053d0e8362b3d57eecd4dbb020",
-  "lib/puppet/type/keystone_paste_ini.rb": "5429630bad1a33ab3f14b45f403ed2af",
-  "lib/puppet/type/keystone_role.rb": "31a7dc4bdf4179b19f01021d03327e93",
-  "lib/puppet/type/keystone_service.rb": "f1ceb0d168964a4211fed962cf0ff156",
-  "lib/puppet/type/keystone_tenant.rb": "a7c8b678ceec538cdc22d6dfc9861e13",
-  "lib/puppet/type/keystone_user.rb": "f0ba9956b6631a7ae07b763fa2c9479c",
-  "lib/puppet/type/keystone_user_role.rb": "01e72389db896e4cf4a3ed8b15fb771c",
-  "lib/puppet/util/openstack.rb": "34cea508fb3cbd0cf2ac426004842c21",
-  "manifests/client.pp": "519836300977db1d5476112864d4782c",
-  "manifests/config.pp": "5e27a3b503cd4931e410a2d41d89fda1",
-  "manifests/cron/token_flush.pp": "4f2ce0209fbb9696eda2758ef84c18d2",
-  "manifests/db/mysql.pp": "c3cb8dc2e1e61392f00f0dc54ee0bc1b",
-  "manifests/db/postgresql.pp": "18cea325841979f63426633794157254",
-  "manifests/db/sync.pp": "3caf7ccd37b6f62714bf3b77d0dbf0f9",
-  "manifests/dev/install.pp": "49ce7909a859d2424cf1fbe5404eab0c",
-  "manifests/endpoint.pp": "da60281981160a38c5e3ca8bc744dca7",
-  "manifests/init.pp": "f9e76044c913474134eb7f58c60a7e7d",
-  "manifests/ldap.pp": "c49c737867f03d49f3fdff6ac46e9c51",
-  "manifests/logging.pp": "5774990dea77d17dfceaad4a8777824c",
-  "manifests/params.pp": "b2cbc2011a21fa630022a36d2975f946",
-  "manifests/policy.pp": "c8a8998316ea42f611a1c7ae6a563461",
-  "manifests/python.pp": "036cd9a1f400a6a150a1967dcb6f1427",
-  "manifests/resource/service_identity.pp": "cd6a8d9c451c6310c840149d50decf79",
-  "manifests/roles/admin.pp": "45b2a2826ff205a28ba30f7c63b0cf45",
-  "manifests/service.pp": "bae5e366e100ea38d9fd5c1885b0cf3b",
-  "manifests/wsgi/apache.pp": "b4215a0b8a59d4c39919b6f893820c97",
-  "metadata.json": "0995a4802848cf7cb6a90293f45aa3a5",
-  "spec/classes/keystone_client_spec.rb": "85457ed6327e795237afca58be906da6",
-  "spec/classes/keystone_cron_token_flush_spec.rb": "4648a3bba9210d5b7d51b9a6c8fff586",
-  "spec/classes/keystone_db_mysql_spec.rb": "6cb71468e5610210be2955305938dcfe",
-  "spec/classes/keystone_db_postgresql_spec.rb": "88f188cea91bd3bc7c46ecc7033e62df",
-  "spec/classes/keystone_endpoint_spec.rb": "581f77946576aaebce9df3b4dad6800e",
-  "spec/classes/keystone_ldap_spec.rb": "c25daffe970799d8619aa690c4c396bb",
-  "spec/classes/keystone_logging_spec.rb": "fe193b49405672cbf75e41b140d3f9b9",
-  "spec/classes/keystone_policy_spec.rb": "24dfcbd1e807015214c31d9e4a313619",
-  "spec/classes/keystone_python_spec.rb": "84f15d4d969b2cb7ab2d770d7ab0278f",
-  "spec/classes/keystone_roles_admin_spec.rb": "6b11c426e9dd91c7b766ef8c707ca129",
-  "spec/classes/keystone_service_spec.rb": "688f35435c12152a021ae39020296186",
-  "spec/classes/keystone_spec.rb": "14dfbd437ce31988a43332752b586c91",
-  "spec/classes/keystone_wsgi_apache_spec.rb": "5af4f3b9ee305f99df34753db9aa8fe1",
-  "spec/defines/keystone_resource_service_identity_spec.rb": "485bd7d1a7d189d88d4b86f5d50df8d0",
-  "spec/shared_examples.rb": "172c63c57efca8c741f297494ed9ef0f",
-  "spec/spec.opts": "a600ded995d948e393fbe2320ba8e51c",
-  "spec/spec_helper.rb": "c6521798536b607695fa32a60c8466aa",
-  "spec/unit/provider/keystone_endpoint/openstack_spec.rb": "8417a7da443c4cfe7c779536c07a2972",
-  "spec/unit/provider/keystone_paste_ini/ini_setting_spec.rb": "8b583280cfc7c67d64a2dfd8caa7a130",
-  "spec/unit/provider/keystone_role/openstack_spec.rb": "3dabd6528075e0f4496b10f4faf769b5",
-  "spec/unit/provider/keystone_service/openstack_spec.rb": "1badc29e61628e320509ce86e076e641",
-  "spec/unit/provider/keystone_spec.rb": "3eaa3720884b2c3096102b1cb37334cb",
-  "spec/unit/provider/keystone_tenant/openstack_spec.rb": "63ac277a61271577ecbcd5c729868cf2",
-  "spec/unit/provider/keystone_user/openstack_spec.rb": "0c68dda06669b26d9d1285196cfed0ec",
-  "spec/unit/provider/keystone_user_role/openstack_spec.rb": "d78aab324756f7183997b2f8300e9309",
-  "spec/unit/provider/openstack_spec.rb": "f06998179568513c4b83d19212d6427b",
-  "spec/unit/type/keystone_endpoint_spec.rb": "5dbd0b540a452bae36218b2a8794a41e",
-  "spec/unit/type/keystone_paste_ini_spec.rb": "9037113f96850d5567e9dc7c540915ae",
-  "spec/unit/type/keystone_user_role_spec.rb": "a03cfa9f55028d6a7f2a351582c1a93d",
-  "tests/site.pp": "0b2eb2ec36b10520aad1517b9a116e50"
-}
\ No newline at end of file
index 310f0a3..5ed2926 100644 (file)
 
 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
 }
index be28d39..8b0fc69 100644 (file)
 
 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::cron::token_flush': }
-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,
index bc45569..09ce7c8 100644 (file)
@@ -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',
 }
@@ -15,58 +15,58 @@ class { 'keystone::roles::admin':
 # 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',
-  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,
+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,
 }
index 41272c5..f3a578c 100644 (file)
@@ -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'
 }
index f5ce498..81c5348 100644 (file)
 #    License for the specific language governing permissions and limitations
 #    under the License.
 
-import logging
-import os
-
-from oslo import i18n
-
-
-# NOTE(dstanek): i18n.enable_lazy() must be called before
-# keystone.i18n._() is called to ensure it has the desired lazy lookup
-# behavior. This includes cases, like keystone.exceptions, where
-# keystone.i18n._() is called at import time.
-i18n.enable_lazy()
-
-
-from keystone import backends
-from keystone.common import dependency
-from keystone.common import environment
-from keystone.common import sql
-from keystone import config
-from keystone.openstack.common import log
-from keystone import service
-
+#
+# This file was copied from https://github.com/openstack/keystone/raw/a4f29db2b8cde1b445b86218fb5543295da2092c/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.
+#
 
-CONF = config.CONF
+import os
 
-config.configure()
-sql.initialize()
-config.set_default_for_default_log_levels()
+from keystone.server import wsgi as wsgi_server
 
-CONF(project='keystone')
-config.setup_logging()
 
-environment.use_stdlib()
 name = os.path.basename(__file__)
 
-if CONF.debug:
-    CONF.log_opt_values(log.getLogger(CONF.prog), logging.DEBUG)
-
-
-drivers = backends.load_backends()
-
 # NOTE(ldbragst): 'application' is required in this context by WSGI spec.
 # The following is a reference to Python Paste Deploy documentation
 # http://pythonpaste.org/deploy/
-application = service.loadapp('config:%s' % config.find_paste_config(), name)
-
-dependency.resolve_future_dependencies()
+application = wsgi_server.initialize_application(name)
index b398a8e..4e7815a 100644 (file)
@@ -1,36 +1,33 @@
 require 'puppet/util/inifile'
 require 'puppet/provider/openstack'
+require 'puppet/provider/openstack/auth'
+require 'puppet/provider/openstack/credentials'
+
 class Puppet::Provider::Keystone < Puppet::Provider::Openstack
 
-  def request(service, action, object, credentials, *properties)
-    begin
-      super
-    rescue Puppet::Error::OpenstackAuthInputError => error
-      keystone_request(service, action, object, credentials, error, *properties)
-    end
-  end
+  extend Puppet::Provider::Openstack::Auth
 
-  def self.request(service, action, object, credentials, *properties)
-    begin
-      super
-    rescue Puppet::Error::OpenstackAuthInputError => error
-      keystone_request(service, action, object, credentials, error, *properties)
-    end
-  end
+  INI_FILENAME = '/etc/keystone/keystone.conf'
 
-  def keystone_request(service, action, object, credentials, error, *properties)
-    self.class.keystone_request(service, action, object, credentials, error, *properties)
+  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.keystone_request(service, action, object, credentials, error, *properties)
-    credentials = {
-      'token'    => get_admin_token,
-      'auth_url' => get_admin_endpoint,
-    }
-    raise error unless (credentials['token'] && credentials['auth_url'])
-    auth_args = token_auth_args(credentials)
-    args = [object, properties, auth_args].flatten.compact
-    authenticate_request(service, action, args)
+  def self.admin_endpoint
+    @admin_endpoint ||= get_admin_endpoint
   end
 
   def self.admin_token
@@ -45,21 +42,12 @@ class Puppet::Provider::Keystone < Puppet::Provider::Openstack
     end
   end
 
-  def self.admin_endpoint
-    @admin_endpoint ||= get_admin_endpoint
-  end
-
-  def get_admin_token
-    self.class.get_admin_token
-  end
-
-
   def self.get_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}/v2.0/"
+          return "#{auth_url}/v#{@credentials.version}/"
         end
 
         if keystone_file['DEFAULT']['admin_port']
@@ -87,22 +75,34 @@ class Puppet::Provider::Keystone < Puppet::Provider::Openstack
       end
     end
 
-    "#{protocol}://#{host}:#{admin_port}/v2.0/"
+    "#{protocol}://#{host}:#{admin_port}/v#{@credentials.version}/"
   end
 
-  def get_admin_endpoint
-    self.class.get_admin_endpoint
+  def self.request(service, action, properties=nil)
+    super
+    rescue Puppet::Error::OpenstackAuthInputError => error
+      request_by_service_token(service, action, error, properties)
   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
+  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 keystone_file
-    self.class.keystone_file
+  def self.ini_filename
+    INI_FILENAME
+  end
+
+  def self.keystone_file
+    return @keystone_file if @keystone_file
+    if File.exists?(ini_filename)
+      @keystone_file = Puppet::Util::IniConfig::File.new
+      @keystone_file.read(ini_filename)
+      @keystone_file
+    end
   end
 
   # Helper functions to use on the pre-validated enabled field
@@ -113,5 +113,4 @@ class Puppet::Provider::Keystone < Puppet::Provider::Openstack
   def sym_to_bool(sym)
     sym == :true ? true : false
   end
-
 end
index ac7780d..97de693 100644 (file)
@@ -7,6 +7,8 @@ Puppet::Type.type(:keystone_endpoint).provide(
 
   desc "Provider to manage keystone endpoints."
 
+  @credentials = Puppet::Provider::Openstack::CredentialsV2_0.new
+
   def initialize(value={})
     super(value)
     @property_flush = {}
@@ -16,6 +18,7 @@ Puppet::Type.type(:keystone_endpoint).provide(
     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]
@@ -30,56 +33,53 @@ Puppet::Type.type(:keystone_endpoint).provide(
       properties << '--adminurl'
       properties << resource[:admin_url]
     end
-    @instance = request('endpoint', 'create', name, resource[:auth], properties)
-  end
-
-  def exists?
-    ! instance(resource[:name]).empty?
+     self.class.request('endpoint', 'create', properties)
+     @property_hash[:ensure] = :present
   end
 
   def destroy
-    id = instance(resource[:name])[:id]
-    request('endpoint', 'delete', id, resource[:auth])
+    self.class.request('endpoint', 'delete', @property_hash[:id])
+    @property_hash.clear
   end
 
+  def exists?
+    @property_hash[:ensure] == :present
+  end
 
   def region
-    instance(resource[:name])[:region]
+    @property_hash[:region]
   end
 
-
   def public_url=(value)
     @property_flush[:public_url] = value
   end
 
   def public_url
-    instance(resource[:name])[:public_url]
+    @property_hash[:public_url]
   end
 
-
   def internal_url=(value)
     @property_flush[:internal_url] = value
   end
 
   def internal_url
-    instance(resource[:name])[:internal_url]
+    @property_hash[:internal_url]
   end
 
-
   def admin_url=(value)
     @property_flush[:admin_url] = value
   end
 
   def admin_url
-    instance(resource[:name])[:admin_url]
+    @property_hash[:admin_url]
   end
 
   def id
-    instance(resource[:name])[:id]
+    @property_hash[:id]
   end
 
   def self.instances
-    list = request('endpoint', 'list', nil, nil, '--long')
+    list = request('endpoint', 'list', '--long')
     list.collect do |endpoint|
       new(
         :name         => "#{endpoint[:region]}/#{endpoint[:service_name]}",
@@ -93,30 +93,20 @@ Puppet::Type.type(:keystone_endpoint).provide(
     end
   end
 
-  def instances
-    instances = request('endpoint', 'list', nil, resource[:auth], '--long')
-    instances.collect do |endpoint|
-      {
-        :name         => "#{endpoint[:region]}/#{endpoint[:service_name]}",
-        :id           => endpoint[:id],
-        :region       => endpoint[:region],
-        :public_url   => endpoint[:publicurl],
-        :internal_url => endpoint[:internalurl],
-        :admin_url    => endpoint[:adminurl]
-      }
+  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 instance(name)
-    @instance ||= instances.select { |instance| instance[:name] == name }.first || {}
-  end
-
   def flush
-    if  ! @property_flush.empty?
+    if ! @property_flush.empty?
       destroy
       create
       @property_flush.clear
     end
   end
-
 end
index b3bd856..b154620 100644 (file)
@@ -7,25 +7,33 @@ Puppet::Type.type(:keystone_role).provide(
 
   desc 'Provider for keystone roles.'
 
-  def create
-    properties = []
-    @instance = request('role', 'create', resource[:name], resource[:auth], properties)
+  @credentials = Puppet::Provider::Openstack::CredentialsV2_0.new
+
+  def initialize(value={})
+    super(value)
+    @property_flush = {}
   end
 
-  def exists?
-    ! instance(resource[:name]).empty?
+  def create
+    self.class.request('role', 'create', name)
+    @property_hash[:ensure] = :present
   end
 
   def destroy
-    request('role', 'delete', resource[:name], resource[:auth])
+    self.class.request('role', 'delete', @property_hash[:id])
+    @property_hash.clear
+  end
+
+  def exists?
+    @property_hash[:ensure] == :present
   end
 
   def id
-    instance(resource[:name])[:id]
+    @property_hash[:id]
   end
 
   def self.instances
-    list = request('role', 'list', nil, nil)
+    list = request('role', 'list')
     list.collect do |role|
       new(
         :name        => role[:name],
@@ -35,18 +43,12 @@ Puppet::Type.type(:keystone_role).provide(
     end
   end
 
-  def instances
-    instances = request('role', 'list', nil, resource[:auth])
-    instances.collect do |role|
-      {
-        :name        => role[:name],
-        :id          => role[:id]
-      }
+  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
-
-  def instance(name)
-    @instance ||= instances.select { |instance| instance[:name] == name }.first || {}
-  end
-
 end
index 54e75f5..40aa8e2 100644 (file)
@@ -7,6 +7,8 @@ Puppet::Type.type(:keystone_service).provide(
 
   desc "Provider to manage keystone services."
 
+  @credentials = Puppet::Provider::Openstack::CredentialsV2_0.new
+
   def initialize(value={})
     super(value)
     @property_flush = {}
@@ -18,46 +20,45 @@ Puppet::Type.type(:keystone_service).provide(
       properties << '--description'
       properties << resource[:description]
     end
-    if resource[:type]
-      properties << '--type'
-      properties << resource[:type]
-    end
-    @instance = request('service', 'create', resource[:name], resource[:auth], properties)
+    raise(Puppet::Error, 'The service type is mandatory') unless resource[:type]
+    properties << '--type'
+    properties << resource[:type]
+    properties << resource[:name]
+    self.class.request('service', 'create', properties)
+    @property_hash[:ensure] = :present
   end
 
   def exists?
-    ! instance(resource[:name]).empty?
+    @property_hash[:ensure] == :present
   end
 
   def destroy
-    request('service', 'delete', resource[:name], resource[:auth])
+    self.class.request('service', 'delete', @property_hash[:id])
+    @property_hash.clear
   end
 
-
   def description=(value)
-    raise(Puppet::Error, "Updating the service is not currently supported.")
+    @property_flush[:description] = value
   end
 
   def description
-    instance(resource[:name])[:description]
+    @property_hash[:description]
   end
 
-
   def type=(value)
-    raise(Puppet::Error, "Updating the service is not currently supported.")
+    @property_flush[:type] = value
   end
 
   def type
-    instance(resource[:name])[:type]
+    @property_hash[:type]
   end
 
-
   def id
-    instance(resource[:name])[:id]
+    @property_hash[:id]
   end
 
   def self.instances
-    list = request('service', 'list', nil, nil, '--long')
+    list = request('service', 'list', '--long')
     list.collect do |service|
       new(
         :name        => service[:name],
@@ -69,30 +70,20 @@ Puppet::Type.type(:keystone_service).provide(
     end
   end
 
-  def instances
-    instances = request('service', 'list', nil, resource[:auth], '--long')
-    instances.collect do |service|
-      {
-        :name        => service[:name],
-        :type        => service[:type],
-        :description => service[:description],
-        :id          => service[:id]
-      }
+  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 instance(name)
-    @instance ||= instances.select { |instance| instance[:name] == name }.first || {}
-  end
-
   def flush
-    options = []
-    if @property_flush
-      # There is a --description flag for the set command, but it does not work if the value is empty
-      (options << '--property' << "type=#{resource[:type]}") if @property_flush[:type]
-      (options << '--property' << "description=#{resource[:description]}") if @property_flush[:description]
-      request('project', 'set', resource[:name], resource[:auth], options) unless options.empty?
+    if ! @property_flush.empty?
+      destroy
+      create
+      @property_flush.clear
     end
   end
-
 end
index 7d19fce..1987984 100644 (file)
@@ -7,13 +7,15 @@ Puppet::Type.type(:keystone_tenant).provide(
 
   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 = []
+    properties = [resource[:name]]
     if resource[:enabled] == :true
       properties << '--enable'
     elsif resource[:enabled] == :false
@@ -23,42 +25,41 @@ Puppet::Type.type(:keystone_tenant).provide(
       properties << '--description'
       properties << resource[:description]
     end
-    @instance = request('project', 'create', resource[:name], resource[:auth], properties)
+     self.class.request('project', 'create', properties)
+     @property_hash[:ensure] = :present
   end
 
   def exists?
-    ! instance(resource[:name]).empty?
+    @property_hash[:ensure] == :present
   end
 
   def destroy
-    request('project', 'delete', resource[:name], resource[:auth])
+    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(instance(resource[:name])[:enabled])
+    bool_to_sym(@property_hash[:enabled])
   end
 
-
   def description=(value)
     @property_flush[:description] = value
   end
 
   def description
-    instance(resource[:name])[:description]
+    @property_hash[:description]
   end
 
-
   def id
-    instance(resource[:name])[:id]
+    @property_hash[:id]
   end
 
   def self.instances
-    list = request('project', 'list', nil, nil, '--long')
+    list = request('project', 'list', '--long')
     list.collect do |project|
       new(
         :name        => project[:name],
@@ -70,30 +71,28 @@ Puppet::Type.type(:keystone_tenant).provide(
     end
   end
 
-  def instances
-    instances = request('project', 'list', nil, resource[:auth], '--long')
-    instances.collect do |project|
-      {
-        :name        => project[:name],
-        :enabled     => project[:enabled].downcase.chomp == 'true' ? true : false,
-        :description => project[:description],
-        :id          => project[:id]
-      }
+  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 instance(name)
-    @instance ||= instances.select { |instance| instance[:name] == name }.first || {}
-  end
-
   def flush
     options = []
-    if @property_flush
-      (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 << '--property' << "description=#{resource[:description]}") if @property_flush[:description]
-      request('project', 'set', resource[:name], resource[:auth], options) unless options.empty?
+    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
 
index 6c8d04a..98a34cd 100644 (file)
@@ -1,6 +1,5 @@
-require 'net/http'
-require 'json'
 require 'puppet/provider/keystone'
+
 Puppet::Type.type(:keystone_user).provide(
   :openstack,
   :parent => Puppet::Provider::Keystone
@@ -8,137 +7,120 @@ Puppet::Type.type(:keystone_user).provide(
 
   desc "Provider to manage keystone users."
 
+  @credentials = Puppet::Provider::Openstack::CredentialsV2_0.new
+
   def initialize(value={})
     super(value)
     @property_flush = {}
   end
 
   def create
-    properties = []
+    properties = [resource[:name]]
     if resource[:enabled] == :true
       properties << '--enable'
     elsif resource[:enabled] == :false
       properties << '--disable'
     end
     if resource[:password]
-      properties << '--password'
-      properties << resource[:password]
+      properties << '--password' << resource[:password]
     end
     if resource[:tenant]
-      properties << '--project'
-      properties << resource[:tenant]
+      properties << '--project' << resource[:tenant]
     end
     if resource[:email]
-      properties << '--email'
-      properties << resource[:email]
+      properties << '--email' << resource[:email]
     end
-    @instance = request('user', 'create', resource[:name], resource[:auth], properties)
+    self.class.request('user', 'create', properties)
+    @property_hash[:ensure] = :present
   end
 
-  def exists?
-    ! instance(resource[:name]).empty?
+  def destroy
+    self.class.request('user', 'delete', @property_hash[:id])
+    @property_hash.clear
   end
 
-  def destroy
-    request('user', 'delete', resource[:name], resource[:auth])
+  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 enabled
-    bool_to_sym(instance(resource[:name])[:enabled])
+  def email
+    @property_hash[:email]
   end
 
+  def email=(value)
+    @property_flush[:email] = value
+  end
 
-  def password=(value)
-    @property_flush[:password] = value
+  def id
+    @property_hash[:id]
   end
 
   def password
-    # if we don't know a password we can't test it
-    return nil if resource[:password] == nil
-    # if the user is disabled then the password can't be changed
-    return resource[:password] if resource[:enabled] == :false
-    # if replacing password is disabled, then don't change it
-    return resource[:password] if resource[:replace_password] == :false
-    # 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
-    endpoint = nil
-    if password_credentials_set?(resource[:auth]) || service_credentials_set?(resource[:auth])
-      endpoint = (resource[:auth])['auth_url']
-    elsif openrc_set?(resource[:auth])
-      endpoint = get_credentials_from_openrc(resource[:auth])['auth_url']
-    elsif env_vars_set?
-      endpoint = ENV['OS_AUTH_URL']
-    else
-      # try to get endpoint from keystone.conf
-      endpoint = get_admin_endpoint
-    end
-    if endpoint == nil
-      raise(Puppet::Error::OpenstackAuthInputError, 'Could not find auth url to check user password.')
+    res = nil
+    return res if resource[:password] == nil
+    if resource[:enabled] == :false || resource[:replace_password] == :false
+      # Unchanged password
+      res = resource[:password]
     else
-      auth_params = {
-        'username'    => resource[:name],
-        'password'    => resource[:password],
-        'tenant_name' => resource[:tenant],
-        'auth_url'    => endpoint,
-      }
-      # LP#1408754
-      # Ideally this would be checked with the `openstack token issue` command,
-      # but that command is not available with version 0.3.0 of openstackclient
-      # which is what ships on Ubuntu during Juno.
-      # Instead we'll check whether the user can authenticate with curl.
-      creds_hash = {
-        :auth => {
-          :passwordCredentials => {
-            :username => auth_params['username'],
-            :password => auth_params['password'],
-          }
-        }
-      }
-      url = URI.parse(endpoint)
-      # There is issue with ipv6 where address has to be in brackets, this causes the
-      # underlying ruby TCPSocket to fail. Net::HTTP.new will fail without brackets on
-      # joining the ipv6 address with :port or passing brackets to TCPSocket. It was
-      # found that if we use Net::HTTP.start with url.hostname the incriminated code
-      # won't be hit.
-      use_ssl = url.scheme == "https" ? true : false
-      http = Net::HTTP.start(url.hostname, url.port, {:use_ssl => use_ssl})
-      request = Net::HTTP::Post.new('/v2.0/tokens')
-      request.body = creds_hash.to_json
-      request.content_type = 'application/json'
-      response = http.request(request)
-      if response.code.to_i == 401 || response.code.to_i == 403 # 401 => unauthorized, 403 => userDisabled
-        return nil
-      elsif ! (response.code == 200 || response.code == 203)
-        return resource[:password]
+      # 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
-        raise(Puppet::Error, "Received bad response while trying to authenticate user: #{response.body}")
+        res = resource[:password] unless token.empty?
       end
     end
+    return res
   end
 
-  def tenant=(value)
-    begin
-      request('user', 'set', resource[:name], resource[:auth], '--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
-    end
-    set_project(value)
+  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 = instance(resource[:name])[:project]
+    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]
@@ -151,7 +133,7 @@ Puppet::Type.type(:keystone_user).provide(
     # 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 = request('user role', 'list', resource[:name], resource[:auth], ['--project', tenant_name])
+    roles = self.class.request('user role', 'list', [resource[:name], '--project', tenant_name])
     if roles.empty?
       return nil
     else
@@ -159,64 +141,48 @@ Puppet::Type.type(:keystone_user).provide(
     end
   end
 
-  def replace_password
-    instance(resource[:name])[:replace_password]
-  end
-
-  def replace_password=(value)
-    @property_flush[:replace_password] = value
-  end
-
-  def email=(value)
-    @property_flush[:email] = value
-  end
-
-  def email
-    instance(resource[:name])[:email]
-  end
-
-  def id
-    instance(resource[:name])[:id]
+  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', nil, nil, '--long')
+    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],
-        :tenant      => user[:project],
+        :project     => user[:project],
         :email       => user[:email],
         :id          => user[:id]
       )
     end
   end
 
-  def instances
-    instances = request('user', 'list', nil, resource[:auth], '--long')
-    instances.collect do |user|
-      {
-        :name        => user[:name],
-        :enabled     => user[:enabled].downcase.chomp == 'true' ? true : false,
-        :password    => user[:password],
-        :project     => user[:project],
-        :email       => user[:email],
-        :id          => user[:id]
-      }
+  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 instance(name)
-    @instance ||= instances.select { |instance| instance[:name] == name }.first || {}
-  end
-
-  def set_project(newproject)
+  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', resource[:name], resource[:auth], ['--project', newproject])
+    roles = request('user role', 'list', [name, '--project', newproject])
     unless roles.empty?
       return # if already set, just skip
     end
@@ -228,26 +194,11 @@ Puppet::Type.type(:keystone_user).provide(
     # ok for a user to have the _member_ role and another role.
     default_role = "_member_"
     begin
-      request('role', 'show', default_role, resource[:auth])
+      request('role', 'show', [default_role])
     rescue
       debug("Keystone role #{default_role} does not exist - creating")
-      request('role', 'create', default_role, resource[:auth])
-    end
-    request('role', 'add', default_role, resource[:auth],
-            '--project', newproject, '--user', resource[:name])
-  end
-
-  def flush
-    options = []
-    if @property_flush
-      (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
-      request('user', 'set', resource[:name], resource[:auth], options) unless options.empty?
+      request('role', 'create', [default_role])
     end
+    request('role', 'add', [default_role, '--project', newproject, '--user', name])
   end
-
 end
index 5b9a1b5..da2b870 100644 (file)
@@ -7,26 +7,41 @@ Puppet::Type.type(:keystone_user_role).provide(
 
   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|
-        request('role', 'add', role, resource[:auth], properties)
+        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 we just ran self.instances, no need to make the request again
-    # instance() will find it cached in @user_role_hash
-    if self.class.user_role_hash
-      return ! instance(resource[:name]).empty?
-    # If we don't have the hash ready, we don't need to rebuild the
-    # whole thing just to check on one particular user/role
+    if @user_role_hash
+      return ! @property_hash[:name].empty?
     else
-      roles = request('user role', 'list', nil, resource[:auth], ['--project', get_project, get_user])
+      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
@@ -44,19 +59,6 @@ Puppet::Type.type(:keystone_user_role).provide(
     end
   end
 
-  def destroy
-    properties = []
-    properties << '--project' << get_project
-    properties << '--user' << get_user
-    if @property_hash[:roles]
-      @property_hash[:roles].each do |role|
-        request('role', 'remove', role, resource[:auth], properties)
-      end
-    end
-    @property_hash[:ensure] = :absent
-  end
-
-
   def roles
     @property_hash[:roles]
   end
@@ -69,14 +71,13 @@ Puppet::Type.type(:keystone_user_role).provide(
     user = get_user
     project = get_project
     add.each do |role_name|
-      request('role', 'add', role_name, resource[:auth], ['--project', project, '--user', user])
+      self.class.request('role', 'add', [role_name, '--project', project, '--user', user])
     end
     remove.each do |role_name|
-      request('role', 'remove', role_name, resource[:auth], ['--project', project, '--user', user])
+      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|
@@ -88,10 +89,6 @@ Puppet::Type.type(:keystone_user_role).provide(
     end
   end
 
-  def instance(name)
-    self.class.user_role_hash.select { |role_name, roles| role_name == name } || {}
-  end
-
   private
 
   def get_user
@@ -102,50 +99,26 @@ Puppet::Type.type(:keystone_user_role).provide(
     resource[:name].rpartition('@').last
   end
 
-  # We split get_projects into class and instance methods
-  # so that the appropriate request method gets called
-  def get_projects
-    request('project', 'list', nil, resource[:auth]).collect do |project|
-      project[:name]
-    end
-  end
-
   def self.get_projects
-    request('project', 'list', nil, nil).collect do |project|
-      project[:name]
-    end
-  end
-
-  def get_users(project)
-    request('user', 'list', nil, resource[:auth], ['--project', project]).collect do |user|
-      user[:name]
-    end
+    request('project', 'list').collect { |project| project[:name] }
   end
 
   def self.get_users(project)
-    request('user', 'list', nil, nil, ['--project', project]).collect do |user|
-      user[:name]
-    end
+    request('user', 'list', ['--project', project]).collect { |user| user[:name] }
   end
 
-  # Class methods for caching user_role_hash so both class and instance
-  # methods can access the value
   def self.set_user_role_hash(user_role_hash)
     @user_role_hash = user_role_hash
   end
 
-  def self.user_role_hash
-    @user_role_hash
-  end
-
   def self.build_user_role_hash
-    hash = 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', nil, nil, ['--project', project, user])
+        user_roles = request('user role', 'list', [user, '--project', project])
         hash["#{user}@#{project}"] = []
         user_roles.each do |role|
           hash["#{user}@#{project}"] << role[:name]
@@ -155,5 +128,4 @@ Puppet::Type.type(:keystone_user_role).provide(
     set_user_role_hash(hash)
     hash
   end
-
 end
diff --git a/3rdparty/modules/keystone/lib/puppet/provider/openstack.rb b/3rdparty/modules/keystone/lib/puppet/provider/openstack.rb
deleted file mode 100644 (file)
index 8236df7..0000000
+++ /dev/null
@@ -1,188 +0,0 @@
-# TODO: This needs to be extracted out into openstacklib in the Kilo cycle
-require 'csv'
-require 'puppet'
-
-class Puppet::Error::OpenstackAuthInputError < Puppet::Error
-end
-
-class Puppet::Error::OpenstackUnauthorizedError < Puppet::Error
-end
-
-class Puppet::Provider::Openstack < Puppet::Provider
-
-  initvars # so commands will work
-  commands :openstack => 'openstack'
-
-  def request(service, action, object, credentials, *properties)
-    if password_credentials_set?(credentials)
-      auth_args = password_auth_args(credentials)
-    elsif openrc_set?(credentials)
-      credentials = get_credentials_from_openrc(credentials['openrc'])
-      auth_args = password_auth_args(credentials)
-    elsif service_credentials_set?(credentials)
-      auth_args = token_auth_args(credentials)
-    elsif env_vars_set?
-      # noop; auth needs no extra arguments
-      auth_args = nil
-    else  # All authentication efforts failed
-      raise(Puppet::Error::OpenstackAuthInputError, 'No credentials provided.')
-    end
-    args = [object, properties, auth_args].flatten.compact
-    authenticate_request(service, action, args)
-  end
-
-  def self.request(service, action, object, *properties)
-    if env_vars_set?
-      # noop; auth needs no extra arguments
-      auth_args = nil
-    else  # All authentication efforts failed
-      raise(Puppet::Error::OpenstackAuthInputError, 'No credentials provided.')
-    end
-    args = [object, properties, auth_args].flatten.compact
-    authenticate_request(service, action, args)
-  end
-
-  # Returns an array of hashes, where the keys are the downcased CSV headers
-  # with underscores instead of spaces
-  def self.authenticate_request(service, action, *args)
-    rv = nil
-    timeout = 10
-    end_time = Time.now.to_i + timeout
-    loop do
-      begin
-        if(action == 'list')
-          response = openstack(service, action, '--quiet', '--format', 'csv', args)
-          response = parse_csv(response)
-          keys = response.delete_at(0) # ID,Name,Description,Enabled
-          rv = response.collect do |line|
-            hash = {}
-            keys.each_index do |index|
-              key = keys[index].downcase.gsub(/ /, '_').to_sym
-              hash[key] = line[index]
-            end
-            hash
-          end
-        elsif(action == 'show' || action == 'create')
-          rv = {}
-          # shell output is name="value"\nid="value2"\ndescription="value3" etc.
-          openstack(service, action, '--format', 'shell', args).split("\n").each do |line|
-            # key is everything before the first "="
-            key, val = line.split("=", 2)
-            next unless val # Ignore warnings
-            # value is everything after the first "=", with leading and trailing double quotes stripped
-            val = val.gsub(/\A"|"\Z/, '')
-            rv[key.downcase.to_sym] = val
-          end
-        else
-          rv = openstack(service, action, args)
-        end
-        break
-      rescue Puppet::ExecutionFailure => e
-        if e.message =~ /HTTP 401/
-          raise(Puppet::Error::OpenstackUnauthorizedError, 'Could not authenticate.')
-        elsif e.message =~ /Unable to establish connection/
-          current_time = Time.now.to_i
-          if current_time > end_time
-            break
-          else
-            wait = end_time - current_time
-            Puppet::debug("Non-fatal error: \"#{e.message}\"; retrying for #{wait} more seconds.")
-            if wait > timeout - 2 # Only notice the first time
-              notice("#{service} service is unavailable. Will retry for up to #{wait} seconds.")
-            end
-          end
-          sleep(2)
-        else
-          raise e
-        end
-      end
-    end
-    return rv
-  end
-
-  def authenticate_request(service, action, *args)
-    self.class.authenticate_request(service, action, *args)
-  end
-
-  private
-
-  def password_credentials_set?(auth_params)
-    auth_params && auth_params['username'] && auth_params['password'] && auth_params['tenant_name'] && auth_params['auth_url']
-  end
-
-
-  def openrc_set?(auth_params)
-    auth_params && auth_params['openrc']
-  end
-
-
-  def service_credentials_set?(auth_params)
-    auth_params && auth_params['token'] && auth_params['auth_url']
-  end
-
-
-  def self.env_vars_set?
-    ENV['OS_USERNAME'] && ENV['OS_PASSWORD'] && ENV['OS_TENANT_NAME'] && ENV['OS_AUTH_URL']
-  end
-
-
-  def env_vars_set?
-    self.class.env_vars_set?
-  end
-
-
-
-  def self.password_auth_args(credentials)
-    ['--os-username',    credentials['username'],
-     '--os-password',    credentials['password'],
-     '--os-tenant-name', credentials['tenant_name'],
-     '--os-auth-url',    credentials['auth_url']]
-  end
-
-  def password_auth_args(credentials)
-    self.class.password_auth_args(credentials)
-  end
-
-
-  def self.token_auth_args(credentials)
-    ['--os-token',    credentials['token'],
-     '--os-url', credentials['auth_url']]
-  end
-
-  def token_auth_args(credentials)
-    self.class.token_auth_args(credentials)
-  end
-
-  def get_credentials_from_openrc(file)
-    creds = {}
-    File.open(file).readlines.delete_if{|l| l=~ /^#/}.each do |line|
-      key, value = line.split('=')
-      key = key.split(' ').last.downcase.sub(/^os_/, '')
-      value = value.chomp.gsub(/'/, '')
-      creds[key] = value
-    end
-    return creds
-  end
-
-
-  def self.get_credentials_from_env
-    env = ENV.to_hash.dup.delete_if { |key, _| ! (key =~ /^OS_/) }
-    credentials = {}
-    env.each do |name, value|
-      credentials[name.downcase.sub(/^os_/, '')] = value
-    end
-    credentials
-  end
-
-  def get_credentials_from_env
-    self.class.get_credentials_from_env
-  end
-
-  def self.parse_csv(text)
-    # Ignore warnings - assume legitimate output starts with a double quoted
-    # string.  Errors will be caught and raised prior to this
-    text = text.split("\n").drop_while { |line| line !~ /^\".*\"/ }.join("\n")
-    return CSV.parse(text + "\n")
-  end
-
-end
index 4b0e6df..43c5eb2 100644 (file)
@@ -1,6 +1,7 @@
 # LP#1408531
 File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
-require 'puppet/util/openstack'
+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 'Type for managing keystone endpoints.'
@@ -38,10 +39,4 @@ Puppet::Type.newtype(:keystone_endpoint) do
     (region, service_name) = self[:name].split('/')
     [service_name]
   end
-
-  auth_param_doc=<<EOT
-If no other credentials are present, the provider will search in
-/etc/keystone/keystone.conf for an admin token and auth url.
-EOT
-  Puppet::Util::Openstack.add_openstack_type_methods(self, auth_param_doc)
 end
index c6e7d1d..3636afb 100644 (file)
@@ -1,6 +1,7 @@
 # LP#1408531
 File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
-require 'puppet/util/openstack'
+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
@@ -24,10 +25,4 @@ Puppet::Type.newtype(:keystone_role) do
   autorequire(:service) do
     ['keystone']
   end
-
-  auth_param_doc=<<EOT
-If no other credentials are present, the provider will search in
-/etc/keystone/keystone.conf for an admin token and auth url.
-EOT
-  Puppet::Util::Openstack.add_openstack_type_methods(self, auth_param_doc)
 end
index 9b2c1d9..a4be4ed 100644 (file)
@@ -1,6 +1,7 @@
 # LP#1408531
 File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
-require 'puppet/util/openstack'
+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 'This type can be used to manage keystone services.'
@@ -37,10 +38,4 @@ Puppet::Type.newtype(:keystone_service) do
   autorequire(:service) do
     ['keystone']
   end
-
-  auth_param_doc=<<EOT
-If no other credentials are present, the provider will search in
-/etc/keystone/keystone.conf for an admin token and auth url.
-EOT
-  Puppet::Util::Openstack.add_openstack_type_methods(self, auth_param_doc)
 end
index 3e1de7f..6195d23 100644 (file)
@@ -1,6 +1,7 @@
 # LP#1408531
 File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
-require 'puppet/util/openstack'
+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 'This type can be used to manage keystone tenants.'
@@ -40,10 +41,4 @@ Puppet::Type.newtype(:keystone_tenant) do
   autorequire(:service) do
     ['keystone']
   end
-
-  auth_param_doc=<<EOT
-If no other credentials are present, the provider will search in
-/etc/keystone/keystone.conf for an admin token and auth url.
-EOT
-  Puppet::Util::Openstack.add_openstack_type_methods(self, auth_param_doc)
 end
index 2186169..b484e7c 100644 (file)
@@ -1,6 +1,7 @@
 # LP#1408531
 File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
-require 'puppet/util/openstack'
+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 'Type for managing keystone users.'
@@ -76,10 +77,4 @@ Puppet::Type.newtype(:keystone_user) do
   autorequire(:service) do
     ['keystone']
   end
-
-  auth_param_doc=<<EOT
-If no other credentials are present, the provider will search in
-/etc/keystone/keystone.conf for an admin token and auth url.
-EOT
-  Puppet::Util::Openstack.add_openstack_type_methods(self, auth_param_doc)
 end
index 9ac24e3..502dc39 100644 (file)
@@ -1,6 +1,7 @@
 # LP#1408531
 File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) }
-require 'puppet/util/openstack'
+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
@@ -15,7 +16,6 @@ Puppet::Type.newtype(:keystone_user_role) do
   ensurable
 
   newparam(:name, :namevar => true) do
-    newvalues(/^\S+@\S+$/)
   end
 
   newproperty(:roles,  :array_matching => :all) do
@@ -42,10 +42,4 @@ Puppet::Type.newtype(:keystone_user_role) do
   autorequire(:service) do
     ['keystone']
   end
-
-  auth_param_doc=<<EOT
-If no other credentials are present, the provider will search in
-/etc/keystone/keystone.conf for an admin token and auth url.
-EOT
-  Puppet::Util::Openstack.add_openstack_type_methods(self, auth_param_doc)
 end
diff --git a/3rdparty/modules/keystone/lib/puppet/util/openstack.rb b/3rdparty/modules/keystone/lib/puppet/util/openstack.rb
deleted file mode 100644 (file)
index 947aa35..0000000
+++ /dev/null
@@ -1,48 +0,0 @@
-# TODO: This should be extracted into openstacklib during the kilo cycle
-# Add the auth parameter to whatever type is given
-module Puppet::Util::Openstack
-  def self.add_openstack_type_methods(type, comment)
-
-    type.newparam(:auth) do
-
-      desc <<EOT
-Hash of authentication credentials. Credentials can be specified as
-password credentials, e.g.:
-
-auth => {
-  'username'    => 'test',
-  'password'    => 'passw0rd',
-  'tenant_name' => 'test',
-  'auth_url'    => 'http://localhost:35357/v2.0',
-}
-
-or a path to an openrc file containing these credentials, e.g.:
-
-auth => {
-  'openrc' => '/root/openrc',
-}
-
-or a service token and host, e.g.:
-
-auth => {
-  'service_token' => 'ADMIN',
-  'auth_url'    => 'http://localhost:35357/v2.0',
-}
-
-If not present, the provider will look for environment variables for
-password credentials.
-
-#{comment}
-EOT
-
-      validate do |value|
-        raise(Puppet::Error, 'This property must be a hash') unless value.is_a?(Hash)
-      end
-    end
-
-    type.autorequire(:package) do
-      'python-openstackclient'
-    end
-
-  end
-end
index d400f39..84a6e08 100644 (file)
@@ -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'
index 3e046f4..dc94896 100644 (file)
@@ -5,19 +5,39 @@
 #
 # == 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*] Deprecated. Does nothing.
+# [*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']
@@ -37,7 +57,7 @@ class keystone::db::mysql(
   $user          = 'keystone',
   $host          = '127.0.0.1',
   $charset       = 'utf8',
-  $collate       = 'utf8_unicode_ci',
+  $collate       = 'utf8_general_ci',
   $mysql_module  = undef,
   $allowed_hosts = undef
 ) {
index 3d7eb73..4bf5a6a 100644 (file)
@@ -1,47 +1,57 @@
+# == Class: keystone::db::postgresql
 #
-# implements postgresql backend for keystone
+# Class that configures postgresql for keystone
+# Requires the Puppetlabs postgresql module.
 #
-# This class can be used to create tables, users and grant
-# privelege for a postgresql keystone database.
-#
-# Requires Puppetlabs Postgresql module.
+# == Authors
 #
-# [*Parameters*]
+#   Stackforge Contributors puppet-openstack@puppetlabs.com
+#   Etienne Pelletier epelletier@morphlabs.com
 #
-# [password] Password that will be used for the keystone db user.
-#   Optional. Defaults to: 'keystone_default_password'
+# == Copyright
 #
-# [dbname] Name of keystone database. Optional. Defaults to keystone.
+# Copyright 2013-2014 Stackforge Contributors
+# Copyright 2012 Etienne Pelletier, unless otherwise noted.
 #
-# [user] Name of keystone user. Optional. Defaults to keystone.
+# === Parameters
 #
-# == Dependencies
-#   Class['postgresql::server']
+# [*password*]
+#   (Required) Password to connect to the database.
 #
-# == Examples
-# == Authors
+# [*dbname*]
+#   (Optional) Name of the database.
+#   Defaults to 'keystone'.
 #
-#   Etienne Pelletier epelletier@morphlabs.com
+# [*user*]
+#   (Optional) User to connect to the database.
+#   Defaults to 'keystone'.
 #
-# == Copyright
+#  [*encoding*]
+#    (Optional) The charset to use for the database.
+#    Default to undef.
 #
-# Copyright 2012 Etienne Pelletier, unless otherwise noted.
+#  [*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::Db[$dbname] ~> Exec<| title == 'keystone-manage db_sync' |>
+  ::Openstacklib::Db::Postgresql['keystone'] ~> Exec<| title == 'keystone-manage db_sync' |>
 
 }
index 3e68113..f52800f 100644 (file)
@@ -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
index c713800..6c821f4 100644 (file)
 # [*version*]
 #   (optional) API version for endpoint. Appended to all endpoint urls. (Defaults to 'v2.0')
 #
-# [*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':
@@ -76,76 +36,17 @@ 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,
 ) {
 
-  warning('keystone::endpoint class is deprecated, use keystone::resource::service_identity instead.')
-
-  if $public_port {
-    warning('The public_port parameter is deprecated, use public_url instead.')
-  }
-
-  if $public_protocol {
-    warning('The public_protocol parameter is deprecated, use public_url instead.')
-  }
-
-  if $public_address {
-    warning('The public_address parameter is deprecated, use public_url instead.')
-  }
-
-  if $internal_address {
-    warning('The internal_address parameter is deprecated, use internal_url instead.')
-  }
-
-  if $internal_port {
-    warning('The internal_port parameter is deprecated, use internal_url instead.')
-  }
-
-  if $admin_address {
-    warning('The admin_address parameter is deprecated, use admin_url instead.')
-  }
+  $public_url_real = "${public_url}/${version}"
+  $admin_url_real = "${admin_url}/${version}"
 
-  if $admin_port {
-    warning('The admin_port parameter is deprecated, use admin_url instead.')
+  if $internal_url {
+    $internal_url_real = "${internal_url}/${version}"
+  } else {
+    $internal_url_real = "${public_url}/${version}"
   }
 
-  $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::resource::service_identity { 'keystone':
     configure_user      => false,
     configure_user_role => false,
index d43bcd2..20c2011 100644 (file)
 #
 # == 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.uuid.Provider'
-#     Supports PKI and UUID.
-#   [token_driver] Driver to use for managing tokens.
-#     Optional.  Defaults to 'keystone.token.persistence.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 in format of server:port.
-#     Used with token_driver 'keystone.token.backends.memcache.Token'.
-#     Optional. Defaults to false. Example: ['localhost:11211']
-#
-#   [cache_backend]
-#     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.
-#     Optional. Defaults to 'keystone.common.cache.noop'
-#
-#   [cache_backend_argument]
-#     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.
-#     Optional. Default to undef.
-#
-#   [debug_cache_backend]
-#     Extra debugging from the cache backend (cache keys, get/set/delete calls).
-#     This has no effects unless 'memcache_servers' is set.
-#     Optional. Default to false.
-#
-#   [token_caching]
-#     Toggle for token system caching. This has no effects unless 'memcache_servers' is set.
-#     Optional. Default to true.
-#
-#   [enabled] If the keystone services should be enabled. Optional. Default to true.
-#
-#   [*database_connection*]
-#     (optional) Url used to connect to database.
-#     Defaults to sqlite:////var/lib/keystone/keystone.db
-#
-#   [*sql_connection*]
-#     (optional) Deprecated. Use database_connection instead.
-#
-#   [*database_idle_timeout*]
-#     (optional) Timeout when db connections should be reaped.
-#     Defaults to 200.
-#
-#   [*idle_timeout*]
-#     (optional) Deprecated. Use database_idle_timeout instead.
-#
-#   [enable_pki_setup] Enable call to pki_setup to generate the cert for signing pki tokens and
-#     revocation lists if it doesn't already exist. This generates a cert and key stored in file
-#     locations based on the signing_certfile and signing_keyfile paramters below. If you are
-#     providing your own signing cert, make this false.
-#   [signing_certfile] Location of the cert file for signing pki tokens and revocation lists.
-#     Optional. Note that if this file already exists (i.e. you are providing your own signing cert),
-#     the file will not be overwritten, even if enable_pki_setup is set to true.
-#     Default: /etc/keystone/ssl/certs/signing_cert.pem
-#   [signing_keyfile] Location of the key 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.
-#     Default: /etc/keystone/ssl/private/signing_key.pem
-#   [signing_ca_certs] Use this CA certs file along with signing_certfile/signing_keyfile for
-#     signing pki tokens and revocation lists. Optional. Default: /etc/keystone/ssl/certs/ca.pem
-#   [signing_ca_key] Use this CA key file along with signing_certfile/signing_keyfile for signing
-#     pki tokens and revocation lists. Optional. Default: /etc/keystone/ssl/private/cakey.pem
-#
-#   [*signing_cert_subject*]
+# [*package_ensure*]
+#   (optional) Desired ensure state of packages.
+#   accepts latest or specific versions.
+#   Defaults to present.
+#
+# [*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*]
+# [*signing_key_size*]
 #   (optional) Key size (in bits) for token signing cert (auto generated certificate)
 #   Defaults to 2048
 #
-#   [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 /.
+# [*rabbit_host*]
+#   (optional) Location of rabbitmq installation.
+#    Defaults to localhost.
 #
-#   [*rabbit_use_ssl*]
-#     (optional) Connect over SSL for RabbitMQ
-#     Defaults to false
+# [*rabbit_port*]
+#   (optional) Port for rabbitmq instance.
+#   Defaults to 5672.
 #
-#   [*kombu_ssl_ca_certs*]
-#     (optional) SSL certification authority file (valid only if SSL enabled).
-#     Defaults to undef
+# [*rabbit_hosts*]
+#   (optional) Location of rabbitmq installation.
+#   Defaults to undef.
 #
-#   [*kombu_ssl_certfile*]
-#     (optional) SSL cert file (valid only if SSL enabled).
-#     Defaults to undef
+# [*rabbit_password*]
+#   (optional) Password used to connect to rabbitmq.
+#   Defaults to guest.
 #
-#   [*kombu_ssl_keyfile*]
-#     (optional) SSL key file (valid only if SSL enabled).
-#     Defaults to undef
+# [*rabbit_userid*]
+#   (optional) User used to connect to rabbitmq.
+#   Defaults to guest.
 #
-#   [*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'
+# [*rabbit_virtual_host*]
+#   (optional) The RabbitMQ virtual host.
+#   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
+# [*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*]
+# [*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)
 #   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)
 #   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*]
+# [*mysql_module*]
 #   (optional) Deprecated. Does nothing.
 #
-#   [*validate_service*]
+# [*validate_service*]
 #   (optional) Whether to validate keystone connections after
 #   the service is started.
 #   Defaults to false
 #
-#   [*validate_insecure*]
+# [*validate_insecure*]
 #   (optional) Whether to validate keystone connections
 #   using the --insecure option with keystone client.
 #   Defaults to false
 #
-#   [*validate_cacert*]
+# [*validate_cacert*]
 #   (optional) Whether to validate keystone connections
 #   using the specified argument with the --os-cacert option
 #   with keystone client.
 #   Defaults to undef
 #
-#   [*validate_auth_url*]
+# [*validate_auth_url*]
 #   (optional) The url to validate keystone against
 #   Defaults to undef
 #
-#   [*service_provider*]
+# [*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*]
+# [*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
 #   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'
-#   NOTE: validate_service only applies if the value is 'keystone'
+#   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
 class keystone(
   $admin_token,
   $package_ensure         = 'present',
-  $bind_host              = false,
+  $client_package_ensure  = 'present',
   $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',
@@ -292,10 +409,10 @@ class keystone(
   $catalog_type           = 'sql',
   $catalog_driver         = false,
   $catalog_template_file  = '/etc/keystone/default_catalog.templates',
-  $token_format           = false,
   $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,
@@ -306,6 +423,7 @@ class keystone(
   $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,
@@ -333,17 +451,25 @@ class keystone(
   $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',
+  $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,
-  $sql_connection         = undef,
-  $idle_timeout           = undef,
+  $compute_port           = undef,
 ) inherits keystone::params {
 
   if ! $catalog_driver {
@@ -354,20 +480,6 @@ class keystone(
     warning('The mysql_module parameter is deprecated. The latest 2.x mysql module will be used.')
   }
 
-  if $sql_connection {
-    warning('The sql_connection parameter is deprecated, use database_connection instead.')
-    $database_connection_real = $sql_connection
-  } else {
-    $database_connection_real = $database_connection
-  }
-
-  if $idle_timeout {
-    warning('The idle_timeout parameter is deprecated, use database_idle_timeout instead.')
-    $database_idle_timeout_real = $idle_timeout
-  } else {
-    $database_idle_timeout_real = $database_idle_timeout
-  }
-
   if ($admin_endpoint and 'v2.0' in $admin_endpoint) {
     warning('Version string /v2.0/ should not be included in keystone::admin_endpoint')
   }
@@ -391,6 +503,8 @@ class keystone(
   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
 
   package { 'keystone':
@@ -398,10 +512,12 @@ class keystone(
     name   => $::keystone::params::package_name,
     tag    => 'openstack',
   }
-  # TODO: Move this to openstacklib::openstackclient in Kilo
-  package { 'python-openstackclient':
-    ensure => present,
-    tag    => 'openstack',
+  if $client_package_ensure == 'present' {
+    include '::openstacklib::openstackclient'
+  } else {
+    class { '::openstacklib::openstackclient':
+      package_ensure => $client_package_ensure,
+    }
   }
 
   group { 'keystone':
@@ -435,27 +551,27 @@ class 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/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 {
@@ -489,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 {
@@ -505,15 +631,15 @@ class keystone(
     }
   }
 
-  if($database_connection_real =~ /mysql:\/\/\S+:\S+@\S+\/\S+/) {
+  if($database_connection =~ /mysql:\/\/\S+:\S+@\S+\/\S+/) {
     require 'mysql::bindings'
     require 'mysql::bindings::python'
-  } elsif($database_connection_real =~ /postgresql:\/\/\S+:\S+@\S+\/\S+/) {
+  } elsif($database_connection =~ /postgresql:\/\/\S+:\S+@\S+\/\S+/) {
 
-  } elsif($database_connection_real =~ /sqlite:\/\//) {
+  } elsif($database_connection =~ /sqlite:\/\//) {
 
   } else {
-    fail("Invalid db connection ${database_connection_real}")
+    fail("Invalid db connection ${database_connection}")
   }
 
   # memcache connection config
@@ -550,8 +676,8 @@ class keystone(
 
   # db connection config
   keystone_config {
-    'database/connection':   value => $database_connection_real, secret => true;
-    'database/idle_timeout': value => $database_idle_timeout_real;
+    'database/connection':   value => $database_connection, secret => true;
+    'database/idle_timeout': value => $database_idle_timeout;
   }
 
   # configure based on the catalog backend
@@ -570,13 +696,6 @@ class keystone(
     'catalog/template_file': value => $catalog_template_file;
   }
 
-  if $token_format {
-    warning('token_format parameter is deprecated. Use token_provider instead.')
-  }
-
-  # remove the old format in case of an upgrade
-  keystone_config { 'signing/token_format': ensure => absent }
-
   # Set the signing key/cert configuration values.
   keystone_config {
     'signing/certfile':     value => $signing_certfile;
@@ -607,12 +726,12 @@ class 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' }
+  keystone_config { 'token/provider': value => $token_provider }
+
+  if $max_token_size {
+    keystone_config { 'DEFAULT/max_token_size': value => $max_token_size }
   } else {
-    keystone_config { 'token/provider': value => $token_provider }
+    keystone_config { 'DEFAULT/max_token_size': ensure => absent }
   }
 
   if $notification_driver {
@@ -625,6 +744,11 @@ class keystone(
   } 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 {
@@ -664,13 +788,22 @@ class keystone(
     }
   }
 
-  if $enabled {
-    $service_ensure = 'running'
+  keystone_config {
+    'DEFAULT/admin_workers':  value => $admin_workers;
+    'DEFAULT/public_workers': value => $public_workers;
+  }
+
+  if $manage_service {
+    if $enabled {
+      $service_ensure = 'running'
+    } else {
+      $service_ensure = 'stopped'
+    }
   } else {
-    $service_ensure = 'stopped'
+    warning('Execution of db_sync does not depend on $enabled anymore. Please use sync_db instead.')
   }
 
-  if $service_name == 'keystone' {
+  if $service_name == $::keystone::params::service_name {
     if $validate_service {
       if $validate_auth_url {
         $v_auth_url = $validate_auth_url
@@ -678,9 +811,9 @@ class keystone(
         $v_auth_url = $admin_endpoint
       }
 
-      class { 'keystone::service':
+      class { '::keystone::service':
         ensure         => $service_ensure,
-        service_name   => $::keystone::params::service_name,
+        service_name   => $service_name,
         enable         => $enabled,
         hasstatus      => true,
         hasrestart     => true,
@@ -692,9 +825,9 @@ class keystone(
         cacert         => $validate_cacert,
       }
     } else {
-      class { 'keystone::service':
+      class { '::keystone::service':
         ensure       => $service_ensure,
-        service_name => $::keystone::params::service_name,
+        service_name => $service_name,
         enable       => $enabled,
         hasstatus    => true,
         hasrestart   => true,
@@ -702,9 +835,19 @@ class keystone(
         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 $enabled {
+  if $sync_db {
     include ::keystone::db::sync
     Class['::keystone::db::sync'] ~> Service[$service_name]
   }
@@ -740,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;
+    }
+  }
+
 }
index 96ec8cd..05428e9 100644 (file)
@@ -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 <ldap_attr>:<user_attr>, where ldap_attr is the
+#   attribute in the LDAP entry and user_attr is the Identity
+#   API attribute. (list value)
+#   Defaults to 'undef'
+#
+# [*project_tree_dn*]
+#   Search base for projects (string value)
+#   Defaults to 'undef'
+#
+# [*project_filter*]
+#   LDAP search filter for projects. (string value)
+#   Defaults to 'undef'
+#
+# [*project_objectclass*]
+#   LDAP objectclass for projects. (string value)
+#   Defaults to 'undef'
+#
+# [*project_id_attribute*]
+#   LDAP attribute mapped to project id. (string value)
+#   Defaults to 'undef'
+#
+# [*project_member_attribute*]
+#   LDAP attribute mapped to project membership for user. (string value)
+#   Defaults to 'undef'
+#
+# [*project_name_attribute*]
+#   LDAP attribute mapped to project name. (string value)
+#   Defaults to 'undef'
+#
+# [*project_desc_attribute*]
+#   LDAP attribute mapped to project description. (string value)
+#   Defaults to 'undef'
+#
+# [*project_enabled_attribute*]
+#   LDAP attribute mapped to project enabled. (string value)
+#   Defaults to 'undef'
+#
+# [*project_domain_id_attribute*]
+#   LDAP attribute mapped to project domain_id. (string value)
+#   Defaults to 'undef'
+#
+# [*project_attribute_ignore*]
+#   List of attributes stripped off the project on update. (list value)
+#   Defaults to 'undef'
+#
+# [*project_allow_create*]
+#   Allow project creation in LDAP backend. (boolean value)
+#   Defaults to 'undef'
+#
+# [*project_allow_update*]
+#   Allow project update in LDAP backend. (boolean value)
+#   Defaults to 'undef'
+#
+# [*project_allow_delete*]
+#   Allow project deletion in LDAP backend. (boolean value)
+#   Defaults to 'undef'
+#
+# [*project_enabled_emulation*]
+#   If true, Keystone uses an alternative method to determine if
+#   a project is enabled or not by checking if they are a member
+#   of the "project_enabled_emulation_dn" group. (boolean value)
+#   Defaults to 'undef'
+#
+# [*project_enabled_emulation_dn*]
+#   DN of the group entry to hold enabled projects when using
+#   enabled emulation. (string value)
+#   Defaults to 'undef'
+#
+# [*project_additional_attribute_mapping*]
+#   Additional attribute mappings for projects. Attribute
+#   mapping format is <ldap_attr>:<user_attr>, where ldap_attr
+#   is the attribute in the LDAP entry and user_attr is the
+#   Identity API attribute. (list value)
+#   Defaults to 'undef'
+#
+# [*role_tree_dn*]
+#   Search base for roles. (string value)
+#   Defaults to 'undef'
+#
+# [*role_filter*]
+#   LDAP search filter for roles. (string value)
+#   Defaults to 'undef'
+#
+# [*role_objectclass*]
+#   LDAP objectclass for roles. (string value)
+#   Defaults to 'undef'
+#
+# [*role_id_attribute*]
+#   LDAP attribute mapped to role id. (string value)
+#   Defaults to 'undef'
+#
+# [*role_name_attribute*]
+#   LDAP attribute mapped to role name. (string value)
+#   Defaults to 'undef'
+#
+# [*role_member_attribute*]
+#   LDAP attribute mapped to role membership. (string value)
+#   Defaults to 'undef'
+#
+# [*role_attribute_ignore*]
+#   List of attributes stripped off the role on update. (list value)
+#   Defaults to 'undef'
+#
+# [*role_allow_create*]
+#   Allow role creation in LDAP backend. (boolean value)
+#   Defaults to 'undef'
+#
+# [*role_allow_update*]
+#   Allow role update in LDAP backend. (boolean value)
+#   Defaults to 'undef'
+#
+# [*role_allow_delete*]
+#   Allow role deletion in LDAP backend. (boolean value)
+#   Defaults to 'undef'
+#
+# [*role_additional_attribute_mapping*]
+#   Additional attribute mappings for roles. Attribute mapping
+#   format is <ldap_attr>:<user_attr>, where ldap_attr is the
+#   attribute in the LDAP entry and user_attr is the Identity
+#   API attribute. (list value)
+#   Defaults to 'undef'
+#
+# [*group_tree_dn*]
+#   Search base for groups. (string value)
+#   Defaults to 'undef'
+#
+# [*group_filter*]
+#   LDAP search filter for groups. (string value)
+#   Defaults to 'undef'
+#
+# [*group_objectclass*]
+#   LDAP objectclass for groups. (string value)
+#   Defaults to 'undef'
+#
+# [*group_id_attribute*]
+#   LDAP attribute mapped to group id. (string value)
+#   Defaults to 'undef'
+#
+# [*group_name_attribute*]
+#   LDAP attribute mapped to group name. (string value)
+#   Defaults to 'undef'
+#
+# [*group_member_attribute*]
+#   LDAP attribute mapped to show group membership. (string value)
+#   Defaults to 'undef'
+#
+# [*group_desc_attribute*]
+#   LDAP attribute mapped to group description. (string value)
+#   Defaults to 'undef'
+#
+# [*group_attribute_ignore*]
+#   List of attributes stripped off the group on update. (list value)
+#   Defaults to 'undef'
+#
+# [*group_allow_create*]
+#   Allow group creation in LDAP backend. (boolean value)
+#   Defaults to 'undef'
+#
+# [*group_allow_update*]
+#   Allow group update in LDAP backend. (boolean value)
+#   Defaults to 'undef'
+#
+# [*group_allow_delete*]
+#   Allow group deletion in LDAP backend. (boolean value)
+#   Defaults to 'undef'
+#
+# [*group_additional_attribute_mapping*]
+#   Additional attribute mappings for groups. Attribute mapping
+#   format is <ldap_attr>:<user_attr>, where ldap_attr is the
+#   attribute in the LDAP entry and user_attr is the Identity
+#   API attribute. (list value)
+#   Defaults to 'undef'
+#
+# [*use_tls*]
+#   Enable TLS for communicating with LDAP servers. (boolean value)
+#   Defaults to 'undef'
+#
+# [*tls_cacertfile*]
+#   CA certificate file path for communicating with LDAP servers. (string value)
+#   Defaults to 'undef'
+#
+# [*tls_cacertdir*]
+#   CA certificate directory path for communicating with LDAP servers. (string value)
+#   Defaults to 'undef'
+#
+# [*tls_req_cert*]
+#   Valid options for tls_req_cert are demand, never, and allow. (string value)
+#   Defaults to 'undef'
+#
+# [*identity_driver*]
+#   Identity backend driver. (string value)
+#   Defaults to 'undef'
+#
+# [*credential_driver*]
+#   Credential backend driver. (string value)
+#   Defaults to 'undef'
+#
+# [*assignment_driver*]
+#   Assignment backend driver. (string value)
+#   Defaults to 'undef'
+#
+# [*use_pool*]
+#   Enable LDAP connection pooling. (boolean value)
+#   Defaults to false
+#
+# [*pool_size*]
+#   Connection pool size. (integer value)
+#   Defaults to '10'
+#
+# [*pool_retry_max*]
+#   Maximum count of reconnect trials. (integer value)
+#   Defaults to '3'
+#
+# [*pool_retry_delay*]
+#   Time span in seconds to wait between two reconnect trials. (floating point value)
+#   Defaults to '0.1'
+#
+# [*pool_connection_timeout*]
+#   Connector timeout in seconds. Value -1 indicates indefinite wait for response. (integer value)
+#   Defaults to '-1'
+#
+# [*pool_connection_lifetime*]
+#   Connection lifetime in seconds. (integer value)
+#   Defaults to '600'
+#
+# [*use_auth_pool*]
+#   Enable LDAP connection pooling for end user authentication.
+#   If use_pool is disabled, then this setting is meaningless and is not used at all. (boolean value)
+#   Defaults to false
+#
+# [*auth_pool_size*]
+#   End user auth connection pool size. (integer value)
+#   Defaults to '100'
+#
+# [*auth_pool_connection_lifetime*]
+#   End user auth connection lifetime in seconds. (integer value)
+#   Defaults to '60'
+#
+# === DEPRECATED group/name
+#
+# [*tenant_tree_dn*]
+# [*tenant_filter*]
+# [*tenant_objectclass*]
+# [*tenant_id_attribute*]
+# [*tenant_member_attribute*]
+# [*tenant_name_attribute*]
+# [*tenant_desc_attribute*]
+# [*tenant_enabled_attribute*]
+# [*tenant_domain_id_attribute*]
+# [*tenant_attribute_ignore*]
+# [*tenant_allow_create*]
+# [*tenant_allow_update*]
+# [*tenant_enabled_emulation*]
+# [*tenant_enabled_emulation_dn*]
+# [*tenant_additional_attribute_mapping*]
+# [*tenant_allow_delete*]
+#
 # == Dependencies
 # == Examples
 # == Authors
@@ -99,6 +473,7 @@ class keystone::ldap(
   $tls_req_cert                        = undef,
   $identity_driver                     = undef,
   $assignment_driver                   = undef,
+  $credential_driver                   = undef,
   $use_pool                            = false,
   $pool_size                           = 10,
   $pool_retry_max                      = 3,
@@ -307,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
@@ -392,6 +773,7 @@ class keystone::ldap(
     '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;
   }
 }
index f3f0f4d..12660ca 100644 (file)
@@ -10,6 +10,7 @@ class keystone::params {
       $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
@@ -31,6 +32,7 @@ class keystone::params {
       $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'
     }
   }
 }
index 858fd65..32adc63 100644 (file)
@@ -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,
index 08eaa7f..9bbd1b1 100644 (file)
 # == Parameters:
 #
 # [*password*]
-# Password to create for the service user;
-# string; required
+#   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'
+#   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
+#   Name of the service;
+#   string; required
 #
 # [*service_type*]
-# Type of the service;
-# string; required
+#   Type of the service;
+#   string; required
 #
 # [*service_description*]
-# Description of the service;
-# string; optional: default to '$name service'
+#   Description of the service;
+#   string; optional: default to '$name service'
 #
 # [*public_url*]
-# Public endpoint URL;
-# string; required
+#   Public endpoint URL;
+#   string; required
 #
 # [*internal_url*]
-# Internal endpoint URL;
-# string; required
+#   Internal endpoint URL;
+#   string; required
 #
 # [*admin_url*]
-# Admin endpoint URL;
-# string; required
+#   Admin endpoint URL;
+#   string; required
 #
 # [*region*]
-# Endpoint region;
-# string; optional: default to 'RegionOne'
+#   Endpoint region;
+#   string; optional: default to 'RegionOne'
 #
 # [*tenant*]
-# Service tenant;
-# string; optional: default to 'services'
+#   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
+#   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']
+#   List of roles;
+#   string; optional: default to ['admin']
 #
 # [*domain*]
-# User domain (keystone v3), not implemented yet.
-# string; optional: default to undef
+#   User domain (keystone v3), not implemented yet.
+#   string; optional: default to undef
 #
 # [*email*]
-# Service email;
-# string; optional: default to '$auth_name@localhost'
+#   Service email;
+#   string; optional: default to '$auth_name@localhost'
 #
 # [*configure_endpoint*]
-# Whether to create the endpoint.
-# string; optional: default to True
+#   Whether to create the endpoint.
+#   string; optional: default to True
 #
 # [*configure_user*]
-# Whether to create the user.
-# string; optional: default to True
+#   Whether to create the user.
+#   string; optional: default to True
 #
 # [*configure_user_role*]
-# Whether to create the user role.
-# string; optional: default to True
+#   Whether to create the user role.
+#   string; optional: default to True
 #
 # [*configure_service*]
-# Whether to create the service.
-# string; optional: default to True
+#   Whether to create the service.
+#   string; optional: default to True
 #
 define keystone::resource::service_identity(
   $admin_url             = false,
index 4fd5e09..aa5abd7 100644 (file)
@@ -1,3 +1,4 @@
+# == Class: keystone::roles::admin
 #
 # This class implements some reasonable admin defaults for keystone.
 #
@@ -8,18 +9,49 @@
 #   * admin role
 #   * adds admin role to admin user on the "admin" tenant
 #
-# [*Parameters*]
-#
-# [email] The email address for the admin. Required.
-# [password] The admin password. Required.
-# [admin_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.
-# [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'.
+# === Parameters:
+#
+# [*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
index 63c148d..4631214 100644 (file)
@@ -9,63 +9,62 @@
 # === Parameters
 #
 # [*ensure*]
-# (optional) The desired state of the keystone service
-# Defaults to 'running'
+#   (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
+#   (optional) The name of the keystone service
+#   Defaults to $::keystone::params::service_name
 #
 # [*enable*]
-# (optional) Whether to enable the keystone service
-# Defaults to true
+#   (optional) Whether to enable the keystone service
+#   Defaults to true
 #
 # [*hasstatus*]
-# (optional) Whether the keystone service has status
-# Defaults to true
+#   (optional) Whether the keystone service has status
+#   Defaults to true
 #
 # [*hasrestart*]
-# (optional) Whether the keystone service has restart
-# Defaults to true
+#   (optional) Whether the keystone service has restart
+#   Defaults to true
 #
 # [*provider*]
-# (optional) Provider for keystone service
-# Defaults to $::keystone::params::service_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
+#   (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
+#   (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'
+#   (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
+#   (optional) Number of times to retry validation
+#   Defaults to 10
 #
 # [*delay*]
-# (optional) Number of seconds between validation attempts
-# Defaults to 2
+#   (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
+#   (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
+#   (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         = 'running',
+  $ensure         = undef,
   $service_name   = $::keystone::params::service_name,
   $enable         = true,
   $hasstatus      = true,
@@ -79,7 +78,7 @@ class keystone::service(
   $insecure       = false,
   $cacert         = undef,
 ) {
-  include keystone::params
+  include ::keystone::params
 
   service { 'keystone':
     ensure     => $ensure,
@@ -103,16 +102,16 @@ class keystone::service(
   }
 
   if $validate and $admin_token and $admin_endpoint {
-    $cmd = "keystone --os-endpoint ${admin_endpoint} --os-token ${admin_token} ${insecure_s} ${cacert_s} user-list"
+    $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
+      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<||>
index 3192821..66e28aa 100644 (file)
@@ -1,7 +1,6 @@
 #
 # Class to serve keystone with apache mod_wsgi in place of keystone service
 #
-#
 # Serving keystone from apache is the recommended way to go for production
 # systems as the current keystone implementation is not multi-processor aware,
 # thus limiting the performance for concurrent accesses.
 #     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
+#
+#   [*wsgi_script_ensure*]
+#     (optional) File ensure parameter for wsgi scripts.
+#     Defaults to 'file'.
+#
+#   [*wsgi_script_source*]
+#     (optional) Wsgi script source.
+#     Defaults to undef.
+#
 # == Dependencies
 #
 #   requires Class['apache'] & Class['keystone']
 #   Copyright 2013 eNovance <licensing@enovance.com>
 #
 class keystone::wsgi::apache (
-  $servername    = $::fqdn,
-  $public_port   = 5000,
-  $admin_port    = 35357,
-  $bind_host     = undef,
-  $public_path   = '/',
-  $admin_path    = '/',
-  $ssl           = true,
-  $workers       = 1,
-  $ssl_cert      = undef,
-  $ssl_key       = undef,
-  $ssl_chain     = undef,
-  $ssl_ca        = undef,
-  $ssl_crl_path  = undef,
-  $ssl_crl       = undef,
-  $ssl_certs_dir = undef,
-  $threads       = $::processorcount,
-  $priority      = '10',
+  $servername         = $::fqdn,
+  $public_port        = 5000,
+  $admin_port         = 35357,
+  $bind_host          = undef,
+  $public_path        = '/',
+  $admin_path         = '/',
+  $ssl                = true,
+  $workers            = 1,
+  $ssl_cert           = undef,
+  $ssl_key            = undef,
+  $ssl_chain          = undef,
+  $ssl_ca             = undef,
+  $ssl_crl_path       = undef,
+  $ssl_crl            = undef,
+  $ssl_certs_dir      = undef,
+  $threads            = $::processorcount,
+  $priority           = '10',
+  $wsgi_script_ensure = 'file',
+  $wsgi_script_source = undef,
 ) {
 
   include ::keystone::params
@@ -134,28 +169,35 @@ class keystone::wsgi::apache (
     require => Package['httpd'],
   }
 
-  file { 'keystone_wsgi_admin':
-    ensure  => file,
-    path    => "${::keystone::params::keystone_wsgi_script_path}/admin",
-    source  => $::keystone::params::keystone_wsgi_script_source,
-    owner   => 'keystone',
-    group   => 'keystone',
-    mode    => '0644',
-    # source file provided by keystone package
-    require => [File[$::keystone::params::keystone_wsgi_script_path], Package['keystone']],
+  $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_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_file_defaults = {
+    'ensure'  => $wsgi_script_ensure,
+    'owner'   => 'keystone',
+    'group'   => 'keystone',
+    'mode'    => '0644',
+    '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,
+  }
+
+  case $wsgi_script_ensure {
+    'link':  { $wsgi_file_source = { 'target' => $wsgi_script_source_real } }
+    default: { $wsgi_file_source = { 'source' => $wsgi_script_source_real } }
+  }
+
+  create_resources('file', $wsgi_files, merge($wsgi_file_defaults, $wsgi_file_source))
+
   $wsgi_daemon_process_options_main = {
     user         => 'keystone',
     group        => 'keystone',
index 6f40ac9..77e23af 100644 (file)
@@ -7,49 +7,33 @@
   "source": "git://github.com/openstack/puppet-keystone.git",
   "project_page": "https://launchpad.net/puppet-keystone",
   "issues_url": "https://bugs.launchpad.net/puppet-keystone",
-  "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"}
-  ],
   "requirements": [
-    {
-      "name": "pe",
-      "version_requirement": "3.x"
-    },
-    {
-      "name": "puppet",
-      "version_requirement": "3.x"
-    }
+    { "name": "pe","version_requirement": "3.x" },
+    { "name": "puppet","version_requirement": "3.x" }
   ],
   "operatingsystem_support": [
     {
       "operatingsystem": "Debian",
-      "operatingsystemrelease": [
-        "7"
-      ]
+      "operatingsystemrelease": ["7"]
     },
     {
       "operatingsystem": "Fedora",
-      "operatingsystemrelease": [
-        "20"
-      ]
+      "operatingsystemrelease": ["20"]
     },
     {
       "operatingsystem": "RedHat",
-      "operatingsystemrelease": [
-        "6.5",
-        "7"
-      ]
+      "operatingsystemrelease": ["6.5","7"]
     },
     {
       "operatingsystem": "Ubuntu",
-      "operatingsystemrelease": [
-        "12.04",
-        "14.04"
-      ]
+      "operatingsystemrelease": ["12.04","14.04"]
     }
   ],
-  "description": "Installs and configures OpenStack Keystone (Identity)."
+  "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/3rdparty/modules/keystone/spec/acceptance/basic_keystone_spec.rb b/3rdparty/modules/keystone/spec/acceptance/basic_keystone_spec.rb
new file mode 100644 (file)
index 0000000..b0fd8d3
--- /dev/null
@@ -0,0 +1,116 @@
+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':
+            release => 'kilo',
+          }
+          package { 'openstack-selinux': ensure => 'latest' }
+        }
+        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 => "http://127.0.0.1:5000/",
+        admin_url  => "http://127.0.0.1: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
+
+    describe 'test keystone user/tenant/service/role/endpoint resources' do
+      it 'should find beaker user' do
+        shell('openstack --os-username admin --os-password a_big_secret --os-tenant-name openstack --os-auth-url http://127.0.0.1:5000/v2.0 user list') do |r|
+          expect(r.stdout).to match(/beaker/)
+          expect(r.stderr).to be_empty
+        end
+      end
+      it 'should find services tenant' do
+        shell('openstack --os-username admin --os-password a_big_secret --os-tenant-name openstack --os-auth-url http://127.0.0.1:5000/v2.0 project list') do |r|
+          expect(r.stdout).to match(/services/)
+          expect(r.stderr).to be_empty
+        end
+      end
+      it 'should find beaker service' do
+        shell('openstack --os-username admin --os-password a_big_secret --os-tenant-name openstack --os-auth-url http://127.0.0.1:5000/v2.0 service list') do |r|
+          expect(r.stdout).to match(/beaker/)
+          expect(r.stderr).to be_empty
+        end
+      end
+      it 'should find admin role' do
+        shell('openstack --os-username admin --os-password a_big_secret --os-tenant-name openstack --os-auth-url http://127.0.0.1:5000/v2.0 role list') do |r|
+          expect(r.stdout).to match(/admin/)
+          expect(r.stderr).to be_empty
+        end
+      end
+      it 'should find beaker endpoints' do
+        shell('openstack --os-username admin --os-password a_big_secret --os-tenant-name openstack --os-auth-url http://127.0.0.1:5000/v2.0 endpoint list --long') do |r|
+          expect(r.stdout).to match(/1234/)
+          expect(r.stderr).to be_empty
+        end
+      end
+    end
+  end
+end
diff --git a/3rdparty/modules/keystone/spec/acceptance/nodesets/default.yml b/3rdparty/modules/keystone/spec/acceptance/nodesets/default.yml
new file mode 100644 (file)
index 0000000..a2c1ecc
--- /dev/null
@@ -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/3rdparty/modules/keystone/spec/acceptance/nodesets/nodepool-centos7.yml b/3rdparty/modules/keystone/spec/acceptance/nodesets/nodepool-centos7.yml
new file mode 100644 (file)
index 0000000..575ae67
--- /dev/null
@@ -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/3rdparty/modules/keystone/spec/acceptance/nodesets/nodepool-trusty.yml b/3rdparty/modules/keystone/spec/acceptance/nodesets/nodepool-trusty.yml
new file mode 100644 (file)
index 0000000..a95d9f3
--- /dev/null
@@ -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
index 5ed6f6b..2e58fad 100644 (file)
@@ -3,7 +3,7 @@ require 'spec_helper'
 describe 'keystone::client' do
 
   describe "with default parameters" do
-    it { should contain_package('python-keystoneclient').with(
+    it { is_expected.to contain_package('python-keystoneclient').with(
         'ensure' => 'present',
         'tag'    => 'openstack'
     ) }
@@ -14,7 +14,7 @@ describe 'keystone::client' do
       {:ensure => '2013.1'}
     end
 
-    it { should contain_package('python-keystoneclient').with(
+    it { is_expected.to contain_package('python-keystoneclient').with(
         'ensure' => '2013.1',
         'tag'    => 'openstack'
     ) }
index 597042b..88e1fd5 100644 (file)
@@ -8,7 +8,7 @@ describe 'keystone::cron::token_flush' do
 
   describe 'with default parameters' do
     it 'configures a cron' do
-      should contain_cron('keystone-manage token_flush').with(
+      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',
@@ -30,7 +30,7 @@ describe 'keystone::cron::token_flush' do
     end
 
     it 'configures a cron with delay' do
-      should contain_cron('keystone-manage token_flush').with(
+      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',
@@ -52,7 +52,7 @@ describe 'keystone::cron::token_flush' do
     end
 
     it 'configures a cron with delay' do
-      should contain_cron('keystone-manage token_flush').with(
+      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',
index f20ea9b..f032aa9 100644 (file)
@@ -20,12 +20,13 @@ describe 'keystone::db::mysql' do
   end
 
   describe 'with only required params' do
-    it { should contain_openstacklib__db__mysql('keystone').with(
+    it { is_expected.to contain_openstacklib__db__mysql('keystone').with(
       'user'          => 'keystone',
       'password_hash' => '*B552157B14BCEDDCEAA06767A012F31BDAA9CE3D',
       'dbname'        => 'keystone',
       'host'          => '127.0.0.1',
-      'charset'       => 'utf8'
+      'charset'       => 'utf8',
+      :collate        => 'utf8_general_ci',
     )}
   end
 
index 7efe946..ecdad5a 100644 (file)
@@ -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
index 61b596a..217d791 100644 (file)
@@ -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
index 088526e..0d36624 100644 (file)
@@ -73,6 +73,7 @@ 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,
@@ -85,104 +86,105 @@ describe 'keystone::ldap' do
         :auth_pool_connection_lifetime => 200,
       }
     end
-    it { should contain_package('python-ldap') }
-    it { should contain_package('python-ldappool') }
+    it { is_expected.to contain_package('python-ldap') }
+    it { is_expected.to contain_package('python-ldappool') }
     it 'should have basic params' do
       # basic params
-      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')
+      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')
 
       # users
-      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_enabled_invert').with_value('False')
-      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')
+      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')
 
       # projects/tenants
-      should contain_keystone_config('ldap/project_tree_dn').with_value('ou=projects,ou=openstack,dc=example,dc=com')
-      should contain_keystone_config('ldap/project_filter').with_value('')
-      should contain_keystone_config('ldap/project_objectclass').with_value('organizationalUnit')
-      should contain_keystone_config('ldap/project_id_attribute').with_value('ou')
-      should contain_keystone_config('ldap/project_member_attribute').with_value('member')
-      should contain_keystone_config('ldap/project_desc_attribute').with_value('description')
-      should contain_keystone_config('ldap/project_name_attribute').with_value('ou')
-      should contain_keystone_config('ldap/project_enabled_attribute').with_value('enabled')
-      should contain_keystone_config('ldap/project_domain_id_attribute').with_value('businessCategory')
-      should contain_keystone_config('ldap/project_attribute_ignore').with_value('')
-      should contain_keystone_config('ldap/project_allow_create').with_value('True')
-      should contain_keystone_config('ldap/project_allow_update').with_value('True')
-      should contain_keystone_config('ldap/project_allow_delete').with_value('True')
-      should contain_keystone_config('ldap/project_enabled_emulation').with_value('False')
-      should contain_keystone_config('ldap/project_enabled_emulation_dn').with_value('True')
-      should contain_keystone_config('ldap/project_additional_attribute_mapping').with_value('cn=enabled,ou=openstack,dc=example,dc=com')
+      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')
 
       # roles
-      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('')
+      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
-      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('')
+      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
-      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')
+      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
-      should contain_keystone_config('ldap/use_pool').with_value('True')
-      should contain_keystone_config('ldap/pool_size').with_value('20')
-      should contain_keystone_config('ldap/pool_retry_max').with_value('2')
-      should contain_keystone_config('ldap/pool_retry_delay').with_value('0.2')
-      should contain_keystone_config('ldap/pool_connection_timeout').with_value('222')
-      should contain_keystone_config('ldap/pool_connection_lifetime').with_value('222')
-      should contain_keystone_config('ldap/use_auth_pool').with_value('True')
-      should contain_keystone_config('ldap/auth_pool_size').with_value('20')
-      should contain_keystone_config('ldap/auth_pool_connection_lifetime').with_value('200')
+      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
-      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')
+      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
 
@@ -208,22 +210,22 @@ describe 'keystone::ldap' do
       }
     end
     it 'should work with deprecated params' do
-      should contain_keystone_config('ldap/project_tree_dn').with_value('ou=projects,ou=openstack,dc=example,dc=com')
-      should contain_keystone_config('ldap/project_filter').with_value('')
-      should contain_keystone_config('ldap/project_objectclass').with_value('organizationalUnit')
-      should contain_keystone_config('ldap/project_id_attribute').with_value('ou')
-      should contain_keystone_config('ldap/project_member_attribute').with_value('member')
-      should contain_keystone_config('ldap/project_desc_attribute').with_value('description')
-      should contain_keystone_config('ldap/project_name_attribute').with_value('ou')
-      should contain_keystone_config('ldap/project_enabled_attribute').with_value('enabled')
-      should contain_keystone_config('ldap/project_domain_id_attribute').with_value('businessCategory')
-      should contain_keystone_config('ldap/project_attribute_ignore').with_value('')
-      should contain_keystone_config('ldap/project_allow_create').with_value('True')
-      should contain_keystone_config('ldap/project_allow_update').with_value('True')
-      should contain_keystone_config('ldap/project_allow_delete').with_value('True')
-      should contain_keystone_config('ldap/project_enabled_emulation').with_value('False')
-      should contain_keystone_config('ldap/project_enabled_emulation_dn').with_value('True')
-      should contain_keystone_config('ldap/project_additional_attribute_mapping').with_value('cn=enabled,ou=openstack,dc=example,dc=com')
+      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
 
@@ -234,10 +236,7 @@ describe 'keystone::ldap' do
         :project_tree_dn => 'ou=projects,ou=new-openstack,dc=example,dc=com',
       }
     end
-    it 'should fail with deprecated and new params both set' do
-        expect {
-            should compile
-        }.to raise_error Puppet::Error, /tenant_tree_dn and project_tree_dn are both set. results may be unexpected/
-    end
+
+    it_raises 'a Puppet::Error', /tenant_tree_dn and project_tree_dn are both set. results may be unexpected/
   end
 end
index 7ae9352..f0ac50d 100644 (file)
@@ -42,36 +42,36 @@ describe 'keystone::logging' do
 
   shared_examples_for 'logging params set' do
     it 'enables logging params' do
-      should contain_keystone_config('DEFAULT/logging_context_format_string').with_value(
+      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')
 
-      should contain_keystone_config('DEFAULT/logging_default_format_string').with_value(
+      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')
 
-      should contain_keystone_config('DEFAULT/logging_debug_format_suffix').with_value(
+      is_expected.to contain_keystone_config('DEFAULT/logging_debug_format_suffix').with_value(
         '%(funcName)s %(pathname)s:%(lineno)d')
 
-      should contain_keystone_config('DEFAULT/logging_exception_prefix').with_value(
+      is_expected.to contain_keystone_config('DEFAULT/logging_exception_prefix').with_value(
        '%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s')
 
-      should contain_keystone_config('DEFAULT/log_config_append').with_value(
+      is_expected.to contain_keystone_config('DEFAULT/log_config_append').with_value(
         '/etc/keystone/logging.conf')
-      should contain_keystone_config('DEFAULT/publish_errors').with_value(
+      is_expected.to contain_keystone_config('DEFAULT/publish_errors').with_value(
         true)
 
-      should contain_keystone_config('DEFAULT/default_log_levels').with_value(
+      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')
 
-      should contain_keystone_config('DEFAULT/fatal_deprecations').with_value(
+      is_expected.to contain_keystone_config('DEFAULT/fatal_deprecations').with_value(
         true)
 
-      should contain_keystone_config('DEFAULT/instance_format').with_value(
+      is_expected.to contain_keystone_config('DEFAULT/instance_format').with_value(
         '[instance: %(uuid)s] ')
 
-      should contain_keystone_config('DEFAULT/instance_uuid_format').with_value(
+      is_expected.to contain_keystone_config('DEFAULT/instance_uuid_format').with_value(
         '[instance: %(uuid)s] ')
 
-      should contain_keystone_config('DEFAULT/log_date_format').with_value(
+      is_expected.to contain_keystone_config('DEFAULT/log_date_format').with_value(
         '%Y-%m-%d %H:%M:%S')
     end
   end
@@ -84,7 +84,7 @@ describe 'keystone::logging' do
      :default_log_levels, :fatal_deprecations,
      :instance_format, :instance_uuid_format,
      :log_date_format, ].each { |param|
-        it { should contain_keystone_config("DEFAULT/#{param}").with_ensure('absent') }
+        it { is_expected.to contain_keystone_config("DEFAULT/#{param}").with_ensure('absent') }
       }
   end
 
index 81f69da..56c8f8b 100644 (file)
@@ -16,7 +16,7 @@ describe 'keystone::policy' do
     end
 
     it 'set up the policies' do
-      should contain_openstacklib__policy__base('context_is_admin').with({
+      is_expected.to contain_openstacklib__policy__base('context_is_admin').with({
         :key   => 'context_is_admin',
         :value => 'foo:bar'
       })
index 1324fb2..500413e 100644 (file)
@@ -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
index ba7d532..bbd6d95 100644 (file)
@@ -11,17 +11,17 @@ 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(
+    it { is_expected.to contain_keystone_user('admin').with(
       :ensure                 => 'present',
       :enabled                => true,
       :tenant                 => 'openstack',
@@ -29,8 +29,8 @@ describe 'keystone::roles::admin' do
       :password               => 'ChangeMe',
       :ignore_default_tenant  => 'false'
     )}
-    it { should contain_keystone_role('admin').with_ensure('present') }
-    it { should contain_keystone_user_role('admin@openstack').with(
+    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'
     )}
@@ -53,17 +53,17 @@ describe 'keystone::roles::admin' do
       }
     end
 
-    it { should contain_keystone_tenant('foobar').with(
+    it { is_expected.to contain_keystone_tenant('foobar').with(
       :ensure  => 'present',
       :enabled => true,
       :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 something else'
     )}
-    it { should contain_keystone_user('admin').with(
+    it { is_expected.to contain_keystone_user('admin').with(
       :ensure                 => 'present',
       :enabled                => true,
       :tenant                 => 'admin',
@@ -71,7 +71,7 @@ describe 'keystone::roles::admin' do
       :password               => 'foo',
       :ignore_default_tenant  => 'true'
     )}
-    it { should contain_keystone_user_role('admin@admin').with(
+    it { is_expected.to contain_keystone_user_role('admin@admin').with(
       :roles  => ['admin', 'heat_stack_owner'],
       :ensure => 'present'
     )}
@@ -86,8 +86,8 @@ describe 'keystone::roles::admin' do
         }
       end
 
-      it { should_not contain_keystone_user('keystone') }
-      it { should contain_keystone_user_role('keystone@openstack') }
+      it { is_expected.to_not contain_keystone_user('keystone') }
+      it { is_expected.to contain_keystone_user_role('keystone@openstack') }
     end
   end
 
@@ -100,8 +100,8 @@ describe 'keystone::roles::admin' do
         }
       end
 
-      it { should_not contain_keystone_user('keystone') }
-      it { should_not contain_keystone_user_role('keystone@openstack') }
+      it { is_expected.to_not contain_keystone_user('keystone') }
+      it { is_expected.to_not contain_keystone_user_role('keystone@openstack') }
     end
   end
 
index 29d90b0..3aa302d 100644 (file)
@@ -3,13 +3,13 @@ require 'spec_helper'
 describe 'keystone::service' do
 
   describe "with default parameters" do
-    it { should contain_service('keystone').with(
-      :ensure     => 'running',
+    it { is_expected.to contain_service('keystone').with(
+      :ensure     => nil,
       :enable     => true,
       :hasstatus  => true,
       :hasrestart => true
     ) }
-    it { should_not contain_exec('validate_keystone_connection') }
+    it { is_expected.to_not contain_exec('validate_keystone_connection') }
   end
 
   describe "with validation on" do
@@ -20,12 +20,12 @@ describe 'keystone::service' do
       }
     end
 
-    it { should contain_service('keystone').with(
-      :ensure     => 'running',
+    it { is_expected.to contain_service('keystone').with(
+      :ensure     => nil,
       :enable     => true,
       :hasstatus  => true,
       :hasrestart => true
     ) }
-    it { should contain_exec('validate_keystone_connection') }
+    it { is_expected.to contain_exec('validate_keystone_connection') }
   end
 end
index ef63585..89c4fc5 100644 (file)
@@ -14,25 +14,27 @@ describe 'keystone' do
     global_facts.merge({
       :osfamily               => 'Debian',
       :operatingsystem        => 'Debian',
-      :operatingsystemrelease => '7.0'
+      :operatingsystemrelease => '7.0',
+      :processorcount         => '1'
     })
   end
 
   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',
-      'compute_port'          => '8774',
       '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',
@@ -41,6 +43,7 @@ describe 'keystone' do
       '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,
@@ -51,21 +54,25 @@ describe 'keystone' do
       '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',
-      'compute_port'          => '8778',
       '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,
@@ -75,6 +82,7 @@ describe 'keystone' do
       '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,
@@ -90,19 +98,24 @@ describe 'keystone' do
   httpd_params = {'service_name' => 'httpd'}.merge(default_params)
 
   shared_examples_for 'core keystone examples' do |param_hash|
-    it { should contain_class('keystone::params') }
+    it { is_expected.to contain_class('keystone::params') }
 
-    it { should contain_package('keystone').with(
+    it { is_expected.to contain_package('keystone').with(
       'ensure' => param_hash['package_ensure'],
       'tag'    => 'openstack'
     ) }
 
-    it { should contain_group('keystone').with(
+    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 { should contain_user('keystone').with(
+    it { is_expected.to contain_user('keystone').with(
       'ensure' => 'present',
       'gid'    => 'keystone',
       'system' => true
@@ -110,7 +123,7 @@ describe 'keystone' do
 
     it 'should contain the expected directories' do
       ['/etc/keystone', '/var/log/keystone', '/var/lib/keystone'].each do |d|
-        should contain_file(d).with(
+        is_expected.to contain_file(d).with(
           'ensure'     => 'directory',
           'owner'      => 'keystone',
           'group'      => 'keystone',
@@ -120,9 +133,9 @@ describe 'keystone' do
       end
     end
 
-    it 'should only synchronize the db if $enabled is true' do
-      if param_hash['enabled']
-        should contain_exec('keystone-manage db_sync').with(
+    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]'],
@@ -137,46 +150,66 @@ describe 'keystone' do
        '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])
+        is_expected.to 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)
+      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
-      should contain_keystone_config('database/idle_timeout').with_value(param_hash['database_idle_timeout'])
-      should contain_keystone_config('database/connection').with_value(param_hash['database_connection']).with_secret(true)
+      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 { should contain_keystone_config('token/provider').with_value(
+    it { is_expected.to 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'])
+      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']
-        should contain_keystone_config('DEFAULT/admin_endpoint').with_value(param_hash['admin_endpoint'])
+        is_expected.to contain_keystone_config('DEFAULT/admin_endpoint').with_value(param_hash['admin_endpoint'])
       else
-        should contain_keystone_config('DEFAULT/admin_endpoint').with_ensure('absent')
+        is_expected.to 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'])
+        is_expected.to contain_keystone_config('DEFAULT/public_endpoint').with_value(param_hash['public_endpoint'])
       else
-        should contain_keystone_config('DEFAULT/public_endpoint').with_ensure('absent')
+        is_expected.to contain_keystone_config('DEFAULT/public_endpoint').with_ensure('absent')
       end
     end
 
     it 'should contain correct rabbit_password' do
-      should contain_keystone_config('DEFAULT/rabbit_password').with_value(param_hash['rabbit_password']).with_secret(true)
+      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
 
@@ -189,8 +222,8 @@ describe 'keystone' do
 
       it_configures 'core keystone examples', param_hash
 
-      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
@@ -199,7 +232,7 @@ describe 'keystone' do
     end
   end
 
-  describe "when using default class parameters for httpd" do
+  shared_examples_for "when using default class parameters for httpd" do
     let :params do
       httpd_params
     end
@@ -212,28 +245,37 @@ describe 'keystone' do
 
     it do
       expect {
-        should contain_service('keystone')
-      }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected that the catalogue would contain Service\[keystone\]/)
+        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 'with deprecated sql_connection parameter' do
-    let :params do
-      { :admin_token    => 'service_token',
-        :sql_connection => 'mysql://a:b@c/d' }
-    end
+  describe 'when using invalid service name for keystone' do
+    let (:params) { {'service_name' => 'foo'}.merge(default_params) }
 
-    it { should contain_keystone_config('database/connection').with_value(params[:sql_connection]) }
+    it_raises 'a Puppet::Error', /Invalid service_name/
   end
 
-  describe 'with deprecated idle_timeout parameter' do
+  describe 'with disabled service managing' do
     let :params do
-      { :admin_token  => 'service_token',
-        :idle_timeout => 365 }
+      { :admin_token    => 'service_token',
+        :manage_service => false,
+        :enabled        => false }
     end
 
-    it { should contain_keystone_config('database/idle_timeout').with_value(params[:idle_timeout]) }
+    it { is_expected.to contain_service('keystone').with(
+      'ensure'     => nil,
+      'enable'     => false,
+      'hasstatus'  => true,
+      'hasrestart' => true
+    ) }
   end
 
   describe 'when configuring signing token provider' do
@@ -245,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
 
@@ -272,23 +314,23 @@ 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
 
@@ -307,30 +349,30 @@ describe 'keystone' do
         }
       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
-        should contain_keystone_config('signing/cert_subject').with_value('signing_cert_subject')
+        is_expected.to contain_keystone_config('signing/cert_subject').with_value('signing_cert_subject')
       end
 
       it 'should contain correct PKI key_size config' do
-        should contain_keystone_config('signing/key_size').with_value('2048')
+        is_expected.to contain_keystone_config('signing/key_size').with_value('2048')
       end
     end
 
@@ -349,30 +391,30 @@ describe 'keystone' do
         }
       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
-        should contain_keystone_config('signing/cert_subject').with_value('signing_cert_subject')
+        is_expected.to contain_keystone_config('signing/cert_subject').with_value('signing_cert_subject')
       end
 
       it 'should contain correct PKI key_size config' do
-        should contain_keystone_config('signing/key_size').with_value('2048')
+        is_expected.to contain_keystone_config('signing/key_size').with_value('2048')
       end
     end
 
@@ -391,99 +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]) }
-    end
-
-    describe 'when configuring deprecated token_format as UUID with enable_pki_setup' do
-      let :params do
-        {
-          'admin_token'    => 'service_token',
-          'token_format'   => 'UUID'
-        }
-      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
-
-    describe 'when configuring deprecated token_format as UUID without enable_pki_setup' do
-      let :params do
-        {
-          'admin_token'      => 'service_token',
-          'token_format'     => 'UUID',
-          'enable_pki_setup' => false
-        }
-      end
-      it { should_not contain_exec('keystone-manage pki_setup') }
-      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.uuid.Provider',
-            'cache_dir'      => '/var/lib/cache/keystone'
-          }
-        end
-        it { should contain_file('/var/lib/cache/keystone') }
-      end
-    end
-
-    describe 'when configuring deprecated token_format as PKI with enable_pki_setup' 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
+      it { is_expected.to contain_keystone_config('catalog/driver').with_value(params[:catalog_driver]) }
     end
-
-    describe 'when configuring deprecated token_format as PKI without enable_pki_setup' do
-      let :params do
-        {
-          'admin_token'       => 'service_token',
-          'token_format'      => 'PKI',
-          'enable_pki_setup'  => false
-        }
-      end
-      it { should_not contain_exec('keystone-manage pki_setup') }
-      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
@@ -494,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
@@ -504,7 +455,18 @@ 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
@@ -518,12 +480,12 @@ describe 'keystone' do
       }
     end
 
-    it { should contain_keystone_config("memcache/servers").with_value('SERVER1:11211,SERVER2:11211') }
-    it { should contain_keystone_config('cache/enabled').with_value(true) }
-    it { should contain_keystone_config('token/caching').with_value(true) }
-    it { should contain_keystone_config('cache/backend').with_value('dogpile.cache.memcached') }
-    it { should contain_keystone_config('cache/backend_argument').with_value('url:SERVER1:12211') }
-    it { should contain_package('python-memcache').with(
+    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'
     ) }
@@ -534,12 +496,12 @@ describe 'keystone' do
       default_params
     end
 
-    it { should contain_keystone_config("cache/enabled").with_ensure('absent') }
-    it { should contain_keystone_config("token/caching").with_ensure('absent') }
-    it { should contain_keystone_config("cache/backend").with_ensure('absent') }
-    it { should contain_keystone_config("cache/backend_argument").with_ensure('absent') }
-    it { should contain_keystone_config("cache/debug_cache_backend").with_ensure('absent') }
-    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
@@ -550,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
 
@@ -559,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
@@ -570,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
@@ -582,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
@@ -600,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
@@ -611,18 +573,8 @@ 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') }
-  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') }
+    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 enabling SSL' do
@@ -634,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
@@ -650,18 +602,19 @@ 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
@@ -676,11 +629,11 @@ describe 'keystone' do
     end
 
     it do
-      should contain_keystone_config('DEFAULT/rabbit_use_ssl').with_value('true')
-      should contain_keystone_config('DEFAULT/kombu_ssl_ca_certs').with_value('/path/to/ssl/ca/certs')
-      should contain_keystone_config('DEFAULT/kombu_ssl_certfile').with_value('/path/to/ssl/cert/file')
-      should contain_keystone_config('DEFAULT/kombu_ssl_keyfile').with_value('/path/to/ssl/keyfile')
-      should contain_keystone_config('DEFAULT/kombu_ssl_version').with_value('TLSv1')
+      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
 
@@ -696,12 +649,20 @@ describe 'keystone' do
     end
 
     it do
-      should contain_keystone_config('DEFAULT/rabbit_use_ssl').with_value('false')
-      should contain_keystone_config('DEFAULT/kombu_ssl_ca_certs').with_ensure('absent')
-      should contain_keystone_config('DEFAULT/kombu_ssl_certfile').with_ensure('absent')
-      should contain_keystone_config('DEFAULT/kombu_ssl_keyfile').with_ensure('absent')
-      should contain_keystone_config('DEFAULT/kombu_ssl_version').with_ensure('absent')
+      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
@@ -709,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
@@ -723,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
@@ -734,8 +697,8 @@ 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
@@ -748,8 +711,8 @@ describe 'keystone' do
       }
     end
 
-    it { should contain_keystone_config('DEFAULT/admin_endpoint').with_value('http://some.host:35357') }
-    it { should contain_class('keystone::service').with(
+    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'
     )}
@@ -764,7 +727,7 @@ describe 'keystone' do
       }
     end
 
-    it { should contain_class('keystone::service').with(
+    it { is_expected.to contain_class('keystone::service').with(
       'validate'       => true,
       'admin_endpoint' => 'http://some.host:35357'
     )}
@@ -779,8 +742,8 @@ 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
@@ -796,7 +759,7 @@ describe 'keystone' do
         { 'admin_token'    => 'service_token' }
       end
 
-      it { should contain_service('keystone').with(
+      it { is_expected.to contain_service('keystone').with(
         :provider => nil
       )}
     end
@@ -809,9 +772,111 @@ describe 'keystone' do
         }
       end
 
-      it { should contain_service('keystone').with(
+      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
index f2a22d6..1942395 100644 (file)
@@ -17,22 +17,22 @@ describe 'keystone::wsgi::apache' do
   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],
@@ -42,7 +42,7 @@ describe 'keystone::wsgi::apache' do
         '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],
@@ -52,7 +52,7 @@ describe 'keystone::wsgi::apache' do
         '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',
@@ -73,7 +73,7 @@ describe 'keystone::wsgi::apache' do
         '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',
@@ -93,7 +93,7 @@ describe 'keystone::wsgi::apache' do
         'wsgi_script_aliases'         => { '/' => "#{platform_parameters[:wsgi_script_path]}/main" },
         'require'                     => 'File[keystone_wsgi_main]'
       )}
-      it { should contain_file("#{platform_parameters[:httpd_ports_file]}") }
+      it { is_expected.to contain_file("#{platform_parameters[:httpd_ports_file]}") }
     end
 
     describe 'when overriding parameters using different ports' do
@@ -108,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',
@@ -129,7 +129,7 @@ describe 'keystone::wsgi::apache' do
         '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',
@@ -150,7 +150,7 @@ describe 'keystone::wsgi::apache' do
         'require'                     => 'File[keystone_wsgi_main]'
       )}
 
-      it { should contain_file("#{platform_parameters[:httpd_ports_file]}") }
+      it { is_expected.to contain_file("#{platform_parameters[:httpd_ports_file]}") }
     end
 
     describe 'when overriding parameters using same port' do
@@ -166,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',
@@ -208,6 +208,35 @@ 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]}]", "Package[keystone]"]
+      )}
+
+      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]}]", "Package[keystone]"]
+      )}
+    end
   end
 
   context 'on RedHat platforms' do
index d7d0a62..1897963 100644 (file)
@@ -36,25 +36,25 @@ describe 'keystone::resource::service_identity' do
         required_params
       end
 
-      it { should contain_keystone_user(title).with(
+      it { is_expected.to contain_keystone_user(title).with(
         :ensure   => 'present',
         :password => 'secrete',
         :email    => 'neutron@localhost',
         :tenant   => 'services',
       )}
 
-      it { should contain_keystone_user_role("#{title}@services").with(
+      it { is_expected.to contain_keystone_user_role("#{title}@services").with(
         :ensure => 'present',
-        :roles  => 'admin',
+        :roles  => ['admin'],
       )}
 
-      it { should contain_keystone_service(title).with(
+      it { is_expected.to contain_keystone_service(title).with(
         :ensure      => 'present',
         :type        => 'network',
         :description => 'neutron service',
       )}
 
-      it { should contain_keystone_endpoint("RegionOne/#{title}").with(
+      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',
@@ -66,7 +66,7 @@ describe 'keystone::resource::service_identity' do
       let :params do
         required_params.delete(:password)
       end
-      it { expect { should raise_error(Puppet::Error) } }
+      it { expect { is_expected.to raise_error(Puppet::Error) } }
     end
 
   end
index d92156a..fec0eac 100644 (file)
@@ -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
index a6c4788..78594f8 100644 (file)
@@ -4,7 +4,6 @@ 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/3rdparty/modules/keystone/spec/spec_helper_acceptance.rb b/3rdparty/modules/keystone/spec/spec_helper_acceptance.rb
new file mode 100644 (file)
index 0000000..2c2634a
--- /dev/null
@@ -0,0 +1,42 @@
+require 'beaker-rspec'
+require 'beaker/puppet_install_helper'
+
+run_puppet_install_helper
+
+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
index a0ac752..9ca5b43 100644 (file)
@@ -6,7 +6,14 @@ provider_class = Puppet::Type.type(:keystone_endpoint).provider(:openstack)
 
 describe provider_class do
 
-  describe 'when updating an endpoint' 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
       {
@@ -15,12 +22,6 @@ describe provider_class do
         :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',
-        :auth         => {
-          'username'    => 'test',
-          'password'    => 'abc123',
-          'tenant_name' => 'foo',
-          'auth_url'    => 'http://127.0.0.1:5000/v2.0',
-        }
       }
     end
 
@@ -32,16 +33,17 @@ describe provider_class do
       provider_class.new(resource)
     end
 
-    describe '#create' do
-      it 'creates an endpoint' do
-        provider.class.stubs(:openstack)
-                      .with('endpoint', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Region","Service Name","Service Type","PublicURL","AdminURL","InternalURL"
+    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', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('adminurl="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"
@@ -50,64 +52,49 @@ 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', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .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', 'delete', [['1cb05cfed7c24279be884ba4f6520262', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-        expect(provider.destroy).to be_nil # We don't really care that it's nil, only that it runs successfully
+          provider.create
+          expect(provider.exists?).to be_truthy
+        end
       end
 
-    end
-
-    describe '#exists' do
-      context 'when endpoint exists' do
-
-        subject(:response) do
+      describe '#destroy' do
+        it 'destroys an endpoint' do
           provider.class.stubs(:openstack)
-                        .with('endpoint', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
+                        .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"
+"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"
 ')
-          response = provider.exists?
+          provider.class.stubs(:openstack)
+                        .with('endpoint', 'delete', [])
+          provider.destroy
+          expect(provider.exists?).to be_falsey
         end
-
-        it { is_expected.to be_truthy }
       end
 
-      context 'when tenant does not exist' do
+      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
 
-        subject(:response) do
-          provider.class.stubs(:openstack)
-                        .with('endpoint', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                        .returns('"ID","Region","Service Name","Service Type","PublicURL","AdminURL","InternalURL"')
-          response = provider.exists?
+          it { is_expected.to be_falsey }
         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', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .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"
+      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 = provider.instances
-        expect(instances.count).to eq(1)
+          instances = Puppet::Type::Keystone_endpoint::ProviderOpenstack.instances
+          expect(instances.count).to eq(1)
+        end
       end
     end
-
   end
 end
index 179574f..09e229b 100644 (file)
@@ -6,96 +6,81 @@ provider_class = Puppet::Type.type(:keystone_role).provider(:openstack)
 
 describe provider_class do
 
-  describe 'when creating a role' 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(:role_attrs) do
-      {
-        :name         => 'foo',
-        :ensure       => 'present',
-        :auth         => {
-          'username'    => 'test',
-          'password'    => 'abc123',
-          'tenant_name' => 'foo',
-          'auth_url'    => 'http://127.0.0.1:5000/v2.0',
+  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', [['--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name"
-"1cb05cfed7c24279be884ba4f6520262","foo"
-')
-        provider.class.stubs(:openstack)
-                      .with('role', 'create', '--format', 'shell', [['foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .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', [['--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name"')
-        provider.class.stubs(:openstack)
-                      .with('role', 'delete', [['foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-        provider.destroy
-        expect(provider.exists?).to be_falsey
+      let(:resource) do
+        Puppet::Type::Keystone_role.new(role_attrs)
       end
 
-    end
-
-    describe '#exists' do
-      context 'when role exists' do
+      let(:provider) do
+        provider_class.new(resource)
+      end
 
-        subject(:response) do
+      describe '#create' do
+        it 'creates a role' do
           provider.class.stubs(:openstack)
-                        .with('role', 'list', '--quiet', '--format', 'csv', [['--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
+                        .with('role', 'list', '--quiet', '--format', 'csv', [])
                         .returns('"ID","Name"
 "1cb05cfed7c24279be884ba4f6520262","foo"
 ')
-          response = provider.exists?
+          provider.class.stubs(:openstack)
+                        .with('role', 'create', '--format', 'shell', 'foo')
+                        .returns('name="foo"')
+          provider.create
+          expect(provider.exists?).to be_truthy
         end
-
-        it { is_expected.to be_truthy }
       end
 
-      context 'when role does not exist' do
-
-        subject(:response) do
+      describe '#destroy' do
+        it 'destroys a role' do
           provider.class.stubs(:openstack)
-                        .with('role', 'list', '--quiet', '--format', 'csv', [['--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name"')
-          response = provider.exists?
+                        .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
 
-        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', [['--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name"
+      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 = provider.instances
-        expect(instances.count).to eq(1)
+          instances = Puppet::Type::Keystone_role::ProviderOpenstack.instances
+          expect(instances.count).to eq(1)
+        end
       end
     end
-
   end
 end
index 5b9814f..5a299a5 100644 (file)
@@ -6,7 +6,14 @@ provider_class = Puppet::Type.type(:keystone_service).provider(:openstack)
 
 describe provider_class do
 
-  describe 'when creating a service' 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
       {
@@ -14,12 +21,6 @@ describe provider_class do
         :description  => 'foo',
         :ensure       => 'present',
         :type         => 'foo',
-        :auth         => {
-          'username'    => 'test',
-          'password'    => 'abc123',
-          'tenant_name' => 'foo',
-          'auth_url'    => 'http://127.0.0.1:5000/v2.0',
-        }
       }
     end
 
@@ -31,78 +32,62 @@ describe provider_class do
       provider_class.new(resource)
     end
 
-    describe '#create' do
-      it 'creates a service' do
-        provider.class.stubs(:openstack)
-                      .with('service', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name","Type","Description"
+    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', [['foo', '--description', 'foo', '--type', 'foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('description="foo"
+          provider.class.stubs(:openstack)
+                        .with('service', 'create', '--format', 'shell', ['--description', 'foo', '--type', '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', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name","Type","Description"')
-        provider.class.stubs(:openstack)
-                      .with('service', 'delete', [['foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-        provider.destroy
-        expect(provider.exists?).to be_falsey
+          provider.create
+          expect(provider.exists?).to be_truthy
+        end
       end
 
-    end
-
-    describe '#exists' do
-      context 'when service exists' do
-
-        subject(:response) do
+      describe '#destroy' do
+        it 'destroys a service' do
           provider.class.stubs(:openstack)
-                        .with('service', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
+                        .with('service', 'list', '--quiet', '--format', 'csv', '--long')
                         .returns('"ID","Name","Type","Description"
 "1cb05cfed7c24279be884ba4f6520262","foo","foo","foo"
 ')
-          response = provider.exists?
-        end
-
-        it { is_expected.to be_truthy }
-      end
-
-      context 'when service does not exist' do
-
-        subject(:response) do
           provider.class.stubs(:openstack)
-                        .with('service', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                        .returns('"ID","Name","Type","Description"')
-          response = provider.exists?
+                        .with('service', 'delete', [])
+          provider.destroy
+          expect(provider.exists?).to be_falsey
         end
 
-        it { is_expected.to be_falsey }
+        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
-    end
 
-    describe '#instances' do
-      it 'finds every service' do
-        provider.class.stubs(:openstack)
-                      .with('service', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name","Type","Description"
-"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo"
+      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 = provider.instances
-        expect(instances.count).to eq(1)
+          instances = Puppet::Type::Keystone_service::ProviderOpenstack.instances
+          expect(instances.count).to eq(1)
+        end
       end
     end
-
   end
 end
index de9ceb0..4981f1e 100644 (file)
@@ -3,10 +3,11 @@ 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
@@ -21,20 +22,15 @@ describe Puppet::Provider::Keystone do
     klass.reset
   end
 
-
   describe 'when retrieving the security token' do
-
     it 'should return nothing 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)
+      File.expects(:exists?).with("/etc/keystone/keystone.conf").returns(false)
       expect(klass.get_admin_token).to be_nil
     end
 
     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(klass.get_admin_token).to be_nil
@@ -42,6 +38,7 @@ describe Puppet::Provider::Keystone do
 
     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(klass.get_admin_token).to be_nil
@@ -49,65 +46,74 @@ describe Puppet::Provider::Keystone do
 
     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')
-      klass.get_admin_endpoint.should == 'http://[::1]:35357/v2.0/'
+      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' }, '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
 
     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.get_admin_endpoint.should == 'https://keystone.example.com/v2.0/'
+      expect(klass.get_admin_endpoint).to eq('https://keystone.example.com/v2.0/')
     end
 
   end
index 11861fc..1dec49e 100644 (file)
@@ -6,7 +6,14 @@ provider_class = Puppet::Type.type(:keystone_tenant).provider(:openstack)
 
 describe provider_class do
 
-  describe 'when updating a tenant' 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
       {
@@ -14,12 +21,6 @@ describe provider_class do
         :description  => 'foo',
         :ensure       => 'present',
         :enabled      => 'True',
-        :auth         => {
-          'username'    => 'test',
-          'password'    => 'abc123',
-          'tenant_name' => 'foo',
-          'auth_url'    => 'http://127.0.0.1:5000/v2.0',
-        }
       }
     end
 
@@ -31,76 +32,59 @@ describe provider_class do
       provider_class.new(resource)
     end
 
-    describe '#create' do
-      it 'creates a tenant' do
-        provider.class.stubs(:openstack)
-                      .with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name","Description","Enabled"
+    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', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('description="foo"
+          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', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name","Description","Enabled"')
-        provider.class.stubs(:openstack)
-                      .with('project', 'delete', [['foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-        provider.destroy
-        expect(provider.exists?).to be_falsey
+          provider.create
+          expect(provider.exists?).to be_truthy
+        end
       end
 
-    end
-
-    describe '#exists' do
-      context 'when tenant exists' do
-
-        subject(:response) do
+      describe '#destroy' do
+        it 'destroys a tenant' do
           provider.class.stubs(:openstack)
-                        .with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                        .returns('"ID","Name","Description","Enabled"
-"1cb05cfed7c24279be884ba4f6520262","foo","foo",True
-')
-          response = provider.exists?
+                        .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
-
-        it { is_expected.to be_truthy }
       end
 
       context 'when tenant does not exist' do
-
         subject(:response) do
           provider.class.stubs(:openstack)
-                        .with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name","Description","Enabled"')
+                        .with('project', 'list', '--quiet', '--format', 'csv', '--long')
+                        .returns('"ID","Name","Description","Enabled"')
           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('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name","Description","Enabled"
+      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 = provider.instances
-        expect(instances.count).to eq(1)
+          instances = Puppet::Type::Keystone_tenant::ProviderOpenstack.instances
+          expect(instances.count).to eq(1)
+        end
       end
     end
-
   end
 end
index 1a74c63..3f545d0 100644 (file)
@@ -6,20 +6,21 @@ 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',
+      :ensure       => :present,
       :enabled      => 'True',
       :password     => 'foo',
       :tenant       => 'foo',
       :email        => 'foo@example.com',
-      :auth         => {
-        'username'    => 'test',
-        'password'    => 'abc123',
-        'tenant_name' => 'foo',
-        'auth_url'    => 'http://127.0.0.1:5000/v2.0',
-      }
     }
   end
 
@@ -31,175 +32,180 @@ describe provider_class do
     provider_class.new(resource)
   end
 
-  describe 'when updating a user' do
-
-    describe '#create' do
-      it 'creates a user' do
-        provider.class.stubs(:openstack)
-                      .with('user', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name","Project","Email","Enabled"
+  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', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('email="foo@example.com"
+          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', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name","Project","Email","Enabled"')
-        provider.class.stubs(:openstack)
-                      .with('user', 'delete', [['foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-        provider.destroy
-        expect(provider.exists?).to be_falsey
+          provider.create
+          expect(provider.exists?).to be_truthy
+        end
       end
 
-    end
-
-    describe '#exists' do
-      context 'when user exists' do
-
-        subject(:response) do
+      describe '#destroy' do
+        it 'destroys a user' do
           provider.class.stubs(:openstack)
-                        .with('user', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                        .returns('"ID","Name","Project","Email","Enabled"
-"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo@example.com",True
-')
-          response = provider.exists?
+                        .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
 
-        it { is_expected.to be_truthy }
       end
 
-      context 'when user does not exist' do
+      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
 
-        subject(:response) do
-          provider.class.stubs(:openstack)
-                        .with('user', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                        .returns('"ID","Name","Project","Email","Enabled"')
-          response = provider.exists?
+          it { is_expected.to be_falsey }
         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', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name","Project","Email","Enabled"
+      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 = provider.instances
-        expect(instances.count).to eq(1)
+          instances = Puppet::Type::Keystone_user::ProviderOpenstack.instances
+          expect(instances.count).to eq(1)
+        end
       end
-    end
 
-    describe '#tenant' do
-      it 'gets the tenant with default backend' do
-        provider.class.stubs(:openstack)
-                      .with('user', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name","Project","Email","Enabled"
+      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
 ')
-        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', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name","Project","Email","Enabled"
-"1cb05cfed7c24279be884ba4f6520262","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"
 ')
-        provider.class.expects(:openstack)
-                      .with('user role', 'list', '--quiet', '--format', 'csv', [['foo', '--project', 'foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name","Project","User"
-"1cb05cfed7c24279be884ba4f6520262","foo","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
 ')
-        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', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-           provider.class.expects(:openstack)
-                         .with('user role', 'list', '--quiet', '--format', 'csv', [['foo', '--project', 'bar', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                         .returns('"ID","Name","Project","User"
+                        .with('user role', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'foo'])
+                        .returns('"ID","Name","Project","User"
 "1cb05cfed7c24279be884ba4f6520262","foo","foo","foo"
 ')
-          provider.tenant=('bar')
+          tenant = provider.tenant
+          expect(tenant).to eq('foo')
         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', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-           provider.class.expects(:openstack)
-                         .with('user role', 'list', '--quiet', '--format', 'csv', [['foo', '--project', 'bar', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                         .returns('')
-          provider.class.expects(:openstack)
-                        .with('role', 'show', '--format', 'shell', [['_member_', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                        .returns('name="_member_"')
-          provider.class.expects(:openstack)
-                        .with('role', 'add', [['_member_', '--project', 'bar', '--user', 'foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-          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', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-           provider.class.expects(:openstack)
-                         .with('user role', 'list', '--quiet', '--format', 'csv', [['foo', '--project', 'bar', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                         .returns('')
-          provider.class.expects(:openstack)
-                        .with('role', 'show', '--format', 'shell', [['_member_', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                        .raises(Puppet::ExecutionFailure, 'no such role _member_')
-          provider.class.expects(:openstack)
-                        .with('role', 'create', '--format', 'shell', [['_member_', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])                      
-                        .returns('name="_member_"')
-          provider.class.expects(:openstack)
-                        .with('role', 'add', [['_member_', '--project', 'bar', '--user', 'foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-          provider.tenant=('bar')
+
+      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
-      end
-      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', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                        .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', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                         .returns('')
-          provider.class.expects(:openstack)
-                        .with('role', 'show', '--format', 'shell', [['_member_', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                        .returns('name="_member_"')
-          provider.class.expects(:openstack)
-                        .with('role', 'add', [['_member_', '--project', 'bar', '--user', 'foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-          provider.tenant=('bar')
+
+        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
-        it 'sets the tenant and gets an unexpected exception message' do
-          provider.class.expects(:openstack)
-                        .with('user', 'set', [['foo', '--project', 'bar', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                        .raises(Puppet::ExecutionFailure, 'unknown error message')
-          expect{ provider.tenant=('bar') }.to raise_error(Puppet::ExecutionFailure, /unknown error message/)
+
+# 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
@@ -211,44 +217,41 @@ username="foo"
         :password     => 'foo',
         :tenant       => 'foo',
         :email        => 'foo@example.com',
-        :auth         => {
-          'username'    => 'test',
-          'password'    => 'abc123',
-          'tenant_name' => 'foo',
-          'auth_url'    => 'https://127.0.0.1:5000/v2.0',
-        }
       }
     end
 
-    it 'checks the password with HTTPS' do
-      httpobj = mock('Net::HTTP')
-      httpobj.stubs(:use_ssl=).with(true)
-      httpobj.stubs(:verify_mode=)
-      Net::HTTP.stubs(:start).returns(httpobj)
-      reqobj = mock('Net::HTTP::Post')
-      reqobj.stubs(:body=)
-      reqobj.stubs(:content_type=)
-      Net::HTTP::Post.stubs(:start).returns(reqobj)
-      respobj = mock('Net::HTTPResponse')
-      respobj.stubs(:code).returns('200')
-      httpobj.stubs(:request).returns(respobj)
-      password = provider.password
-      expect(password).to eq('foo')
+    let(:resource) do
+      Puppet::Type::Keystone_user.new(user_attrs)
     end
-    it 'fails the password check with HTTPS' do
-      httpobj = mock('Net::HTTP')
-      httpobj.stubs(:use_ssl=).with(true)
-      httpobj.stubs(:verify_mode=)
-      Net::HTTP.stubs(:start).returns(httpobj)
-      reqobj = mock('Net::HTTP::Post')
-      reqobj.stubs(:body=)
-      reqobj.stubs(:content_type=)
-      Net::HTTP::Post.stubs(:start).returns(reqobj)
-      respobj = mock('Net::HTTPResponse')
-      respobj.stubs(:code).returns('401')
-      httpobj.stubs(:request).returns(respobj)
-      password = provider.password
-      expect(password).to eq(nil)
+
+    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
@@ -262,23 +265,9 @@ username="foo"
           :replace_password => 'False',
           :tenant           => 'foo',
           :email            => 'foo@example.com',
-          :auth             => {
-            'username'      => 'test',
-            'password'      => 'abc123',
-            'tenant_name'   => 'foo',
-            'auth_url'      => 'http://127.0.0.1:5000/v2.0',
-          }
         }
       end
 
-      let(:resource) do
-        Puppet::Type::Keystone_user.new(user_attrs)
-      end
-
-      let :provider do
-        provider_class.new(resource)
-      end
-
       it 'should not try to check password' do
         expect(provider.password).to eq('foo')
       end
index f3c35dc..2490adc 100644 (file)
@@ -6,89 +6,84 @@ provider_class = Puppet::Type.type(:keystone_user_role).provider(:openstack)
 
 describe provider_class do
 
-  describe 'when updating a user\'s role' 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_role_attrs) do
-      {
-        :name         => 'foo@example.com@foo',
-        :ensure       => 'present',
-        :roles        => ['foo', 'bar'],
-        :auth         => {
-          'username'    => 'test',
-          'password'    => 'abc123',
-          'tenant_name' => 'foo',
-          'auth_url'    => 'http://127.0.0.1:5000/v2.0',
+  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
+      end
 
-    let(:provider) do
-      provider_class.new(resource)
-    end
+      let(:resource) do
+        Puppet::Type::Keystone_user_role.new(user_role_attrs)
+      end
 
-    before(:each) do
-      provider.class.stubs(:openstack)
-                    .with('user', 'list', '--quiet', '--format', 'csv', [['--project', 'foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                    .returns('"ID","Name"
-"1cb05cfed7c24279be884ba4f6520262","foo@example.com"
-')
-      provider.class.stubs(:openstack)
-                    .with('project', 'list', '--quiet', '--format', 'csv', [['--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                    .returns('"ID","Name"
-"1cb05cfed7c24279be884ba4f6520262","foo"
-')
-    end
+      let(:provider) do
+        provider_class.new(resource)
+      end
 
-    describe '#create' do
-      it 'adds all the roles to the user' do
+      before(:each) do
         provider.class.stubs(:openstack)
-                      .with('user role', 'list', '--quiet', '--format', 'csv', [['--project', 'foo', 'foo@example.com', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
+                      .with('user', 'list', '--quiet', '--format', 'csv', ['foo', '--project', 'foo'])
                       .returns('"ID","Name","Project","User"
-"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo@example.com"
-"1cb05cfed7c24279be884ba4f6520263","bar","foo","foo@example.com"
+"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo"
 ')
-        provider.class.stubs(:openstack)
-                      .with('role', 'add', [['foo', '--project', 'foo', '--user', 'foo@example.com', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-        provider.class.stubs(:openstack)
-                      .with('role', 'add', [['bar', '--project', 'foo', '--user', 'foo@example.com', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-        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', [['--project', 'foo', 'foo@example.com', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name","Project","User"')
-        provider.class.stubs(:openstack)
-                      .with('role', 'remove', [['foo', '--project', 'foo', '--user', 'foo@example.com', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-        provider.class.stubs(:openstack)
-                      .with('role', 'remove', [['bar', '--project', 'foo', '--user', 'foo@example.com', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-        provider.destroy
-        expect(provider.exists?).to be_falsey
+      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
 
-    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
 
-    describe '#exists' do
-      subject(:response) do
-        provider.class.stubs(:openstack)
-                      .with('user role', 'list', '--quiet', '--format', 'csv', [['--project', 'foo', 'foo@example.com', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name","Project","User"
-"1cb05ed7c24279be884ba4f6520262","foo","foo","foo@example.com"
-"1cb05ed7c24279be884ba4f6520262","bar","foo","foo@example.com"
-')
-        response = provider.exists?
       end
 
-      it { is_expected.to be_truthy }
+      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
 
-    end
+        it { is_expected.to be_truthy }
 
+      end
+    end
   end
 end
diff --git a/3rdparty/modules/keystone/spec/unit/provider/openstack_spec.rb b/3rdparty/modules/keystone/spec/unit/provider/openstack_spec.rb
deleted file mode 100644 (file)
index fa431fd..0000000
+++ /dev/null
@@ -1,261 +0,0 @@
-# TODO: This should be extracted into openstacklib during the Kilo cycle
-# Load libraries from aviator here to simulate how they live together in a real puppet run
-$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'modules', 'aviator', 'lib'))
-require 'puppet'
-require 'spec_helper'
-require 'puppet/provider/openstack'
-
-
-describe Puppet::Provider::Openstack do
-
-  before(:each) do
-    ENV['OS_USERNAME']    = nil
-    ENV['OS_PASSWORD']    = nil
-    ENV['OS_TENANT_NAME'] = nil
-    ENV['OS_AUTH_URL']    = nil
-  end
-
-  let(:type) do
-    Puppet::Type.newtype(:test_resource) do
-      newparam(:name, :namevar => true)
-      newparam(:auth)
-      newparam(:log_file)
-    end
-  end
-
-  shared_examples 'authenticating with environment variables' do
-    it 'makes a successful request' do
-      ENV['OS_USERNAME']    = 'test'
-      ENV['OS_PASSWORD']    = 'abc123'
-      ENV['OS_TENANT_NAME'] = 'test'
-      ENV['OS_AUTH_URL']    = 'http://127.0.0.1:35357/v2.0'
-      if provider.class == Class
-        provider.stubs(:openstack)
-                .with('project', 'list', '--quiet', '--format', 'csv', [[ '--long' ]])
-                .returns('"ID","Name","Description","Enabled"
-"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
-')
-      else
-        provider.class.stubs(:openstack)
-                    .with('project', 'list', '--quiet', '--format', 'csv', [[ '--long' ]])
-                    .returns('"ID","Name","Description","Enabled"
-"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
-')
-      end
-      response = provider.request('project', 'list', nil, nil, '--long' )
-      expect(response.first[:description]).to match /Test tenant/
-    end
-  end
-
-  shared_examples 'it has no credentials' do
-    it 'fails to authenticate' do
-      expect{ provider.request('project', 'list', nil, nil, '--long') }.to raise_error(Puppet::Error::OpenstackAuthInputError, /No credentials provided/)
-    end
-  end
-
-  describe '#request' do
-
-    context 'with valid password credentials in parameters' do
-      let(:resource_attrs) do
-        {
-          :name         => 'stubresource',
-          :auth         => {
-            'username'    => 'test',
-            'password'    => 'abc123',
-            'tenant_name' => 'test',
-            'auth_url'    => 'http://127.0.0.1:5000/v2.0',
-          }
-        }
-      end
-      let(:provider) do
-        Puppet::Provider::Openstack.new(type.new(resource_attrs))
-      end
-
-      it 'makes a successful request' do
-        provider.class.stubs(:openstack)
-                      .with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'test', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name","Description","Enabled"
-"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
-')
-        response = provider.request('project', 'list', nil, resource_attrs[:auth], '--long')
-        expect(response.first[:description]).to match /Test tenant/
-      end
-    end
-
-    context 'with valid openrc file in parameters' do
-      mock = "export OS_USERNAME='test'\nexport OS_PASSWORD='abc123'\nexport OS_TENANT_NAME='test'\nexport OS_AUTH_URL='http://127.0.0.1:5000/v2.0'"
-      let(:resource_attrs) do
-        {
-          :name         => 'stubresource',
-          :auth         => {
-            'openrc' => '/root/openrc'
-          }
-        }
-      end
-      let(:provider) do
-        Puppet::Provider::Openstack.new(type.new(resource_attrs))
-      end
-
-      it 'makes a successful request' do
-        File.expects(:open).with('/root/openrc').returns(StringIO.new(mock))
-        provider.class.stubs(:openstack)
-                      .with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'test', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name","Description","Enabled"
-"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
-')
-        response = provider.request('project', 'list', nil, resource_attrs[:auth], '--long')
-        expect(response.first[:description]).to match /Test tenant/
-      end
-    end
-
-    context 'with valid service token in parameters' do
-      let(:resource_attrs) do
-        {
-          :name         => 'stubresource',
-          :auth         => {
-            'token' => 'secrettoken',
-            'auth_url'      => 'http://127.0.0.1:5000/v2.0'
-          }
-        }
-      end
-      let(:provider) do
-        Puppet::Provider::Openstack.new(type.new(resource_attrs))
-      end
-
-      it 'makes a successful request' do
-        provider.class.stubs(:openstack)
-                      .with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-token', 'secrettoken', '--os-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('"ID","Name","Description","Enabled"
-"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
-')
-        response = provider.request('project', 'list', nil, resource_attrs[:auth], '--long')
-        expect(response.first[:description]).to match /Test tenant/
-      end
-
-      it 'makes a successful show request' do
-        provider.class.stubs(:openstack)
-                      .with('project', 'show', '--format', 'shell', [['test', '--os-token', 'secrettoken', '--os-url', 'http://127.0.0.1:5000/v2.0']])
-                      .returns('ID="1cb05cfed7c24279be884ba4f6520262"
-Name="test"
-Description="Test Tenant"
-Enabled="True"
-')
-        response = provider.request('project', 'show', 'test', resource_attrs[:auth])
-        expect(response[:description]).to match /Test Tenant/
-        expect(response[:id]).to match /1cb05cfed7c24279be884ba4f6520262/
-        expect(response[:name]).to match /test/
-        expect(response[:enabled]).to match /True/
-      end
-
-    end
-
-    context 'with valid password credentials in environment variables' do
-      it_behaves_like 'authenticating with environment variables' do
-        let(:resource_attrs) do
-          {
-            :name => 'stubresource',
-          }
-        end
-        let(:provider) do
-          Puppet::Provider::Openstack.new(type.new(resource_attrs))
-        end
-      end
-    end
-
-    context 'with no valid credentials' do
-      it_behaves_like 'it has no credentials' do
-        let(:resource_attrs) do
-          {
-            :name => 'stubresource',
-          }
-        end
-        let(:provider) do
-          Puppet::Provider::Openstack.new(type.new(resource_attrs))
-        end
-      end
-    end
-
-    context 'it retries on connection errors' do
-      let(:resource_attrs) do
-        {
-          :name         => 'stubresource',
-          :auth         => {
-            'username'    => 'test',
-            'password'    => 'abc123',
-            'tenant_name' => 'test',
-            'auth_url'    => 'http://127.0.0.1:5000/v2.0',
-          }
-        }
-      end
-      let(:provider) do
-        Puppet::Provider::Openstack.new(type.new(resource_attrs))
-      end
-      it 'retries' do
-        provider.class.stubs(:openstack)
-                      .with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'test', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']])
-                      .raises(Puppet::ExecutionFailure, 'Unable to establish connection')
-                      .then
-                      .returns('')
-        provider.class.expects(:sleep).with(2).returns(nil)
-        provider.request('project', 'list', nil, resource_attrs[:auth], '--long')
-      end
-    end
-  end
-
-
-  describe '::request' do
-
-    context 'with valid password credentials in environment variables' do
-      it_behaves_like 'authenticating with environment variables' do
-        let(:resource_attrs) do
-          {
-            :name => 'stubresource',
-          }
-        end
-        let(:provider) do
-          Puppet::Provider::Openstack.dup
-        end
-      end
-    end
-
-    context 'with no valid credentials' do
-      it_behaves_like 'it has no credentials' do
-        let(:provider) { Puppet::Provider::Openstack.dup }
-      end
-    end
-
-  end
-
-  describe 'parse_csv' do
-    context 'with mixed stderr' do
-      text = "ERROR: Testing\n\"field\",\"test\",1,2,3\n"
-      csv = Puppet::Provider::Openstack.parse_csv(text)
-      it 'should ignore non-CSV text at the beginning of the input' do
-        expect(csv).to be_kind_of(Array)
-        expect(csv[0]).to match_array(['field', 'test', '1', '2', '3'])
-        expect(csv.size).to eq(1)
-      end
-    end
-
-    context 'with \r\n line endings' do
-      text = "ERROR: Testing\r\n\"field\",\"test\",1,2,3\r\n"
-      csv = Puppet::Provider::Openstack.parse_csv(text)
-      it 'ignore the carriage returns' do
-        expect(csv).to be_kind_of(Array)
-        expect(csv[0]).to match_array(['field', 'test', '1', '2', '3'])
-        expect(csv.size).to eq(1)
-      end
-    end
-
-    context 'with embedded newlines' do
-      text = "ERROR: Testing\n\"field\",\"te\nst\",1,2,3\n"
-      csv = Puppet::Provider::Openstack.parse_csv(text)
-      it 'should parse correctly' do
-        expect(csv).to be_kind_of(Array)
-        expect(csv[0]).to match_array(['field', "te\nst", '1', '2', '3'])
-        expect(csv.size).to eq(1)
-      end
-    end
-  end
-
-end
index ddd3355..c3a3fbb 100644 (file)
@@ -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/",
   }
diff --git a/3rdparty/modules/openstacklib/CHANGELOG.md b/3rdparty/modules/openstacklib/CHANGELOG.md
new file mode 100644 (file)
index 0000000..944eb5d
--- /dev/null
@@ -0,0 +1,19 @@
+##2015-06-17 - 5.1.0
+###Summary
+
+This is a feature and bugfix release in the Juno series.
+
+####Features
+- Adding augeas insertion check
+
+####Bugfixes
+- MySQL: change default MySQL collate to utf8_general_ci
+
+####Maintenance
+- Update .gitreview file for project rename
+- spec: pin rspec-puppet to 1.0.1
+
+##2014-11-25 - 5.0.0
+###Summary
+
+Initial release for Juno.
index fedea52..1fce4aa 100644 (file)
@@ -2,15 +2,24 @@ source 'https://rubygems.org'
 
 group :development, :test do
   gem 'puppetlabs_spec_helper', :require => false
+  gem 'rspec-puppet', '~> 2.1.0', :require => false
+
+  gem 'puppet-lint', '~> 1.1.0'
   gem 'metadata-json-lint'
-  gem 'puppet-lint', '~> 0.3.2'
-  gem 'rspec-puppet', '~> 1.0.1'
-  gem 'rake', '10.1.1'
-  gem 'rspec'
+  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 'beaker-rspec', :require => false
   gem 'mocha'
   gem 'json'
-  gem 'faraday', '0.8.8',       :require => false
-  gem 'vcr',                    :require => false
 end
 
 if puppetversion = ENV['PUPPET_GEM_VERSION']
index 7aaad11..88a11a0 100644 (file)
-                                 Apache License
-                           Version 2.0, January 2004
-                        http://www.apache.org/licenses/
+Copyright 2012 OpenStack Foundation
 
-   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+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
 
-   1. Definitions.
+    http://www.apache.org/licenses/LICENSE-2.0
 
-      "License" shall mean the terms and conditions for use, reproduction,
-      and distribution as defined by Sections 1 through 9 of this document.
-
-      "Licensor" shall mean the copyright owner or entity authorized by
-      the copyright owner that is granting the License.
-
-      "Legal Entity" shall mean the union of the acting entity and all
-      other entities that control, are controlled by, or are under common
-      control with that entity. For the purposes of this definition,
-      "control" means (i) the power, direct or indirect, to cause the
-      direction or management of such entity, whether by contract or
-      otherwise, or (ii) ownership of fifty percent (50%) or more of the
-      outstanding shares, or (iii) beneficial ownership of such entity.
-
-      "You" (or "Your") shall mean an individual or Legal Entity
-      exercising permissions granted by this License.
-
-      "Source" form shall mean the preferred form for making modifications,
-      including but not limited to software source code, documentation
-      source, and configuration files.
-
-      "Object" form shall mean any form resulting from mechanical
-      transformation or translation of a Source form, including but
-      not limited to compiled object code, generated documentation,
-      and conversions to other media types.
-
-      "Work" shall mean the work of authorship, whether in Source or
-      Object form, made available under the License, as indicated by a
-      copyright notice that is included in or attached to the work
-      (an example is provided in the Appendix below).
-
-      "Derivative Works" shall mean any work, whether in Source or Object
-      form, that is based on (or derived from) the Work and for which the
-      editorial revisions, annotations, elaborations, or other modifications
-      represent, as a whole, an original work of authorship. For the purposes
-      of this License, Derivative Works shall not include works that remain
-      separable from, or merely link (or bind by name) to the interfaces of,
-      the Work and Derivative Works thereof.
-
-      "Contribution" shall mean any work of authorship, including
-      the original version of the Work and any modifications or additions
-      to that Work or Derivative Works thereof, that is intentionally
-      submitted to Licensor for inclusion in the Work by the copyright owner
-      or by an individual or Legal Entity authorized to submit on behalf of
-      the copyright owner. For the purposes of this definition, "submitted"
-      means any form of electronic, verbal, or written communication sent
-      to the Licensor or its representatives, including but not limited to
-      communication on electronic mailing lists, source code control systems,
-      and issue tracking systems that are managed by, or on behalf of, the
-      Licensor for the purpose of discussing and improving the Work, but
-      excluding communication that is conspicuously marked or otherwise
-      designated in writing by the copyright owner as "Not a Contribution."
-
-      "Contributor" shall mean Licensor and any individual or Legal Entity
-      on behalf of whom a Contribution has been received by Licensor and
-      subsequently incorporated within the Work.
-
-   2. Grant of Copyright License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      copyright license to reproduce, prepare Derivative Works of,
-      publicly display, publicly perform, sublicense, and distribute the
-      Work and such Derivative Works in Source or Object form.
-
-   3. Grant of Patent License. Subject to the terms and conditions of
-      this License, each Contributor hereby grants to You a perpetual,
-      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
-      (except as stated in this section) patent license to make, have made,
-      use, offer to sell, sell, import, and otherwise transfer the Work,
-      where such license applies only to those patent claims licensable
-      by such Contributor that are necessarily infringed by their
-      Contribution(s) alone or by combination of their Contribution(s)
-      with the Work to which such Contribution(s) was submitted. If You
-      institute patent litigation against any entity (including a
-      cross-claim or counterclaim in a lawsuit) alleging that the Work
-      or a Contribution incorporated within the Work constitutes direct
-      or contributory patent infringement, then any patent licenses
-      granted to You under this License for that Work shall terminate
-      as of the date such litigation is filed.
-
-   4. Redistribution. You may reproduce and distribute copies of the
-      Work or Derivative Works thereof in any medium, with or without
-      modifications, and in Source or Object form, provided that You
-      meet the following conditions:
-
-      (a) You must give any other recipients of the Work or
-          Derivative Works a copy of this License; and
-
-      (b) You must cause any modified files to carry prominent notices
-          stating that You changed the files; and
-
-      (c) You must retain, in the Source form of any Derivative Works
-          that You distribute, all copyright, patent, trademark, and
-          attribution notices from the Source form of the Work,
-          excluding those notices that do not pertain to any part of
-          the Derivative Works; and
-
-      (d) If the Work includes a "NOTICE" text file as part of its
-          distribution, then any Derivative Works that You distribute must
-          include a readable copy of the attribution notices contained
-          within such NOTICE file, excluding those notices that do not
-          pertain to any part of the Derivative Works, in at least one
-          of the following places: within a NOTICE text file distributed
-          as part of the Derivative Works; within the Source form or
-          documentation, if provided along with the Derivative Works; or,
-          within a display generated by the Derivative Works, if and
-          wherever such third-party notices normally appear. The contents
-          of the NOTICE file are for informational purposes only and
-          do not modify the License. You may add Your own attribution
-          notices within Derivative Works that You distribute, alongside
-          or as an addendum to the NOTICE text from the Work, provided
-          that such additional attribution notices cannot be construed
-          as modifying the License.
-
-      You may add Your own copyright statement to Your modifications and
-      may provide additional or different license terms and conditions
-      for use, reproduction, or distribution of Your modifications, or
-      for any such Derivative Works as a whole, provided Your use,
-      reproduction, and distribution of the Work otherwise complies with
-      the conditions stated in this License.
-
-   5. Submission of Contributions. Unless You explicitly state otherwise,
-      any Contribution intentionally submitted for inclusion in the Work
-      by You to the Licensor shall be under the terms and conditions of
-      this License, without any additional terms or conditions.
-      Notwithstanding the above, nothing herein shall supersede or modify
-      the terms of any separate license agreement you may have executed
-      with Licensor regarding such Contributions.
-
-   6. Trademarks. This License does not grant permission to use the trade
-      names, trademarks, service marks, or product names of the Licensor,
-      except as required for reasonable and customary use in describing the
-      origin of the Work and reproducing the content of the NOTICE file.
-
-   7. Disclaimer of Warranty. Unless required by applicable law or
-      agreed to in writing, Licensor provides the Work (and each
-      Contributor provides its Contributions) on an "AS IS" BASIS,
-      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
-      implied, including, without limitation, any warranties or conditions
-      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
-      PARTICULAR PURPOSE. You are solely responsible for determining the
-      appropriateness of using or redistributing the Work and assume any
-      risks associated with Your exercise of permissions under this License.
-
-   8. Limitation of Liability. In no event and under no legal theory,
-      whether in tort (including negligence), contract, or otherwise,
-      unless required by applicable law (such as deliberate and grossly
-      negligent acts) or agreed to in writing, shall any Contributor be
-      liable to You for damages, including any direct, indirect, special,
-      incidental, or consequential damages of any character arising as a
-      result of this License or out of the use or inability to use the
-      Work (including but not limited to damages for loss of goodwill,
-      work stoppage, computer failure or malfunction, or any and all
-      other commercial damages or losses), even if such Contributor
-      has been advised of the possibility of such damages.
-
-   9. Accepting Warranty or Additional Liability. While redistributing
-      the Work or Derivative Works thereof, You may choose to offer,
-      and charge a fee for, acceptance of support, warranty, indemnity,
-      or other liability obligations and/or rights consistent with this
-      License. However, in accepting such obligations, You may act only
-      on Your own behalf and on Your sole responsibility, not on behalf
-      of any other Contributor, and only if You agree to indemnify,
-      defend, and hold each Contributor harmless for any liability
-      incurred by, or claims asserted against, such Contributor by reason
-      of your accepting any such warranty or additional liability.
-
-   END OF TERMS AND CONDITIONS
-
-   APPENDIX: How to apply the Apache License to your work.
-
-      To apply the Apache License to your work, attach the following
-      boilerplate notice, with the fields enclosed by brackets "[]"
-      replaced with your own identifying information. (Don't include
-      the brackets!) The text should be enclosed in the appropriate
-      comment syntax for the file format. We also recommend that a
-      file or class name and description of purpose be included on the
-      same "printed page" as the copyright notice for easier
-      identification within third-party archives.
-
-   Copyright 2014 Puppet Labs Inc
-
-   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.
+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.
index 4e9b7ae..90fb090 100644 (file)
@@ -11,7 +11,6 @@ openstacklib
 5. [Limitations - OS compatibility, etc.](#limitations)
 6. [Development - Guide for contributing to the module](#development)
 7. [Contributors - Those with commits](#contributors)
-8. [Release Notes - Notes on the most recent updates to the module](#release-notes)
 
 Overview
 --------
@@ -120,6 +119,60 @@ array or string; optional; default to undef
 Privileges given to the database user;
 string or array of strings; optional; default to 'ALL'
 
+#### Defined type: openstacklib::db::postgresql
+
+The db::postgresql resource is a library resource that can be used by nova,
+cinder, ceilometer, etc., to create a postgresql database and a user with
+configurable privileges.
+
+Typically this resource will be declared with a notify parameter to configure
+the sync command to execute when the database resource is changed.
+
+For example, in heat::db::postgresql you might declare:
+
+```
+::openstacklib::db::postgresql { $dbname:
+  password_hash => postgresql_password($user, $password),
+  dbname        => $dbname,
+  user          => $user,
+  notify        => Exec['heat-dbsync'],
+}
+```
+
+Some modules should ensure that the database is created before the service is
+set up. For example, in keystone::db::postgresql you would have:
+
+```
+::openstacklib::db::postgresql { $dbname:
+  password_hash => postgresql_password($user, $password),
+  dbname        => $dbname,
+  user          => $user,
+  notify        => Exec['keystone-manage db_sync'],
+  before        => Service['keystone'],
+}
+```
+
+** Parameters for openstacklib::db::postgresql: **
+
+#####`password_hash`
+Password hash to use for the database user for this service;
+string; required
+
+#####`dbname`
+The name of the database
+string; optional; default to the $title of the resource, i.e. 'nova'
+
+#####`user`
+The database user to create;
+string; optional; default to the $title of the resource, i.e. 'nova'
+
+#####`encoding`
+The encoding use for the database;
+string; optional; default to undef
+
+#####`privileges`
+Privileges given to the database user;
+string or array of strings; optional; default to 'ALL'
 
 #### Defined type: openstacklib::service_validation
 
@@ -228,7 +281,23 @@ configuration and extra functionality through types and providers.
 Limitations
 -----------
 
-* Limitations will be added as they are discovered.
+The python-migrate system package for RHEL 6 and below is out of date and may
+fail to correctly migrate postgresql databases. While this module does not
+handle database migrations, it is common to set up refresh relationships
+between openstacklib::db::postgresql resource and the database sync exec
+resource. Relying on this behavior may cause errors.
+
+Beaker-Rspec
+------------
+
+This module has beaker-rspec tests
+
+To run:
+
+```shell
+bundle install
+bundle exec rspec spec/acceptance
+```
 
 Development
 -----------
@@ -255,17 +324,3 @@ Puppet Module :: OpenStack Version :: OpenStack Codename
 4.0.0         -> 2014.1.0          -> Icehouse
 5.0.0         -> 2014.2.0          -> Juno
 ```
-
-Release Notes
--------------
-
-**5.1.0**
-
-* Update .gitreview file for project rename
-* Adding augeas insertion check
-* MySQL: change default MySQL collate to utf8_general_ci
-* spec: pin rspec-puppet to 1.0.1
-
-**5.0.0**
-
-* This is the initial release of this module.
diff --git a/3rdparty/modules/openstacklib/checksums.json b/3rdparty/modules/openstacklib/checksums.json
deleted file mode 100644 (file)
index c808945..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-{
-  "Gemfile": "2c4e4ae399db74816aafb47dbc3951a5",
-  "LICENSE": "53173ea25085d832ebb1e9d131dc645d",
-  "README.md": "023e14103588e6eb16aee599338f0798",
-  "Rakefile": "a61c67fc9275174b6d502c7a97d58fba",
-  "lib/puppet/parser/functions/os_database_connection.rb": "f50c5c418a4745f67b863351aa421371",
-  "lib/puppet/provider/aviator.rb": "dfec34e1929a1bb260d26b5382d596a2",
-  "lib/puppet/util/aviator.rb": "6a2f5145b59f2011f04b9598db4d66d6",
-  "manifests/db/mysql/host_access.pp": "0d4b41a44213cd2cae0febe63032b74e",
-  "manifests/db/mysql.pp": "4b2ac1ae2ef9c32c2bdcf5330faa2c85",
-  "manifests/messaging/rabbitmq.pp": "4f2a699c774c57aa645ef7300c87eb9c",
-  "manifests/policy/base.pp": "9fcbf53d8442a2e258cbe1260ac6dc6b",
-  "manifests/policy.pp": "843e98d897e3df8d8d70f8017f7b6e6e",
-  "manifests/service_validation.pp": "7b0ed110553298231d947a131e2570f5",
-  "metadata.json": "a1e6434b728214cb8a0f235468260e86",
-  "spec/classes/init_spec.rb": "62493b66358f3c7acf24b0cfe8a98391",
-  "spec/classes/openstacklib_policy_spec.rb": "806f398cc4a8a9cf11c005608879374c",
-  "spec/defines/openstacklib_db_mysql_host_access_spec.rb": "4e498ba905f57bebc98480207f73e253",
-  "spec/defines/openstacklib_db_mysql_spec.rb": "edac2c0018bb0baaf4b55920b39564e6",
-  "spec/defines/openstacklib_messaging_rabbitmq_spec.rb": "7551d7034f07951fff7cd28ca05adf42",
-  "spec/defines/openstacklib_policy_spec.rb": "6fc8d604b44f2c559bcd2222210031b3",
-  "spec/defines/openstacklib_service_validation_spec.rb": "cbb6e09a2c2bca9b04d699e3509b4827",
-  "spec/fixtures/vcr/aviator/request/with_session.yml": "36b855c8d25e2652a711b4d76ab16b20",
-  "spec/fixtures/vcr/aviator/request/without_session.yml": "ab811807ab346574e7cab61bf111be20",
-  "spec/fixtures/vcr/aviator/session/with_password.yml": "4ceea78a734539233b9de4fe60cb856c",
-  "spec/fixtures/vcr/aviator/session/with_token.yml": "ab811807ab346574e7cab61bf111be20",
-  "spec/functions/os_database_connection_spec.rb": "0cfa88f055785516f56672b1f773a461",
-  "spec/spec_helper.rb": "93f9c20dc020eba3bc244c347b8e5d34",
-  "spec/unit/provider/aviator_spec.rb": "2d736d88dbcd3bb2b4960067df71d51f"
-}
\ No newline at end of file
diff --git a/3rdparty/modules/openstacklib/lib/puppet/provider/aviator.rb b/3rdparty/modules/openstacklib/lib/puppet/provider/aviator.rb
deleted file mode 100644 (file)
index 8de1bf2..0000000
+++ /dev/null
@@ -1,297 +0,0 @@
-require 'puppet'
-require 'puppet/feature/aviator'
-require 'puppet/util/inifile'
-
-class Puppet::Provider::Aviator < Puppet::Provider
-
-  def session
-    @session ||= authenticate(resource[:auth], resource[:log_file])
-  end
-
-  def self.session
-    @session ||= authenticate(nil, nil)
-  end
-
-  def request(service, request, &block)
-    self.class.make_request(service, request, session_data, &block)
-  end
-
-  def self.request(service, request, &block)
-    self.make_request(service, request, session_data, &block)
-  end
-
-  # needed for tests
-  def session_data
-    @session_data
-  end
-
-  def self.session_data
-    @session_data
-  end
-
-  def session_data=(data)
-    @session_data=data
-  end
-
-  def self.session_data=(data)
-    @session_data=data
-  end
-
-  private
-
-  # Attempt to find credentials in this order:
-  # 1. username,password,tenant,host set in type parameters
-  # 2. openrc file path set in type parameters
-  # 3. service token and host set in type parameters
-  # 4. username,password,tenant,host set in environment variables
-  # 5. service token and host set in keystone.conf (backwards compatible version)
-  def authenticate(auth_params, log_file)
-    auth_params ||= {}
-    if password_credentials_set?(auth_params)
-      @session = get_authenticated_session(auth_params, log_file)
-
-    elsif openrc_set?(auth_params)
-      credentials = get_credentials_from_openrc(auth_params['openrc'])
-      @session = get_authenticated_session(credentials, log_file)
-
-    elsif service_credentials_set?(auth_params)
-      session_hash = get_unauthenticated_session(auth_params, log_file)
-      @session_data = session_hash[:data]
-      @session = session_hash[:session]
-
-    elsif env_vars_set?
-      credentials = get_credentials_from_env
-      @session = get_authenticated_session(credentials, log_file)
-
-    else  # Last effort: try to get the token from keystone.conf
-      session_hash = self.class.try_auth_with_token(keystone_file, log_file)
-      @session_data = session_hash[:data]
-      @session = session_hash[:session]
-    end
-  end
-
-  def self.authenticate(auth_params, log_file)
-    auth_params = {} unless auth_params
-    if env_vars_set?
-      credentials = get_credentials_from_env
-      @session = get_authenticated_session(credentials, log_file)
-
-    else  # Last effort: try to get the token from keystone.conf
-      session_hash = try_auth_with_token(keystone_file, log_file)
-      @session_data = session_hash[:data]
-      @session = session_hash[:session]
-    end
-  end
-
-
-  def self.try_auth_with_token(conf_file, log_file)
-    service_token = get_admin_token_from_keystone_file(conf_file)
-    auth_url = get_auth_url_from_keystone_file(conf_file)
-    session_hash = {}
-    if service_token
-      credentials = {
-        'service_token' => service_token,
-        'host_uri'      => auth_url,
-      }
-      session_hash = get_unauthenticated_session(credentials, log_file)
-    else  # All authentication efforts failed
-      raise(Puppet::Error, 'No credentials provided.')
-    end
-  end
-
-
-  def self.make_request(service, request, session_data, &block)
-    response = nil
-    if service && service.default_session_data
-      response = service.request(request, :endpoint_type => 'admin') do |params|
-        yield(params) if block
-      end
-    elsif session_data
-      response = service.request(request, :endpoint_type => 'admin',
-                                 :session_data => session_data) do |params|
-        yield(params) if block
-      end
-    else
-      raise(Puppet::Error, 'Cannot make a request with no session data.')
-    end
-    if response.body.hash['error']
-      raise(Puppet::Error, "Error making request: #{response.body.hash['error']['code']} #{response.body.hash['error']['title']}")
-    end
-    response
-  end
-
-
-  def password_credentials_set?(auth_params)
-    auth_params['username'] && auth_params['password'] && auth_params['tenant_name'] && auth_params['host_uri']
-  end
-
-
-  def openrc_set?(auth_params)
-    auth_params['openrc']
-  end
-
-
-  def service_credentials_set?(auth_params)
-    auth_params['service_token'] && auth_params['host_uri']
-  end
-
-
-  def self.env_vars_set?
-    ENV['OS_USERNAME'] && ENV['OS_PASSWORD'] && ENV['OS_TENANT_NAME'] && ENV['OS_AUTH_URL']
-  end
-
-
-  def env_vars_set?
-    self.class.env_vars_set?
-  end
-
-
-  def get_credentials_from_openrc(file)
-    creds = {}
-    begin
-      File.open(file).readlines.delete_if{|l| l=~ /^#/}.each do |line|
-        key, value = line.split('=')
-        key = key.split(' ').last
-        value = value.chomp.gsub(/'/, '')
-        creds[key] = value
-      end
-      return creds
-    rescue Exception => error
-      return {}
-    end
-  end
-
-
-  def self.get_credentials_from_env
-    ENV.to_hash.dup.delete_if { |key, _| ! (key =~ /^OS/) } # Ruby 1.8.7
-  end
-
-  def get_credentials_from_env
-    self.class.get_credentials_from_env
-  end
-
-
-  def self.keystone_file
-    keystone_file = Puppet::Util::IniConfig::File.new
-    keystone_file.read('/etc/keystone/keystone.conf')
-    keystone_file
-  end
-
-  def 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.get_admin_token_from_keystone_file(conf_file)
-    if conf_file and conf_file['DEFAULT'] and conf_file['DEFAULT']['admin_token']
-      return "#{conf_file['DEFAULT']['admin_token'].strip}"
-    else
-      return nil
-    end
-  end
-
-  def get_admin_token_from_keystone_file
-    conf_file = keystone_file
-    self.class.get_admin_token_from_keystone_file(conf_file)
-  end
-
-
-  def self.get_auth_url_from_keystone_file(conf_file)
-    if conf_file
-      if conf_file['DEFAULT']
-        if conf_file['DEFAULT']['admin_endpoint']
-          auth_url = conf_file['DEFAULT']['admin_endpoint'].strip
-          return versioned_endpoint(auth_url)
-        end
-
-        if conf_file['DEFAULT']['admin_port']
-          admin_port = conf_file['DEFAULT']['admin_port'].strip
-        else
-          admin_port = '35357'
-        end
-
-        if conf_file['DEFAULT']['admin_bind_host']
-          host = conf_file['DEFAULT']['admin_bind_host'].strip
-          if host == "0.0.0.0"
-            host = "127.0.0.1"
-          end
-        else
-          host = "127.0.0.1"
-        end
-      end
-
-      if conf_file['ssl'] && conf_file['ssl']['enable'] && conf_file['ssl']['enable'].strip.downcase == 'true'
-        protocol = 'https'
-      else
-        protocol = 'http'
-      end
-    end
-
-    "#{protocol}://#{host}:#{admin_port}/v2.0/"
-  end
-
-  def get_auth_url_from_keystone_file
-    self.class.get_auth_url_from_keystone_file(keystone_file)
-  end
-
-
-  def self.make_configuration(credentials)
-    host_uri = versioned_endpoint(credentials['host_uri'] || credentials['OS_AUTH_URL'], credentials['api_version'])
-    {
-      :provider => 'openstack',
-      :auth_service => {
-        :name        => 'identity',
-        :host_uri    => host_uri,
-        :request     => 'create_token',
-        :validator   => 'list_tenants',
-      },
-      :auth_credentials => {
-        :username    => credentials['username'] || credentials['OS_USERNAME'],
-        :password    => credentials['password'] || credentials['OS_PASSWORD'],
-        :tenant_name => credentials['tenant_name'] || credentials['OS_TENANT_NAME']
-      }
-    }
-  end
-
-
-  def self.get_authenticated_session(credentials, log_file)
-    configuration = make_configuration(credentials)
-    session = ::Aviator::Session.new(:config => configuration, :log_file => log_file)
-    session.authenticate
-    session
-  end
-
-  def get_authenticated_session(credentials, log_file)
-    self.class.get_authenticated_session(credentials, log_file)
-  end
-
-
-  def self.get_unauthenticated_session(credentials, log_file)
-    configuration = {
-      :provider => 'openstack',
-    }
-    session_data = {
-      :base_url      => credentials['host_uri'],
-      :service_token => credentials['service_token']
-    }
-    session = ::Aviator::Session.new(:config => configuration, :log_file => log_file)
-    { :session => session, :data => session_data }
-  end
-
-  def get_unauthenticated_session(credentials, log_file)
-    self.class.get_unauthenticated_session(credentials, log_file)
-  end
-
-
-  def self.versioned_endpoint(endpoint, version = 'v2.0')
-    version = 'v2.0' if version.nil?
-    if endpoint =~ /\/#{version}\/?$/ || endpoint =~ /\/v2.0\/?$/ || endpoint =~ /\/v3\/?$/
-      endpoint
-    else
-      "#{endpoint.chomp('/')}/#{version}"
-    end
-  end
-end
diff --git a/3rdparty/modules/openstacklib/lib/puppet/provider/openstack.rb b/3rdparty/modules/openstacklib/lib/puppet/provider/openstack.rb
new file mode 100644 (file)
index 0000000..155e5b9
--- /dev/null
@@ -0,0 +1,84 @@
+require 'csv'
+require 'puppet'
+
+class Puppet::Error::OpenstackAuthInputError < Puppet::Error
+end
+
+class Puppet::Error::OpenstackUnauthorizedError < Puppet::Error
+end
+
+class Puppet::Provider::Openstack < Puppet::Provider
+
+  initvars # so commands will work
+  commands :openstack => 'openstack'
+
+  # Returns an array of hashes, where the keys are the downcased CSV headers
+  # with underscores instead of spaces
+  def self.request(service, action, properties, credentials=nil)
+    env = credentials ? credentials.to_env : {}
+    Puppet::Util.withenv(env) do
+      rv = nil
+      timeout = 10
+      end_time = Time.now.to_i + timeout
+      loop do
+        begin
+          if(action == 'list')
+            response = openstack(service, action, '--quiet', '--format', 'csv', properties)
+            response = parse_csv(response)
+            keys = response.delete_at(0) # ID,Name,Description,Enabled
+            rv = response.collect do |line|
+              hash = {}
+              keys.each_index do |index|
+                key = keys[index].downcase.gsub(/ /, '_').to_sym
+                hash[key] = line[index]
+              end
+              hash
+            end
+          elsif(action == 'show' || action == 'create')
+            rv = {}
+            # shell output is name="value"\nid="value2"\ndescription="value3" etc.
+            openstack(service, action, '--format', 'shell', properties).split("\n").each do |line|
+              # key is everything before the first "="
+              key, val = line.split("=", 2)
+              next unless val # Ignore warnings
+              # value is everything after the first "=", with leading and trailing double quotes stripped
+              val = val.gsub(/\A"|"\Z/, '')
+              rv[key.downcase.to_sym] = val
+            end
+          else
+            rv = openstack(service, action, properties)
+          end
+          break
+        rescue Puppet::ExecutionFailure => e
+          if e.message =~ /HTTP 401/
+            raise(Puppet::Error::OpenstackUnauthorizedError, 'Could not authenticate.')
+          elsif e.message =~ /Unable to establish connection/
+            current_time = Time.now.to_i
+            if current_time > end_time
+              break
+            else
+              wait = end_time - current_time
+              Puppet::debug("Non-fatal error: \"#{e.message}\"; retrying for #{wait} more seconds.")
+              if wait > timeout - 2 # Only notice the first time
+                notice("#{service} service is unavailable. Will retry for up to #{wait} seconds.")
+              end
+            end
+            sleep(2)
+          else
+            raise e
+          end
+        end
+      end
+      return rv
+    end
+  end
+
+  private
+
+  def self.parse_csv(text)
+    # Ignore warnings - assume legitimate output starts with a double quoted
+    # string.  Errors will be caught and raised prior to this
+    text = text.split("\n").drop_while { |line| line !~ /^\".*\"/ }.join("\n")
+    return CSV.parse(text + "\n")
+  end
+end
diff --git a/3rdparty/modules/openstacklib/lib/puppet/provider/openstack/auth.rb b/3rdparty/modules/openstacklib/lib/puppet/provider/openstack/auth.rb
new file mode 100644 (file)
index 0000000..93a054e
--- /dev/null
@@ -0,0 +1,49 @@
+require 'puppet/provider/openstack/credentials'
+
+module Puppet::Provider::Openstack::Auth
+
+  RCFILENAME = "#{ENV['HOME']}/openrc"
+
+  def get_os_vars_from_env
+    env = {}
+    ENV.each { |k,v| env.merge!(k => v) if k =~ /^OS_/ }
+    return env
+  end
+
+  def get_os_vars_from_rcfile(filename)
+    env = {}
+    if File.exists?(filename)
+      File.open(filename).readlines.delete_if{|l| l=~ /^#|^$/ }.each do |line|
+        key, value = line.split('=')
+        key = key.split(' ').last
+        value = value.chomp.gsub(/'/, '')
+        env.merge!(key => value) if key =~ /OS_/
+      end
+    end
+    return env
+  end
+
+  def rc_filename
+    RCFILENAME
+  end
+
+  def request(service, action, properties=nil)
+    properties ||= []
+    set_credentials(@credentials, get_os_vars_from_env)
+    unless @credentials.set?
+      @credentials.unset
+      set_credentials(@credentials, get_os_vars_from_rcfile(rc_filename))
+    end
+    unless @credentials.set?
+      raise(Puppet::Error::OpenstackAuthInputError, 'Insufficient credentials to authenticate')
+    end
+    super(service, action, properties, @credentials)
+  end
+
+  def set_credentials(creds, env)
+    env.each do |key, val|
+      var = key.sub(/^OS_/,'').downcase
+      creds.set(var, val)
+    end
+  end
+end
diff --git a/3rdparty/modules/openstacklib/lib/puppet/provider/openstack/credentials.rb b/3rdparty/modules/openstacklib/lib/puppet/provider/openstack/credentials.rb
new file mode 100644 (file)
index 0000000..0dec787
--- /dev/null
@@ -0,0 +1,93 @@
+require 'puppet'
+require 'puppet/provider/openstack'
+
+class Puppet::Provider::Openstack::Credentials
+
+  KEYS = [
+    :auth_url, :password, :project_name, :username,
+    :token, :url,
+    :identity_api_version
+  ]
+
+  KEYS.each { |var| attr_accessor var }
+
+  def self.defined?(name)
+    KEYS.include?(name.to_sym)
+  end
+
+  def set(key, val)
+    if self.class.defined?(key.to_sym)
+      self.instance_variable_set("@#{key}".to_sym, val)
+    end
+  end
+
+  def set?
+    return true if user_password_set? || service_token_set?
+  end
+
+  def service_token_set?
+    return true if @token && @url
+  end
+
+  def to_env
+    env = {}
+    self.instance_variables.each do |var|
+      name = var.to_s.sub(/^@/,'OS_').upcase
+      env.merge!(name => self.instance_variable_get(var))
+    end
+    env
+  end
+
+  def user_password_set?
+    return true if @username && @password && @project_name && @auth_url
+  end
+
+  def unset
+    KEYS.each do |key|
+      if key != :identity_api_version &&
+        self.instance_variable_defined?("@#{key}")
+        set(key, '')
+      end
+    end
+  end
+
+  def version
+    self.class.to_s.sub(/.*V/,'').sub('_','.')
+  end
+end
+
+class Puppet::Provider::Openstack::CredentialsV2_0 < Puppet::Provider::Openstack::Credentials
+end
+
+class Puppet::Provider::Openstack::CredentialsV3 < Puppet::Provider::Openstack::Credentials
+
+  KEYS = [
+    :cacert,
+    :cert,
+    :default_domain,
+    :domain_id,
+    :domain_name,
+    :key,
+    :project_domain_id,
+    :project_domain_name,
+    :project_id,
+    :trust_id,
+    :user_domain_id,
+    :user_domain_name,
+    :user_id
+  ]
+
+  KEYS.each { |var| attr_accessor var }
+
+  def self.defined?(name)
+    KEYS.include?(name.to_sym) || super
+  end
+
+  def user_password_set?
+    return true if (@username || @user_id) && @password && (@project_name || @project_id) && @auth_url
+  end
+
+  def initialize
+    set(:identity_api_version, version)
+  end
+end
diff --git a/3rdparty/modules/openstacklib/lib/puppet/util/aviator.rb b/3rdparty/modules/openstacklib/lib/puppet/util/aviator.rb
deleted file mode 100644 (file)
index bc24b02..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-# Add the auth parameter to whatever type is given
-module Puppet::Util::Aviator
-  def self.add_aviator_params(type)
-
-    type.newparam(:auth) do
-
-      desc <<EOT
-Hash of authentication credentials. Credentials can be specified as
-password credentials, e.g.:
-
-auth => {
-  'username'    => 'test',
-  'password'    => 'passw0rd',
-  'tenant_name' => 'test',
-  'host_uri'    => 'http://localhost:35357/v2.0',
-}
-
-or a path to an openrc file containing these credentials, e.g.:
-
-auth => {
-  'openrc' => '/root/openrc',
-}
-
-or a service token and host, e.g.:
-
-auth => {
-  'service_token' => 'ADMIN',
-  'host_uri'    => 'http://localhost:35357/v2.0',
-}
-
-If not present, the provider will first look for environment variables
-for password credentials and then to /etc/keystone/keystone.conf for a
-service token.
-EOT
-
-      validate do |value|
-        raise(Puppet::Error, 'This property must be a hash') unless value.is_a?(Hash)
-      end
-    end
-
-    type.newparam(:log_file) do
-      desc 'Log file. Defaults to no logging.'
-      defaultto('/dev/null')
-    end
-  end
-end
diff --git a/3rdparty/modules/openstacklib/manifests/db/postgresql.pp b/3rdparty/modules/openstacklib/manifests/db/postgresql.pp
new file mode 100644 (file)
index 0000000..febbb44
--- /dev/null
@@ -0,0 +1,46 @@
+# == Definition: openstacklib::db::postgresql
+#
+# This resource configures a postgresql database for an OpenStack service
+#
+# == Parameters:
+#
+#  [*password_hash*]
+#    Password hash to use for the database user for this service;
+#    string; required
+#
+#  [*dbname*]
+#    The name of the database
+#    string; optional; default to the $title of the resource, i.e. 'nova'
+#
+#  [*user*]
+#    The database user to create;
+#    string; optional; default to the $title of the resource, i.e. 'nova'
+#
+#  [*encoding*]
+#    The charset to use for the database;
+#    string; optional; default to undef
+#
+#  [*privileges*]
+#    Privileges given to the database user;
+#    string or array of strings; optional; default to 'ALL'
+
+define openstacklib::db::postgresql (
+  $password_hash,
+  $dbname     = $title,
+  $user       = $title,
+  $encoding   = undef,
+  $privileges = 'ALL',
+){
+
+  if ((($::operatingsystem == 'RedHat' or $::operatingsystem == 'CentOS') and (versioncmp($::operatingsystemmajrelease, '6') <= 0))
+    or ($::operatingsystem == 'Fedora' and (versioncmp($::operatingsystemmajrelease, '14') <= 0))) {
+    warning('The system packages handling the postgresql infrastructure for OpenStack are out of date and should not be relied on for database migrations.')
+  }
+
+  postgresql::server::db { $dbname:
+    user     => $user,
+    password => $password_hash,
+    encoding => $encoding,
+    grant    => $privileges,
+  }
+}
diff --git a/3rdparty/modules/openstacklib/manifests/openstackclient.pp b/3rdparty/modules/openstacklib/manifests/openstackclient.pp
new file mode 100644 (file)
index 0000000..096741c
--- /dev/null
@@ -0,0 +1,18 @@
+# == Class: openstacklib::openstackclient
+#
+# Installs the openstackclient
+#
+# == Parameters
+#
+#  [*package_ensure*]
+#    Ensure state of the openstackclient package.
+#    Optional. Defaults to 'present'.
+#
+class openstacklib::openstackclient(
+  $package_ensure = 'present',
+){
+  package { 'python-openstackclient':
+    ensure => $package_ensure,
+    tag    => 'openstack',
+  }
+}
index 01919fe..d5c457a 100644 (file)
@@ -28,17 +28,17 @@ define openstacklib::policy::base (
     incl    => $file_path,
     changes => [
       "set dict/entry[last()+1] \"${key}\"",
-      "set dict/entry[last()]/string \"${value}\""
+      "set dict/entry[last()]/string \"${value}\"",
     ],
-    onlyif  => "match dict/entry[*][.=\"${key}\"] size == 0"
+    onlyif  => "match dict/entry[*][.=\"${key}\"] size == 0",
   }
 
   # Requires that the entry is added before this call or it will fail.
   augeas { "${file_path}-${key}-${value}" :
     lens    => 'Json.lns',
     incl    => $file_path,
-    changes => "set dict/entry[*][.=\"${key}\"]/string ${value}",
-    require => Augeas["${file_path}-${key}-${value}-add"]
+    changes => "set dict/entry[*][.=\"${key}\"]/string \"${value}\"",
+    require => Augeas["${file_path}-${key}-${value}-add"],
   }
 
 }
diff --git a/3rdparty/modules/openstacklib/manifests/wsgi/apache.pp b/3rdparty/modules/openstacklib/manifests/wsgi/apache.pp
new file mode 100644 (file)
index 0000000..3b497ff
--- /dev/null
@@ -0,0 +1,204 @@
+#
+# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
+#
+# Author: Emilien Macchi <emilien.macchi@enovance.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+# == Class: openstacklib::wsgi::apache
+#
+# Serve a service with apache mod_wsgi
+# When using this class you should disable your service.
+#
+# == Parameters
+#
+# [*service_name*]
+#   (optional) Name of the service to run.
+#   Example: nova-api
+#   Defaults to $name
+#
+# [*servername*]
+#   (optional) The servername for the virtualhost.
+#   Defaults to $::fqdn
+#
+# [*bind_host*]
+#   (optional) The host/ip address Apache will listen on.
+#   Defaults to undef (listen on all ip addresses).
+#
+# [*bind_port*]
+#   (optional) The port to listen.
+#   Defaults to undef
+#
+# [*group*]
+#   (optional) Group with permissions on the script
+#   Defaults to undef
+#
+# [*path*]
+#   (optional) The prefix for the endpoint.
+#   Defaults to '/'
+#
+# [*priority*]
+#   (optional) The priority for the vhost.
+#   Defaults to '10'
+#
+# [*ssl*]
+#   (optional) Use ssl ? (boolean)
+#   Defaults to false
+#
+# [*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*]
+#   (optional) Path to SSL certificate directory
+#   Default to apache::vhost 'ssl_*' defaults.
+#
+# [*threads*]
+#   (optional) The number of threads for the vhost.
+#   Defaults to $::processorcount
+#
+# [*user*]
+#   (optional) User with permissions on the script
+#   Defaults to undef
+#
+# [*workers*]
+#   (optional) The number of workers for the vhost.
+#   Defaults to '1'
+#
+# [*wsgi_daemon_process*]
+#   (optional) Name of the WSGI daemon process.
+#   Defaults to $name
+#
+# [*wsgi_process_group*]
+#   (optional) Name of the WSGI process group.
+#   Defaults to $name
+#
+# [*wsgi_script_dir*]
+#   (optional) The directory path of the WSGI script.
+#   Defaults to undef
+#
+# [*wsgi_script_file*]
+#   (optional) The file path of the WSGI script.
+#   Defaults to undef
+#
+# [*wsgi_script_source*]
+#   (optional) The source of the WSGI script.
+#   Defaults to undef
+#
+define openstacklib::wsgi::apache (
+  $service_name        = $name,
+  $bind_host           = undef,
+  $bind_port           = undef,
+  $group               = undef,
+  $path                = '/',
+  $priority            = '10',
+  $servername          = $::fqdn,
+  $ssl                 = false,
+  $ssl_ca              = undef,
+  $ssl_cert            = undef,
+  $ssl_certs_dir       = undef,
+  $ssl_chain           = undef,
+  $ssl_crl             = undef,
+  $ssl_crl_path        = undef,
+  $ssl_key             = undef,
+  $threads             = $::processorcount,
+  $user                = undef,
+  $workers             = 1,
+  $wsgi_daemon_process = $name,
+  $wsgi_process_group  = $name,
+  $wsgi_script_dir     = undef,
+  $wsgi_script_file    = undef,
+  $wsgi_script_source  = undef,
+) {
+
+  include ::apache
+  include ::apache::mod::wsgi
+  if $ssl {
+    include ::apache::mod::ssl
+  }
+
+  # Ensure there's no trailing '/' except if this is also the only character
+  $path_real = regsubst($path, '(^/.*)/$', '\1')
+
+  if !defined(File[$wsgi_script_dir]) {
+    file { $wsgi_script_dir:
+      ensure  => directory,
+      owner   => $user,
+      group   => $group,
+      require => Package['httpd'],
+    }
+  }
+
+  file { $service_name:
+    ensure  => file,
+    path    => "${wsgi_script_dir}/${wsgi_script_file}",
+    source  => $wsgi_script_source,
+    owner   => $user,
+    group   => $group,
+    mode    => '0644',
+    require => File[$wsgi_script_dir],
+  }
+
+  $wsgi_daemon_process_options = {
+    user      => $user,
+    group     => $group,
+    processes => $workers,
+    threads   => $threads,
+  }
+  $wsgi_script_aliases = hash([$path_real,"${wsgi_script_dir}/${wsgi_script_file}"])
+
+  ::apache::vhost { $service_name:
+    ensure                      => 'present',
+    servername                  => $servername,
+    ip                          => $bind_host,
+    port                        => $bind_port,
+    docroot                     => $wsgi_script_dir,
+    docroot_owner               => $user,
+    docroot_group               => $group,
+    priority                    => $priority,
+    ssl                         => $ssl,
+    ssl_cert                    => $ssl_cert,
+    ssl_key                     => $ssl_key,
+    ssl_chain                   => $ssl_chain,
+    ssl_ca                      => $ssl_ca,
+    ssl_crl_path                => $ssl_crl_path,
+    ssl_crl                     => $ssl_crl,
+    ssl_certs_dir               => $ssl_certs_dir,
+    wsgi_daemon_process         => $wsgi_daemon_process,
+    wsgi_daemon_process_options => $wsgi_daemon_process_options,
+    wsgi_process_group          => $wsgi_process_group,
+    wsgi_script_aliases         => $wsgi_script_aliases,
+    require                     => File[$service_name],
+  }
+
+}
index e941bfd..3bd6d9f 100644 (file)
@@ -7,49 +7,34 @@
   "source": "git://github.com/openstack/puppet-openstacklib.git",
   "project_page": "https://launchpad.net/puppet-openstacklib",
   "issues_url": "https://bugs.launchpad.net/puppet-openstacklib",
-  "dependencies": [
-    {"name":"aimonb/aviator","version_requirement":">=0.4.2 <1.0.0"},
-    {"name":"puppetlabs/mysql","version_requirement":">=2.2.0 <3.0.0"},
-    {"name":"puppetlabs/stdlib","version_requirement":">=4.0.0 <5.0.0"},
-    {"name":"puppetlabs/rabbitmq","version_requirement":">=2.0.2 <4.0.0"}
-  ],
   "requirements": [
-    {
-      "name": "pe",
-      "version_requirement": "3.x"
-    },
-    {
-      "name": "puppet",
-      "version_requirement": "3.x"
-    }
+    { "name": "pe","version_requirement": "3.x" },
+    { "name": "puppet","version_requirement": "3.x" }
   ],
   "operatingsystem_support": [
     {
       "operatingsystem": "Debian",
-      "operatingsystemrelease": [
-        "7"
-      ]
+      "operatingsystemrelease": ["7"]
     },
     {
       "operatingsystem": "Fedora",
-      "operatingsystemrelease": [
-        "20"
-      ]
+      "operatingsystemrelease": ["20"]
     },
     {
       "operatingsystem": "RedHat",
-      "operatingsystemrelease": [
-        "6.5",
-        "7"
-      ]
+      "operatingsystemrelease": ["6.5","7"]
     },
     {
       "operatingsystem": "Ubuntu",
-      "operatingsystemrelease": [
-        "12.04",
-        "14.04"
-      ]
+      "operatingsystemrelease": ["12.04","14.04"]
     }
   ],
-  "description": "Puppet module library to expose common functionality between OpenStack modules."
+  "description": "Puppet module library to expose common functionality between OpenStack modules.",
+  "dependencies": [
+    { "name": "puppetlabs/apache", "version_requirement": ">=1.0.0 <2.0.0" },
+    { "name": "puppetlabs/mysql", "version_requirement": ">=3.0.0 <4.0.0" },
+    { "name": "puppetlabs/stdlib", "version_requirement": ">=4.0.0 <5.0.0" },
+    { "name": "puppetlabs/rabbitmq", "version_requirement": ">=2.0.2 <4.0.0" },
+    { "name": "puppetlabs/postgresql", "version_requirement": ">=3.3.0 <4.0.0" }
+  ]
 }
diff --git a/3rdparty/modules/openstacklib/spec/acceptance/mysql_spec.rb b/3rdparty/modules/openstacklib/spec/acceptance/mysql_spec.rb
new file mode 100644 (file)
index 0000000..0088971
--- /dev/null
@@ -0,0 +1,35 @@
+require 'spec_helper_acceptance'
+
+describe 'openstacklib mysql' do
+
+  context 'default parameters' do
+
+    it 'should work with no errors' do
+      pp= <<-EOS
+      Exec { logoutput => 'on_failure' }
+
+      class { '::mysql::server': }
+
+      ::openstacklib::db::mysql { 'beaker':
+        password_hash => mysql_password('keystone'),
+        allowed_hosts => '127.0.0.1',
+      }
+      EOS
+
+      # Run it twice and test for idempotency
+      apply_manifest(pp, :catch_failures => true)
+      apply_manifest(pp, :catch_changes => true)
+    end
+
+    describe port(3306) do
+      it { is_expected.to be_listening.with('tcp') }
+    end
+
+    describe 'test database listing' do
+      it 'should list beaker database' do
+        expect(shell("mysql -e 'show databases;'|grep -q beaker").exit_code).to be_zero
+      end
+    end
+
+  end
+end
diff --git a/3rdparty/modules/openstacklib/spec/acceptance/nodesets/default.yml b/3rdparty/modules/openstacklib/spec/acceptance/nodesets/default.yml
new file mode 100644 (file)
index 0000000..a2c1ecc
--- /dev/null
@@ -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/3rdparty/modules/openstacklib/spec/acceptance/nodesets/nodepool-centos7.yml b/3rdparty/modules/openstacklib/spec/acceptance/nodesets/nodepool-centos7.yml
new file mode 100644 (file)
index 0000000..575ae67
--- /dev/null
@@ -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/3rdparty/modules/openstacklib/spec/acceptance/nodesets/nodepool-trusty.yml b/3rdparty/modules/openstacklib/spec/acceptance/nodesets/nodepool-trusty.yml
new file mode 100644 (file)
index 0000000..a95d9f3
--- /dev/null
@@ -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/3rdparty/modules/openstacklib/spec/acceptance/rabbitmq_spec.rb b/3rdparty/modules/openstacklib/spec/acceptance/rabbitmq_spec.rb
new file mode 100644 (file)
index 0000000..51e8e99
--- /dev/null
@@ -0,0 +1,65 @@
+require 'spec_helper_acceptance'
+
+describe 'openstacklib class' do
+
+  context 'default parameters' do
+
+    it 'should work with no errors' do
+      pp= <<-EOS
+      Exec { logoutput => 'on_failure' }
+
+      if $::osfamily == 'RedHat' {
+        # RabbitMQ is not available in default repo
+        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,
+            },
+          },
+        }
+        $package_provider = 'yum'
+      } else {
+        $package_provider = 'apt'
+      }
+
+      class { '::rabbitmq':
+        delete_guest_user => true,
+        package_provider  => $package_provider
+      }
+
+      # openstacklib resources
+      include ::openstacklib::openstackclient
+
+      ::openstacklib::messaging::rabbitmq { 'beaker':
+        userid   => 'beaker',
+        is_admin => true,
+      }
+      EOS
+
+      # Run it twice and test for idempotency
+      apply_manifest(pp, :catch_failures => true)
+      apply_manifest(pp, :catch_changes => true)
+    end
+
+    describe 'test rabbitmq resources' do
+      it 'should list rabbitmq beaker resources' do
+        shell('rabbitmqctl list_users') do |r|
+          expect(r.stdout).to match(/^beaker/)
+          expect(r.stdout).not_to match(/^guest/)
+          expect(r.exit_code).to eq(0)
+        end
+
+        shell('rabbitmqctl list_permissions') do |r|
+          expect(r.stdout).to match(/^beaker\t\.\*\t\.\*\t\.\*$/)
+          expect(r.exit_code).to eq(0)
+        end
+      end
+    end
+
+  end
+end
index 9d6927c..9c11441 100644 (file)
@@ -15,7 +15,7 @@ describe 'openstacklib::policy' do
   end
 
   it 'configures the proper policy' do
-    should contain_openstacklib__policy__base('foo').with(
+    is_expected.to contain_openstacklib__policy__base('foo').with(
       :file_path => '/etc/nova/policy.json',
       :key       => 'context_is_admin',
       :value     => 'foo:bar'
index 8f47bfa..d3e1d30 100644 (file)
@@ -19,11 +19,11 @@ describe 'openstacklib::db::mysql::host_access' do
           :privileges    => 'ALL' }
       end
 
-      it { should contain_mysql_user("#{params[:user]}@10.0.0.1").with(
+      it { is_expected.to contain_mysql_user("#{params[:user]}@10.0.0.1").with(
         :password_hash => params[:password_hash]
       )}
 
-      it { should contain_mysql_grant("#{params[:user]}@10.0.0.1/#{params[:database]}.*").with(
+      it { is_expected.to contain_mysql_grant("#{params[:user]}@10.0.0.1/#{params[:database]}.*").with(
         :user       => "#{params[:user]}@10.0.0.1",
         :privileges => 'ALL',
         :table      => "#{params[:database]}.*"
index fc9b54e..ca6884a 100644 (file)
@@ -19,11 +19,11 @@ describe 'openstacklib::db::mysql' do
         required_params
       end
 
-      it { should contain_mysql_database(title).with(
+      it { is_expected.to contain_mysql_database(title).with(
         :charset => 'utf8',
         :collate => 'utf8_general_ci'
       )}
-      it { should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
+      it { is_expected.to contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
         :user       => title,
         :database   => title,
         :privileges => 'ALL'
@@ -35,11 +35,11 @@ describe 'openstacklib::db::mysql' do
         { :dbname => 'foobar' }.merge(required_params)
       end
 
-      it { should contain_mysql_database(params[:dbname]).with(
+      it { is_expected.to contain_mysql_database(params[:dbname]).with(
         :charset => 'utf8',
         :collate => 'utf8_general_ci'
       )}
-      it { should contain_openstacklib__db__mysql__host_access("#{params[:dbname]}_127.0.0.1").with(
+      it { is_expected.to contain_openstacklib__db__mysql__host_access("#{params[:dbname]}_127.0.0.1").with(
         :user       => title,
         :database   => params[:dbname],
         :privileges => 'ALL'
@@ -51,11 +51,11 @@ describe 'openstacklib::db::mysql' do
         { :user => 'foobar' }.merge(required_params)
       end
 
-      it { should contain_mysql_database(title).with(
+      it { is_expected.to contain_mysql_database(title).with(
         :charset => 'utf8',
         :collate => 'utf8_general_ci'
       )}
-      it { should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
+      it { is_expected.to contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
         :user       => params[:user],
         :database   => title,
         :privileges => 'ALL',
@@ -67,14 +67,14 @@ describe 'openstacklib::db::mysql' do
         { :charset => 'latin1' }.merge(required_params)
       end
 
-      it { should contain_mysql_database(title).with_charset(params[:charset]) }
+      it { is_expected.to contain_mysql_database(title).with_charset(params[:charset]) }
     end
 
     context 'when omitting the required parameter password_hash' do
       let :params do
         required_params.delete(:password_hash)
       end
-      it { expect { should raise_error(Puppet::Error) } }
+      it { expect { is_expected.to raise_error(Puppet::Error) } }
     end
 
     context 'when notifying other resources' do
@@ -85,7 +85,7 @@ describe 'openstacklib::db::mysql' do
         { :notify => 'Exec[nova-db-sync]'}.merge(required_params)
       end
 
-      it { should contain_exec('nova-db-sync').that_subscribes_to("Openstacklib::Db::Mysql[#{title}]") }
+      it { is_expected.to contain_exec('nova-db-sync').that_subscribes_to("Openstacklib::Db::Mysql[#{title}]") }
     end
 
     context 'when required for other openstack services' do
@@ -99,7 +99,7 @@ describe 'openstacklib::db::mysql' do
         { :before => 'Service[keystone]'}.merge(required_params)
       end
 
-      it { should contain_service('keystone').that_requires("Openstacklib::Db::Mysql[keystone]") }
+      it { is_expected.to contain_service('keystone').that_requires("Openstacklib::Db::Mysql[keystone]") }
     end
 
     context "overriding allowed_hosts parameter with array value" do
@@ -107,12 +107,12 @@ describe 'openstacklib::db::mysql' do
         { :allowed_hosts  => ['127.0.0.1','%'] }.merge(required_params)
       end
 
-      it {should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
+      it {is_expected.to contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
         :user          => title,
         :password_hash => params[:password_hash],
         :database      => title
       )}
-      it {should contain_openstacklib__db__mysql__host_access("#{title}_%").with(
+      it {is_expected.to contain_openstacklib__db__mysql__host_access("#{title}_%").with(
         :user          => title,
         :password_hash => params[:password_hash],
         :database      => title
@@ -124,7 +124,7 @@ describe 'openstacklib::db::mysql' do
         { :allowed_hosts => '192.168.1.1' }.merge(required_params)
       end
 
-      it {should contain_openstacklib__db__mysql__host_access("#{title}_192.168.1.1").with(
+      it {is_expected.to contain_openstacklib__db__mysql__host_access("#{title}_192.168.1.1").with(
         :user          => title,
         :password_hash => params[:password_hash],
         :database      => title
@@ -136,7 +136,7 @@ describe 'openstacklib::db::mysql' do
         { :allowed_hosts => '127.0.0.1' }.merge(required_params)
       end
 
-      it {should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
+      it {is_expected.to contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
         :user          => title,
         :password_hash => params[:password_hash],
         :database      => title
diff --git a/3rdparty/modules/openstacklib/spec/defines/openstacklib_db_postgresql_spec.rb b/3rdparty/modules/openstacklib/spec/defines/openstacklib_db_postgresql_spec.rb
new file mode 100644 (file)
index 0000000..4e2dfc7
--- /dev/null
@@ -0,0 +1,133 @@
+require 'spec_helper'
+
+describe 'openstacklib::db::postgresql' do
+  password_hash = 'AA1420F182E88B9E5F874F6FBE7459291E8F4601'
+  title = 'nova'
+  let (:title) { title }
+
+  let :required_params do
+    { :password_hash => password_hash }
+  end
+
+  context 'on a RedHat osfamily' do
+    let :facts do
+      {
+        :postgres_default_version => '8.4',
+        :osfamily => 'RedHat'
+      }
+    end
+
+    context 'with only required parameters' do
+      let :params do
+        required_params
+      end
+
+      it { is_expected.to contain_postgresql__server__db(title).with(
+        :user     => title,
+        :password => password_hash
+      )}
+    end
+
+    context 'when overriding encoding' do
+      let :params do
+        { :encoding => 'latin1' }.merge(required_params)
+      end
+      it { is_expected.to contain_postgresql__server__db(title).with_encoding(params[:encoding]) }
+    end
+
+    context 'when omitting the required parameter password_hash' do
+      let :params do
+        required_params.delete(:password_hash)
+      end
+
+      it { expect { is_expected.to raise_error(Puppet::Error) } }
+    end
+
+    context 'when notifying other resources' do
+      let :pre_condition do
+        'exec { "nova-db-sync": }'
+      end
+      let :params do
+        { :notify => 'Exec[nova-db-sync]'}.merge(required_params)
+      end
+
+      it {is_expected.to contain_exec('nova-db-sync').that_subscribes_to("Openstacklib::Db::Postgresql[#{title}]") }
+    end
+
+    context 'when required for other openstack services' do
+      let :pre_condition do
+        'service {"keystone":}'
+      end
+      let :title do
+        'keystone'
+      end
+      let :params do
+        { :before => 'Service[keystone]'}.merge(required_params)
+      end
+
+      it { is_expected.to contain_service('keystone').that_requires("Openstacklib::Db::Postgresql[keystone]") }
+    end
+
+  end
+
+  context 'on a Debian osfamily' do
+    let :facts do
+      {
+        :osfamily => 'Debian'
+      }
+    end
+
+    context 'with only required parameters' do
+      let :params do
+        required_params
+      end
+
+      it { is_expected.to contain_postgresql__server__db(title).with(
+        :user     => title,
+        :password => password_hash
+      )}
+    end
+
+    context 'when overriding encoding' do
+      let :params do
+        { :encoding => 'latin1' }.merge(required_params)
+      end
+      it { is_expected.to contain_postgresql__server__db(title).with_encoding(params[:encoding]) }
+    end
+
+    context 'when omitting the required parameter password_hash' do
+      let :params do
+        required_params.delete(:password_hash)
+      end
+
+      it { expect { is_expected.to raise_error(Puppet::Error) } }
+    end
+
+    context 'when notifying other resources' do
+      let :pre_condition do
+        'exec { "nova-db-sync": }'
+      end
+      let :params do
+        { :notify => 'Exec[nova-db-sync]'}.merge(required_params)
+      end
+
+      it {is_expected.to contain_exec('nova-db-sync').that_subscribes_to("Openstacklib::Db::Postgresql[#{title}]") }
+    end
+
+    context 'when required for other openstack services' do
+      let :pre_condition do
+        'service {"keystone":}'
+      end
+      let :title do
+        'keystone'
+      end
+      let :params do
+        { :before => 'Service[keystone]'}.merge(required_params)
+      end
+
+      it { is_expected.to contain_service('keystone').that_requires("Openstacklib::Db::Postgresql[keystone]") }
+    end
+
+  end
+
+end
index 953c53b..47e6c41 100644 (file)
@@ -28,18 +28,18 @@ describe 'openstacklib::messaging::rabbitmq' do
     end
 
     context 'with default parameters' do
-      it { should contain_rabbitmq_user('guest').with(
+      it { is_expected.to contain_rabbitmq_user('guest').with(
         :admin    => false,
         :password => 'guest',
         :provider => 'rabbitmqctl',
       )}
-      it { should contain_rabbitmq_user_permissions('guest@/').with(
+      it { is_expected.to contain_rabbitmq_user_permissions('guest@/').with(
         :configure_permission => '.*',
         :write_permission     => '.*',
         :read_permission      => '.*',
         :provider             => 'rabbitmqctl',
       )}
-      it { should contain_rabbitmq_vhost('/').with(
+      it { is_expected.to contain_rabbitmq_vhost('/').with(
         :provider => 'rabbitmqctl',
       )}
     end
@@ -57,18 +57,18 @@ describe 'openstacklib::messaging::rabbitmq' do
         )
       end
 
-      it { should contain_rabbitmq_user('nova').with(
+      it { is_expected.to contain_rabbitmq_user('nova').with(
         :admin    => true,
         :password => 'secrete',
         :provider => 'rabbitmqctl',
       )}
-      it { should contain_rabbitmq_user_permissions('nova@/nova').with(
+      it { is_expected.to contain_rabbitmq_user_permissions('nova@/nova').with(
         :configure_permission => '.nova',
         :write_permission     => '.nova',
         :read_permission      => '.nova',
         :provider             => 'rabbitmqctl',
       )}
-      it { should contain_rabbitmq_vhost('/nova').with(
+      it { is_expected.to contain_rabbitmq_vhost('/nova').with(
         :provider => 'rabbitmqctl',
       )}
     end
@@ -78,7 +78,7 @@ describe 'openstacklib::messaging::rabbitmq' do
         params.merge!( :manage_vhost => false )
       end
 
-      it { should_not contain_rabbitmq_vhost }
+      it { is_expected.not_to contain_rabbitmq_vhost }
     end
 
   end
index 89be58c..6e0bb91 100644 (file)
@@ -8,28 +8,28 @@ describe 'openstacklib::policy::base' do
 
   let :params do
     {:file_path => '/etc/nova/policy.json',
-    :key       => 'context_is_admin',
+    :key       => 'context_is_admin or owner',
     :value     => 'foo:bar'}
   end
 
-  it 'configures the proper policy' do
-    should contain_augeas('/etc/nova/policy.json-context_is_admin-foo:bar').with(
+  it 'configures (modifies) the proper policy' do
+    is_expected.to contain_augeas('/etc/nova/policy.json-context_is_admin or owner-foo:bar').with(
       'lens'    => 'Json.lns',
       'incl'    => '/etc/nova/policy.json',
-      'changes' => 'set dict/entry[*][.="context_is_admin"]/string foo:bar',
-      'require' => 'Augeas[/etc/nova/policy.json-context_is_admin-foo:bar-add]'
+      'changes' => 'set dict/entry[*][.="context_is_admin or owner"]/string "foo:bar"',
+      'require' => 'Augeas[/etc/nova/policy.json-context_is_admin or owner-foo:bar-add]'
     )
   end
 
-  it 'configures the proper policy' do
-    should contain_augeas('/etc/nova/policy.json-context_is_admin-foo:bar-add').with(
+  it 'configures (adds) the proper policy' do
+    is_expected.to contain_augeas('/etc/nova/policy.json-context_is_admin or owner-foo:bar-add').with(
       'lens'    => 'Json.lns',
       'incl'    => '/etc/nova/policy.json',
       'changes' => [
-          'set dict/entry[last()+1] "context_is_admin"',
+          'set dict/entry[last()+1] "context_is_admin or owner"',
           'set dict/entry[last()]/string "foo:bar"'
       ],
-      'onlyif' => 'match dict/entry[*][.="context_is_admin"] size == 0'
+      'onlyif' => 'match dict/entry[*][.="context_is_admin or owner"] size == 0'
     )
   end
 
index 17e4389..cc196f0 100644 (file)
@@ -32,7 +32,7 @@ describe 'openstacklib::service_validation' do
         required_params
       end
 
-      it { should contain_exec("execute #{title} validation").with(
+      it { is_expected.to contain_exec("execute #{title} validation").with(
         :path      => '/usr/bin:/bin:/usr/sbin:/sbin',
         :provider  => 'shell',
         :command   => 'nova list',
@@ -40,7 +40,7 @@ describe 'openstacklib::service_validation' do
         :try_sleep => '2',
       )}
 
-      it { should contain_anchor("create #{title} anchor").with(
+      it { is_expected.to contain_anchor("create #{title} anchor").with(
         :require => "Exec[execute #{title} validation]",
       )}
 
@@ -50,7 +50,7 @@ describe 'openstacklib::service_validation' do
       let :params do
         required_params.delete(:command)
       end
-      it { expect { should raise_error(Puppet::Error) } }
+      it { expect { is_expected.to raise_error(Puppet::Error) } }
     end
 
   end
diff --git a/3rdparty/modules/openstacklib/spec/defines/openstacklib_wsgi_apache_spec.rb b/3rdparty/modules/openstacklib/spec/defines/openstacklib_wsgi_apache_spec.rb
new file mode 100644 (file)
index 0000000..15bd3f0
--- /dev/null
@@ -0,0 +1,127 @@
+#
+# Copyright (C) 2014 eNovance SAS <licensing@enovance.com>
+#
+# Author: Emilien Macchi <emilien.macchi@enovance.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+
+require 'spec_helper'
+
+describe 'openstacklib::wsgi::apache' do
+
+  let (:title) { 'keystone_wsgi' }
+
+  let :global_facts do
+    {
+      :processorcount => 42,
+      :concat_basedir => '/var/lib/puppet/concat',
+      :fqdn           => 'some.host.tld'
+    }
+  end
+
+  let :params do
+    {
+      :bind_port          => 5000,
+      :group              => 'keystone',
+      :ssl                => true,
+      :user               => 'keystone',
+      :wsgi_script_dir    => '/var/www/cgi-bin/keystone',
+      :wsgi_script_file   => 'main',
+      :wsgi_script_source => '/usr/share/keystone/keystone.wsgi'
+    }
+  end
+
+  shared_examples_for 'apache serving a service with mod_wsgi' do
+    it { is_expected.to contain_service('httpd').with_name(platform_parameters[:httpd_service_name]) }
+    it { is_expected.to contain_class('apache') }
+    it { is_expected.to contain_class('apache::mod::wsgi') }
+
+    describe 'with default parameters' do
+
+      it { is_expected.to contain_file('/var/www/cgi-bin/keystone').with(
+        'ensure'  => 'directory',
+        'owner'   => 'keystone',
+        'group'   => 'keystone',
+        'require' => 'Package[httpd]'
+      )}
+
+      it { is_expected.to contain_file('keystone_wsgi').with(
+        'ensure'  => 'file',
+        'path'    => '/var/www/cgi-bin/keystone/main',
+        'source'  => '/usr/share/keystone/keystone.wsgi',
+        'owner'   => 'keystone',
+        'group'   => 'keystone',
+        'mode'    => '0644',
+      )}
+
+      it { is_expected.to contain_apache__vhost('keystone_wsgi').with(
+        'servername'                  => 'some.host.tld',
+        'ip'                          => nil,
+        'port'                        => '5000',
+        'docroot'                     => '/var/www/cgi-bin/keystone',
+        'docroot_owner'               => 'keystone',
+        'docroot_group'               => 'keystone',
+        'ssl'                         => 'true',
+        'wsgi_daemon_process'         => 'keystone_wsgi',
+        'wsgi_process_group'          => 'keystone_wsgi',
+        'wsgi_script_aliases'         => { '/' => "/var/www/cgi-bin/keystone/main" },
+        'wsgi_daemon_process_options' => {
+          'user'      => 'keystone',
+          'group'     => 'keystone',
+          'processes' => 1,
+          'threads'   => global_facts[:processorcount],
+        },
+        'require'                     => 'File[keystone_wsgi]'
+      )}
+      it { is_expected.to contain_file("#{platform_parameters[:httpd_ports_file]}") }
+    end
+
+  end
+
+  context 'on RedHat platforms' do
+    let :facts do
+      global_facts.merge({
+        :osfamily               => 'RedHat',
+        :operatingsystemrelease => '7.0'
+      })
+    end
+
+    let :platform_parameters do
+      {
+        :httpd_service_name => 'httpd',
+        :httpd_ports_file   => '/etc/httpd/conf/ports.conf',
+      }
+    end
+
+    it_configures 'apache serving a service with mod_wsgi'
+  end
+
+  context 'on Debian platforms' do
+    let :facts do
+      global_facts.merge({
+        :osfamily               => 'Debian',
+        :operatingsystem        => 'Debian',
+        :operatingsystemrelease => '7.0'
+      })
+    end
+
+    let :platform_parameters do
+      {
+        :httpd_service_name => 'apache2',
+        :httpd_ports_file   => '/etc/apache2/ports.conf',
+      }
+    end
+
+    it_configures 'apache serving a service with mod_wsgi'
+  end
+end
diff --git a/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/request/with_session.yml b/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/request/with_session.yml
deleted file mode 100644 (file)
index 2d052df..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
---- 
-  http_interactions: 
-    - request: 
-        method: post
-        uri: "http://192.168.11.4:35357/v2.0/tokens"
-        body: 
-          encoding: UTF-8
-          string: "{\x22auth\x22:{\x22passwordCredentials\x22:{\x22username\x22:\x22admin\x22,\x22password\x22:\x22fyby-tet\x22},\x22tenantName\x22:\x22admin\x22}}"
-        headers: 
-          Content-Type: 
-            - application/json
-          User-Agent: 
-            - "Faraday v0.8.8"
-      response: 
-        status: 
-          code: 200
-          message: 
-        headers: 
-          vary: 
-            - X-Auth-Token
-          content-type: 
-            - application/json
-          content-length: 
-            - "9780"
-          date: 
-            - "Tue, 30 Sep 2014 06:59:48 GMT"
-          connection: 
-            - close
-        body: 
-          encoding: UTF-8
-          string: "{\x22access\x22: {\x22token\x22: {\x22issued_at\x22: \x222014-09-30T06:59:48.338940\x22, \x22expires\x22: \x222014-09-30T07:59:48Z\x22, \x22id\x22: \x22MIIRIAYJKoZIhvcNAQcCoIIRETCCEQ0CAQExCTAHBgUrDgMCGjCCD3YGCSqGSIb3DQEHAaCCD2cEgg9jeyJhY2Nlc3MiOiB7InRva2VuIjogeyJpc3N1ZWRfYXQiOiAiMjAxNC0wOS0zMFQwNjo1OTo0OC4zMzg5NDAiLCAiZXhwaXJlcyI6ICIyMDE0LTA5LTMwVDA3OjU5OjQ4WiIsICJpZCI6ICJwbGFjZWhvbGRlciIsICJ0ZW5hbnQiOiB7ImRlc2NyaXB0aW9uIjogImFkbWluIHRlbmFudCIsICJlbmFibGVkIjogdHJ1ZSwgImlkIjogImM1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgIm5hbWUiOiAiYWRtaW4ifX0sICJzZXJ2aWNlQ2F0YWxvZyI6IFt7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc0L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMWJiNzU4NWIzMzgxNGI4Mjk4NzJlYjQ0MjAyMTg5OGEiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NC92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJjb21wdXRlIiwgIm5hbWUiOiAibm92YSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJpZCI6ICJhYTdkNDU2NTNhYjI0ZGY2YmE5ZDE4NGE1ZWRkNGYxMyIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo5Njk2LyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJuZXR3b3JrIiwgIm5hbWUiOiAibmV1dHJvbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMmJmNGQ5YzZiYTgwNDM1M2JjZGNlZGZjNTAxMDNiYjYiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWV2MiIsICJuYW1lIjogImNpbmRlcnYyIn0sIHsiZW5kcG9pbnRzIjogW3siYWRtaW5VUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjMiLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3NC92MyIsICJpZCI6ICIzZmQ4NDBjYmFkZDM0NmFiOTE2YjA2YWYxZjRlNWJmMCIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo4Nzc0L3YzIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImNvbXB1dGV2MyIsICJuYW1lIjogIm5vdmF2MyJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5MjkyIiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40OjkyOTIiLCAiaWQiOiAiMTJjOTM1NzkwYmM5NGE3ODljNzJmOWJiYjIxZjM5YmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6OTI5MiJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJpbWFnZSIsICJuYW1lIjogImdsYW5jZSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc3IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzciLCAiaWQiOiAiMWNlNDkwMWQ4OTE1NDIzZTk2ZGFiM2ZlMWZiMzY2M2MiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJtZXRlcmluZyIsICJuYW1lIjogImNlaWxvbWV0ZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAiaWQiOiAiNWU4ZjExYzk3ZTgwNDNiNWJkZTA1YmVhMmRlNDYxNmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODAwMC92MS8ifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiY2xvdWRmb3JtYXRpb24iLCAibmFtZSI6ICJoZWF0LWNmbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiNTRiOWVjMjhiYzYwNDI1MmIwMGNmZTZlMGU0NGFhOTQiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWUiLCAibmFtZSI6ICJjaW5kZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3My9zZXJ2aWNlcy9BZG1pbiIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4NzczL3NlcnZpY2VzL0Nsb3VkIiwgImlkIjogIjA3NWVjNzliMGJlMzQxYmFhYmUyZTliMTIwNTkxZjQ4IiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40Ojg3NzMvc2VydmljZXMvQ2xvdWQifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiZWMyIiwgIm5hbWUiOiAibm92YV9lYzIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwNC92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4MDA0L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgImlkIjogIjI2MmM0YjM3MzY3ODQ2OGE5ODU1YTNlYmM2MDE1OTYwIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40OjgwMDQvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAib3JjaGVzdHJhdGlvbiIsICJuYW1lIjogImhlYXQifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6MzUzNTcvdjIuMCIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo1MDAwL3YyLjAiLCAiaWQiOiAiMDg5ZmRiMjIyNDk1NDZiOTlhMWU1N2FlYzBiMWU3NmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6NTAwMC92Mi4wIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImlkZW50aXR5IiwgIm5hbWUiOiAia2V5c3RvbmUifV0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJhZG1pbiIsICJyb2xlc19saW5rcyI6IFtdLCAiaWQiOiAiM2Y3NmI5NDY2NzQzNGNmM2JkYzMyM2NmMDIxYzUwZjgiLCAicm9sZXMiOiBbeyJuYW1lIjogImFkbWluIn1dLCAibmFtZSI6ICJhZG1pbiJ9LCAibWV0YWRhdGEiOiB7ImlzX2FkbWluIjogMCwgInJvbGVzIjogWyIxZThiYzVkMWYzYTQ0OGU5YTJhMWNkYTU4ZDk3ZjkyYiJdfX19MYIBgTCCAX0CAQEwXDBXMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVW5zZXQxDjAMBgNVBAcMBVVuc2V0MQ4wDAYDVQQKDAVVbnNldDEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tAgEBMAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIIBAHGQ0NFb0OcE74KIU9DmmvgVyYCrNwwWrwG1CObr9111AHfEr+bn6YfX1ePRUhB2KpcuBPLeIfM-RlLHNwpLzYtvKIwdj0TxIecbF9PuTkWMEZ9Kxl+KE8F4dJOnv0XnAiWZ8QzrMZOo4d+owLJmNNLE1TKfGqv8ughdcrjHtUicHT2E0AOfO3ylEhJPsazUl8XIIWQ4sMWTrs0ROMiZnWPWbomYb49LIaREHD6nDfZX+EDZbHSfPVLTYVL-+qkiIH52-lXqz-OKPCn+Lt3RzXYDzapZd8cpzVgJpTuq2YKMZ+H06yvHFCTZNN49j6kZHz0Qkn2MjbwU8sH10wA7W6k=\x22, \x22tenant\x22: {\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}}, \x22serviceCatalog\x22: [{\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8774/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8774/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x221bb7585b33814b829872eb442021898a\x22, \x22publicURL\x22: \x22http://192.168.11.4:8774/v2/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22compute\x22, \x22name\x22: \x22nova\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:9696/\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:9696/\x22, \x22id\x22: \x22aa7d45653ab24df6ba9d184a5edd4f13\x22, \x22publicURL\x22: \x22http://192.168.11.4:9696/\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22network\x22, \x22name\x22: \x22neutron\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8776/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8776/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x222bf4d9c6ba804353bcdcedfc50103bb6\x22, \x22publicURL\x22: \x22http://192.168.11.4:8776/v2/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22volumev2\x22, \x22name\x22: \x22cinderv2\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8774/v3\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8774/v3\x22, \x22id\x22: \x223fd840cbadd346ab916b06af1f4e5bf0\x22, \x22publicURL\x22: \x22http://192.168.11.4:8774/v3\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22computev3\x22, \x22name\x22: \x22novav3\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:9292\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:9292\x22, \x22id\x22: \x2212c935790bc94a789c72f9bbb21f39bc\x22, \x22publicURL\x22: \x22http://192.168.11.4:9292\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22image\x22, \x22name\x22: \x22glance\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8777\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8777\x22, \x22id\x22: \x221ce4901d8915423e96dab3fe1fb3663c\x22, \x22publicURL\x22: \x22http://192.168.11.4:8777\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22metering\x22, \x22name\x22: \x22ceilometer\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8000/v1/\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8000/v1/\x22, \x22id\x22: \x225e8f11c97e8043b5bde05bea2de4616c\x22, \x22publicURL\x22: \x22http://192.168.11.4:8000/v1/\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22cloudformation\x22, \x22name\x22: \x22heat-cfn\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8776/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8776/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x2254b9ec28bc604252b00cfe6e0e44aa94\x22, \x22publicURL\x22: \x22http://192.168.11.4:8776/v1/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22volume\x22, \x22name\x22: \x22cinder\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8773/services/Admin\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8773/services/Cloud\x22, \x22id\x22: \x22075ec79b0be341baabe2e9b120591f48\x22, \x22publicURL\x22: \x22http://192.168.11.4:8773/services/Cloud\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22ec2\x22, \x22name\x22: \x22nova_ec2\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8004/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8004/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x22262c4b373678468a9855a3ebc6015960\x22, \x22publicURL\x22: \x22http://192.168.11.4:8004/v1/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22orchestration\x22, \x22name\x22: \x22heat\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:35357/v2.0\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:5000/v2.0\x22, \x22id\x22: \x22089fdb22249546b99a1e57aec0b1e76c\x22, \x22publicURL\x22: \x22http://192.168.11.4:5000/v2.0\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22identity\x22, \x22name\x22: \x22keystone\x22}], \x22user\x22: {\x22username\x22: \x22admin\x22, \x22roles_links\x22: [], \x22id\x22: \x223f76b94667434cf3bdc323cf021c50f8\x22, \x22roles\x22: [{\x22name\x22: \x22admin\x22}], \x22name\x22: \x22admin\x22}, \x22metadata\x22: {\x22is_admin\x22: 0, \x22roles\x22: [\x221e8bc5d1f3a448e9a2a1cda58d97f92b\x22]}}}"
-        http_version: 
-      recorded_at: "Tue, 30 Sep 2014 06:59:48 GMT"
-    - request: 
-        method: get
-        uri: "http://172.16.33.4:35357/v2.0/tenants"
-        body: 
-          encoding: US-ASCII
-          string: ""
-        headers: 
-          Content-Type: 
-            - application/json
-          User-Agent: 
-            - "Faraday v0.8.8"
-          X-Auth-Token: 
-            - "MIIRIAYJKoZIhvcNAQcCoIIRETCCEQ0CAQExCTAHBgUrDgMCGjCCD3YGCSqGSIb3DQEHAaCCD2cEgg9jeyJhY2Nlc3MiOiB7InRva2VuIjogeyJpc3N1ZWRfYXQiOiAiMjAxNC0wOS0zMFQwNjo1OTo0OC4zMzg5NDAiLCAiZXhwaXJlcyI6ICIyMDE0LTA5LTMwVDA3OjU5OjQ4WiIsICJpZCI6ICJwbGFjZWhvbGRlciIsICJ0ZW5hbnQiOiB7ImRlc2NyaXB0aW9uIjogImFkbWluIHRlbmFudCIsICJlbmFibGVkIjogdHJ1ZSwgImlkIjogImM1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgIm5hbWUiOiAiYWRtaW4ifX0sICJzZXJ2aWNlQ2F0YWxvZyI6IFt7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc0L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMWJiNzU4NWIzMzgxNGI4Mjk4NzJlYjQ0MjAyMTg5OGEiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NC92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJjb21wdXRlIiwgIm5hbWUiOiAibm92YSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJpZCI6ICJhYTdkNDU2NTNhYjI0ZGY2YmE5ZDE4NGE1ZWRkNGYxMyIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo5Njk2LyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJuZXR3b3JrIiwgIm5hbWUiOiAibmV1dHJvbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMmJmNGQ5YzZiYTgwNDM1M2JjZGNlZGZjNTAxMDNiYjYiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWV2MiIsICJuYW1lIjogImNpbmRlcnYyIn0sIHsiZW5kcG9pbnRzIjogW3siYWRtaW5VUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjMiLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3NC92MyIsICJpZCI6ICIzZmQ4NDBjYmFkZDM0NmFiOTE2YjA2YWYxZjRlNWJmMCIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo4Nzc0L3YzIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImNvbXB1dGV2MyIsICJuYW1lIjogIm5vdmF2MyJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5MjkyIiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40OjkyOTIiLCAiaWQiOiAiMTJjOTM1NzkwYmM5NGE3ODljNzJmOWJiYjIxZjM5YmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6OTI5MiJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJpbWFnZSIsICJuYW1lIjogImdsYW5jZSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc3IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzciLCAiaWQiOiAiMWNlNDkwMWQ4OTE1NDIzZTk2ZGFiM2ZlMWZiMzY2M2MiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJtZXRlcmluZyIsICJuYW1lIjogImNlaWxvbWV0ZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAiaWQiOiAiNWU4ZjExYzk3ZTgwNDNiNWJkZTA1YmVhMmRlNDYxNmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODAwMC92MS8ifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiY2xvdWRmb3JtYXRpb24iLCAibmFtZSI6ICJoZWF0LWNmbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiNTRiOWVjMjhiYzYwNDI1MmIwMGNmZTZlMGU0NGFhOTQiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWUiLCAibmFtZSI6ICJjaW5kZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3My9zZXJ2aWNlcy9BZG1pbiIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4NzczL3NlcnZpY2VzL0Nsb3VkIiwgImlkIjogIjA3NWVjNzliMGJlMzQxYmFhYmUyZTliMTIwNTkxZjQ4IiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40Ojg3NzMvc2VydmljZXMvQ2xvdWQifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiZWMyIiwgIm5hbWUiOiAibm92YV9lYzIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwNC92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4MDA0L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgImlkIjogIjI2MmM0YjM3MzY3ODQ2OGE5ODU1YTNlYmM2MDE1OTYwIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40OjgwMDQvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAib3JjaGVzdHJhdGlvbiIsICJuYW1lIjogImhlYXQifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6MzUzNTcvdjIuMCIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo1MDAwL3YyLjAiLCAiaWQiOiAiMDg5ZmRiMjIyNDk1NDZiOTlhMWU1N2FlYzBiMWU3NmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6NTAwMC92Mi4wIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImlkZW50aXR5IiwgIm5hbWUiOiAia2V5c3RvbmUifV0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJhZG1pbiIsICJyb2xlc19saW5rcyI6IFtdLCAiaWQiOiAiM2Y3NmI5NDY2NzQzNGNmM2JkYzMyM2NmMDIxYzUwZjgiLCAicm9sZXMiOiBbeyJuYW1lIjogImFkbWluIn1dLCAibmFtZSI6ICJhZG1pbiJ9LCAibWV0YWRhdGEiOiB7ImlzX2FkbWluIjogMCwgInJvbGVzIjogWyIxZThiYzVkMWYzYTQ0OGU5YTJhMWNkYTU4ZDk3ZjkyYiJdfX19MYIBgTCCAX0CAQEwXDBXMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVW5zZXQxDjAMBgNVBAcMBVVuc2V0MQ4wDAYDVQQKDAVVbnNldDEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tAgEBMAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIIBAHGQ0NFb0OcE74KIU9DmmvgVyYCrNwwWrwG1CObr9111AHfEr+bn6YfX1ePRUhB2KpcuBPLeIfM-RlLHNwpLzYtvKIwdj0TxIecbF9PuTkWMEZ9Kxl+KE8F4dJOnv0XnAiWZ8QzrMZOo4d+owLJmNNLE1TKfGqv8ughdcrjHtUicHT2E0AOfO3ylEhJPsazUl8XIIWQ4sMWTrs0ROMiZnWPWbomYb49LIaREHD6nDfZX+EDZbHSfPVLTYVL-+qkiIH52-lXqz-OKPCn+Lt3RzXYDzapZd8cpzVgJpTuq2YKMZ+H06yvHFCTZNN49j6kZHz0Qkn2MjbwU8sH10wA7W6k="
-      response: 
-        status: 
-          code: 200
-          message: 
-        headers: 
-          vary: 
-            - X-Auth-Token
-          content-type: 
-            - application/json
-          content-length: 
-            - "491"
-          date: 
-            - "Tue, 30 Sep 2014 06:59:48 GMT"
-          connection: 
-            - close
-        body: 
-          encoding: UTF-8
-          string: "{\x22tenants_links\x22: [], \x22tenants\x22: [{\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x2234e463e2bab24f78990ca864e4a28ba2\x22, \x22name\x22: \x22test2\x22}, {\x22description\x22: \x22Tenant for the openstack services\x22, \x22enabled\x22: true, \x22id\x22: \x2268c8fcf77aff4b409cc158c0f6cbff7b\x22, \x22name\x22: \x22services\x22}, {\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c330f1bc663648df9c1e7835a1e7a955\x22, \x22name\x22: \x22test\x22}, {\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}]}"
-        http_version: 
-      recorded_at: "Tue, 30 Sep 2014 06:59:48 GMT"
-  recorded_with: "VCR 2.9.3"
\ No newline at end of file
diff --git a/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/request/without_session.yml b/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/request/without_session.yml
deleted file mode 100644 (file)
index 784fb2f..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
---- 
-  http_interactions: 
-    - request: 
-        method: get
-        uri: "http://192.168.11.4:35357/v2.0/tenants"
-        body: 
-          encoding: US-ASCII
-          string: ""
-        headers: 
-          Content-Type: 
-            - application/json
-          User-Agent: 
-            - "Faraday v0.8.8"
-          X-Auth-Token: 
-            - sosp-kyl
-      response: 
-        status: 
-          code: 200
-          message: 
-        headers: 
-          vary: 
-            - X-Auth-Token
-          content-type: 
-            - application/json
-          content-length: 
-            - "491"
-          date: 
-            - "Tue, 30 Sep 2014 06:59:48 GMT"
-          connection: 
-            - close
-        body: 
-          encoding: UTF-8
-          string: "{\x22tenants_links\x22: [], \x22tenants\x22: [{\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x2234e463e2bab24f78990ca864e4a28ba2\x22, \x22name\x22: \x22test2\x22}, {\x22description\x22: \x22Tenant for the openstack services\x22, \x22enabled\x22: true, \x22id\x22: \x2268c8fcf77aff4b409cc158c0f6cbff7b\x22, \x22name\x22: \x22services\x22}, {\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c330f1bc663648df9c1e7835a1e7a955\x22, \x22name\x22: \x22test\x22}, {\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}]}"
-        http_version: 
-      recorded_at: "Tue, 30 Sep 2014 06:59:48 GMT"
-  recorded_with: "VCR 2.9.3"
\ No newline at end of file
diff --git a/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/session/with_password.yml b/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/session/with_password.yml
deleted file mode 100644 (file)
index 3faa474..0000000
+++ /dev/null
@@ -1,67 +0,0 @@
---- 
-  http_interactions: 
-    - request: 
-        method: post
-        uri: "http://192.168.11.4:35357/v2.0/tokens"
-        body: 
-          encoding: UTF-8
-          string: "{\x22auth\x22:{\x22passwordCredentials\x22:{\x22username\x22:\x22admin\x22,\x22password\x22:\x22fyby-tet\x22},\x22tenantName\x22:\x22admin\x22}}"
-        headers: 
-          Content-Type: 
-            - application/json
-          User-Agent: 
-            - "Faraday v0.8.8"
-      response: 
-        status: 
-          code: 200
-          message: 
-        headers: 
-          vary: 
-            - X-Auth-Token
-          content-type: 
-            - application/json
-          content-length: 
-            - "9780"
-          date: 
-            - "Tue, 30 Sep 2014 07:16:15 GMT"
-          connection: 
-            - close
-        body: 
-          encoding: UTF-8
-          string: "{\x22access\x22: {\x22token\x22: {\x22issued_at\x22: \x222014-09-30T07:16:15.042778\x22, \x22expires\x22: \x222014-09-30T08:16:15Z\x22, \x22id\x22: \x22MIIRIAYJKoZIhvcNAQcCoIIRETCCEQ0CAQExCTAHBgUrDgMCGjCCD3YGCSqGSIb3DQEHAaCCD2cEgg9jeyJhY2Nlc3MiOiB7InRva2VuIjogeyJpc3N1ZWRfYXQiOiAiMjAxNC0wOS0zMFQwNzoxNjoxNS4wNDI3NzgiLCAiZXhwaXJlcyI6ICIyMDE0LTA5LTMwVDA4OjE2OjE1WiIsICJpZCI6ICJwbGFjZWhvbGRlciIsICJ0ZW5hbnQiOiB7ImRlc2NyaXB0aW9uIjogImFkbWluIHRlbmFudCIsICJlbmFibGVkIjogdHJ1ZSwgImlkIjogImM1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgIm5hbWUiOiAiYWRtaW4ifX0sICJzZXJ2aWNlQ2F0YWxvZyI6IFt7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc0L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMWJiNzU4NWIzMzgxNGI4Mjk4NzJlYjQ0MjAyMTg5OGEiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NC92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJjb21wdXRlIiwgIm5hbWUiOiAibm92YSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJpZCI6ICJhYTdkNDU2NTNhYjI0ZGY2YmE5ZDE4NGE1ZWRkNGYxMyIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo5Njk2LyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJuZXR3b3JrIiwgIm5hbWUiOiAibmV1dHJvbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMmJmNGQ5YzZiYTgwNDM1M2JjZGNlZGZjNTAxMDNiYjYiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWV2MiIsICJuYW1lIjogImNpbmRlcnYyIn0sIHsiZW5kcG9pbnRzIjogW3siYWRtaW5VUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjMiLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3NC92MyIsICJpZCI6ICIzZmQ4NDBjYmFkZDM0NmFiOTE2YjA2YWYxZjRlNWJmMCIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo4Nzc0L3YzIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImNvbXB1dGV2MyIsICJuYW1lIjogIm5vdmF2MyJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5MjkyIiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40OjkyOTIiLCAiaWQiOiAiMTJjOTM1NzkwYmM5NGE3ODljNzJmOWJiYjIxZjM5YmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6OTI5MiJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJpbWFnZSIsICJuYW1lIjogImdsYW5jZSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc3IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzciLCAiaWQiOiAiMWNlNDkwMWQ4OTE1NDIzZTk2ZGFiM2ZlMWZiMzY2M2MiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJtZXRlcmluZyIsICJuYW1lIjogImNlaWxvbWV0ZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAiaWQiOiAiNWU4ZjExYzk3ZTgwNDNiNWJkZTA1YmVhMmRlNDYxNmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODAwMC92MS8ifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiY2xvdWRmb3JtYXRpb24iLCAibmFtZSI6ICJoZWF0LWNmbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiNTRiOWVjMjhiYzYwNDI1MmIwMGNmZTZlMGU0NGFhOTQiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWUiLCAibmFtZSI6ICJjaW5kZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3My9zZXJ2aWNlcy9BZG1pbiIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4NzczL3NlcnZpY2VzL0Nsb3VkIiwgImlkIjogIjA3NWVjNzliMGJlMzQxYmFhYmUyZTliMTIwNTkxZjQ4IiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40Ojg3NzMvc2VydmljZXMvQ2xvdWQifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiZWMyIiwgIm5hbWUiOiAibm92YV9lYzIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwNC92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4MDA0L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgImlkIjogIjI2MmM0YjM3MzY3ODQ2OGE5ODU1YTNlYmM2MDE1OTYwIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40OjgwMDQvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAib3JjaGVzdHJhdGlvbiIsICJuYW1lIjogImhlYXQifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6MzUzNTcvdjIuMCIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo1MDAwL3YyLjAiLCAiaWQiOiAiMDg5ZmRiMjIyNDk1NDZiOTlhMWU1N2FlYzBiMWU3NmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6NTAwMC92Mi4wIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImlkZW50aXR5IiwgIm5hbWUiOiAia2V5c3RvbmUifV0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJhZG1pbiIsICJyb2xlc19saW5rcyI6IFtdLCAiaWQiOiAiM2Y3NmI5NDY2NzQzNGNmM2JkYzMyM2NmMDIxYzUwZjgiLCAicm9sZXMiOiBbeyJuYW1lIjogImFkbWluIn1dLCAibmFtZSI6ICJhZG1pbiJ9LCAibWV0YWRhdGEiOiB7ImlzX2FkbWluIjogMCwgInJvbGVzIjogWyIxZThiYzVkMWYzYTQ0OGU5YTJhMWNkYTU4ZDk3ZjkyYiJdfX19MYIBgTCCAX0CAQEwXDBXMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVW5zZXQxDjAMBgNVBAcMBVVuc2V0MQ4wDAYDVQQKDAVVbnNldDEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tAgEBMAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIIBAEOAl3MRmSUB+J+kRi+qRhwOrNRmj-wDqT5nJTlbafOjofSXsHG683LaipA7oPoH-ARUPDxXIZfevRue7bQQB3I4cWIUSItIPyW4xDpF+iHy3QOm+I-3v3ctze2Z3Rp0TRaYFsItTZZETsSXI28yBt9+3Dsk3a7Vv10HAZetbV1i6qu6avLcJsmN-1J3KLwCDSEvpMgDAcpzAnhba1fi+X8GrCCTz4c1uIcPfsHxX4g8gNkB4-VT0lkRmfSxdrGeRz0uN12oDqgCL64IV1mJ6Bi9Unh15QFcLwU0F8ote+joG9G29fw3WDzneXHIeEIZSBXmOAX2kQBOnZa2sZg8gls=\x22, \x22tenant\x22: {\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}}, \x22serviceCatalog\x22: [{\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8774/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8774/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x221bb7585b33814b829872eb442021898a\x22, \x22publicURL\x22: \x22http://192.168.11.4:8774/v2/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22compute\x22, \x22name\x22: \x22nova\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:9696/\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:9696/\x22, \x22id\x22: \x22aa7d45653ab24df6ba9d184a5edd4f13\x22, \x22publicURL\x22: \x22http://192.168.11.4:9696/\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22network\x22, \x22name\x22: \x22neutron\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8776/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8776/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x222bf4d9c6ba804353bcdcedfc50103bb6\x22, \x22publicURL\x22: \x22http://192.168.11.4:8776/v2/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22volumev2\x22, \x22name\x22: \x22cinderv2\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8774/v3\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8774/v3\x22, \x22id\x22: \x223fd840cbadd346ab916b06af1f4e5bf0\x22, \x22publicURL\x22: \x22http://192.168.11.4:8774/v3\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22computev3\x22, \x22name\x22: \x22novav3\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:9292\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:9292\x22, \x22id\x22: \x2212c935790bc94a789c72f9bbb21f39bc\x22, \x22publicURL\x22: \x22http://192.168.11.4:9292\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22image\x22, \x22name\x22: \x22glance\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8777\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8777\x22, \x22id\x22: \x221ce4901d8915423e96dab3fe1fb3663c\x22, \x22publicURL\x22: \x22http://192.168.11.4:8777\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22metering\x22, \x22name\x22: \x22ceilometer\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8000/v1/\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8000/v1/\x22, \x22id\x22: \x225e8f11c97e8043b5bde05bea2de4616c\x22, \x22publicURL\x22: \x22http://192.168.11.4:8000/v1/\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22cloudformation\x22, \x22name\x22: \x22heat-cfn\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8776/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8776/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x2254b9ec28bc604252b00cfe6e0e44aa94\x22, \x22publicURL\x22: \x22http://192.168.11.4:8776/v1/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22volume\x22, \x22name\x22: \x22cinder\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8773/services/Admin\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8773/services/Cloud\x22, \x22id\x22: \x22075ec79b0be341baabe2e9b120591f48\x22, \x22publicURL\x22: \x22http://192.168.11.4:8773/services/Cloud\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22ec2\x22, \x22name\x22: \x22nova_ec2\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8004/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8004/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x22262c4b373678468a9855a3ebc6015960\x22, \x22publicURL\x22: \x22http://192.168.11.4:8004/v1/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22orchestration\x22, \x22name\x22: \x22heat\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:35357/v2.0\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:5000/v2.0\x22, \x22id\x22: \x22089fdb22249546b99a1e57aec0b1e76c\x22, \x22publicURL\x22: \x22http://192.168.11.4:5000/v2.0\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22identity\x22, \x22name\x22: \x22keystone\x22}], \x22user\x22: {\x22username\x22: \x22admin\x22, \x22roles_links\x22: [], \x22id\x22: \x223f76b94667434cf3bdc323cf021c50f8\x22, \x22roles\x22: [{\x22name\x22: \x22admin\x22}], \x22name\x22: \x22admin\x22}, \x22metadata\x22: {\x22is_admin\x22: 0, \x22roles\x22: [\x221e8bc5d1f3a448e9a2a1cda58d97f92b\x22]}}}"
-        http_version: 
-      recorded_at: "Tue, 30 Sep 2014 07:16:15 GMT"
-    - request: 
-        method: get
-        uri: "http://192.168.11.4:5000/v2.0/tenants"
-        body: 
-          encoding: US-ASCII
-          string: ""
-        headers: 
-          Content-Type: 
-            - application/json
-          User-Agent: 
-            - "Faraday v0.8.8"
-          X-Auth-Token: 
-            - "MIIRIAYJKoZIhvcNAQcCoIIRETCCEQ0CAQExCTAHBgUrDgMCGjCCD3YGCSqGSIb3DQEHAaCCD2cEgg9jeyJhY2Nlc3MiOiB7InRva2VuIjogeyJpc3N1ZWRfYXQiOiAiMjAxNC0wOS0zMFQwNzoxNjoxNS4wNDI3NzgiLCAiZXhwaXJlcyI6ICIyMDE0LTA5LTMwVDA4OjE2OjE1WiIsICJpZCI6ICJwbGFjZWhvbGRlciIsICJ0ZW5hbnQiOiB7ImRlc2NyaXB0aW9uIjogImFkbWluIHRlbmFudCIsICJlbmFibGVkIjogdHJ1ZSwgImlkIjogImM1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgIm5hbWUiOiAiYWRtaW4ifX0sICJzZXJ2aWNlQ2F0YWxvZyI6IFt7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc0L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMWJiNzU4NWIzMzgxNGI4Mjk4NzJlYjQ0MjAyMTg5OGEiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NC92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJjb21wdXRlIiwgIm5hbWUiOiAibm92YSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJpZCI6ICJhYTdkNDU2NTNhYjI0ZGY2YmE5ZDE4NGE1ZWRkNGYxMyIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo5Njk2LyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJuZXR3b3JrIiwgIm5hbWUiOiAibmV1dHJvbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMmJmNGQ5YzZiYTgwNDM1M2JjZGNlZGZjNTAxMDNiYjYiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWV2MiIsICJuYW1lIjogImNpbmRlcnYyIn0sIHsiZW5kcG9pbnRzIjogW3siYWRtaW5VUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjMiLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3NC92MyIsICJpZCI6ICIzZmQ4NDBjYmFkZDM0NmFiOTE2YjA2YWYxZjRlNWJmMCIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo4Nzc0L3YzIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImNvbXB1dGV2MyIsICJuYW1lIjogIm5vdmF2MyJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5MjkyIiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40OjkyOTIiLCAiaWQiOiAiMTJjOTM1NzkwYmM5NGE3ODljNzJmOWJiYjIxZjM5YmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6OTI5MiJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJpbWFnZSIsICJuYW1lIjogImdsYW5jZSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc3IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzciLCAiaWQiOiAiMWNlNDkwMWQ4OTE1NDIzZTk2ZGFiM2ZlMWZiMzY2M2MiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJtZXRlcmluZyIsICJuYW1lIjogImNlaWxvbWV0ZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAiaWQiOiAiNWU4ZjExYzk3ZTgwNDNiNWJkZTA1YmVhMmRlNDYxNmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODAwMC92MS8ifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiY2xvdWRmb3JtYXRpb24iLCAibmFtZSI6ICJoZWF0LWNmbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiNTRiOWVjMjhiYzYwNDI1MmIwMGNmZTZlMGU0NGFhOTQiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWUiLCAibmFtZSI6ICJjaW5kZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3My9zZXJ2aWNlcy9BZG1pbiIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4NzczL3NlcnZpY2VzL0Nsb3VkIiwgImlkIjogIjA3NWVjNzliMGJlMzQxYmFhYmUyZTliMTIwNTkxZjQ4IiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40Ojg3NzMvc2VydmljZXMvQ2xvdWQifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiZWMyIiwgIm5hbWUiOiAibm92YV9lYzIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwNC92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4MDA0L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgImlkIjogIjI2MmM0YjM3MzY3ODQ2OGE5ODU1YTNlYmM2MDE1OTYwIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40OjgwMDQvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAib3JjaGVzdHJhdGlvbiIsICJuYW1lIjogImhlYXQifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6MzUzNTcvdjIuMCIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo1MDAwL3YyLjAiLCAiaWQiOiAiMDg5ZmRiMjIyNDk1NDZiOTlhMWU1N2FlYzBiMWU3NmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6NTAwMC92Mi4wIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImlkZW50aXR5IiwgIm5hbWUiOiAia2V5c3RvbmUifV0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJhZG1pbiIsICJyb2xlc19saW5rcyI6IFtdLCAiaWQiOiAiM2Y3NmI5NDY2NzQzNGNmM2JkYzMyM2NmMDIxYzUwZjgiLCAicm9sZXMiOiBbeyJuYW1lIjogImFkbWluIn1dLCAibmFtZSI6ICJhZG1pbiJ9LCAibWV0YWRhdGEiOiB7ImlzX2FkbWluIjogMCwgInJvbGVzIjogWyIxZThiYzVkMWYzYTQ0OGU5YTJhMWNkYTU4ZDk3ZjkyYiJdfX19MYIBgTCCAX0CAQEwXDBXMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVW5zZXQxDjAMBgNVBAcMBVVuc2V0MQ4wDAYDVQQKDAVVbnNldDEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tAgEBMAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIIBAEOAl3MRmSUB+J+kRi+qRhwOrNRmj-wDqT5nJTlbafOjofSXsHG683LaipA7oPoH-ARUPDxXIZfevRue7bQQB3I4cWIUSItIPyW4xDpF+iHy3QOm+I-3v3ctze2Z3Rp0TRaYFsItTZZETsSXI28yBt9+3Dsk3a7Vv10HAZetbV1i6qu6avLcJsmN-1J3KLwCDSEvpMgDAcpzAnhba1fi+X8GrCCTz4c1uIcPfsHxX4g8gNkB4-VT0lkRmfSxdrGeRz0uN12oDqgCL64IV1mJ6Bi9Unh15QFcLwU0F8ote+joG9G29fw3WDzneXHIeEIZSBXmOAX2kQBOnZa2sZg8gls="
-      response: 
-        status: 
-          code: 200
-          message: 
-        headers: 
-          vary: 
-            - X-Auth-Token
-          content-type: 
-            - application/json
-          content-length: 
-            - "143"
-          date: 
-            - "Tue, 30 Sep 2014 07:16:15 GMT"
-          connection: 
-            - close
-        body: 
-          encoding: UTF-8
-          string: "{\x22tenants_links\x22: [], \x22tenants\x22: [{\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}]}"
-        http_version: 
-      recorded_at: "Tue, 30 Sep 2014 07:16:15 GMT"
-  recorded_with: "VCR 2.9.3"
\ No newline at end of file
diff --git a/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/session/with_token.yml b/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/session/with_token.yml
deleted file mode 100644 (file)
index 784fb2f..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
---- 
-  http_interactions: 
-    - request: 
-        method: get
-        uri: "http://192.168.11.4:35357/v2.0/tenants"
-        body: 
-          encoding: US-ASCII
-          string: ""
-        headers: 
-          Content-Type: 
-            - application/json
-          User-Agent: 
-            - "Faraday v0.8.8"
-          X-Auth-Token: 
-            - sosp-kyl
-      response: 
-        status: 
-          code: 200
-          message: 
-        headers: 
-          vary: 
-            - X-Auth-Token
-          content-type: 
-            - application/json
-          content-length: 
-            - "491"
-          date: 
-            - "Tue, 30 Sep 2014 06:59:48 GMT"
-          connection: 
-            - close
-        body: 
-          encoding: UTF-8
-          string: "{\x22tenants_links\x22: [], \x22tenants\x22: [{\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x2234e463e2bab24f78990ca864e4a28ba2\x22, \x22name\x22: \x22test2\x22}, {\x22description\x22: \x22Tenant for the openstack services\x22, \x22enabled\x22: true, \x22id\x22: \x2268c8fcf77aff4b409cc158c0f6cbff7b\x22, \x22name\x22: \x22services\x22}, {\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c330f1bc663648df9c1e7835a1e7a955\x22, \x22name\x22: \x22test\x22}, {\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}]}"
-        http_version: 
-      recorded_at: "Tue, 30 Sep 2014 06:59:48 GMT"
-  recorded_with: "VCR 2.9.3"
\ No newline at end of file
index 6819e7e..62d03f2 100644 (file)
@@ -3,27 +3,27 @@ require 'spec_helper'
 describe 'os_database_connection' do
 
   it 'refuses String' do
-    should run.with_params('foo').\
+    is_expected.to run.with_params('foo').\
       and_raise_error(Puppet::ParseError, /Requires an hash/)
   end
 
   it 'refuses Array' do
-    should run.with_params(['foo']).\
+    is_expected.to run.with_params(['foo']).\
       and_raise_error(Puppet::ParseError, /Requires an hash/)
   end
 
   it 'refuses without at least one argument' do
-    should run.with_params().\
+    is_expected.to run.with_params().\
       and_raise_error(Puppet::ParseError, /Wrong number of arguments/)
   end
 
   it 'refuses too many arguments' do
-    should run.with_params('foo', 'bar').\
+    is_expected.to run.with_params('foo', 'bar').\
       and_raise_error(Puppet::ParseError, /Wrong number of arguments/)
   end
 
   it 'fails if port is provided with missing host' do
-    should run.with_params({
+    is_expected.to run.with_params({
         'dialect'  => 'sqlite',
         'database' => '/var/lib/keystone/keystone.db',
         'port'     => '3306',
@@ -34,7 +34,7 @@ describe 'os_database_connection' do
   context 'creates the correct connection URI' do
 
     it 'with all parameters' do
-      should run.with_params({
+      is_expected.to run.with_params({
           'dialect'  => 'mysql',
           'host'     => '127.0.0.1',
           'port'     => '3306',
@@ -46,7 +46,7 @@ describe 'os_database_connection' do
     end
 
     it 'without port' do
-      should run.with_params({
+      is_expected.to run.with_params({
           'dialect'  => 'mysql',
           'host'     => '127.0.0.1',
           'database' => 'test',
@@ -57,7 +57,7 @@ describe 'os_database_connection' do
     end
 
     it 'without host and port' do
-      should run.with_params({
+      is_expected.to run.with_params({
           'dialect'  => 'sqlite',
           'database' => '/var/lib/keystone/keystone.db',
           'charset'  => 'utf-8'
@@ -65,7 +65,7 @@ describe 'os_database_connection' do
     end
 
     it 'without username and password' do
-      should run.with_params({
+      is_expected.to run.with_params({
           'dialect'  => 'mysql',
           'host'     => '127.0.0.1',
           'port'     => '3306',
@@ -75,7 +75,7 @@ describe 'os_database_connection' do
     end
 
     it 'with username set to undef' do
-      should run.with_params({
+      is_expected.to run.with_params({
           'dialect'  => 'mysql',
           'host'     => '127.0.0.1',
           'port'     => '3306',
@@ -86,7 +86,7 @@ describe 'os_database_connection' do
     end
 
     it 'with username set to an empty string' do
-      should run.with_params({
+      is_expected.to run.with_params({
           'dialect'  => 'mysql',
           'host'     => '127.0.0.1',
           'port'     => '3306',
@@ -97,7 +97,7 @@ describe 'os_database_connection' do
     end
 
     it 'without password' do
-      should run.with_params({
+      is_expected.to run.with_params({
           'dialect'  => 'mysql',
           'host'     => '127.0.0.1',
           'port'     => '3306',
@@ -108,7 +108,7 @@ describe 'os_database_connection' do
     end
 
     it 'with password set to undef' do
-      should run.with_params({
+      is_expected.to run.with_params({
           'dialect'  => 'mysql',
           'host'     => '127.0.0.1',
           'port'     => '3306',
@@ -120,7 +120,7 @@ describe 'os_database_connection' do
     end
 
     it 'with password set to an empty string' do
-      should run.with_params({
+      is_expected.to run.with_params({
           'dialect'  => 'mysql',
           'host'     => '127.0.0.1',
           'port'     => '3306',
diff --git a/3rdparty/modules/openstacklib/spec/shared_examples.rb b/3rdparty/modules/openstacklib/spec/shared_examples.rb
new file mode 100644 (file)
index 0000000..fec0eac
--- /dev/null
@@ -0,0 +1,5 @@
+shared_examples_for "a Puppet::Error" do |description|
+  it "with message matching #{description.inspect}" do
+    expect { is_expected.to have_class_count(1) }.to raise_error(Puppet::Error, description)
+  end
+end
index ecd609a..53d4dd0 100644 (file)
@@ -1,7 +1,7 @@
 require 'puppetlabs_spec_helper/module_spec_helper'
-require 'vcr'
+require 'shared_examples'
 
-VCR.configure do |c|
-  c.cassette_library_dir = 'spec/fixtures/vcr'
-  c.hook_into :faraday
+RSpec.configure do |c|
+  c.alias_it_should_behave_like_to :it_configures, 'configures'
+  c.alias_it_should_behave_like_to :it_raises, 'raises'
 end
diff --git a/3rdparty/modules/openstacklib/spec/spec_helper_acceptance.rb b/3rdparty/modules/openstacklib/spec/spec_helper_acceptance.rb
new file mode 100644 (file)
index 0000000..1879cbf
--- /dev/null
@@ -0,0 +1,42 @@
+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','puppetlabs-apache'), { :acceptable_exit_codes => 0 }
+      on host, puppet('module','install','puppetlabs-postgresql'), { :acceptable_exit_codes => 0 }
+      on host, puppet('module','install','stahnma-epel'), { :acceptable_exit_codes => 0 }
+      # until https://github.com/tamaskozak/puppetlabs-rabbitmq/commit/8bbfe320035fae2ae900211501008d63dc3c171c is part of a release
+      shell('git clone https://github.com/puppetlabs/puppetlabs-rabbitmq /etc/puppet/modules/rabbitmq')
+      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 => 'openstacklib')
+      # List modules installed to help with debugging
+      on hosts[0], puppet('module','list'), { :acceptable_exit_codes => 0 }
+    end
+  end
+end
diff --git a/3rdparty/modules/openstacklib/spec/unit/provider/aviator_spec.rb b/3rdparty/modules/openstacklib/spec/unit/provider/aviator_spec.rb
deleted file mode 100644 (file)
index 35564e6..0000000
+++ /dev/null
@@ -1,320 +0,0 @@
-# Load libraries from aviator here to simulate how they live together in a real puppet run
-$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'modules', 'aviator', 'lib'))
-require 'puppet'
-require 'vcr'
-require 'spec_helper'
-require 'puppet/provider/aviator'
-
-
-describe Puppet::Provider::Aviator do
-
-  before(:each) do
-    ENV['OS_USERNAME']    = nil
-    ENV['OS_PASSWORD']    = nil
-    ENV['OS_TENANT_NAME'] = nil
-    ENV['OS_AUTH_URL']    = nil
-  end
-
-  let(:log_file) { '/tmp/aviator_spec.log' }
-
-  let(:type) do
-    Puppet::Type.newtype(:test_resource) do
-      newparam(:name, :namevar => true)
-      newparam(:auth)
-      newparam(:log_file)
-    end
-  end
-
-
-  shared_examples 'creating a session using environment variables' do
-    it 'creates an authenticated session' do
-      ENV['OS_USERNAME']    = 'admin'
-      ENV['OS_PASSWORD']    = 'fyby-tet'
-      ENV['OS_TENANT_NAME'] = 'admin'
-      ENV['OS_AUTH_URL']    = 'http://192.168.11.4:35357/v2.0'
-      response = nil
-      VCR.use_cassette('aviator/session/with_password') do
-        session = provider.session
-        response = session.identity_service.request(:list_tenants, :session_data => provider.session_data)
-      end
-      expect(response.status).to eq(200)
-    end
-  end
-
-  shared_examples 'creating a session using a service token from keystone.conf' do
-    it 'creates an unauthenticated session' do
-      data = "[DEFAULT]\nadmin_token=sosp-kyl\nadmin_endpoint=http://192.168.11.4:35357/v2.0"
-      response = nil
-      VCR.use_cassette('aviator/session/with_token') do
-        # Stubbing File.read produces inconsistent results because of how IniConfig
-        # overrides the File class in some versions of Puppet.
-        # Stubbing FileType.filetype(:flat) simplifies working with IniConfig
-        Puppet::Util::FileType.filetype(:flat).any_instance.expects(:read).returns(StringIO.new(data).read)
-        session = provider.session
-        Puppet::Util::FileType.filetype(:flat).any_instance.unstub(:read)
-        response = session.identity_service.request(:list_tenants, :session_data => provider.session_data)
-      end
-
-      expect(response.status).to eq(200)
-    end
-  end
-
-  shared_examples 'it has no credentials' do
-    it 'fails to authenticate' do
-      expect{ provider.session }.to raise_error(Puppet::Error, /No credentials provided/)
-    end
-  end
-
-  shared_examples 'making request with an existing session' do
-   it 'makes a successful request' do
-     VCR.use_cassette('aviator/request/with_session') do
-       session = provider.session
-       response = provider.request(session.identity_service, :list_tenants)
-       expect(response.status).to eq(200)
-     end
-   end
-  end
-
-  shared_examples 'making request with injected session data' do
-    it 'makes a successful request' do
-      VCR.use_cassette('aviator/request/without_session') do
-        session = provider.session
-        response = provider.request(session.identity_service, :list_tenants)
-        expect(response.status).to eq(200)
-      end
-    end
-  end
-
-  shared_examples 'making request with no session or session data' do
-    it 'fails to make a request' do
-      expect{ provider.request(nil, :list_tenants) }.to raise_error(Puppet::Error, /Cannot make a request/)
-    end
-  end
-
-  describe '#session' do
-
-    context 'with valid password credentials in parameters' do
-      let(:resource_attrs) do
-        {
-          :name         => 'stubresource',
-          :auth         => {
-            'username'    => 'admin',
-            'password'    => 'fyby-tet',
-            'tenant_name' => 'admin',
-            'host_uri'    => 'http://192.168.11.4:35357/v2.0',
-          }
-        }
-      end
-
-      it 'creates a session' do
-        provider = Puppet::Provider::Aviator.new(type.new(resource_attrs))
-        response = nil
-        VCR.use_cassette('aviator/session/with_password') do
-          session = provider.session
-          response = session.identity_service.request(:list_tenants)
-        end
-        expect(response.status).to eq(200)
-      end
-    end
-
-    context 'with valid openrc file in parameters' do
-      data = "export OS_USERNAME='admin'\nexport OS_PASSWORD='fyby-tet'\nexport OS_TENANT_NAME='admin'\nexport OS_AUTH_URL='http://192.168.11.4:35357/v2.0'"
-      let(:resource_attrs) do
-        {
-          :name         => 'stubresource',
-          :auth         => {
-            'openrc' => '/root/openrc'
-          }
-        }
-      end
-
-      it 'creates a session' do
-        provider = Puppet::Provider::Aviator.new(type.new(resource_attrs))
-        response = nil
-        VCR.use_cassette('aviator/session/with_password') do
-          File.expects(:open).with('/root/openrc').returns(StringIO.new(data))
-          session = provider.session
-          File.unstub(:open)  # Ignore File.open calls to cassette file
-          response = session.identity_service.request(:list_tenants)
-        end
-        expect(response.status).to eq(200)
-      end
-    end
-
-    context 'with valid service token in parameters' do
-      let(:resource_attrs) do
-        {
-          :name         => 'stubresource',
-          :auth         => {
-            'service_token' => 'sosp-kyl',
-            'host_uri'      => 'http://192.168.11.4:35357/v2.0'
-          }
-        }
-      end
-
-      subject(:session) do
-        provider = Puppet::Provider::Aviator.new(type.new(resource_attrs))
-        VCR.use_cassette('aviator/session/with_token') do
-          session = provider.session
-          response = session.identity_service.request(:list_tenants, :session_data => provider.session_data)
-        end
-      end
-
-      it 'creates a session' do
-        expect(session.status).to eq(200)
-      end
-
-    end
-
-    context 'with valid password credentials in environment variables' do
-      it_behaves_like 'creating a session using environment variables' do
-        let(:resource_attrs) do
-          {
-            :name => 'stubresource',
-          }
-        end
-        let(:provider) do
-          Puppet::Provider::Aviator.new(type.new(resource_attrs))
-        end
-      end
-    end
-
-    context 'with valid service token in keystone.conf' do
-      it_behaves_like 'creating a session using a service token from keystone.conf' do
-        let(:resource_attrs) do
-          {
-            :name => 'stubresource',
-          }
-        end
-        let(:provider) do
-          Puppet::Provider::Aviator.new(type.new(resource_attrs))
-        end
-      end
-
-    end
-
-    context 'with no valid credentials' do
-      it_behaves_like 'it has no credentials' do
-        let(:resource_attrs) do
-          {
-            :name => 'stubresource',
-          }
-        end
-        let(:provider) { Puppet::Provider::Aviator.new(type.new(resource_attrs)) }
-      end
-    end
-
-  end
-
-
-  describe '::session' do
-
-    context 'with valid password credentials in environment variables' do
-      it_behaves_like 'creating a session using environment variables' do
-        let(:provider) { Puppet::Provider::Aviator.dup }
-      end
-    end
-
-    context 'with valid service token in keystone.conf' do
-      it_behaves_like 'creating a session using a service token from keystone.conf' do
-        let(:provider) { Puppet::Provider::Aviator.dup }
-      end
-    end
-
-    context 'with no valid credentials' do
-      it_behaves_like 'it has no credentials' do
-        let(:provider) { Puppet::Provider::Aviator.dup }
-      end
-    end
-  end
-
-  describe '#request' do
-    context 'when a session exists' do
-      it_behaves_like 'making request with an existing session' do
-        let(:resource_attrs) do
-          {
-            :name         => 'stubresource',
-            :auth         => {
-              'username'    => 'admin',
-              'password'    => 'fyby-tet',
-              'tenant_name' => 'admin',
-              'host_uri'    => 'http://192.168.11.4:35357/v2.0',
-            }
-          }
-        end
-        let (:provider) { Puppet::Provider::Aviator.new(type.new(resource_attrs)) }
-      end
-    end
-
-    context 'when injecting session data' do
-      let(:resource_attrs) do
-        {
-          :name         => 'stubresource',
-          :auth         => {
-            'service_token' => 'sosp-kyl',
-            'host_uri'      => 'http://192.168.11.4:35357/v2.0'
-          }
-        }
-      end
-      let(:provider) { Puppet::Provider::Aviator.new(type.new(resource_attrs)) }
-      it 'makes a successful request' do
-        provider = Puppet::Provider::Aviator.new(type.new(resource_attrs))
-        VCR.use_cassette('aviator/request/without_session') do
-          session = provider.session
-          response = provider.request(session.identity_service, :list_tenants)
-          expect(response.status).to eq(200)
-        end
-      end
-    end
-
-    context 'when there is no session or session data' do
-      it_behaves_like 'making request with no session or session data' do
-        let(:resource_attrs) do
-          {
-            :name => 'stubresource',
-          }
-        end
-        let(:provider) {Puppet::Provider::Aviator.new(type.new(resource_attrs)) }
-      end
-    end
-  end
-
-  describe '::request' do
-    context 'when a session exists' do
-
-      it_behaves_like 'making request with an existing session' do
-        let(:provider) { provider = Puppet::Provider::Aviator.dup }
-        before(:each) do
-          ENV['OS_USERNAME']    = 'admin'
-          ENV['OS_PASSWORD']    = 'fyby-tet'
-          ENV['OS_TENANT_NAME'] = 'admin'
-          ENV['OS_AUTH_URL']    = 'http://192.168.11.4:35357/v2.0'
-        end
-      end
-    end
-
-    context 'when injecting session data' do
-      let(:session_data) do
-        {
-          :base_url      => 'http://192.168.11.4:35357/v2.0',
-          :service_token => 'sosp-kyl'
-        }
-      end
-      it 'makes a successful request' do
-        provider = Puppet::Provider::Aviator.dup
-        VCR.use_cassette('aviator/request/without_session') do
-          session = ::Aviator::Session.new(:config => { :provider => 'openstack' }, :log_file => log_file)
-          provider.session_data = session_data
-          response = provider.request(session.identity_service, :list_tenants)
-          expect(response.status).to eq(200)
-        end
-      end
-    end
-
-    context 'when there is no session or session data' do
-      it_behaves_like 'making request with no session or session data' do
-        let(:provider) { Puppet::Provider::Aviator.dup }
-      end
-    end
-  end
-end
diff --git a/3rdparty/modules/openstacklib/spec/unit/provider/openstack/auth_spec.rb b/3rdparty/modules/openstacklib/spec/unit/provider/openstack/auth_spec.rb
new file mode 100644 (file)
index 0000000..7a25944
--- /dev/null
@@ -0,0 +1,222 @@
+require 'puppet'
+require 'spec_helper'
+require 'puppet/provider/openstack'
+require 'puppet/provider/openstack/auth'
+require 'tempfile'
+
+class Puppet::Provider::Openstack::AuthTester < Puppet::Provider::Openstack
+  extend Puppet::Provider::Openstack::Auth
+end
+
+klass = Puppet::Provider::Openstack::AuthTester
+
+describe Puppet::Provider::Openstack::Auth do
+
+  let(:type) do
+    Puppet::Type.newtype(:test_resource) do
+      newparam(:name, :namevar => true)
+      newparam(:log_file)
+    end
+  end
+
+  let(:resource_attrs) do
+    {
+      :name => 'stubresource'
+    }
+  end
+
+  let(:provider) do
+    klass.new(type.new(resource_attrs))
+  end
+
+  before(:each) do
+    ENV['OS_USERNAME']     = nil
+    ENV['OS_PASSWORD']     = nil
+    ENV['OS_PROJECT_NAME'] = nil
+    ENV['OS_AUTH_URL']     = nil
+    ENV['OS_TOKEN']        = nil
+    ENV['OS_URL']          = nil
+  end
+
+  describe '#set_credentials' do
+    it 'adds keys to the object' do
+      credentials = Puppet::Provider::Openstack::CredentialsV2_0.new
+      set = { 'OS_USERNAME'             => 'user',
+              'OS_PASSWORD'             => 'secret',
+              'OS_PROJECT_NAME'         => 'tenant',
+              'OS_AUTH_URL'             => 'http://127.0.0.1:5000',
+              'OS_TOKEN'                => 'token',
+              'OS_URL'                  => 'http://127.0.0.1:35357',
+              'OS_IDENTITY_API_VERSION' => '2.0',
+              'OS_NOT_VALID'            => 'notvalid'
+        }
+      klass.set_credentials(credentials, set)
+      expect(credentials.to_env).to eq(
+        "OS_AUTH_URL"             => "http://127.0.0.1:5000",
+        "OS_IDENTITY_API_VERSION" => '2.0',
+        "OS_PASSWORD"             => "secret",
+        "OS_PROJECT_NAME"         => "tenant",
+        "OS_TOKEN"                => "token",
+        "OS_URL"                  => "http://127.0.0.1:35357",
+        "OS_USERNAME"             => "user")
+    end
+  end
+
+  describe '#rc_filename' do
+    it 'returns RCFILENAME' do
+      expect(klass.rc_filename).to eq("#{ENV['HOME']}/openrc")
+    end
+  end
+
+  describe '#get_os_from_env' do
+    context 'with Openstack environment variables set' do
+      it 'provides a hash' do
+        ENV['OS_AUTH_URL']     = 'http://127.0.0.1:5000'
+        ENV['OS_PASSWORD']     = 'abc123'
+        ENV['OS_PROJECT_NAME'] = 'test'
+        ENV['OS_USERNAME']     = 'test'
+        response = klass.get_os_vars_from_env
+        expect(response).to eq({
+          "OS_AUTH_URL"     => "http://127.0.0.1:5000",
+          "OS_PASSWORD"     => "abc123",
+          "OS_PROJECT_NAME" => "test",
+          "OS_USERNAME"     => "test"})
+      end
+    end
+  end
+
+  describe '#get_os_vars_from_rcfile' do
+    context 'with a valid RC file' do
+      it 'provides a hash' do
+        mock = "export OS_USERNAME='test'\nexport OS_PASSWORD='abc123'\nexport OS_PROJECT_NAME='test'\nexport OS_AUTH_URL='http://127.0.0.1:5000'"
+        filename = 'file'
+        File.expects(:exists?).with('file').returns(true)
+        File.expects(:open).with('file').returns(StringIO.new(mock))
+
+        response = klass.get_os_vars_from_rcfile(filename)
+        expect(response).to eq({
+          "OS_AUTH_URL"     => "http://127.0.0.1:5000",
+          "OS_PASSWORD"     => "abc123",
+          "OS_PROJECT_NAME" => "test",
+          "OS_USERNAME"     => "test"})
+      end
+    end
+
+    context 'with an empty file' do
+      it 'provides an empty hash' do
+        filename = 'file'
+        File.expects(:exists?).with(filename).returns(true)
+        File.expects(:open).with(filename).returns(StringIO.new(""))
+
+        response = klass.get_os_vars_from_rcfile(filename)
+        expect(response).to eq({})
+      end
+    end
+  end
+
+  before(:each) do
+    class Puppet::Provider::Openstack::AuthTester
+      @credentials =  Puppet::Provider::Openstack::CredentialsV2_0.new
+    end
+  end
+
+  describe '#request' do
+    context 'with no valid credentials' do
+      it 'fails to authenticate' do
+        expect { klass.request('project', 'list', ['--long']) }.to raise_error(Puppet::Error::OpenstackAuthInputError, "Insufficient credentials to authenticate")
+        expect(klass.instance_variable_get(:@credentials).to_env).to eq({})
+      end
+    end
+
+    context 'with user credentials in env' do
+      it 'is successful' do
+        klass.expects(:get_os_vars_from_env)
+             .returns({ 'OS_USERNAME'     => 'test',
+                        'OS_PASSWORD'     => 'abc123',
+                        'OS_PROJECT_NAME' => 'test',
+                        'OS_AUTH_URL'     => 'http://127.0.0.1:5000',
+                        'OS_NOT_VALID'    => 'notvalid' })
+        klass.expects(:openstack)
+             .with('project', 'list', '--quiet', '--format', 'csv', ['--long'])
+             .returns('"ID","Name","Description","Enabled"
+"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
+')
+        response = klass.request('project', 'list', ['--long'])
+        expect(response.first[:description]).to eq("Test tenant")
+        expect(klass.instance_variable_get(:@credentials).to_env).to eq({
+          'OS_USERNAME'     => 'test',
+          'OS_PASSWORD'     => 'abc123',
+          'OS_PROJECT_NAME' => 'test',
+          'OS_AUTH_URL'     => 'http://127.0.0.1:5000'
+        })
+      end
+    end
+
+    context 'with service token credentials in env' do
+      it 'is successful' do
+        klass.expects(:get_os_vars_from_env)
+             .returns({ 'OS_TOKEN'     => 'test',
+                        'OS_URL'       => 'http://127.0.0.1:5000',
+                        'OS_NOT_VALID' => 'notvalid' })
+        klass.expects(:openstack)
+             .with('project', 'list', '--quiet', '--format', 'csv', ['--long'])
+             .returns('"ID","Name","Description","Enabled"
+"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
+')
+        response = klass.request('project', 'list', ['--long'])
+        expect(response.first[:description]).to eq("Test tenant")
+        expect(klass.instance_variable_get(:@credentials).to_env).to eq({
+          'OS_TOKEN' => 'test',
+          'OS_URL'   => 'http://127.0.0.1:5000',
+        })
+      end
+    end
+
+    context 'with a RC file containing user credentials' do
+      it 'is successful' do
+        # return incomplete creds from env
+        klass.expects(:get_os_vars_from_env)
+             .returns({ 'OS_USERNAME' => 'incompleteusername',
+                        'OS_AUTH_URL' => 'incompleteauthurl' })
+        mock = "export OS_USERNAME='test'\nexport OS_PASSWORD='abc123'\nexport OS_PROJECT_NAME='test'\nexport OS_AUTH_URL='http://127.0.0.1:5000'\nexport OS_NOT_VALID='notvalid'"
+        File.expects(:exists?).with("#{ENV['HOME']}/openrc").returns(true)
+        File.expects(:open).with("#{ENV['HOME']}/openrc").returns(StringIO.new(mock))
+        klass.expects(:openstack)
+             .with('project', 'list', '--quiet', '--format', 'csv', ['--long'])
+             .returns('"ID","Name","Description","Enabled"
+"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
+')
+        response = provider.class.request('project', 'list', ['--long'])
+        expect(response.first[:description]).to eq("Test tenant")
+        expect(klass.instance_variable_get(:@credentials).to_env).to eq({
+          'OS_USERNAME'     => 'test',
+          'OS_PASSWORD'     => 'abc123',
+          'OS_PROJECT_NAME' => 'test',
+          'OS_AUTH_URL'     => 'http://127.0.0.1:5000'
+        })
+      end
+    end
+
+    context 'with a RC file containing service token credentials' do
+      it 'is successful' do
+        # return incomplete creds from env
+        klass.expects(:get_os_vars_from_env)
+             .returns({ 'OS_TOKEN' => 'incomplete' })
+        mock = "export OS_TOKEN='test'\nexport OS_URL='abc123'\nexport OS_NOT_VALID='notvalid'\n"
+        File.expects(:exists?).with("#{ENV['HOME']}/openrc").returns(true)
+        File.expects(:open).with("#{ENV['HOME']}/openrc").returns(StringIO.new(mock))
+        klass.expects(:openstack)
+             .with('project', 'list', '--quiet', '--format', 'csv', ['--long'])
+             .returns('"ID","Name","Description","Enabled"
+"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
+')
+        response = klass.request('project', 'list', ['--long'])
+        expect(response.first[:description]).to eq("Test tenant")
+        expect(klass.instance_variable_get(:@credentials).to_env).to eq({
+          'OS_TOKEN' => 'test',
+          'OS_URL'   => 'abc123',
+        })
+      end
+    end
+  end
+end
diff --git a/3rdparty/modules/openstacklib/spec/unit/provider/openstack/credentials_spec.rb b/3rdparty/modules/openstacklib/spec/unit/provider/openstack/credentials_spec.rb
new file mode 100644 (file)
index 0000000..aa81ec2
--- /dev/null
@@ -0,0 +1,158 @@
+require 'puppet'
+require 'spec_helper'
+require 'puppet/provider/openstack'
+require 'puppet/provider/openstack/credentials'
+
+
+describe Puppet::Provider::Openstack::Credentials do
+
+  let(:creds) do
+    creds = Puppet::Provider::Openstack::CredentialsV2_0.new
+  end
+
+  describe "#set with valid value" do
+    it 'works with valid value' do
+      expect(creds.class.defined?('auth_url')).to be_truthy
+      creds.set('auth_url', 'http://localhost:5000/v2.0')
+      expect(creds.auth_url).to eq('http://localhost:5000/v2.0')
+    end
+  end
+
+  describe "#set with invalid value" do
+    it 'works with invalid value' do
+      expect(creds.class.defined?('foo')).to be_falsey
+      creds.set('foo', 'junk')
+      expect(creds.respond_to?(:foo)).to be_falsey
+      expect(creds.instance_variable_defined?(:@foo)).to be_falsey
+      expect { creds.foo }.to raise_error(NoMethodError, /undefined method/)
+    end
+  end
+
+  describe '#service_token_set?' do
+    context "with service credentials" do
+      it 'is successful' do
+        creds.token = 'token'
+        creds.url = 'url'
+        expect(creds.service_token_set?).to be_truthy
+        expect(creds.user_password_set?).to be_falsey
+      end
+
+      it 'fails' do
+        creds.token = 'token'
+        expect(creds.service_token_set?).to be_falsey
+        expect(creds.user_password_set?).to be_falsey
+      end
+    end
+  end
+
+  describe '#password_set?' do
+    context "with user credentials" do
+      it 'is successful' do
+        creds.auth_url = 'auth_url'
+        creds.password = 'password'
+        creds.project_name = 'project_name'
+        creds.username = 'username'
+        expect(creds.user_password_set?).to be_truthy
+        expect(creds.service_token_set?).to be_falsey
+      end
+
+      it 'fails' do
+        creds.auth_url = 'auth_url'
+        creds.password = 'password'
+        creds.project_name = 'project_name'
+        expect(creds.user_password_set?).to be_falsey
+        expect(creds.service_token_set?).to be_falsey
+      end
+    end
+  end
+
+  describe '#set?' do
+    context "without any credential" do
+      it 'fails' do
+        expect(creds.set?).to be_falsey
+      end
+    end
+  end
+
+  describe '#version' do
+    it 'is version 2' do
+      expect(creds.version).to eq('2.0')
+    end
+  end
+
+  describe '#unset' do
+    context "with all instance variables set" do
+      it 'resets all but the identity_api_version' do
+        creds.auth_url = 'auth_url'
+        creds.password = 'password'
+        creds.project_name = 'project_name'
+        creds.username = 'username'
+        creds.token = 'token'
+        creds.url = 'url'
+        creds.identity_api_version = 'identity_api_version'
+        creds.unset
+        expect(creds.auth_url).to eq('')
+        expect(creds.password).to eq('')
+        expect(creds.project_name).to eq('')
+        expect(creds.username).to eq('')
+        expect(creds.token).to eq('')
+        expect(creds.url).to eq('')
+        expect(creds.identity_api_version).to eq('identity_api_version')
+        newcreds = Puppet::Provider::Openstack::CredentialsV3.new
+        expect(newcreds.identity_api_version).to eq('3')
+      end
+    end
+  end
+
+  describe '#to_env' do
+    context "with an exhaustive data set" do
+      it 'successfully returns content' do
+        creds.auth_url = 'auth_url'
+        creds.password = 'password'
+        creds.project_name = 'project_name'
+        creds.username = 'username'
+        creds.token = 'token'
+        creds.url = 'url'
+        creds.identity_api_version = 'identity_api_version'
+        expect(creds.to_env).to eq({
+          'OS_USERNAME'             => 'username',
+          'OS_PASSWORD'             => 'password',
+          'OS_PROJECT_NAME'         => 'project_name',
+          'OS_AUTH_URL'             => 'auth_url',
+          'OS_TOKEN'                => 'token',
+          'OS_URL'                  => 'url',
+          'OS_IDENTITY_API_VERSION' => 'identity_api_version'
+        })
+      end
+    end
+  end
+
+  describe 'using v3' do
+    let(:creds) do
+      creds = Puppet::Provider::Openstack::CredentialsV3.new
+    end
+    describe 'with v3' do
+      it 'uses v3 identity api' do
+        creds.identity_api_version == '3'
+      end
+    end
+    describe '#password_set? with username and project_name' do
+      it 'is successful' do
+        creds.auth_url = 'auth_url'
+        creds.password = 'password'
+        creds.project_name = 'project_name'
+        creds.username = 'username'
+        expect(creds.user_password_set?).to be_truthy
+      end
+    end
+    describe '#password_set? with user_id and project_id' do
+      it 'is successful' do
+        creds.auth_url = 'auth_url'
+        creds.password = 'password'
+        creds.project_id = 'projid'
+        creds.user_id = 'userid'
+        expect(creds.user_password_set?).to be_truthy
+      end
+    end
+  end
+end
diff --git a/3rdparty/modules/openstacklib/spec/unit/provider/openstack_spec.rb b/3rdparty/modules/openstacklib/spec/unit/provider/openstack_spec.rb
new file mode 100644 (file)
index 0000000..c9c22ee
--- /dev/null
@@ -0,0 +1,89 @@
+require 'puppet'
+require 'spec_helper'
+require 'puppet/provider/openstack'
+
+describe Puppet::Provider::Openstack do
+  before(:each) do
+    ENV['OS_USERNAME']     = nil
+    ENV['OS_PASSWORD']     = nil
+    ENV['OS_PROJECT_NAME'] = nil
+    ENV['OS_AUTH_URL']     = nil
+  end
+
+  let(:type) do
+    Puppet::Type.newtype(:test_resource) do
+      newparam(:name, :namevar => true)
+      newparam(:log_file)
+    end
+  end
+
+  describe '#request' do
+    let(:resource_attrs) do
+      {
+        :name => 'stubresource',
+      }
+    end
+
+    let(:provider) do
+      Puppet::Provider::Openstack.new(type.new(resource_attrs))
+    end
+
+    it 'makes a successful request' do
+      provider.class.stubs(:openstack)
+                    .with('project', 'list', '--quiet', '--format', 'csv', ['--long'])
+                    .returns('"ID","Name","Description","Enabled"
+"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True
+')
+      response = Puppet::Provider::Openstack.request('project', 'list', ['--long'])
+      expect(response.first[:description]).to eq("Test tenant")
+    end
+
+    context 'on connection errors' do
+      it 'retries' do
+        ENV['OS_USERNAME']     = 'test'
+        ENV['OS_PASSWORD']     = 'abc123'
+        ENV['OS_PROJECT_NAME'] = 'test'
+        ENV['OS_AUTH_URL']     = 'http://127.0.0.1:5000'
+        provider.class.stubs(:openstack)
+                      .with('project', 'list', '--quiet', '--format', 'csv', ['--long'])
+                      .raises(Puppet::ExecutionFailure, 'Unable to establish connection')
+                      .then
+                      .returns('')
+        provider.class.expects(:sleep).with(2).returns(nil)
+        Puppet::Provider::Openstack.request('project', 'list', ['--long'])
+      end
+    end
+  end
+
+  describe 'parse_csv' do
+    context 'with mixed stderr' do
+      text = "ERROR: Testing\n\"field\",\"test\",1,2,3\n"
+      csv = Puppet::Provider::Openstack.parse_csv(text)
+      it 'should ignore non-CSV text at the beginning of the input' do
+        expect(csv).to be_kind_of(Array)
+        expect(csv[0]).to match_array(['field', 'test', '1', '2', '3'])
+        expect(csv.size).to eq(1)
+      end
+    end
+
+    context 'with \r\n line endings' do
+      text = "ERROR: Testing\r\n\"field\",\"test\",1,2,3\r\n"
+      csv = Puppet::Provider::Openstack.parse_csv(text)
+      it 'ignore the carriage returns' do
+        expect(csv).to be_kind_of(Array)
+        expect(csv[0]).to match_array(['field', 'test', '1', '2', '3'])
+        expect(csv.size).to eq(1)
+      end
+    end
+
+    context 'with embedded newlines' do
+      text = "ERROR: Testing\n\"field\",\"te\nst\",1,2,3\n"
+      csv = Puppet::Provider::Openstack.parse_csv(text)
+      it 'should parse correctly' do
+        expect(csv).to be_kind_of(Array)
+        expect(csv[0]).to match_array(['field', "te\nst", '1', '2', '3'])
+        expect(csv.size).to eq(1)
+      end
+    end
+  end
+end