Import plugin's code
Change-Id: I8d7f3d88401eadfb627795c4dc72ec1b8a1d9769
This commit is contained in:
parent
4d6486d5ca
commit
5fff5a4964
|
@ -0,0 +1,201 @@
|
|||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
|
@ -0,0 +1,52 @@
|
|||
# Copyright 2017 Sberbank
|
||||
#
|
||||
# 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.
|
||||
|
||||
notice('fuel-plugin-tempest: tempest_install.pp')
|
||||
|
||||
$plugin_hash = hiera_hash('tempest', {})
|
||||
|
||||
if has_key($plugin_hash, 'image_name') {
|
||||
$image_name = $plugin_hash['image_name']
|
||||
} else {
|
||||
$image_name = 'TestVM'
|
||||
}
|
||||
|
||||
$service_endpoint = hiera('service_endpoint')
|
||||
$auth_url_v2 = "http://${service_endpoint}:35357/v2.0"
|
||||
$auth_url_v3 = "http://${service_endpoint}:35357/v3"
|
||||
|
||||
class { 'tempest':
|
||||
package_ensure => 'latest',
|
||||
tempest_workspace => '/var/lib/tempest/default',
|
||||
tempest_config_file => '/var/lib/tempest/default/etc/tempest.conf',
|
||||
lock_path => '/var/lib/tempest/default/tempest_lock',
|
||||
install_from_source => false,
|
||||
git_clone => false,
|
||||
image_name => $image_name,
|
||||
image_name_alt => $image_name,
|
||||
configure_networks => false,
|
||||
identity_uri => $auth_url_v2,
|
||||
identity_uri_v3 => $auth_url_v3,
|
||||
auth_version => 'v3',
|
||||
region_name => hiera('region', 'RegionOne'),
|
||||
manage_tests_packages => false,
|
||||
admin_username => 'admin',
|
||||
admin_password => 'admin',
|
||||
admin_project_name => 'admin',
|
||||
admin_role => 'admin',
|
||||
admin_domain_name => 'Default',
|
||||
img_dir => undef,
|
||||
img_file => undef,
|
||||
min_compute_nodes => 3,
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
# Copyright 2017 Sberbank
|
||||
#
|
||||
# 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.
|
||||
|
||||
notice('fuel-plugin-tempest: tempest_run.pp')
|
||||
|
||||
$plugin_hash = hiera_hash('tempest', {})
|
||||
$run_tests = $plugin_hash['run_tests']
|
||||
|
||||
if $run_tests {
|
||||
$run_script = $plugin_hash['run_script']
|
||||
|
||||
file { '/tmp/tempest-run.sh':
|
||||
ensure => file,
|
||||
owner => 'root',
|
||||
mode => '0744',
|
||||
content => inline_template("#!/bin/bash -eux\n$run_script"),
|
||||
}->
|
||||
exec { 'run_tempest_tests':
|
||||
command => 'bash /tmp/tempest-run.sh',
|
||||
path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
|
||||
user => 'root',
|
||||
logoutput => 'on_failure',
|
||||
}
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
pkg/
|
||||
Gemfile.lock
|
||||
vendor/
|
||||
spec/fixtures/
|
||||
.vagrant/
|
||||
.bundle/
|
||||
coverage/
|
||||
.idea/
|
||||
*.swp
|
||||
*.iml
|
||||
/openstack/
|
||||
|
||||
# Files created by releasenotes build
|
||||
releasenotes/build
|
||||
.tox
|
|
@ -0,0 +1,4 @@
|
|||
[gerrit]
|
||||
host=review.openstack.org
|
||||
port=29418
|
||||
project=openstack/puppet-openstacklib.git
|
|
@ -0,0 +1,78 @@
|
|||
## 8.0.0 and beyond
|
||||
|
||||
From 8.0.0 release and beyond, release notes are published on
|
||||
[docs.openstack.org](http://docs.openstack.org/releasenotes/puppet-openstacklib/).
|
||||
|
||||
##2015-11-24 - 7.0.0
|
||||
###Summary
|
||||
|
||||
This is a backwards-compatible major release for OpenStack Liberty.
|
||||
|
||||
####Features
|
||||
- fallback to default rcfile
|
||||
- prepare $::os_package_type
|
||||
- add a proxy inifile provider
|
||||
- allow the use of an ensure_absent_val param
|
||||
- create is_service_default function
|
||||
- create os_service_default fact
|
||||
- allow to path custom fragment to vhost
|
||||
- pass necessary options to Apache when using WSGI
|
||||
|
||||
####Bugfixes
|
||||
- fix fact for puppet facter 2.0.1+
|
||||
|
||||
####Maintenance
|
||||
- initial msync run for all Puppet OpenStack modules
|
||||
- enable acceptance tests for openstack_config
|
||||
- remove class_parameter_defaults puppet-lint check
|
||||
|
||||
##2015-10-10 - 6.1.0
|
||||
###Summary
|
||||
|
||||
This is a maintenance release in the Kilo series.
|
||||
|
||||
####Maintenance
|
||||
- acceptance: checkout stable/kilo puppet modules
|
||||
|
||||
##2015-07-08 - 6.0.0
|
||||
###Summary
|
||||
|
||||
This is a backwards-incompatible major release for OpenStack Kilo.
|
||||
|
||||
####Backwards-incompatible changes
|
||||
- MySQL: change default MySQL collate to utf8_general_ci
|
||||
|
||||
####Features
|
||||
- Puppet 4.x support
|
||||
- Add db::postgresql to openstacklib
|
||||
- Implement openstacklib::wsgi::apache
|
||||
- Move openstackclient parent provider to openstacklib
|
||||
- Keystone V3 API support
|
||||
- Restructures authentication for resource providers
|
||||
|
||||
####Bugfixes
|
||||
- Properly handle policy values containing spaces
|
||||
|
||||
####Maintenance
|
||||
- Bump mysql version to 3.x
|
||||
- Acceptance tests with Beaker
|
||||
|
||||
##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.
|
|
@ -0,0 +1,21 @@
|
|||
source ENV['GEM_SOURCE'] || "https://rubygems.org"
|
||||
|
||||
group :development, :test, :system_tests do
|
||||
gem 'puppet-openstack_spec_helper',
|
||||
:git => 'https://git.openstack.org/openstack/puppet-openstack_spec_helper',
|
||||
:require => false
|
||||
end
|
||||
|
||||
if facterversion = ENV['FACTER_GEM_VERSION']
|
||||
gem 'facter', facterversion, :require => false
|
||||
else
|
||||
gem 'facter', :require => false
|
||||
end
|
||||
|
||||
if puppetversion = ENV['PUPPET_GEM_VERSION']
|
||||
gem 'puppet', puppetversion, :require => false
|
||||
else
|
||||
gem 'puppet', :require => false
|
||||
end
|
||||
|
||||
# vim:ft=ruby
|
|
@ -0,0 +1,13 @@
|
|||
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.
|
||||
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.
|
|
@ -0,0 +1,333 @@
|
|||
Team and repository tags
|
||||
========================
|
||||
|
||||
[![Team and repository tags](http://governance.openstack.org/badges/puppet-openstacklib.svg)](http://governance.openstack.org/reference/tags/index.html)
|
||||
|
||||
<!-- Change things from this point on -->
|
||||
|
||||
openstacklib
|
||||
============
|
||||
|
||||
#### Table of Contents
|
||||
|
||||
1. [Overview - What is the openstacklib module?](#overview)
|
||||
2. [Module Description - What does the module do?](#module-description)
|
||||
3. [Setup - The basics of getting started with openstacklib](#setup)
|
||||
4. [Implementation - An under-the-hood peek at what the module is doing](#implementation)
|
||||
5. [Limitations - OS compatibility, etc.](#limitations)
|
||||
6. [Development - Guide for contributing to the module](#development)
|
||||
7. [Contributors - Those with commits](#contributors)
|
||||
|
||||
Overview
|
||||
--------
|
||||
|
||||
The openstacklib 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 not part
|
||||
of the core software. The module itself is used to expose common functionality
|
||||
between Openstack modules as a library that can be utilized to avoid code
|
||||
duplication.
|
||||
|
||||
Module Description
|
||||
------------------
|
||||
|
||||
The openstacklib module is a library module for other Openstack modules to
|
||||
utilize. A thorough description will be added later.
|
||||
|
||||
This module is tested in combination with other modules needed to build and
|
||||
leverage an entire Openstack software stack.
|
||||
|
||||
Setup
|
||||
-----
|
||||
|
||||
### Installing openstacklib
|
||||
|
||||
puppet module install openstack/openstacklib
|
||||
|
||||
Usage
|
||||
-----
|
||||
|
||||
### Classes and Defined Types
|
||||
|
||||
#### Defined type: openstacklib::db::mysql
|
||||
|
||||
The db::mysql resource is a library resource that can be used by nova, cinder,
|
||||
ceilometer, etc., to create a mysql database with configurable privileges for
|
||||
a user connecting from defined hosts.
|
||||
|
||||
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::mysql you might declare:
|
||||
|
||||
```
|
||||
::openstacklib::db::mysql { 'heat':
|
||||
password_hash => mysql_password($password),
|
||||
dbname => $dbname,
|
||||
user => $user,
|
||||
host => $host,
|
||||
charset => $charset,
|
||||
collate => $collate,
|
||||
allowed_hosts => $allowed_hosts,
|
||||
notify => Exec['heat-dbsync'],
|
||||
}
|
||||
```
|
||||
|
||||
Some modules should ensure that the database is created before the service is
|
||||
set up. For example, in keystone::db::mysql you would have:
|
||||
|
||||
```
|
||||
::openstacklib::db::mysql { 'keystone':
|
||||
password_hash => mysql_password($password),
|
||||
dbname => $dbname,
|
||||
user => $user,
|
||||
host => $host,
|
||||
charset => $charset,
|
||||
collate => $collate,
|
||||
allowed_hosts => $allowed_hosts,
|
||||
notify => Exec['keystone-manage db_sync'],
|
||||
before => Service['keystone'],
|
||||
}
|
||||
```
|
||||
|
||||
** Parameters for openstacklib::db::mysql: **
|
||||
|
||||
#####`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'
|
||||
|
||||
#####`host`
|
||||
The IP address or hostname of the user in mysql_grant;
|
||||
string; optional; default to '127.0.0.1'
|
||||
|
||||
#####`charset`
|
||||
The charset to use for the database;
|
||||
string; optional; default to 'utf8'
|
||||
|
||||
#####`collate`
|
||||
The collate to use for the database;
|
||||
string; optional; default to 'utf8_general_ci'
|
||||
|
||||
#####`allowed_hosts`
|
||||
Additional hosts that are allowed to access this database;
|
||||
array or string; optional; default to undef
|
||||
|
||||
#####`privileges`
|
||||
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
|
||||
|
||||
The service_validation resource is a library resource that can be used by nova, cinder,
|
||||
ceilometer, etc., to validate that a resource is actually up and running.
|
||||
|
||||
For example, in nova::api you might declare:
|
||||
|
||||
```
|
||||
::openstacklib::service_validation { 'nova-api':
|
||||
command => 'nova list',
|
||||
}
|
||||
```
|
||||
This defined resource creates an exec-anchor pair where the anchor depends upon
|
||||
the successful exec run.
|
||||
|
||||
** Parameters for openstacklib::service_validation: **
|
||||
|
||||
#####`command`
|
||||
Command to run for validating the service;
|
||||
string; required
|
||||
|
||||
#####`service_name`
|
||||
The name of the service to validate;
|
||||
string; optional; default to the $title of the resource, i.e. 'nova-api'
|
||||
|
||||
#####`path`
|
||||
The path of the command to validate the service;
|
||||
string; optional; default to '/usr/bin:/bin:/usr/sbin:/sbin'
|
||||
|
||||
#####`provider`
|
||||
The provider to use for the exec command;
|
||||
string; optional; default to 'shell'
|
||||
|
||||
#####`tries`
|
||||
Number of times to retry validation;
|
||||
string; optional; default to '10'
|
||||
|
||||
#####`try_sleep`
|
||||
Number of seconds between validation attempts;
|
||||
string; optional; default to '2'
|
||||
|
||||
#### Defined provider for openstack_config: ini_setting
|
||||
|
||||
It provides an interface to any INI configuration file as they are
|
||||
used in Openstack modules.
|
||||
|
||||
You use it like this:
|
||||
|
||||
```
|
||||
Puppet::Type.type(:<module>_config).provide(
|
||||
:openstackconfig,
|
||||
:parent => Puppet::Type.type(:openstack_config).provider(:ini_setting)
|
||||
) do
|
||||
```
|
||||
|
||||
It has the standard features of the upstream puppetlabs' `inifile`
|
||||
module as it's a direct children of it. Furthermore it can transform
|
||||
a value with some function of you're choice, enabling you to get value
|
||||
that get filled at run-time like an `uuid`.
|
||||
|
||||
For an example of how that's working you can have a look at this
|
||||
[review](https://review.openstack.org/#/c/347468/)
|
||||
|
||||
#### Defined provider for openstack_config: ruby
|
||||
|
||||
This one has the same basic features as the ini_setting one but the
|
||||
ability to transformation the value. It offers another feature,
|
||||
though. It can parse array. What it enables one to do is to parse
|
||||
this correctly:
|
||||
|
||||
```
|
||||
[DEFAULT]
|
||||
conf1 = value1
|
||||
conf1 = value2
|
||||
```
|
||||
|
||||
On the opposite side if you put that:
|
||||
|
||||
```
|
||||
module_config { 'DEFAULT/conf1' : value => ['value1', 'value2'] }
|
||||
```
|
||||
|
||||
in your manifest, it will properly be written as the example above.
|
||||
|
||||
To use this provider you use this:
|
||||
|
||||
```
|
||||
Puppet::Type.type(:<module>_config).provide(
|
||||
:openstackconfig,
|
||||
:parent => Puppet::Type.type(:openstack_config).provider(:ruby)
|
||||
) do
|
||||
```
|
||||
|
||||
and define you type with ```:array_matching => :all```. An example of
|
||||
such provider is ```nova_config```. Have a look for inspiration.
|
||||
|
||||
Implementation
|
||||
--------------
|
||||
|
||||
### openstacklib
|
||||
|
||||
openstacklib is a combination of Puppet manifest and ruby code to delivery
|
||||
configuration and extra functionality through types and providers.
|
||||
|
||||
Limitations
|
||||
-----------
|
||||
|
||||
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
|
||||
-----------
|
||||
|
||||
Developer documentation for the entire puppet-openstack project.
|
||||
|
||||
* http://docs.openstack.org/developer/puppet-openstack-guide/
|
||||
|
||||
Contributors
|
||||
------------
|
||||
|
||||
* https://github.com/stackforge/puppet-openstacklib/graphs/contributors
|
||||
|
||||
Versioning
|
||||
----------
|
||||
|
||||
This module has been given version 5 to track the puppet-openstack modules. The
|
||||
versioning for the puppet-openstack modules are as follows:
|
||||
|
||||
```
|
||||
Puppet Module :: OpenStack Version :: OpenStack Codename
|
||||
2.0.0 -> 2013.1.0 -> Grizzly
|
||||
3.0.0 -> 2013.2.0 -> Havana
|
||||
4.0.0 -> 2014.1.0 -> Icehouse
|
||||
5.0.0 -> 2014.2.0 -> Juno
|
||||
6.0.0 -> 2015.1.0 -> Kilo
|
||||
7.0.0 -> 2015.2.0 -> Liberty
|
||||
```
|
|
@ -0,0 +1 @@
|
|||
require 'puppet-openstack_spec_helper/rake_tasks'
|
|
@ -0,0 +1,11 @@
|
|||
Exec { logoutput => 'on_failure' }
|
||||
|
||||
include ::openstacklib::defaults
|
||||
|
||||
if $::osfamily == 'RedHat' {
|
||||
# Virtual package name, present in @base.
|
||||
package { 'perl(Net::HTTP)':
|
||||
ensure => present,
|
||||
tag => 'openstack',
|
||||
}
|
||||
}
|
|
@ -0,0 +1 @@
|
|||
os_service_default=<SERVICE DEFAULT>
|
|
@ -0,0 +1,38 @@
|
|||
#
|
||||
# We need this to be able to make decision of what style of package we are
|
||||
# working with: Debian style package (for example, it uses a nova-consoleproxy
|
||||
# package and not nova-novncproxy, or it has a openstack-dashboard-apache,
|
||||
# etc.), or just the Ubuntu style package.
|
||||
#
|
||||
# This is needed, because in some cases, we are using the Debian style packages
|
||||
# but running under Ubuntu. For example, that's the case when running with MOS
|
||||
# over Ubuntu. For this case, a manual override is provided, in the form of a
|
||||
# /etc/facter/facts.d/os_package_type.txt containing:
|
||||
# os_package_type=debian
|
||||
#
|
||||
# In all other cases, we can consider that we're using vanilia (ie: unmodified)
|
||||
# distribution packages, and we can set $::os_package_type depending on the
|
||||
# value of $::operatingsystem.
|
||||
#
|
||||
# Having the below snipets helps simplifying checks within individual project
|
||||
# manifests, so that we can just reuse $::os_package_type directly without
|
||||
# having to also check if it contains a value, then check for the content of
|
||||
# $::operatingsystem (ie: what's below factors the check once and for all).
|
||||
Facter.add('os_package_type') do
|
||||
setcode do
|
||||
case Facter.value(:osfamily)
|
||||
when 'Debian'
|
||||
if Facter.value(:operatingsystem) == 'Debian' then
|
||||
'debian'
|
||||
else
|
||||
'ubuntu'
|
||||
end
|
||||
when 'RedHat'
|
||||
'rpm'
|
||||
when 'Solaris'
|
||||
'solaris'
|
||||
else
|
||||
'unknown'
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,14 @@
|
|||
#
|
||||
# This adds the os_service_default fact for people with facter < 2.0.1
|
||||
# For people with facter >= 2.0.1, the facts.d/os_service_default.txt should
|
||||
# provide this information
|
||||
#
|
||||
require 'puppet/util/package'
|
||||
|
||||
if Puppet::Util::Package.versioncmp(Facter.value(:facterversion), '2.0.1') < 0
|
||||
Facter.add('os_service_default') do
|
||||
setcode do
|
||||
'<SERVICE DEFAULT>'
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,50 @@
|
|||
#
|
||||
# We've found that using $::processorcount for workers/threads can lead to
|
||||
# unexpected memory or process counts for people deploying on baremetal or
|
||||
# if they have large number of cpus. This fact allows us to tweak the formula
|
||||
# used to determine number of workers in a single place but use it across all
|
||||
# modules.
|
||||
#
|
||||
# The value for os_workers is max between '(<# processors> / 4)' and '2' with
|
||||
# a cap of 8.
|
||||
#
|
||||
# This fact can be overloaded by an external fact from /etc/factor/facts.d if
|
||||
# a user would like to provide their own default value.
|
||||
#
|
||||
Facter.add(:os_workers_small) do
|
||||
has_weight 100
|
||||
setcode do
|
||||
processors = Facter.value('processorcount')
|
||||
[ [ (processors.to_i / 4), 2 ].max, 8 ].min
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# The value above for os_workers performs 3x worse in many cases compared to
|
||||
# the prevuous default of $::processorcount.
|
||||
#
|
||||
# Based on performance data [1], the following calculation is within 1-2%.
|
||||
#
|
||||
# The value for os_workers is max between '(<# processors> / 2)' and '2' with
|
||||
# a cap of 12.
|
||||
#
|
||||
# [1] http://elk.browbeatproject.org:80/goto/a23307fd511e314b975dedca6f65425d
|
||||
#
|
||||
Facter.add(:os_workers) do
|
||||
has_weight 100
|
||||
setcode do
|
||||
processors = Facter.value('processorcount')
|
||||
[ [ (processors.to_i / 2), 2 ].max, 12 ].min
|
||||
end
|
||||
end
|
||||
|
||||
#
|
||||
# For cases where services are not co-located together (ie monolithic).
|
||||
#
|
||||
Facter.add(:os_workers_large) do
|
||||
has_weight 100
|
||||
setcode do
|
||||
processors = Facter.value('processorcount')
|
||||
[ (processors.to_i / 2) ]
|
||||
end
|
||||
end
|
|
@ -0,0 +1,27 @@
|
|||
#
|
||||
# is_service_default.rb
|
||||
#
|
||||
# This function can be used to check if a variable is set to the default value
|
||||
# of '<SERVICE DEFAULT>'
|
||||
#
|
||||
# For reference:
|
||||
# http://lists.openstack.org/pipermail/openstack-dev/2015-July/069823.html
|
||||
# https://github.com/openstack/puppet-openstacklib/commit/3b85306d042292713d0fd89fa508e0a0fbf99671
|
||||
#
|
||||
module Puppet::Parser::Functions
|
||||
newfunction(:is_service_default, :type => :rvalue, :doc => <<-EOS
|
||||
Returns true if the variable passed to this function is '<SERVICE DEFAULT>'
|
||||
EOS
|
||||
) do |arguments|
|
||||
raise(Puppet::ParseError, "is_service_default(): Wrong number of arguments" +
|
||||
"given (#{arguments.size} for 1)") if arguments.size != 1
|
||||
|
||||
value = arguments[0]
|
||||
|
||||
unless value.is_a?(String)
|
||||
return false
|
||||
end
|
||||
|
||||
return (value == '<SERVICE DEFAULT>')
|
||||
end
|
||||
end
|
|
@ -0,0 +1,37 @@
|
|||
require 'ipaddr'
|
||||
|
||||
module Puppet::Parser::Functions
|
||||
newfunction(:normalize_ip_for_uri,
|
||||
:type => :rvalue,
|
||||
:doc => <<-EOD
|
||||
Add brackets if the argument is an IPv6 address.
|
||||
Returns the argument untouched otherwise.
|
||||
CAUTION: this code "fails" when the user is passing
|
||||
an IPv6 address with the port in it without the
|
||||
brackets: 2001::1:8080, to specify address 2001::1
|
||||
and port 8080. This code will change it to
|
||||
[2001::1:8080] as it's a valid ip address. This
|
||||
shouldn't be an issue in most cases.
|
||||
If an array is given, each member will be normalized to
|
||||
a valid IPv6 address with brackets when needed.
|
||||
EOD
|
||||
) do |args|
|
||||
result = []
|
||||
args = args[0] if args[0].kind_of?(Array)
|
||||
args.each do |ip|
|
||||
begin
|
||||
if IPAddr.new(ip).ipv6?
|
||||
unless ip.match(/\[.+\]/)
|
||||
Puppet.debug("IP #{ip} is changed to [#{ip}]")
|
||||
ip = "[#{ip}]"
|
||||
end
|
||||
end
|
||||
rescue ArgumentError
|
||||
# ignore it
|
||||
end
|
||||
result << ip
|
||||
end
|
||||
return result[0] if args.size == 1
|
||||
result
|
||||
end
|
||||
end
|
|
@ -0,0 +1,81 @@
|
|||
require 'puppet/parser/functions'
|
||||
|
||||
Puppet::Parser::Functions.newfunction(:os_database_connection,
|
||||
:type => :rvalue,
|
||||
:doc => <<-EOS
|
||||
This function builds a os_database_connection string from various parameters.
|
||||
EOS
|
||||
) do |arguments|
|
||||
|
||||
require 'uri'
|
||||
|
||||
if (arguments.size != 1) then
|
||||
raise(Puppet::ParseError, "os_database_connection(): Wrong number of arguments " +
|
||||
"given (#{arguments.size} for 1)")
|
||||
end
|
||||
|
||||
v = arguments[0]
|
||||
klass = v.class
|
||||
|
||||
unless klass == Hash
|
||||
raise(Puppet::ParseError, "os_database_connection(): Requires an hash, got #{klass}")
|
||||
end
|
||||
|
||||
v.keys.each do |key|
|
||||
klass = (key == 'extra') ? Hash : String
|
||||
unless (v[key].class == klass) or (v[key] == :undef)
|
||||
raise(Puppet::ParseError, "os_database_connection(): #{key} should be a #{klass}")
|
||||
end
|
||||
end
|
||||
|
||||
parts = {}
|
||||
|
||||
unless v.include?('dialect')
|
||||
raise(Puppet::ParseError, 'os_database_connection(): dialect is required')
|
||||
end
|
||||
|
||||
if v.include?('host')
|
||||
parts[:host] = v['host']
|
||||
end
|
||||
|
||||
unless v.include?('database')
|
||||
raise(Puppet::ParseError, 'os_database_connection(): database is required')
|
||||
end
|
||||
|
||||
if v.include?('port')
|
||||
if v.include?('host')
|
||||
parts[:port] = v['port'].to_i
|
||||
else
|
||||
raise(Puppet::ParseError, 'os_database_connection(): host is required with port')
|
||||
end
|
||||
end
|
||||
|
||||
if v.include?('username') and (v['username'] != :undef) and (v['username'].to_s != '')
|
||||
parts[:userinfo] = URI.escape(v['username'])
|
||||
if v.include?('password') and (v['password'] != :undef) and (v['password'].to_s != '')
|
||||
parts[:userinfo] += ":#{URI.escape(v['password'])}"
|
||||
end
|
||||
end
|
||||
|
||||
# support previous charset option on the function. Setting charset will
|
||||
# override charset if passed in via the extra parameters
|
||||
if v.include?('charset')
|
||||
if v.include?('extra')
|
||||
v['extra'].merge!({ 'charset' => v['charset'] })
|
||||
else
|
||||
v['extra'] = { 'charset' => v['charset'] }
|
||||
end
|
||||
end
|
||||
|
||||
parts[:query] = v['extra'].map{ |k,v| "#{k}=#{v}" }.join('&') if v.include?('extra')
|
||||
|
||||
parts[:scheme] = v['dialect']
|
||||
|
||||
if v.include?('host')
|
||||
parts[:path] = "/#{v['database']}"
|
||||
else
|
||||
parts[:path] = "///#{v['database']}"
|
||||
end
|
||||
|
||||
URI::Generic.build(parts).to_s
|
||||
end
|
|
@ -0,0 +1,157 @@
|
|||
require 'puppet/parser/functions'
|
||||
|
||||
Puppet::Parser::Functions.newfunction(:os_transport_url,
|
||||
:type => :rvalue,
|
||||
:arity => 1,
|
||||
:doc => <<-EOS
|
||||
This function builds a os_transport_url string from a hash of parameters.
|
||||
|
||||
Valid hash parameteres:
|
||||
* transport - (string) type of transport, 'rabbit' or 'amqp'
|
||||
* host - (string) single host
|
||||
* hosts - (array) array of hosts to use
|
||||
* port - (string | integer) port to connect to
|
||||
* username - (string) connection username
|
||||
* password - (string) connection password
|
||||
* virtual_host - (string) virtual host to connect to
|
||||
* ssl - (string) is the connection ssl or not ('1' or '0'). overrides the ssl
|
||||
key in the query parameter
|
||||
* query - (hash) hash of key,value pairs used to create a query string for
|
||||
the transport_url.
|
||||
|
||||
Only 'transport' and either 'host' or 'hosts' are required keys for the
|
||||
parameters hash.
|
||||
|
||||
The url format that will be generated:
|
||||
transport://user:pass@host:port[,userN:passN@hostN:portN]/virtual_host?query
|
||||
|
||||
NOTE: ipv6 addresses will automatically be bracketed for the URI using the
|
||||
normalize_ip_for_uri function.
|
||||
|
||||
Single Host Example:
|
||||
os_transport_url({
|
||||
'transport' => 'rabbit',
|
||||
'host' => '1.1.1.1',
|
||||
'port' => '5672',
|
||||
'username' => 'username',
|
||||
'password' => 'password',
|
||||
'virtual_host' => 'virtual_host',
|
||||
'ssl' => '1',
|
||||
'query' => { 'key' => 'value' },
|
||||
})
|
||||
Generates:
|
||||
rabbit://username:password@1.1.1.1:5672/virtual_host?key=value&ssl=1
|
||||
|
||||
Multiple Hosts Example:
|
||||
os_transport_url({
|
||||
'transport' => 'rabbit',
|
||||
'hosts' => [ '1.1.1.1', '2.2.2.2' ],
|
||||
'port' => '5672',
|
||||
'username' => 'username',
|
||||
'password' => 'password',
|
||||
'virtual_host' => 'virtual_host',
|
||||
'query' => { 'key' => 'value' },
|
||||
})
|
||||
Generates:
|
||||
rabbit://username:password@1.1.1.1:5672,username:password@2.2.2.2:5672/virtual_host?key=value
|
||||
EOS
|
||||
) do |arguments|
|
||||
|
||||
require 'uri'
|
||||
|
||||
v = arguments[0]
|
||||
klass = v.class
|
||||
|
||||
unless klass == Hash
|
||||
raise(Puppet::ParseError, "os_transport_url(): Requires an hash, got #{klass}")
|
||||
end
|
||||
|
||||
# type checking for the parameter hash
|
||||
v.keys.each do |key|
|
||||
v[key] = v[key].to_s if key == 'port'
|
||||
klass = (key == 'hosts') ? Array : String
|
||||
klass = (key == 'query') ? Hash : klass
|
||||
unless (v[key].class == klass) or (v[key] == :undef)
|
||||
raise(Puppet::ParseError, "os_transport_url(): #{key} should be a #{klass}")
|
||||
end
|
||||
end
|
||||
|
||||
# defaults
|
||||
parts = {
|
||||
:transport => 'rabbit',
|
||||
:hostinfo => 'localhost',
|
||||
:path => '/',
|
||||
}
|
||||
|
||||
unless v.include?('transport')
|
||||
raise(Puppet::ParseError, 'os_transport_url(): transport is required')
|
||||
end
|
||||
|
||||
unless v.include?('host') or v.include?('hosts')
|
||||
raise(Puppet::ParseError, 'os_transport_url(): host or hosts is required')
|
||||
end
|
||||
|
||||
if v.include?('host') and v.include?('hosts')
|
||||
raise(Puppet::ParseError, 'os_transport_url(): cannot use both host and hosts.')
|
||||
end
|
||||
|
||||
parts[:transport] = v['transport']
|
||||
|
||||
if v.include?('username') and (v['username'] != :undef) and (v['username'].to_s != '')
|
||||
parts[:userinfo] = URI.escape(v['username'])
|
||||
if v.include?('password') and (v['password'] != :undef) and (v['password'].to_s != '')
|
||||
parts[:userinfo] += ":#{URI.escape(v['password'])}"
|
||||
end
|
||||
end
|
||||
|
||||
if v.include?('host')
|
||||
host = function_normalize_ip_for_uri([v['host']])
|
||||
host += ":#{v['port'].to_s}" if v.include?('port')
|
||||
if parts.include?(:userinfo)
|
||||
parts[:hostinfo] = "#{parts[:userinfo]}@#{host}"
|
||||
else
|
||||
parts[:hostinfo] = "#{host}"
|
||||
end
|
||||
end
|
||||
|
||||
if v.include?('hosts')
|
||||
hosts = function_normalize_ip_for_uri([v['hosts']])
|
||||
# normalize_ip_for_uri may return a string, so check that we still have an
|
||||
# array
|
||||
hosts = [hosts] if hosts.kind_of?(String)
|
||||
hosts = hosts.map{ |h| "#{h}:#{v['port'].to_s}" } if v.include?('port')
|
||||
if parts.include?(:userinfo)
|
||||
parts[:hostinfo] = hosts.map { |h| "#{parts[:userinfo]}@#{h}" }.join(',')
|
||||
else
|
||||
parts[:hostinfo] = hosts.join(',')
|
||||
end
|
||||
end
|
||||
|
||||
parts[:path] = "/#{v['virtual_host']}" if v.include?('virtual_host')
|
||||
|
||||
# support previous ssl option on the function. Setting ssl will
|
||||
# override ssl if passed in via the query parameters
|
||||
if v.include?('ssl')
|
||||
# ssl can be passed in as a query paramter but should be 0/1. See
|
||||
# http://docs.celeryproject.org/projects/kombu/en/latest/userguide/connections.html#urls
|
||||
# so we rely on the stdlib str2bool and bool2num to ensure it's in the
|
||||
# format
|
||||
ssl_val = function_bool2num([function_str2bool([v['ssl']])])
|
||||
if v.include?('query')
|
||||
v['query'].merge!({ 'ssl' => ssl_val })
|
||||
else
|
||||
v['query'] = { 'ssl' => ssl_val }
|
||||
end
|
||||
end
|
||||
|
||||
parts[:query] = v['query'].map{ |k,val| "#{k}=#{val}" }.join('&') if v.include?('query')
|
||||
|
||||
|
||||
url_parts = []
|
||||
url_parts << parts[:transport]
|
||||
url_parts << '://'
|
||||
url_parts << parts[:hostinfo]
|
||||
url_parts << parts[:path]
|
||||
url_parts << '?' << parts[:query] if parts.include?(:query)
|
||||
url_parts.join()
|
||||
end
|
|
@ -0,0 +1,153 @@
|
|||
require 'csv'
|
||||
require 'puppet'
|
||||
require 'timeout'
|
||||
|
||||
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_command => 'openstack'
|
||||
|
||||
@@no_retry_actions = %w(create remove delete)
|
||||
@@command_timeout = 40
|
||||
# Fails on the 5th retry for a max of 212s (~3.5min) before total
|
||||
# failure.
|
||||
@@request_timeout = 170
|
||||
@@retry_sleep = 3
|
||||
class << self
|
||||
[:no_retry_actions, :request_timeout, :retry_sleep].each do |m|
|
||||
define_method m do
|
||||
self.class_variable_get("@@#{m}")
|
||||
end
|
||||
define_method :"#{m}=" do |value|
|
||||
self.class_variable_set("@@#{m}", value)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
# timeout the openstack command
|
||||
# after this number of seconds
|
||||
# retry the command until the request_timeout,
|
||||
# unless it's a no_retry_actions call
|
||||
def self.command_timeout(action=nil)
|
||||
# give no_retry actions the full time limit to finish
|
||||
return self.request_timeout() if no_retry_actions.include? action
|
||||
self.class_variable_get("@@command_timeout")
|
||||
end
|
||||
|
||||
# with command_timeout
|
||||
def self.openstack(*args)
|
||||
begin
|
||||
action = args[1]
|
||||
Timeout.timeout(command_timeout(action)) do
|
||||
openstack_command *args
|
||||
end
|
||||
rescue Timeout::Error
|
||||
raise Puppet::ExecutionFailure, "Command: 'openstack #{args.inspect}' has been running for more than #{command_timeout(action)} seconds"
|
||||
end
|
||||
end
|
||||
|
||||
# get the current timestamp
|
||||
def self.current_time
|
||||
Time.now.to_i
|
||||
end
|
||||
|
||||
def self.request_without_retry(&block)
|
||||
previous_timeout = self.request_timeout
|
||||
rc = nil
|
||||
if block_given?
|
||||
self.request_timeout = 0
|
||||
rc = yield
|
||||
end
|
||||
ensure
|
||||
self.request_timeout = previous_timeout
|
||||
rc
|
||||
end
|
||||
|
||||
# Returns an array of hashes, where the keys are the downcased CSV headers
|
||||
# with underscores instead of spaces
|
||||
#
|
||||
# @param options [Hash] Other options
|
||||
# @options :no_retry_exception_msgs [Array<Regexp>,Regexp] exception without retries
|
||||
def self.request(service, action, properties, credentials=nil, options={})
|
||||
env = credentials ? credentials.to_env : {}
|
||||
no_retry = options[:no_retry_exception_msgs]
|
||||
|
||||
Puppet::Util.withenv(env) do
|
||||
rv = nil
|
||||
end_time = current_time + request_timeout
|
||||
start_time = current_time
|
||||
retry_count = 0
|
||||
loop do
|
||||
begin
|
||||
if action == 'list'
|
||||
# shell output is:
|
||||
# ID,Name,Description,Enabled
|
||||
response = openstack(service, action, '--quiet', '--format', 'csv', properties)
|
||||
response = parse_csv(response)
|
||||
keys = response.delete_at(0)
|
||||
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' or action == 'create'
|
||||
rv = {}
|
||||
# shell output is:
|
||||
# name="value1"
|
||||
# id="value2"
|
||||
# description="value3"
|
||||
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 => exception
|
||||
raise Puppet::Error::OpenstackUnauthorizedError, 'Could not authenticate' if exception.message =~ /HTTP 40[13]/
|
||||
if current_time > end_time
|
||||
error_message = exception.message
|
||||
error_message += " (tried #{retry_count}, for a total of #{end_time - start_time } seconds)"
|
||||
raise(Puppet::ExecutionFailure, error_message)
|
||||
end
|
||||
|
||||
raise exception if no_retry_actions.include? action
|
||||
if no_retry
|
||||
no_retry = [no_retry] unless no_retry.is_a?(Array)
|
||||
no_retry.each do |nr|
|
||||
raise exception if exception.message.match(nr)
|
||||
end
|
||||
end
|
||||
debug "Non-fatal error: '#{exception.message}'. Retrying for #{end_time - current_time} more seconds"
|
||||
sleep retry_sleep
|
||||
retry_count += 1
|
||||
retry
|
||||
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
|
|
@ -0,0 +1,51 @@
|
|||
#require 'puppet/provider/openstack/credentials'
|
||||
require File.join(File.dirname(__FILE__), '..','..','..', '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 = {}
|
||||
rcfile = [filename, '/root/openrc'].detect { |f| File.exists? f }
|
||||
unless rcfile.nil?
|
||||
File.open(rcfile).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, options={})
|
||||
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, options)
|
||||
end
|
||||
|
||||
def set_credentials(creds, env)
|
||||
env.each do |key, val|
|
||||
var = key.sub(/^OS_/,'').downcase
|
||||
creds.set(var, val)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,95 @@
|
|||
require 'puppet'
|
||||
require 'puppet/provider/openstack'
|
||||
|
||||
class Puppet::Provider::Openstack::Credentials
|
||||
|
||||
KEYS = [
|
||||
:auth_url, :password, :project_name, :username,
|
||||
:token, :url,
|
||||
:identity_api_version,
|
||||
:region_name,
|
||||
:interface
|
||||
]
|
||||
|
||||
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
|
|
@ -0,0 +1,73 @@
|
|||
Puppet::Type.type(:openstack_config).provide(
|
||||
:ini_setting,
|
||||
:parent => Puppet::Type.type(:ini_setting).provider(:ruby)
|
||||
) do
|
||||
|
||||
def exists?
|
||||
if resource[:value] == ensure_absent_val
|
||||
resource[:ensure] = :absent
|
||||
end
|
||||
super
|
||||
end
|
||||
|
||||
def create
|
||||
resource[:value] = transform(:to, resource[:value])
|
||||
super
|
||||
end
|
||||
|
||||
def section
|
||||
resource[:name].split('/', 2).first
|
||||
end
|
||||
|
||||
def setting
|
||||
resource[:name].split('/', 2).last
|
||||
end
|
||||
|
||||
def value=(value)
|
||||
new_value = transform(:to, value)
|
||||
|
||||
ini_file.set_value(section, setting, new_value)
|
||||
ini_file.save
|
||||
end
|
||||
|
||||
def value
|
||||
value = ini_file.get_value(section, setting)
|
||||
new_value = transform(:from, value)
|
||||
@property_hash[:value] = new_value
|
||||
new_value
|
||||
end
|
||||
|
||||
def ensure_absent_val
|
||||
resource[:ensure_absent_val]
|
||||
end
|
||||
|
||||
def transform_to
|
||||
return nil unless resource.to_hash.has_key? :transform_to
|
||||
resource[:transform_to]
|
||||
end
|
||||
|
||||
def transform_to=(value)
|
||||
@property_hash[:transform_to] = value
|
||||
end
|
||||
|
||||
def separator
|
||||
'='
|
||||
end
|
||||
|
||||
def file_path
|
||||
self.class.file_path
|
||||
end
|
||||
|
||||
def transform(direction, value)
|
||||
new_value = value
|
||||
if !transform_to.nil? && !transform_to.empty?
|
||||
transformation_function = "#{direction}_#{transform_to}".to_sym
|
||||
if self.respond_to?(transformation_function)
|
||||
new_value = send(transformation_function, value)
|
||||
else
|
||||
error("Cannot find transformation #{transformation_function} for #{value}")
|
||||
end
|
||||
end
|
||||
new_value
|
||||
end
|
||||
end
|
|
@ -0,0 +1,94 @@
|
|||
|
||||
require File.expand_path('../../../util/openstackconfig', __FILE__)
|
||||
|
||||
|
||||
Puppet::Type.type(:openstack_config).provide(:ruby) do
|
||||
|
||||
def self.instances
|
||||
if self.respond_to?(:file_path)
|
||||
config = Puppet::Util::OpenStackConfig.new(file_path)
|
||||
resources = []
|
||||
config.section_names.each do |section_name|
|
||||
config.get_settings(section_name).each do |setting, value|
|
||||
resources.push(
|
||||
new(
|
||||
:name => namevar(section_name, setting),
|
||||
:value => value,
|
||||
:ensure => :present
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
resources
|
||||
else
|
||||
raise(Puppet::Error,
|
||||
'OpenStackConfig only support collecting instances when a file path ' +
|
||||
'is hard coded'
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def self.namevar(section_name, setting)
|
||||
"#{section_name}/#{setting}"
|
||||
end
|
||||
|
||||
def exists?
|
||||
if resource[:value] == ensure_absent_val
|
||||
resource[:ensure] = :absent
|
||||
end
|
||||
!config.get_value(section, setting).nil?
|
||||
end
|
||||
|
||||
def create
|
||||
config.set_value(section, setting, resource[:value])
|
||||
config.save
|
||||
@config = nil
|
||||
end
|
||||
|
||||
def destroy
|
||||
config.remove_setting(section, setting)
|
||||
config.save
|
||||
@config = nil
|
||||
end
|
||||
|
||||
def value=(value)
|
||||
config.set_value(section, setting, resource[:value])
|
||||
config.save
|
||||
end
|
||||
|
||||
def value
|
||||
val = config.get_value(section, setting)
|
||||
if !val.kind_of?(Array)
|
||||
[val]
|
||||
else
|
||||
val
|
||||
end
|
||||
end
|
||||
|
||||
def section
|
||||
resource[:name].split('/', 2).first
|
||||
end
|
||||
|
||||
def setting
|
||||
resource[:name].split('/', 2).last
|
||||
end
|
||||
|
||||
def ensure_absent_val
|
||||
# :array_matching => :all values comes in form of array even when they
|
||||
# are passed as single string
|
||||
if resource[:value].kind_of?(Array) and not resource[:ensure_absent_val].kind_of?(Array)
|
||||
[resource[:ensure_absent_val]]
|
||||
else
|
||||
resource[:ensure_absent_val]
|
||||
end
|
||||
end
|
||||
|
||||
def file_path
|
||||
self.class.file_path
|
||||
end
|
||||
|
||||
private
|
||||
def config
|
||||
@config ||= Puppet::Util::OpenStackConfig.new(file_path)
|
||||
end
|
||||
end
|
|
@ -0,0 +1,91 @@
|
|||
Puppet::Type.type(:policy_rcd).provide(:policy_rcd) do
|
||||
|
||||
desc 'Provider for managing policy-rc.d for Ubuntu'
|
||||
|
||||
mk_resource_methods
|
||||
|
||||
def check_os
|
||||
Facter.value(:osfamily) == 'Debian'
|
||||
end
|
||||
|
||||
def check_policy_rcd
|
||||
return File.exist? policy_rcd
|
||||
end
|
||||
|
||||
def file_lines
|
||||
@file_lines ||= File.open(policy_rcd).readlines
|
||||
end
|
||||
|
||||
def policy_rcd
|
||||
'/usr/sbin/policy-rc.d'
|
||||
end
|
||||
|
||||
def service
|
||||
@resource[:service]
|
||||
end
|
||||
|
||||
def set_code
|
||||
@resource[:set_code]
|
||||
end
|
||||
|
||||
def self.write_to_file(file, content, truncate=false)
|
||||
File.truncate(file, 0) if truncate
|
||||
policy = File.open(file, 'a+')
|
||||
policy.puts(content)
|
||||
policy.close
|
||||
File.chmod(0744, file)
|
||||
end
|
||||
|
||||
def exists?
|
||||
# we won't do anything if os family is not debian
|
||||
return true unless check_os
|
||||
if check_policy_rcd
|
||||
file_lines.each do |line|
|
||||
unless line =~ /"#{@resource[:service]}"/
|
||||
next
|
||||
end
|
||||
return true
|
||||
end
|
||||
end
|
||||
false
|
||||
end
|
||||
|
||||
def create
|
||||
unless check_policy_rcd
|
||||
header = "#!/bin/bash\n# THIS FILE MANAGED BY PUPPET\n"
|
||||
else
|
||||
header = ""
|
||||
end
|
||||
content = "#{header}[[ \"$1\" == \"#{@resource[:service]}\" ]] && exit #{@resource[:set_code]}\n"
|
||||
self.class.write_to_file(policy_rcd, content)
|
||||
end
|
||||
|
||||
def destroy
|
||||
if check_policy_rcd
|
||||
file_lines.delete_if { |l| l =~ /"#{@resource[:service]}"/ }
|
||||
self.class.write_to_file(policy_rcd, file_lines, true)
|
||||
end
|
||||
end
|
||||
|
||||
def flush
|
||||
if @resource[:ensure] == :present and ! file_lines.nil?
|
||||
new_line = nil
|
||||
outdated_line = nil
|
||||
file_lines.each do |line|
|
||||
unless line =~ /"#{@resource[:service]}"/
|
||||
next
|
||||
end
|
||||
code = line.match(/exit\s(\d+)/)[1]
|
||||
if code != @resource[:set_code]
|
||||
new_line = "[[ \"$1\" == \"#{@resource[:service]}\" ]] && exit #{@resource[:set_code]}\n"
|
||||
outdated_line = line
|
||||
end
|
||||
end
|
||||
unless new_line.nil?
|
||||
file_lines.delete(outdated_line)
|
||||
file_lines.push(new_line)
|
||||
self.class.write_to_file(policy_rcd, file_lines, true)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,3 @@
|
|||
Puppet::Type.newtype(:openstack_config) do
|
||||
|
||||
end
|
|
@ -0,0 +1,21 @@
|
|||
Puppet::Type.newtype(:policy_rcd) do
|
||||
ensurable
|
||||
|
||||
newparam(:name, :namevar => true) do
|
||||
newvalues(/\S+/)
|
||||
end
|
||||
|
||||
newproperty(:service) do
|
||||
defaultto { @resource[:name] }
|
||||
newvalues(/\S+/)
|
||||
end
|
||||
|
||||
newproperty(:set_code) do
|
||||
defaultto('101')
|
||||
validate do |value|
|
||||
# validate codes according to https://people.debian.org/~hmh/invokerc.d-policyrc.d-specification.txt
|
||||
allowed_codes = [ '0', '1', '100', '101', '102', '103', '104', '105', '106' ]
|
||||
raise ArgumentError, 'Unknown exit status code is set' unless allowed_codes.include?(value)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,117 @@
|
|||
#
|
||||
# Author: Martin Magr <mmagr@redhat.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.
|
||||
#
|
||||
# Forked from https://github.com/puppetlabs/puppetlabs-inifile .
|
||||
|
||||
require File.expand_path('../openstackconfig/section', __FILE__)
|
||||
|
||||
|
||||
module Puppet
|
||||
module Util
|
||||
class OpenStackConfig
|
||||
|
||||
@@SECTION_REGEX = /^\s*\[(.*)\]\s*$/
|
||||
|
||||
def initialize(path)
|
||||
@path = path
|
||||
@order = []
|
||||
@sections = {}
|
||||
parse_file
|
||||
end
|
||||
|
||||
attr_reader :path
|
||||
|
||||
def section_names
|
||||
@sections.keys
|
||||
end
|
||||
|
||||
def get_settings(section_name)
|
||||
@sections[section_name].settings
|
||||
end
|
||||
|
||||
def get_value(section_name, setting_name)
|
||||
if @sections.has_key?(section_name)
|
||||
@sections[section_name].settings[setting_name]
|
||||
end
|
||||
end
|
||||
|
||||
def set_value(section_name, setting_name, value)
|
||||
unless @sections.has_key?(section_name)
|
||||
add_section(section_name)
|
||||
end
|
||||
if @sections[section_name].settings.has_key?(setting_name)
|
||||
@sections[section_name].update_setting(setting_name, value)
|
||||
else
|
||||
@sections[section_name].add_setting(setting_name, value)
|
||||
end
|
||||
end
|
||||
|
||||
def remove_setting(section_name, setting_name, value=nil)
|
||||
@sections[section_name].remove_setting(setting_name, value)
|
||||
end
|
||||
|
||||
def save
|
||||
File.open(@path, 'w') do |fh|
|
||||
@order.each do |section_name|
|
||||
if section_name.length > 0
|
||||
fh.puts("[#{section_name}]")
|
||||
end
|
||||
unless @sections[section_name].lines.empty?
|
||||
@sections[section_name].lines.each do |line|
|
||||
fh.puts(line)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
# This is mostly here because it makes testing easier
|
||||
# --we don't have to try to stub any methods on File.
|
||||
def self.readlines(path)
|
||||
# If this type is ever used with very large files, we should
|
||||
# write this in a different way, using a temp
|
||||
# file; for now assuming that this type is only used on
|
||||
# small-ish config files that can fit into memory without
|
||||
# too much trouble.
|
||||
File.file?(path) ? File.readlines(path) : []
|
||||
end
|
||||
|
||||
def parse_file
|
||||
# We always create a "global" section at the beginning of the file,
|
||||
# for anything that appears before the first named section.
|
||||
lines = []
|
||||
current_section = ''
|
||||
OpenStackConfig.readlines(@path).each do |line|
|
||||
if match = @@SECTION_REGEX.match(line)
|
||||
add_section(current_section, lines)
|
||||
# start new section parsing
|
||||
lines = []
|
||||
current_section = match[1]
|
||||
else
|
||||
lines.push(line)
|
||||
end
|
||||
end
|
||||
add_section(current_section, lines)
|
||||
end
|
||||
|
||||
def add_section(section_name, lines=nil)
|
||||
@order.push(section_name)
|
||||
@sections[section_name] = Section.new(section_name, lines)
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,178 @@
|
|||
#
|
||||
# Author: Martin Magr <mmagr@redhat.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.
|
||||
#
|
||||
# Forked from https://github.com/puppetlabs/puppetlabs-inifile .
|
||||
|
||||
|
||||
module Puppet
|
||||
module Util
|
||||
class OpenStackConfig
|
||||
class Section
|
||||
|
||||
@@SETTING_REGEX = /^(\s*)([^#;\s]|[^#;\s].*?[^\s=])(\s*=[ \t]*)(.*)\s*$/
|
||||
@@COMMENTED_SETTING_REGEX = /^(\s*)[#;]+(\s*)(.*?[^\s=])(\s*=[ \t]*)(.*)\s*$/
|
||||
|
||||
def initialize(name, lines=nil)
|
||||
@name = name
|
||||
@lines = lines.nil? ? [] : lines
|
||||
# parse lines
|
||||
@indentation = nil
|
||||
@settings = {}
|
||||
@lines.each do |line|
|
||||
if match = @@SETTING_REGEX.match(line)
|
||||
indent = match[1].length
|
||||
@indentation = [indent, @indentation || indent].min
|
||||
if @settings.include?(match[2])
|
||||
if not @settings[match[2]].kind_of?(Array)
|
||||
@settings[match[2]] = [@settings[match[2]]]
|
||||
end
|
||||
@settings[match[2]].push(match[4])
|
||||
else
|
||||
@settings[match[2]] = match[4]
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
attr_reader :name, :indentation
|
||||
|
||||
def settings
|
||||
Marshal.load(Marshal.dump(@settings))
|
||||
end
|
||||
|
||||
def lines
|
||||
@lines.clone
|
||||
end
|
||||
|
||||
def is_global?
|
||||
@name == ''
|
||||
end
|
||||
|
||||
def is_new_section?
|
||||
@lines.empty?
|
||||
end
|
||||
|
||||
def setting_names
|
||||
@settings.keys
|
||||
end
|
||||
|
||||
def add_setting(setting_name, value)
|
||||
@settings[setting_name] = value
|
||||
add_lines(setting_name, value)
|
||||
end
|
||||
|
||||
def update_setting(setting_name, value)
|
||||
old_value = @settings[setting_name]
|
||||
@settings[setting_name] = value
|
||||
if value.kind_of?(Array) or old_value.kind_of?(Array)
|
||||
# ---- update lines for multi setting ----
|
||||
old_value = old_value.kind_of?(Array) ? old_value : [old_value]
|
||||
new_value = value.kind_of?(Array) ? value : [value]
|
||||
if useless = old_value - new_value
|
||||
remove_lines(setting_name, useless)
|
||||
end
|
||||
if missing = new_value - old_value
|
||||
add_lines(setting_name, missing)
|
||||
end
|
||||
else
|
||||
# ---- update lines for single setting ----
|
||||
@lines.each_with_index do |line, index|
|
||||
if match = @@SETTING_REGEX.match(line)
|
||||
if (match[2] == setting_name)
|
||||
@lines[index] = "#{match[1]}#{match[2]}#{match[3]}#{value}\n"
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def remove_setting(setting_name, value=nil)
|
||||
if value.nil? or @settings[setting_name] == value
|
||||
@settings.delete(setting_name)
|
||||
else
|
||||
value.each do |val|
|
||||
@settings[setting_name].delete(val)
|
||||
end
|
||||
end
|
||||
remove_lines(setting_name, value)
|
||||
end
|
||||
|
||||
private
|
||||
def find_commented_setting(setting_name)
|
||||
@lines.each_with_index do |line, index|
|
||||
if match = @@COMMENTED_SETTING_REGEX.match(line)
|
||||
if match[3] == setting_name
|
||||
return index
|
||||
end
|
||||
end
|
||||
end
|
||||
nil
|
||||
end
|
||||
|
||||
def find_last_setting(setting_name)
|
||||
result = nil
|
||||
@lines.each_with_index do |line, index|
|
||||
if match = @@SETTING_REGEX.match(line)
|
||||
if match[2] == setting_name
|
||||
result = index
|
||||
end
|
||||
end
|
||||
end
|
||||
result
|
||||
end
|
||||
|
||||
def remove_lines(setting_name, value=nil)
|
||||
if value.kind_of?(Array)
|
||||
val_arr = value
|
||||
else
|
||||
val_arr = [value]
|
||||
end
|
||||
val_arr.each do |val|
|
||||
@lines.each_with_index do |line, index|
|
||||
if (match = @@SETTING_REGEX.match(line))
|
||||
if match[2] == setting_name
|
||||
if val.nil? or val_arr.include?(match[4])
|
||||
@lines.delete_at(index)
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def add_lines(setting_name, value)
|
||||
indent_str = ' ' * (indentation || 0)
|
||||
if current = find_last_setting(setting_name)
|
||||
offset = current
|
||||
elsif comment = find_commented_setting(setting_name)
|
||||
offset = comment + 1
|
||||
else
|
||||
offset = @lines.length
|
||||
end
|
||||
if value.kind_of?(Array)
|
||||
value.each do |val|
|
||||
@lines.insert(offset, "#{indent_str}#{setting_name}=#{val}\n")
|
||||
offset += 1
|
||||
end
|
||||
else
|
||||
@lines.insert(offset, "#{indent_str}#{setting_name}=#{value}\n")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,91 @@
|
|||
# == Definition: openstacklib::db::mysql
|
||||
#
|
||||
# This resource configures a mysql 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'
|
||||
#
|
||||
# [*host*]
|
||||
# The IP address or hostname of the user in mysql_grant;
|
||||
# string; optional; default to '127.0.0.1'
|
||||
#
|
||||
# [*charset*]
|
||||
# The charset to use for the database;
|
||||
# string; optional; default to 'utf8'
|
||||
#
|
||||
# [*collate*]
|
||||
# The collate to use for the database;
|
||||
# string; optional; default to 'utf8_general_ci'
|
||||
#
|
||||
# [*allowed_hosts*]
|
||||
# Additional hosts that are allowed to access this database;
|
||||
# array or string; optional; default to undef
|
||||
#
|
||||
# [*privileges*]
|
||||
# Privileges given to the database user;
|
||||
# string or array of strings; optional; default to 'ALL'
|
||||
#
|
||||
# [*create_user*]
|
||||
# Flag to allow for the skipping of the user as part of the database setup.
|
||||
# Set to false to skip the user creation.
|
||||
# Defaults to true.
|
||||
#
|
||||
# [*create_grant*]
|
||||
# Flag to allow for the skipping of the user grants as part of the database
|
||||
# setup. Set to false to skip the user creation.
|
||||
# Defaults to true.
|
||||
#
|
||||
# [*tls_options*]
|
||||
# The TLS options that the user will have
|
||||
# Defaults to ['NONE']
|
||||
#
|
||||
define openstacklib::db::mysql (
|
||||
$password_hash,
|
||||
$dbname = $title,
|
||||
$user = $title,
|
||||
$host = '127.0.0.1',
|
||||
$charset = 'utf8',
|
||||
$collate = 'utf8_general_ci',
|
||||
$allowed_hosts = [],
|
||||
$privileges = 'ALL',
|
||||
$create_user = true,
|
||||
$create_grant = true,
|
||||
$tls_options = ['NONE'],
|
||||
) {
|
||||
|
||||
include ::mysql::server
|
||||
include ::mysql::client
|
||||
|
||||
mysql_database { $dbname:
|
||||
ensure => present,
|
||||
charset => $charset,
|
||||
collate => $collate,
|
||||
require => [ Class['mysql::server'], Class['mysql::client'] ],
|
||||
}
|
||||
|
||||
if $create_user or $create_grant {
|
||||
$allowed_hosts_list = unique(concat(any2array($allowed_hosts), [$host]))
|
||||
$real_allowed_hosts = prefix($allowed_hosts_list, "${dbname}_")
|
||||
|
||||
openstacklib::db::mysql::host_access { $real_allowed_hosts:
|
||||
user => $user,
|
||||
password_hash => $password_hash,
|
||||
database => $dbname,
|
||||
privileges => $privileges,
|
||||
create_user => $create_user,
|
||||
create_grant => $create_grant,
|
||||
tls_options => $tls_options,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,63 @@
|
|||
# Allow a user to access the database for the service
|
||||
#
|
||||
# == Namevar
|
||||
# String with the form dbname_host. The host part of the string is the host
|
||||
# to allow
|
||||
#
|
||||
# == Parameters
|
||||
# [*user*]
|
||||
# username to allow
|
||||
#
|
||||
# [*password_hash*]
|
||||
# user password hash
|
||||
#
|
||||
# [*database*]
|
||||
# the database name
|
||||
#
|
||||
# [*privileges*]
|
||||
# the privileges to grant to this user
|
||||
#
|
||||
# [*create_user*]
|
||||
# Flag to allow for the skipping of the user as part of the database setup.
|
||||
# Set to false to skip the user creation.
|
||||
# Defaults to true.
|
||||
#
|
||||
# [*create_grant*]
|
||||
# Flag to allow for the skipping of the user grants as part of the database
|
||||
# setup. Set to false to skip the user creation.
|
||||
# Defaults to true.
|
||||
#
|
||||
# [*tls_options*]
|
||||
# The TLS options that the user will have
|
||||
# Defaults to ['NONE']
|
||||
#
|
||||
define openstacklib::db::mysql::host_access (
|
||||
$user,
|
||||
$password_hash,
|
||||
$database,
|
||||
$privileges,
|
||||
$create_user = true,
|
||||
$create_grant = true,
|
||||
$tls_options = ['NONE'],
|
||||
) {
|
||||
validate_re($title, '_', 'Title must be $dbname_$host')
|
||||
|
||||
$host = inline_template('<%= @title.split("_").last.downcase %>')
|
||||
|
||||
if $create_user {
|
||||
mysql_user { "${user}@${host}":
|
||||
password_hash => $password_hash,
|
||||
tls_options => $tls_options,
|
||||
require => Mysql_database[$database],
|
||||
}
|
||||
}
|
||||
|
||||
if $create_grant {
|
||||
mysql_grant { "${user}@${host}/${database}.*":
|
||||
privileges => $privileges,
|
||||
table => "${database}.*",
|
||||
require => Mysql_user["${user}@${host}"],
|
||||
user => "${user}@${host}",
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
# == 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,
|
||||
}
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
# == Class: openstacklib::defaults
|
||||
#
|
||||
# Default configuration for all openstack-puppet module.
|
||||
#
|
||||
# This file is loaded in the params.pp of each class.
|
||||
#
|
||||
class openstacklib::defaults {
|
||||
# Ensure all package resources have virtual package enable.
|
||||
if versioncmp($::puppetversion, '4.0.0') < 0 and versioncmp($::puppetversion, '3.6.1') >= 0 {
|
||||
Package<| tag == 'openstack' |> {
|
||||
allow_virtual => true,
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,105 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
# == Definition: openstacklib::messaging::rabbitmq
|
||||
#
|
||||
# This resource creates RabbitMQ resources for an OpenStack service.
|
||||
#
|
||||
# == Parameters:
|
||||
#
|
||||
# [*userid*]
|
||||
# (optional) The username to use when connecting to Rabbit
|
||||
# Defaults to 'guest'
|
||||
#
|
||||
# [*password*]
|
||||
# (optional) The password to use when connecting to Rabbit
|
||||
# Defaults to 'guest'
|
||||
#
|
||||
# [*virtual_host*]
|
||||
# (optional) The virtual host to use when connecting to Rabbit
|
||||
# Defaults to '/'
|
||||
#
|
||||
# [*is_admin*]
|
||||
# (optional) If the user should be admin or not
|
||||
# Defaults to false
|
||||
#
|
||||
# [*configure_permission*]
|
||||
# (optional) Define configure permission
|
||||
# Defaults to '.*'
|
||||
#
|
||||
# [*write_permission*]
|
||||
# (optional) Define write permission
|
||||
# Defaults to '.*'
|
||||
#
|
||||
# [*read_permission*]
|
||||
# (optional) Define read permission
|
||||
# Defaults to '.*'
|
||||
#
|
||||
# [*manage_user*]
|
||||
# (optional) Manage or not the user
|
||||
# Defaults to true
|
||||
#
|
||||
# [*manage_user_permissions*]
|
||||
# (optional) Manage or not user permissions
|
||||
# Defaults to true
|
||||
#
|
||||
# [*manage_vhost*]
|
||||
# (optional) Manage or not the vhost
|
||||
# Defaults to true
|
||||
#
|
||||
define openstacklib::messaging::rabbitmq(
|
||||
$userid = 'guest',
|
||||
$password = 'guest',
|
||||
$virtual_host = '/',
|
||||
$is_admin = false,
|
||||
$configure_permission = '.*',
|
||||
$write_permission = '.*',
|
||||
$read_permission = '.*',
|
||||
$manage_user = true,
|
||||
$manage_user_permissions = true,
|
||||
$manage_vhost = true,
|
||||
) {
|
||||
|
||||
if $manage_user {
|
||||
if $userid == 'guest' {
|
||||
$is_admin_real = false
|
||||
} else {
|
||||
$is_admin_real = $is_admin
|
||||
}
|
||||
ensure_resource('rabbitmq_user', $userid, {
|
||||
'admin' => $is_admin_real,
|
||||
'password' => $password,
|
||||
'provider' => 'rabbitmqctl',
|
||||
})
|
||||
}
|
||||
|
||||
if $manage_user_permissions {
|
||||
ensure_resource('rabbitmq_user_permissions', "${userid}@${virtual_host}", {
|
||||
'configure_permission' => $configure_permission,
|
||||
'write_permission' => $write_permission,
|
||||
'read_permission' => $read_permission,
|
||||
'provider' => 'rabbitmqctl',
|
||||
})
|
||||
}
|
||||
|
||||
if $manage_vhost {
|
||||
ensure_resource('rabbitmq_vhost', $virtual_host, {
|
||||
'provider' => 'rabbitmqctl',
|
||||
})
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
# == 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',
|
||||
){
|
||||
ensure_packages('python-openstackclient', {'ensure' => $package_ensure, tag => 'openstack'})
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
# == Class: openstacklib::policies
|
||||
#
|
||||
# This resource is an helper to call the policy definition
|
||||
#
|
||||
# == Parameters:
|
||||
#
|
||||
# [*policies*]
|
||||
# Hash of policies one would like to set to specific values
|
||||
# hash; optional
|
||||
#
|
||||
class openstacklib::policy (
|
||||
$policies = {},
|
||||
) {
|
||||
|
||||
validate_hash($policies)
|
||||
|
||||
create_resources('openstacklib::policy::base', $policies)
|
||||
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
# == Definition: openstacklib::policy::base
|
||||
#
|
||||
# This resource configures the policy.json file for an OpenStack service
|
||||
#
|
||||
# == Parameters:
|
||||
#
|
||||
# [*file_path*]
|
||||
# Path to the policy.json file
|
||||
# string; required
|
||||
#
|
||||
# [*key*]
|
||||
# The key to replace the value for
|
||||
# string; required; the key to replace the value for
|
||||
#
|
||||
# [*value*]
|
||||
# The value to set
|
||||
# string; optional; the value to set
|
||||
#
|
||||
define openstacklib::policy::base (
|
||||
$file_path,
|
||||
$key,
|
||||
$value = '',
|
||||
) {
|
||||
|
||||
# Add entry if it doesn't exists
|
||||
augeas { "${file_path}-${key}-${value}-add":
|
||||
lens => 'Json.lns',
|
||||
incl => $file_path,
|
||||
changes => [
|
||||
"set dict/entry[last()+1] \"${key}\"",
|
||||
"set dict/entry[last()]/string \"${value}\"",
|
||||
],
|
||||
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"],
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
#
|
||||
# Copyright (C) 2016 Matthew J. Black
|
||||
#
|
||||
# Author: Matthew J. Black <mjblack@gmail.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::policyrcd
|
||||
#
|
||||
# [*services*]
|
||||
# (required) The services that should be in the policy-rc.d shell script
|
||||
# that should not autostart on install.
|
||||
#
|
||||
class openstacklib::policyrcd(
|
||||
$services
|
||||
) {
|
||||
|
||||
validate_array($services)
|
||||
|
||||
if $::osfamily == 'Debian' {
|
||||
# We put this out there so openstack services wont auto start
|
||||
# when installed.
|
||||
file { '/usr/sbin/policy-rc.d':
|
||||
ensure => present,
|
||||
content => template('openstacklib/policy-rc.d.erb'),
|
||||
mode => '0755',
|
||||
owner => root,
|
||||
group => root,
|
||||
}
|
||||
|
||||
File['/usr/sbin/policy-rc.d'] -> Package<| tag == 'openstack' |>
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
#
|
||||
# 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.
|
||||
#
|
||||
# == Definition: openstacklib::service_validation
|
||||
#
|
||||
# This resource does service validation for an OpenStack service.
|
||||
#
|
||||
# == Parameters:
|
||||
#
|
||||
# [*command*]
|
||||
# Command to run for validating the service;
|
||||
# string; required
|
||||
#
|
||||
# [*service_name*]
|
||||
# The name of the service to validate;
|
||||
# string; optional; default to the $title of the resource, i.e. 'nova-api'
|
||||
#
|
||||
# [*path*]
|
||||
# The path of the command to validate the service;
|
||||
# string; optional; default to '/usr/bin:/bin:/usr/sbin:/sbin'
|
||||
#
|
||||
# [*provider*]
|
||||
# The provider to use for the exec command;
|
||||
# string; optional; default to 'shell'
|
||||
#
|
||||
# [*refreshonly*]
|
||||
# If the service validation should only occur on a refresh/notification;
|
||||
# boolean; optional; default to false
|
||||
#
|
||||
# [*timeout*]
|
||||
# The maximum time the command should take;
|
||||
# string; optional; default to '60'
|
||||
#
|
||||
# [*tries*]
|
||||
# Number of times to retry validation;
|
||||
# string; optional; default to '10'
|
||||
#
|
||||
# [*try_sleep*]
|
||||
# Number of seconds between validation attempts;
|
||||
# string; optional; default to '2'
|
||||
#
|
||||
# [*onlyif*]
|
||||
# Run the exec if all conditions in the array return true.
|
||||
# string or array; optional; default to 'undef'
|
||||
#
|
||||
# [*unless*]
|
||||
# Run the exec if all conditions in the array return false.
|
||||
# string or array; optional; default to 'undef'
|
||||
#
|
||||
define openstacklib::service_validation(
|
||||
$command,
|
||||
$service_name = $name,
|
||||
$path = '/usr/bin:/bin:/usr/sbin:/sbin',
|
||||
$provider = shell,
|
||||
$refreshonly = false,
|
||||
$timeout = '60',
|
||||
$tries = '10',
|
||||
$try_sleep = '2',
|
||||
$onlyif = undef,
|
||||
$unless = undef,
|
||||
) {
|
||||
|
||||
if $onlyif and $unless {
|
||||
fail ('Only one parameter should be declared: onlyif or unless')
|
||||
}
|
||||
|
||||
exec { "execute ${service_name} validation":
|
||||
command => $command,
|
||||
path => $path,
|
||||
provider => $provider,
|
||||
refreshonly => $refreshonly,
|
||||
timeout => $timeout,
|
||||
tries => $tries,
|
||||
try_sleep => $try_sleep,
|
||||
onlyif => $onlyif,
|
||||
unless => $unless,
|
||||
logoutput => 'on_failure',
|
||||
}
|
||||
|
||||
anchor { "create ${service_name} anchor":
|
||||
require => Exec["execute ${service_name} validation"],
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,248 @@
|
|||
#
|
||||
# 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 $::os_workers
|
||||
#
|
||||
# [*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_display_name*]
|
||||
# (optional) Name of the WSGI process display-name.
|
||||
# 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
|
||||
#
|
||||
# [*wsgi_application_group*]
|
||||
# (optional) The application group of the WSGI script.
|
||||
# Defaults to '%{GLOBAL}'
|
||||
#
|
||||
# [*wsgi_pass_authorization*]
|
||||
# (optional) Whether HTTP authorisation headers are passed through to a WSGI
|
||||
# script when the equivalent HTTP request headers are present.
|
||||
# Defaults to undef
|
||||
#
|
||||
# [*wsgi_chunked_request*]
|
||||
# (optional) Makes the vhost allow chunked requests which is useful for
|
||||
# handling TE (Transfer-Encoding), chunked or gzip. This sets the
|
||||
# WSGIChunkedRequest option in the vhost.
|
||||
# Defaults to undef
|
||||
#
|
||||
# [*vhost_custom_fragment*]
|
||||
# (optional) Passes a string of custom configuration
|
||||
# directives to be placed at the end of the vhost configuration.
|
||||
# Defaults to undef.
|
||||
#
|
||||
# [*allow_encoded_slashes*]
|
||||
# (optional) If set, uses apache's AllowEncodedSlashes option in the vhost.
|
||||
# This option is passed to puppetlabs-apache, which accepts only 4
|
||||
# options: undef, "on", "off" or "nodecode". This is thus validated in the
|
||||
# underlying vhost resource.
|
||||
# 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 = $::os_workers,
|
||||
$user = undef,
|
||||
$workers = 1,
|
||||
$wsgi_daemon_process = $name,
|
||||
$wsgi_process_display_name = $name,
|
||||
$wsgi_process_group = $name,
|
||||
$wsgi_script_dir = undef,
|
||||
$wsgi_script_file = undef,
|
||||
$wsgi_script_source = undef,
|
||||
$wsgi_application_group = '%{GLOBAL}',
|
||||
$wsgi_pass_authorization = undef,
|
||||
$wsgi_chunked_request = undef,
|
||||
$vhost_custom_fragment = undef,
|
||||
$allow_encoded_slashes = 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,
|
||||
display-name => $wsgi_process_display_name,
|
||||
}
|
||||
$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,
|
||||
setenvif => ['X-Forwarded-Proto https HTTPS=1'],
|
||||
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,
|
||||
wsgi_application_group => $wsgi_application_group,
|
||||
wsgi_pass_authorization => $wsgi_pass_authorization,
|
||||
wsgi_chunked_request => $wsgi_chunked_request,
|
||||
custom_fragment => $vhost_custom_fragment,
|
||||
allow_encoded_slashes => $allow_encoded_slashes,
|
||||
require => File[$service_name],
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
{
|
||||
"author": "Puppet Labs and OpenStack Contributors",
|
||||
"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/mysql",
|
||||
"version_requirement": ">=3.10.0 <4.0.0"
|
||||
},
|
||||
{
|
||||
"name": "puppetlabs/stdlib",
|
||||
"version_requirement": ">=4.0.0 <5.0.0"
|
||||
},
|
||||
{
|
||||
"name": "puppetlabs/rabbitmq",
|
||||
"version_requirement": ">=2.0.2 <6.0.0"
|
||||
},
|
||||
{
|
||||
"name": "puppetlabs/postgresql",
|
||||
"version_requirement": ">=3.3.0 <5.0.0"
|
||||
}
|
||||
],
|
||||
"description": "Puppet module library to expose common functionality between OpenStack modules.",
|
||||
"issues_url": "https://bugs.launchpad.net/puppet-openstacklib",
|
||||
"license": "Apache-2.0",
|
||||
"name": "openstack-openstacklib",
|
||||
"operatingsystem_support": [
|
||||
{
|
||||
"operatingsystem": "Debian",
|
||||
"operatingsystemrelease": [
|
||||
"8"
|
||||
]
|
||||
},
|
||||
{
|
||||
"operatingsystem": "Fedora",
|
||||
"operatingsystemrelease": [
|
||||
"24"
|
||||
]
|
||||
},
|
||||
{
|
||||
"operatingsystem": "RedHat",
|
||||
"operatingsystemrelease": [
|
||||
"7"
|
||||
]
|
||||
},
|
||||
{
|
||||
"operatingsystem": "Ubuntu",
|
||||
"operatingsystemrelease": [
|
||||
"16.04"
|
||||
]
|
||||
}
|
||||
],
|
||||
"project_page": "https://launchpad.net/puppet-openstacklib",
|
||||
"requirements": [
|
||||
{
|
||||
"name": "pe",
|
||||
"version_requirement": "4.x"
|
||||
},
|
||||
{
|
||||
"name": "puppet",
|
||||
"version_requirement": "4.x"
|
||||
}
|
||||
],
|
||||
"source": "git://github.com/openstack/puppet-openstacklib.git",
|
||||
"summary": "Puppet OpenStack Libraries",
|
||||
"version": "11.0.0"
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
features:
|
||||
- For the users that result from the usage of the mysql resource, it is now
|
||||
possible to specify the TLS options. This is useful if one wants to force
|
||||
the user to only connect using TLS, or if one wants to force the usage of
|
||||
client certificates for this specific user.
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
fixes:
|
||||
- Bugfix 1664561. Allow to use Integers and Strings
|
||||
for the port parameter.
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
fixes:
|
||||
- Catch HTTP 403 responses (not authorized requests) in openstack provider.
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
features:
|
||||
- Add a manifest which is loaded by all puppet modules in
|
||||
manifests/param.pp. This is described in
|
||||
`bug 1599113
|
||||
<https://bugs.launchpad.net/puppet-openstacklib/+bug/1599113>`__
|
||||
|
||||
fixes:
|
||||
- The first feature would help fixing RDO package using virtual
|
||||
package which is a recurring problem. Example of such problem is
|
||||
`bug 1599113
|
||||
<https://bugs.launchpad.net/puppet-keystone/+bug/1597753>`__
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
features:
|
||||
- Add the possibility to exclude some exception from retry
|
||||
mechanism. It helps to fix `bug 1597357
|
||||
<https://bugs.launchpad.net/puppet-keystone/+bug/1597357>`__
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
features:
|
||||
- Add the ability to transform values in config files. This allows
|
||||
operators to configure input directly at assignment by specifying
|
||||
a 'transform_to' attribute.
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
features:
|
||||
- Allow to give an array of IP addresses to normalize_ip_for_uri and normalize
|
||||
each IP in the list.
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
features:
|
||||
- Utility to handle IPv6 address brackets with normalize_ip_for_uri
|
||||
is a function that help us to add brackets to IPv6 addresses
|
||||
when missing. The function moved to puppetlabs-stdlib but is not in latest release
|
||||
yet. Once it's done, we'll probably drop this function so our modules will use stdlib.
|
|
@ -0,0 +1,11 @@
|
|||
---
|
||||
features:
|
||||
- Add a class that takes an array of services that can be
|
||||
configured to not autostart on package install. The most
|
||||
notable example is keystone. The policy-rc.d file is
|
||||
generated to return the correct exit code to prevent the
|
||||
services from autostarting on package install. This change
|
||||
is only meant for debian based systems.
|
||||
issues:
|
||||
- ubuntu cloud archive keystone package is auto-starting the
|
||||
eventlet process on package install.
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
features:
|
||||
- Add an "extra" hash parameter to os_database_connection that allows to extend
|
||||
the database uri configuration.
|
|
@ -0,0 +1,9 @@
|
|||
---
|
||||
features:
|
||||
- Add the ability to skip the mysql user and/or grant creation as part of the
|
||||
openstack::db::mysql resource.
|
||||
fixes:
|
||||
- openstack::db::mysql could not be used to create multiple databases
|
||||
with the same user/password for access due to a duplicate mysql_user
|
||||
resource declaration. Now the user and/or grant creation process can be
|
||||
skipped if they already exist.
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
fixes:
|
||||
- bug 1651215 The transport parameter was not being used so
|
||||
transport was fixed value 'rabbit'
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
features:
|
||||
- os_transport_url puppet parser function can be used to generate valid
|
||||
transport_url URIs from a hash of connection parameters.
|
|
@ -0,0 +1,12 @@
|
|||
---
|
||||
features:
|
||||
- Moved existing $::os_workers to $::os_workers_small
|
||||
- Updated $::os_workers to have a value between '2' and '12'.
|
||||
The value of this fact is the larger value between '2'
|
||||
and the number of processors divided by '2' but will not
|
||||
exceed '12'.
|
||||
- Created fact $::os_workers_large to have a value of number
|
||||
of processors divided by '2'
|
||||
fixes:
|
||||
- bug 1650424 The current calculation for os_workers negatively
|
||||
impacts api response times
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
features:
|
||||
- Created a new fact called $::os_workers to be used as the defaults for any
|
||||
of the openstack service worker configurations. This fact will have a value
|
||||
between '2' and '8'. The value of this fact is the larger value between '2'
|
||||
and the number of processors divided by '4' but will not exceed '8'.
|
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
other:
|
||||
- Parameters that control the number of spawned child processes for
|
||||
distributing processing have had their default value changed from
|
||||
::processorcount to ::os_workers.
|
|
@ -0,0 +1,3 @@
|
|||
---
|
||||
features:
|
||||
- Added policy_rcd provider for managing policy-rc.d for Debian family.
|
|
@ -0,0 +1,7 @@
|
|||
---
|
||||
fixes:
|
||||
- Add retries to the openstack command.
|
||||
Increase command timeout to 20s and request timeout to 60s
|
||||
and sleep 3s between retries. Do not retry non-idempotent actions.
|
||||
This is a more robust implementation that will prevent failures in case
|
||||
of Keystone API failures during a deployment.
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
fixes:
|
||||
- Add support for multiple regions in base provider code used by other puppet
|
||||
modules.
|
|
@ -0,0 +1,4 @@
|
|||
---
|
||||
features:
|
||||
- Release notes are no longer maintained by hand, we now use the reno tool to
|
||||
manage them.
|
|
@ -0,0 +1,262 @@
|
|||
# -*- coding: utf-8 -*-
|
||||
# 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.
|
||||
#
|
||||
|
||||
# If extensions (or modules to document with autodoc) are in another directory,
|
||||
# add these directories to sys.path here. If the directory is relative to the
|
||||
# documentation root, use os.path.abspath to make it absolute, like shown here.
|
||||
#sys.path.insert(0, os.path.abspath('.'))
|
||||
|
||||
# -- General configuration ------------------------------------------------
|
||||
|
||||
# If your documentation needs a minimal Sphinx version, state it here.
|
||||
#needs_sphinx = '1.0'
|
||||
|
||||
# Add any Sphinx extension module names here, as strings. They can be
|
||||
# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom
|
||||
# ones.
|
||||
extensions = [
|
||||
'oslosphinx',
|
||||
'reno.sphinxext',
|
||||
]
|
||||
|
||||
# Add any paths that contain templates here, relative to this directory.
|
||||
templates_path = ['_templates']
|
||||
|
||||
# The suffix of source filenames.
|
||||
source_suffix = '.rst'
|
||||
|
||||
# The encoding of source files.
|
||||
#source_encoding = 'utf-8-sig'
|
||||
|
||||
# The master toctree document.
|
||||
master_doc = 'index'
|
||||
|
||||
# General information about the project.
|
||||
project = u'puppet-openstacklib Release Notes'
|
||||
copyright = u'2017, Puppet OpenStack Developers'
|
||||
|
||||
# The version info for the project you're documenting, acts as replacement for
|
||||
# |version| and |release|, also used in various other places throughout the
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = '11.0.0'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = '11.0.0'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
#language = None
|
||||
|
||||
# There are two options for replacing |today|: either, you set today to some
|
||||
# non-false value, then it is used:
|
||||
#today = ''
|
||||
# Else, today_fmt is used as the format for a strftime call.
|
||||
#today_fmt = '%B %d, %Y'
|
||||
|
||||
# List of patterns, relative to source directory, that match files and
|
||||
# directories to ignore when looking for source files.
|
||||
exclude_patterns = []
|
||||
|
||||
# The reST default role (used for this markup: `text`) to use for all
|
||||
# documents.
|
||||
#default_role = None
|
||||
|
||||
# If true, '()' will be appended to :func: etc. cross-reference text.
|
||||
#add_function_parentheses = True
|
||||
|
||||
# If true, the current module name will be prepended to all description
|
||||
# unit titles (such as .. function::).
|
||||
#add_module_names = True
|
||||
|
||||
# If true, sectionauthor and moduleauthor directives will be shown in the
|
||||
# output. They are ignored by default.
|
||||
#show_authors = False
|
||||
|
||||
# The name of the Pygments (syntax highlighting) style to use.
|
||||
pygments_style = 'sphinx'
|
||||
|
||||
# A list of ignored prefixes for module index sorting.
|
||||
#modindex_common_prefix = []
|
||||
|
||||
# If true, keep warnings as "system message" paragraphs in the built documents.
|
||||
#keep_warnings = False
|
||||
|
||||
|
||||
# -- Options for HTML output ----------------------------------------------
|
||||
|
||||
# The theme to use for HTML and HTML Help pages. See the documentation for
|
||||
# a list of builtin themes.
|
||||
html_theme = 'default'
|
||||
|
||||
# Theme options are theme-specific and customize the look and feel of a theme
|
||||
# further. For a list of options available for each theme, see the
|
||||
# documentation.
|
||||
#html_theme_options = {}
|
||||
|
||||
# Add any paths that contain custom themes here, relative to this directory.
|
||||
#html_theme_path = []
|
||||
|
||||
# The name for this set of Sphinx documents. If None, it defaults to
|
||||
# "<project> v<release> documentation".
|
||||
#html_title = None
|
||||
|
||||
# A shorter title for the navigation bar. Default is the same as html_title.
|
||||
#html_short_title = None
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top
|
||||
# of the sidebar.
|
||||
#html_logo = None
|
||||
|
||||
# The name of an image file (within the static path) to use as favicon of the
|
||||
# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32
|
||||
# pixels large.
|
||||
#html_favicon = None
|
||||
|
||||
# Add any paths that contain custom static files (such as style sheets) here,
|
||||
# relative to this directory. They are copied after the builtin static files,
|
||||
# so a file named "default.css" will overwrite the builtin "default.css".
|
||||
html_static_path = ['_static']
|
||||
|
||||
# Add any extra paths that contain custom files (such as robots.txt or
|
||||
# .htaccess) here, relative to this directory. These files are copied
|
||||
# directly to the root of the documentation.
|
||||
#html_extra_path = []
|
||||
|
||||
# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,
|
||||
# using the given strftime format.
|
||||
#html_last_updated_fmt = '%b %d, %Y'
|
||||
|
||||
# If true, SmartyPants will be used to convert quotes and dashes to
|
||||
# typographically correct entities.
|
||||
#html_use_smartypants = True
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
#html_sidebars = {}
|
||||
|
||||
# Additional templates that should be rendered to pages, maps page names to
|
||||
# template names.
|
||||
#html_additional_pages = {}
|
||||
|
||||
# If false, no module index is generated.
|
||||
#html_domain_indices = True
|
||||
|
||||
# If false, no index is generated.
|
||||
#html_use_index = True
|
||||
|
||||
# If true, the index is split into individual pages for each letter.
|
||||
#html_split_index = False
|
||||
|
||||
# If true, links to the reST sources are added to the pages.
|
||||
#html_show_sourcelink = True
|
||||
|
||||
# If true, "Created using Sphinx" is shown in the HTML footer. Default is True.
|
||||
#html_show_sphinx = True
|
||||
|
||||
# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True.
|
||||
#html_show_copyright = True
|
||||
|
||||
# If true, an OpenSearch description file will be output, and all pages will
|
||||
# contain a <link> tag referring to it. The value of this option must be the
|
||||
# base URL from which the finished HTML is served.
|
||||
#html_use_opensearch = ''
|
||||
|
||||
# This is the file name suffix for HTML files (e.g. ".xhtml").
|
||||
#html_file_suffix = None
|
||||
|
||||
# Output file base name for HTML help builder.
|
||||
htmlhelp_basename = 'puppet-openstacklibReleaseNotesdoc'
|
||||
|
||||
|
||||
# -- Options for LaTeX output ---------------------------------------------
|
||||
|
||||
latex_elements = {
|
||||
# The paper size ('letterpaper' or 'a4paper').
|
||||
#'papersize': 'letterpaper',
|
||||
|
||||
# The font size ('10pt', '11pt' or '12pt').
|
||||
#'pointsize': '10pt',
|
||||
|
||||
# Additional stuff for the LaTeX preamble.
|
||||
#'preamble': '',
|
||||
}
|
||||
|
||||
# Grouping the document tree into LaTeX files. List of tuples
|
||||
# (source start file, target name, title,
|
||||
# author, documentclass [howto, manual, or own class]).
|
||||
latex_documents = [
|
||||
('index', 'puppet-openstacklibReleaseNotes.tex', u'puppet-openstacklib Release Notes Documentation',
|
||||
u'2017, Puppet OpenStack Developers', 'manual'),
|
||||
]
|
||||
|
||||
# The name of an image file (relative to this directory) to place at the top of
|
||||
# the title page.
|
||||
#latex_logo = None
|
||||
|
||||
# For "manual" documents, if this is true, then toplevel headings are parts,
|
||||
# not chapters.
|
||||
#latex_use_parts = False
|
||||
|
||||
# If true, show page references after internal links.
|
||||
#latex_show_pagerefs = False
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#latex_show_urls = False
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#latex_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#latex_domain_indices = True
|
||||
|
||||
|
||||
# -- Options for manual page output ---------------------------------------
|
||||
|
||||
# One entry per manual page. List of tuples
|
||||
# (source start file, name, description, authors, manual section).
|
||||
man_pages = [
|
||||
('index', 'puppet-openstacklibreleasenotes', u'puppet-openstacklib Release Notes Documentation',
|
||||
[u'2017, Puppet OpenStack Developers'], 1)
|
||||
]
|
||||
|
||||
# If true, show URL addresses after external links.
|
||||
#man_show_urls = False
|
||||
|
||||
|
||||
# -- Options for Texinfo output -------------------------------------------
|
||||
|
||||
# Grouping the document tree into Texinfo files. List of tuples
|
||||
# (source start file, target name, title, author,
|
||||
# dir menu entry, description, category)
|
||||
texinfo_documents = [
|
||||
('index', 'puppet-openstacklibReleaseNotes', u'puppet-openstacklib Release Notes Documentation',
|
||||
u'2017, Puppet OpenStack Developers', 'puppet-openstacklibReleaseNotes', 'One line description of project.',
|
||||
'Miscellaneous'),
|
||||
]
|
||||
|
||||
# Documents to append as an appendix to all manuals.
|
||||
#texinfo_appendices = []
|
||||
|
||||
# If false, no module index is generated.
|
||||
#texinfo_domain_indices = True
|
||||
|
||||
# How to display URL addresses: 'footnote', 'no', or 'inline'.
|
||||
#texinfo_show_urls = 'footnote'
|
||||
|
||||
# If true, do not generate a @detailmenu in the "Top" node's menu.
|
||||
#texinfo_no_detailmenu = False
|
||||
|
||||
# -- Options for Internationalization output ------------------------------
|
||||
locale_dirs = ['locale/']
|
|
@ -0,0 +1,21 @@
|
|||
=============================================
|
||||
Welcome to puppet-openstacklib Release Notes!
|
||||
=============================================
|
||||
|
||||
Contents
|
||||
========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
||||
unreleased
|
||||
ocata
|
||||
newton
|
||||
mitaka
|
||||
|
||||
|
||||
Indices and tables
|
||||
==================
|
||||
|
||||
* :ref:`genindex`
|
||||
* :ref:`search`
|
|
@ -0,0 +1,6 @@
|
|||
============================
|
||||
Mitaka Series Release Notes
|
||||
============================
|
||||
|
||||
.. release-notes::
|
||||
:branch: origin/stable/mitaka
|
|
@ -0,0 +1,6 @@
|
|||
===================================
|
||||
Newton Series Release Notes
|
||||
===================================
|
||||
|
||||
.. release-notes::
|
||||
:branch: origin/stable/newton
|
|
@ -0,0 +1,6 @@
|
|||
===================================
|
||||
Ocata Series Release Notes
|
||||
===================================
|
||||
|
||||
.. release-notes::
|
||||
:branch: origin/stable/ocata
|
|
@ -0,0 +1,5 @@
|
|||
==============================
|
||||
Current Series Release Notes
|
||||
==============================
|
||||
|
||||
.. release-notes::
|
|
@ -0,0 +1,13 @@
|
|||
[metadata]
|
||||
name = puppet-openstacklib
|
||||
summary = Puppet module for OpenStack Openstacklib
|
||||
description-file =
|
||||
README.md
|
||||
author = Puppet Labs and OpenStack Contributors
|
||||
author-email = openstack-dev@lists.openstack.org
|
||||
home-page = http://docs.openstack.org/developer/puppet-openstack-guide
|
||||
classifier =
|
||||
Intended Audience :: Developers
|
||||
Intended Audience :: System Administrators
|
||||
License :: OSI Approved :: Apache Software License
|
||||
Operating System :: POSIX :: Linux
|
|
@ -0,0 +1,22 @@
|
|||
#!/usr/bin/env python
|
||||
# Copyright (c) 2013 Hewlett-Packard Development Company, L.P.
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
# implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
# THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT
|
||||
import setuptools
|
||||
|
||||
setuptools.setup(
|
||||
setup_requires=['pbr'],
|
||||
pbr=True)
|
|
@ -0,0 +1,7 @@
|
|||
require 'spec_helper_acceptance'
|
||||
|
||||
describe 'Defaults manifest' do
|
||||
context 'virtual_package' do
|
||||
it_behaves_like 'puppet_apply_success_from_example', 'virtual_packages'
|
||||
end
|
||||
end
|
|
@ -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
|
|
@ -0,0 +1,11 @@
|
|||
HOSTS:
|
||||
centos-server-70-x64:
|
||||
roles:
|
||||
- master
|
||||
platform: el-7-x86_64
|
||||
box: puppetlabs/centos-7.0-64-nocm
|
||||
box_url: https://vagrantcloud.com/puppetlabs/centos-7.0-64-nocm
|
||||
hypervisor: vagrant
|
||||
CONFIG:
|
||||
log_level: debug
|
||||
type: foss
|
|
@ -0,0 +1,10 @@
|
|||
HOSTS:
|
||||
ubuntu-server-14.04-amd64:
|
||||
roles:
|
||||
- master
|
||||
platform: ubuntu-14.04-amd64
|
||||
box: puppetlabs/ubuntu-14.04-64-nocm
|
||||
box_url: https://vagrantcloud.com/puppetlabs/ubuntu-14.04-64-nocm
|
||||
hypervisor: vagrant
|
||||
CONFIG:
|
||||
type: foss
|
|
@ -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
|
|
@ -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
|
|
@ -0,0 +1,10 @@
|
|||
HOSTS:
|
||||
ubuntu-16.04-amd64:
|
||||
roles:
|
||||
- master
|
||||
platform: ubuntu-16.04-amd64
|
||||
hypervisor: none
|
||||
ip: 127.0.0.1
|
||||
CONFIG:
|
||||
type: foss
|
||||
set_env: false
|
|
@ -0,0 +1,11 @@
|
|||
HOSTS:
|
||||
ubuntu-server-14.04-amd64:
|
||||
roles:
|
||||
- master
|
||||
platform: ubuntu-14.04-amd64
|
||||
box: puppetlabs/ubuntu-14.04-64-nocm
|
||||
box_url: https://vagrantcloud.com/puppetlabs/ubuntu-14.04-64-nocm
|
||||
hypervisor: vagrant
|
||||
CONFIG:
|
||||
log_level: debug
|
||||
type: foss
|
|
@ -0,0 +1,57 @@
|
|||
require 'spec_helper_acceptance'
|
||||
|
||||
describe 'basic config provider resource' do
|
||||
|
||||
context 'default parameters' do
|
||||
|
||||
it 'should work with no errors' do
|
||||
pp= <<-EOS
|
||||
Exec { logoutput => 'on_failure' }
|
||||
|
||||
# We create the file manually here because we only want to test
|
||||
# the logic of the provider hence installing the whole stack would
|
||||
# result in some overhead that is already tested in puppet-keystone
|
||||
File <||> -> Keystone_config <||>
|
||||
file { '/etc/keystone' :
|
||||
ensure => directory,
|
||||
}
|
||||
file { '/etc/keystone/keystone.conf' :
|
||||
ensure => file,
|
||||
}
|
||||
|
||||
keystone_config { 'DEFAULT/thisshouldexist' :
|
||||
value => 'foo',
|
||||
}
|
||||
|
||||
keystone_config { 'DEFAULT/thisshouldnotexist' :
|
||||
value => '<SERVICE DEFAULT>',
|
||||
}
|
||||
|
||||
keystone_config { 'DEFAULT/thisshouldexist2' :
|
||||
value => '<SERVICE DEFAULT>',
|
||||
ensure_absent_val => 'toto',
|
||||
}
|
||||
|
||||
keystone_config { 'DEFAULT/thisshouldnotexist2' :
|
||||
value => 'toto',
|
||||
ensure_absent_val => 'toto',
|
||||
}
|
||||
EOS
|
||||
|
||||
|
||||
# Run it twice and test for idempotency
|
||||
apply_manifest(pp, :catch_failures => true)
|
||||
apply_manifest(pp, :catch_changes => true)
|
||||
end
|
||||
|
||||
describe file('/etc/keystone/keystone.conf') do
|
||||
it { should exist }
|
||||
it { should contain('thisshouldexist=foo') }
|
||||
it { should contain('thisshouldexist2=<SERVICE DEFAULT>') }
|
||||
|
||||
its(:content) { should_not match /thisshouldnotexist/ }
|
||||
end
|
||||
|
||||
|
||||
end
|
||||
end
|
|
@ -0,0 +1,55 @@
|
|||
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' {
|
||||
class { '::openstack_extras::repo::redhat::redhat':
|
||||
release => 'kilo',
|
||||
manage_epel => false,
|
||||
}
|
||||
} else {
|
||||
include ::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
|
|
@ -0,0 +1,33 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'openstacklib::defaults', type: :class do
|
||||
on_supported_os.each do |os, facts|
|
||||
let(:pre_condition) do
|
||||
<<-eof
|
||||
package { 'my_virt_package' :
|
||||
ensure => present,
|
||||
tag => 'openstack'
|
||||
}
|
||||
eof
|
||||
end
|
||||
|
||||
context "Puppet < 4.0.0" do
|
||||
context "on #{os}" do
|
||||
let(:facts) { facts.merge(:puppetversion => '3.8.0') }
|
||||
it { is_expected.to compile.with_all_deps }
|
||||
it { is_expected.to contain_class('openstacklib::defaults') }
|
||||
it { is_expected.to contain_package('my_virt_package')
|
||||
.with(:allow_virtual => true)}
|
||||
end
|
||||
end
|
||||
context "Puppet >= 4.0.0" do
|
||||
context "on #{os}" do
|
||||
let(:facts) { facts.merge(:puppetversion => '4.0.0') }
|
||||
it { is_expected.to compile.with_all_deps }
|
||||
it { is_expected.to contain_class('openstacklib::defaults') }
|
||||
it { is_expected.to contain_package('my_virt_package')
|
||||
.without(:allow_virtual)}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,41 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'openstacklib::policy' do
|
||||
|
||||
shared_examples_for 'openstacklib::policy' do
|
||||
context 'with basic configuration' do
|
||||
let :params do
|
||||
{
|
||||
:policies => {
|
||||
'foo' => {
|
||||
'file_path' => '/etc/nova/policy.json',
|
||||
'key' => 'context_is_admin',
|
||||
'value' => 'foo:bar'
|
||||
}
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
it 'configures the proper policy' do
|
||||
is_expected.to contain_openstacklib__policy__base('foo').with(
|
||||
:file_path => '/etc/nova/policy.json',
|
||||
:key => 'context_is_admin',
|
||||
:value => 'foo:bar'
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
on_supported_os({
|
||||
:supported_os => OSDefaults.get_supported_os
|
||||
}).each do |os,facts|
|
||||
context "on #{os}" do
|
||||
let (:facts) do
|
||||
facts.merge!(OSDefaults.get_facts())
|
||||
end
|
||||
|
||||
it_configures 'openstacklib::policy'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,102 @@
|
|||
#
|
||||
# Copyright (C) 2016 Matthew J. Black
|
||||
#
|
||||
# Author: Matthew J. Black <mjblack@gmail.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.
|
||||
#
|
||||
# Unit tests for openstacklib::policyrcd
|
||||
#
|
||||
require 'spec_helper'
|
||||
|
||||
describe 'openstacklib::policyrcd' do
|
||||
|
||||
shared_examples_for 'openstacklib::policyrcd on Debian platforms' do
|
||||
context "with single service" do
|
||||
let :params do
|
||||
{ :services => ['keystone'] }
|
||||
end
|
||||
|
||||
let(:contents) {
|
||||
<<-eof
|
||||
#!/bin/bash
|
||||
|
||||
if [ "$1" == "keystone" ]
|
||||
then
|
||||
exit 101
|
||||
fi
|
||||
|
||||
|
||||
eof
|
||||
}
|
||||
|
||||
it 'creates policy-rc.d file' do
|
||||
is_expected.to contain_file('/usr/sbin/policy-rc.d').with_content(contents)
|
||||
end
|
||||
end
|
||||
|
||||
context "with multiple services" do
|
||||
let :params do
|
||||
{ :services => ['keystone', 'nova'] }
|
||||
end
|
||||
|
||||
let(:contents) {
|
||||
<<-eof
|
||||
#!/bin/bash
|
||||
|
||||
if [ "$1" == "keystone" ]
|
||||
then
|
||||
exit 101
|
||||
fi
|
||||
|
||||
if [ "$1" == "nova" ]
|
||||
then
|
||||
exit 101
|
||||
fi
|
||||
|
||||
|
||||
eof
|
||||
}
|
||||
|
||||
it 'creates policy-rc.d file' do
|
||||
is_expected.to contain_file('/usr/sbin/policy-rc.d').with_content(contents)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
shared_examples_for 'openstacklib::policyrcd on RedHat platforms' do
|
||||
describe "with single service" do
|
||||
let :params do
|
||||
{ :services => ['keystone'] }
|
||||
end
|
||||
|
||||
it 'does not create policy-rc.d file' do
|
||||
is_expected.to_not contain_file('/usr/sbin/policy-rc.d')
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
on_supported_os({
|
||||
:supported_os => OSDefaults.get_supported_os
|
||||
}).each do |os,facts|
|
||||
context "on #{os}" do
|
||||
let (:facts) do
|
||||
facts.merge!(OSDefaults.get_facts())
|
||||
end
|
||||
|
||||
it_configures "openstacklib::policyrcd on #{facts[:osfamily]} platforms"
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,102 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'openstacklib::db::mysql::host_access' do
|
||||
|
||||
let :pre_condition do
|
||||
"include mysql::server\n" +
|
||||
"openstacklib::db::mysql { 'nova':\n" +
|
||||
" password_hash => 'AA1420F182E88B9E5F874F6FBE7459291E8F4601'}"
|
||||
end
|
||||
|
||||
shared_examples 'openstacklib::db::mysql::host_access examples' do
|
||||
|
||||
context 'with required parameters' do
|
||||
let (:title) { 'nova_10.0.0.1' }
|
||||
let :params do
|
||||
{ :user => 'foobar',
|
||||
:password_hash => 'AA1420F182E88B9E5F874F6FBE7459291E8F4601',
|
||||
:database => 'nova',
|
||||
:privileges => 'ALL' }
|
||||
end
|
||||
|
||||
it { is_expected.to contain_mysql_user("#{params[:user]}@10.0.0.1").with(
|
||||
:password_hash => params[:password_hash],
|
||||
:tls_options => ['NONE']
|
||||
)}
|
||||
|
||||
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]}.*"
|
||||
)}
|
||||
end
|
||||
|
||||
context 'with skipping user creation' do
|
||||
let (:title) { 'nova_10.0.0.1' }
|
||||
let :params do
|
||||
{ :user => 'foobar',
|
||||
:password_hash => 'AA1420F182E88B9E5F874F6FBE7459291E8F4601',
|
||||
:database => 'nova',
|
||||
:privileges => 'ALL',
|
||||
:create_user => false,
|
||||
}
|
||||
end
|
||||
|
||||
it { is_expected.to_not contain_mysql_user("#{params[:user]}@10.0.0.1") }
|
||||
|
||||
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]}.*"
|
||||
)}
|
||||
end
|
||||
|
||||
context 'with skipping grant creation' do
|
||||
let (:title) { 'nova_10.0.0.1' }
|
||||
let :params do
|
||||
{ :user => 'foobar',
|
||||
:password_hash => 'AA1420F182E88B9E5F874F6FBE7459291E8F4601',
|
||||
:database => 'nova',
|
||||
:privileges => 'ALL',
|
||||
:create_grant => false,
|
||||
}
|
||||
end
|
||||
|
||||
it { is_expected.to contain_mysql_user("#{params[:user]}@10.0.0.1").with(
|
||||
:password_hash => params[:password_hash]
|
||||
)}
|
||||
|
||||
it { is_expected.to_not contain_mysql_grant("#{params[:user]}@10.0.0.1/#{params[:database]}.*") }
|
||||
end
|
||||
|
||||
context 'with skipping user and grant creation' do
|
||||
let (:title) { 'nova_10.0.0.1' }
|
||||
let :params do
|
||||
{ :user => 'foobar',
|
||||
:password_hash => 'AA1420F182E88B9E5F874F6FBE7459291E8F4601',
|
||||
:database => 'nova',
|
||||
:privileges => 'ALL',
|
||||
:create_user => false,
|
||||
:create_grant => false,
|
||||
}
|
||||
end
|
||||
|
||||
it { is_expected.to_not contain_mysql_user("#{params[:user]}@10.0.0.1") }
|
||||
|
||||
it { is_expected.to_not contain_mysql_grant("#{params[:user]}@10.0.0.1/#{params[:database]}.*") }
|
||||
end
|
||||
end
|
||||
|
||||
on_supported_os({
|
||||
:supported_os => OSDefaults.get_supported_os
|
||||
}).each do |os,facts|
|
||||
context "on #{os}" do
|
||||
let (:facts) do
|
||||
facts.merge!(OSDefaults.get_facts())
|
||||
end
|
||||
|
||||
it_configures 'openstacklib::db::mysql::host_access examples'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,229 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'openstacklib::db::mysql' do
|
||||
|
||||
let :pre_condition do
|
||||
'include mysql::server'
|
||||
end
|
||||
|
||||
let (:title) { 'nova' }
|
||||
|
||||
let :required_params do
|
||||
{ :password_hash => 'AA1420F182E88B9E5F874F6FBE7459291E8F4601' }
|
||||
end
|
||||
|
||||
shared_examples 'openstacklib::db::mysql examples' do
|
||||
|
||||
context 'with only required parameters' do
|
||||
let :params do
|
||||
required_params
|
||||
end
|
||||
|
||||
it { is_expected.to contain_mysql_database(title).with(
|
||||
:charset => 'utf8',
|
||||
:collate => 'utf8_general_ci'
|
||||
)}
|
||||
it { is_expected.to contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
|
||||
:user => title,
|
||||
:database => title,
|
||||
:privileges => 'ALL',
|
||||
:tls_options => ['NONE'],
|
||||
)}
|
||||
end
|
||||
|
||||
context 'with overriding dbname parameter' do
|
||||
let :params do
|
||||
{ :dbname => 'foobar' }.merge(required_params)
|
||||
end
|
||||
|
||||
it { is_expected.to contain_mysql_database(params[:dbname]).with(
|
||||
:charset => 'utf8',
|
||||
:collate => 'utf8_general_ci'
|
||||
)}
|
||||
it { is_expected.to contain_openstacklib__db__mysql__host_access("#{params[:dbname]}_127.0.0.1").with(
|
||||
:user => title,
|
||||
:database => params[:dbname],
|
||||
:privileges => 'ALL',
|
||||
:create_user => true,
|
||||
:create_grant => true,
|
||||
:tls_options => ['NONE'],
|
||||
)}
|
||||
end
|
||||
|
||||
context 'with overriding user parameter' do
|
||||
let :params do
|
||||
{ :user => 'foobar' }.merge(required_params)
|
||||
end
|
||||
|
||||
it { is_expected.to contain_mysql_database(title).with(
|
||||
:charset => 'utf8',
|
||||
:collate => 'utf8_general_ci'
|
||||
)}
|
||||
it { is_expected.to contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
|
||||
:user => params[:user],
|
||||
:database => title,
|
||||
:privileges => 'ALL',
|
||||
:create_user => true,
|
||||
:create_grant => true,
|
||||
:tls_options => ['NONE'],
|
||||
)}
|
||||
end
|
||||
|
||||
context 'when overriding charset parameter' do
|
||||
let :params do
|
||||
{ :charset => 'latin1' }.merge(required_params)
|
||||
end
|
||||
|
||||
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 { 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::Mysql[#{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::Mysql[keystone]") }
|
||||
end
|
||||
|
||||
context "overriding allowed_hosts parameter with array value" do
|
||||
let :params do
|
||||
{ :allowed_hosts => ['127.0.0.1','%'] }.merge(required_params)
|
||||
end
|
||||
|
||||
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 {is_expected.to contain_openstacklib__db__mysql__host_access("#{title}_%").with(
|
||||
:user => title,
|
||||
:password_hash => params[:password_hash],
|
||||
:database => title
|
||||
)}
|
||||
end
|
||||
|
||||
context "overriding allowed_hosts parameter with string value" do
|
||||
let :params do
|
||||
{ :allowed_hosts => '192.168.1.1' }.merge(required_params)
|
||||
end
|
||||
|
||||
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
|
||||
)}
|
||||
end
|
||||
|
||||
context "overriding allowed_hosts parameter equals to host param " do
|
||||
let :params do
|
||||
{ :allowed_hosts => '127.0.0.1' }.merge(required_params)
|
||||
end
|
||||
|
||||
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
|
||||
)}
|
||||
end
|
||||
|
||||
context 'with skipping user creation' do
|
||||
let :params do
|
||||
{ :create_user => false }.merge(required_params)
|
||||
end
|
||||
|
||||
it { is_expected.to contain_mysql_database(title).with(
|
||||
:charset => 'utf8',
|
||||
:collate => 'utf8_general_ci'
|
||||
)}
|
||||
it { is_expected.to contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
|
||||
:user => title,
|
||||
:database => title,
|
||||
:privileges => 'ALL',
|
||||
:create_user => false,
|
||||
:create_grant => true,
|
||||
)}
|
||||
end
|
||||
|
||||
context 'with skipping grant creation' do
|
||||
let :params do
|
||||
{ :create_grant => false }.merge(required_params)
|
||||
end
|
||||
|
||||
it { is_expected.to contain_mysql_database(title).with(
|
||||
:charset => 'utf8',
|
||||
:collate => 'utf8_general_ci'
|
||||
)}
|
||||
it { is_expected.to contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with(
|
||||
:user => title,
|
||||
:database => title,
|
||||
:privileges => 'ALL',
|
||||
:create_user => true,
|
||||
:create_grant => false,
|
||||
)}
|
||||
end
|
||||
|
||||
context 'with skipping user and grant creation' do
|
||||
let :params do
|
||||
{ :create_user => false,
|
||||
:create_grant => false }.merge(required_params)
|
||||
end
|
||||
|
||||
it { is_expected.to contain_mysql_database(title).with(
|
||||
:charset => 'utf8',
|
||||
:collate => 'utf8_general_ci'
|
||||
)}
|
||||
it { is_expected.to_not contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1") }
|
||||
end
|
||||
|
||||
context "overriding tls_options" do
|
||||
let :params do
|
||||
{ :tls_options => ['SSL'] }.merge(required_params)
|
||||
end
|
||||
|
||||
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,
|
||||
:tls_options => ['SSL'],
|
||||
)}
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
on_supported_os({
|
||||
:supported_os => OSDefaults.get_supported_os
|
||||
}).each do |os,facts|
|
||||
context "on #{os}" do
|
||||
let (:facts) do
|
||||
facts.merge!(OSDefaults.get_facts())
|
||||
end
|
||||
|
||||
it_configures 'openstacklib::db::mysql examples'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,81 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'openstacklib::db::postgresql' do
|
||||
let (:title) { 'nova' }
|
||||
|
||||
let :required_params do
|
||||
{ :password_hash => 'AA1420F182E88B9E5F874F6FBE7459291E8F4601' }
|
||||
end
|
||||
|
||||
let (:pre_condition) do
|
||||
"include ::postgresql::server"
|
||||
end
|
||||
|
||||
shared_examples 'openstacklib::db::postgresql examples' do
|
||||
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 => params[: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
|
||||
"include ::postgresql::server
|
||||
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
|
||||
"include ::postgresql::server
|
||||
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
|
||||
|
||||
on_supported_os({
|
||||
:supported_os => OSDefaults.get_supported_os
|
||||
}).each do |os,facts|
|
||||
context "on #{os}" do
|
||||
let (:facts) do
|
||||
facts.merge!(OSDefaults.get_facts())
|
||||
end
|
||||
|
||||
it_configures 'openstacklib::db::postgresql examples'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,98 @@
|
|||
#
|
||||
# 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::messaging::rabbitmq' do
|
||||
|
||||
let (:title) { 'nova' }
|
||||
|
||||
shared_examples 'openstacklib::messaging::rabbitmq examples' do
|
||||
|
||||
let :params do
|
||||
{}
|
||||
end
|
||||
|
||||
context 'with default parameters' do
|
||||
it { is_expected.to contain_rabbitmq_user('guest').with(
|
||||
:admin => false,
|
||||
:password => 'guest',
|
||||
:provider => 'rabbitmqctl',
|
||||
)}
|
||||
it { is_expected.to contain_rabbitmq_user_permissions('guest@/').with(
|
||||
:configure_permission => '.*',
|
||||
:write_permission => '.*',
|
||||
:read_permission => '.*',
|
||||
:provider => 'rabbitmqctl',
|
||||
)}
|
||||
it { is_expected.to contain_rabbitmq_vhost('/').with(
|
||||
:provider => 'rabbitmqctl',
|
||||
)}
|
||||
end
|
||||
|
||||
context 'with custom parameters' do
|
||||
before :each do
|
||||
params.merge!(
|
||||
:userid => 'nova',
|
||||
:password => 'secrete',
|
||||
:virtual_host => '/nova',
|
||||
:is_admin => true,
|
||||
:configure_permission => '.nova',
|
||||
:write_permission => '.nova',
|
||||
:read_permission => '.nova'
|
||||
)
|
||||
end
|
||||
|
||||
it { is_expected.to contain_rabbitmq_user('nova').with(
|
||||
:admin => true,
|
||||
:password => 'secrete',
|
||||
:provider => 'rabbitmqctl',
|
||||
)}
|
||||
it { is_expected.to contain_rabbitmq_user_permissions('nova@/nova').with(
|
||||
:configure_permission => '.nova',
|
||||
:write_permission => '.nova',
|
||||
:read_permission => '.nova',
|
||||
:provider => 'rabbitmqctl',
|
||||
)}
|
||||
it { is_expected.to contain_rabbitmq_vhost('/nova').with(
|
||||
:provider => 'rabbitmqctl',
|
||||
)}
|
||||
end
|
||||
|
||||
context 'when disabling vhost management' do
|
||||
before :each do
|
||||
params.merge!( :manage_vhost => false )
|
||||
end
|
||||
|
||||
it { is_expected.not_to contain_rabbitmq_vhost('/') }
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
on_supported_os({
|
||||
:supported_os => OSDefaults.get_supported_os
|
||||
}).each do |os,facts|
|
||||
context "on #{os}" do
|
||||
let (:facts) do
|
||||
facts.merge!(OSDefaults.get_facts())
|
||||
end
|
||||
|
||||
it_configures 'openstacklib::messaging::rabbitmq examples'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,54 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'openstacklib::policy::base' do
|
||||
|
||||
|
||||
shared_examples_for 'openstacklib::policy' do
|
||||
context 'with some basic parameters' do
|
||||
let :title do
|
||||
'nova-contest_is_admin'
|
||||
end
|
||||
|
||||
let :params do
|
||||
{:file_path => '/etc/nova/policy.json',
|
||||
:key => 'context_is_admin or owner',
|
||||
:value => 'foo:bar'}
|
||||
end
|
||||
|
||||
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 or owner"]/string "foo:bar"',
|
||||
'require' => 'Augeas[/etc/nova/policy.json-context_is_admin or owner-foo:bar-add]'
|
||||
)
|
||||
end
|
||||
|
||||
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 or owner"',
|
||||
'set dict/entry[last()]/string "foo:bar"'
|
||||
],
|
||||
'onlyif' => 'match dict/entry[*][.="context_is_admin or owner"] size == 0'
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
on_supported_os({
|
||||
:supported_os => OSDefaults.get_supported_os
|
||||
}).each do |os,facts|
|
||||
context "on #{os}" do
|
||||
let (:facts) do
|
||||
facts.merge!(OSDefaults.get_facts())
|
||||
end
|
||||
|
||||
it_configures 'openstacklib::policy'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -0,0 +1,117 @@
|
|||
#
|
||||
# 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::service_validation' do
|
||||
|
||||
let (:title) { 'nova-api' }
|
||||
|
||||
let :required_params do
|
||||
{ :command => 'nova list' }
|
||||
end
|
||||
|
||||
shared_examples 'openstacklib::service_validation examples' do
|
||||
|
||||
context 'with only required parameters' do
|
||||
let :params do
|
||||
required_params
|
||||
end
|
||||
|
||||
it { is_expected.to contain_exec("execute #{title} validation").with(
|
||||
:path => '/usr/bin:/bin:/usr/sbin:/sbin',
|
||||
:provider => 'shell',
|
||||
:command => 'nova list',
|
||||
:refreshonly => false,
|
||||
:timeout => '60',
|
||||
:tries => '10',
|
||||
:try_sleep => '2',
|
||||
:logoutput => 'on_failure',
|
||||
)}
|
||||
|
||||
it { is_expected.to contain_anchor("create #{title} anchor").with(
|
||||
:require => "Exec[execute #{title} validation]",
|
||||
)}
|
||||
|
||||
end
|
||||
|
||||
context 'with unless parameter' do
|
||||
let :params do
|
||||
required_params.merge!({ :unless => 'pwd' })
|
||||
end
|
||||
|
||||
it { is_expected.to contain_exec("execute #{title} validation").with(
|
||||
:path => '/usr/bin:/bin:/usr/sbin:/sbin',
|
||||
:provider => 'shell',
|
||||
:command => 'nova list',
|
||||
:refreshonly => false,
|
||||
:timeout => '60',
|
||||
:tries => '10',
|
||||
:try_sleep => '2',
|
||||
:unless => 'pwd',
|
||||
)}
|
||||
|
||||
it { is_expected.to contain_anchor("create #{title} anchor").with(
|
||||
:require => "Exec[execute #{title} validation]",
|
||||
)}
|
||||
|
||||
end
|
||||
|
||||
context 'with onlyif parameter' do
|
||||
let :params do
|
||||
required_params.merge!({:onlyif => 'pwd' })
|
||||
end
|
||||
|
||||
it { is_expected.to contain_exec("execute #{title} validation").with(
|
||||
:path => '/usr/bin:/bin:/usr/sbin:/sbin',
|
||||
:provider => 'shell',
|
||||
:command => 'nova list',
|
||||
:refreshonly => false,
|
||||
:timeout => '60',
|
||||
:tries => '10',
|
||||
:try_sleep => '2',
|
||||
:onlyif => 'pwd',
|
||||
)}
|
||||
|
||||
it { is_expected.to contain_anchor("create #{title} anchor").with(
|
||||
:require => "Exec[execute #{title} validation]",
|
||||
)}
|
||||
|
||||
end
|
||||
|
||||
context 'when omitting a required parameter command' do
|
||||
let :params do
|
||||
required_params.delete(:command)
|
||||
end
|
||||
it { expect { is_expected.to raise_error(Puppet::Error) } }
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
on_supported_os({
|
||||
:supported_os => OSDefaults.get_supported_os
|
||||
}).each do |os,facts|
|
||||
context "on #{os}" do
|
||||
let (:facts) do
|
||||
facts.merge!(OSDefaults.get_facts())
|
||||
end
|
||||
|
||||
it_configures 'openstacklib::service_validation examples'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,161 @@
|
|||
#
|
||||
# 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
|
||||
{
|
||||
:os_workers => 8,
|
||||
: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_params[: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[:os_workers],
|
||||
'display-name' => 'keystone_wsgi',
|
||||
},
|
||||
'wsgi_application_group' => '%{GLOBAL}',
|
||||
'require' => 'File[keystone_wsgi]',
|
||||
'setenvif' => ['X-Forwarded-Proto https HTTPS=1']
|
||||
)}
|
||||
it { is_expected.to contain_concat("#{platform_params[:httpd_ports_file]}") }
|
||||
end
|
||||
|
||||
describe 'when overriding parameters' do
|
||||
let :params do
|
||||
{
|
||||
:wsgi_script_dir => '/var/www/cgi-bin/keystone',
|
||||
:wsgi_script_file => 'main',
|
||||
:wsgi_script_source => '/usr/share/keystone/keystone.wsgi',
|
||||
:wsgi_pass_authorization => 'On',
|
||||
:wsgi_chunked_request => 'On',
|
||||
:servername => 'dummy.host',
|
||||
:bind_host => '10.42.51.1',
|
||||
:bind_port => 4142,
|
||||
:user => 'keystone',
|
||||
:group => 'keystone',
|
||||
:ssl => false,
|
||||
:workers => 37,
|
||||
:vhost_custom_fragment => 'LimitRequestFieldSize 81900',
|
||||
:allow_encoded_slashes => 'on',
|
||||
}
|
||||
end
|
||||
it { is_expected.to contain_apache__vhost('keystone_wsgi').with(
|
||||
'servername' => 'dummy.host',
|
||||
'ip' => '10.42.51.1',
|
||||
'port' => '4142',
|
||||
'docroot' => "/var/www/cgi-bin/keystone",
|
||||
'ssl' => 'false',
|
||||
'wsgi_daemon_process' => 'keystone_wsgi',
|
||||
'wsgi_daemon_process_options' => {
|
||||
'user' => 'keystone',
|
||||
'group' => 'keystone',
|
||||
'processes' => '37',
|
||||
'threads' => '8',
|
||||
'display-name' => 'keystone_wsgi',
|
||||
},
|
||||
'wsgi_process_group' => 'keystone_wsgi',
|
||||
'wsgi_script_aliases' => { '/' => "/var/www/cgi-bin/keystone/main" },
|
||||
'wsgi_application_group' => '%{GLOBAL}',
|
||||
'wsgi_pass_authorization' => 'On',
|
||||
'wsgi_chunked_request' => 'On',
|
||||
'require' => 'File[keystone_wsgi]',
|
||||
'custom_fragment' => 'LimitRequestFieldSize 81900',
|
||||
'allow_encoded_slashes' => 'on',
|
||||
)}
|
||||
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
on_supported_os({
|
||||
:supported_os => OSDefaults.get_supported_os
|
||||
}).each do |os,facts|
|
||||
context "on #{os}" do
|
||||
let (:facts) do
|
||||
facts.merge!(OSDefaults.get_facts(global_facts))
|
||||
end
|
||||
|
||||
let(:platform_params) do
|
||||
case facts[:osfamily]
|
||||
when 'Debian'
|
||||
{ :httpd_service_name => 'apache2',
|
||||
:httpd_ports_file => '/etc/apache2/ports.conf', }
|
||||
when 'RedHat'
|
||||
{ :httpd_service_name => 'httpd',
|
||||
:httpd_ports_file => '/etc/httpd/conf/ports.conf', }
|
||||
end
|
||||
end
|
||||
it_configures 'apache serving a service with mod_wsgi'
|
||||
end
|
||||
end
|
||||
|
||||
end
|
|
@ -0,0 +1,40 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'is_service_default' do
|
||||
|
||||
it 'refuses without at least one argument' do
|
||||
is_expected.to run.with_params().\
|
||||
and_raise_error(Puppet::ParseError, /Wrong number of arguments/)
|
||||
end
|
||||
|
||||
it 'refuses too many arguments' do
|
||||
is_expected.to run.with_params('foo', 'bar').\
|
||||
and_raise_error(Puppet::ParseError, /Wrong number of arguments/)
|
||||
end
|
||||
|
||||
context 'is_service_default' do
|
||||
it 'with <SERVICE DEFAULT>' do
|
||||
is_expected.to run.with_params('<SERVICE DEFAULT>').and_return(true)
|
||||
end
|
||||
|
||||
it 'with string != <SERVICE DEFAULT>' do
|
||||
is_expected.to run.with_params('a value').and_return(false)
|
||||
end
|
||||
|
||||
it 'with array' do
|
||||
is_expected.to run.with_params([1,2,3]).and_return(false)
|
||||
end
|
||||
|
||||
it 'with hash' do
|
||||
is_expected.to run.with_params({'foo' => 'bar'}).and_return(false)
|
||||
end
|
||||
|
||||
it 'with integer' do
|
||||
is_expected.to run.with_params(1234).and_return(false)
|
||||
end
|
||||
|
||||
it 'with boolean' do
|
||||
is_expected.to run.with_params(false).and_return(false)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,15 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'normalize_ip_for_uri' do
|
||||
it { should run.with_params(false).and_return(false)}
|
||||
it { should run.with_params('not_an_ip').and_return('not_an_ip')}
|
||||
it { should run.with_params('127.0.0.1').and_return('127.0.0.1')}
|
||||
it { should run.with_params('::1').and_return('[::1]')}
|
||||
it { should run.with_params('[2001::01]').and_return('[2001::01]')}
|
||||
# You're not forced to pass an array, a list of argument will do.
|
||||
it { should run.with_params('::1','::2').and_return(['[::1]','[::2]'])}
|
||||
it { should run.with_params(['::1','::2']).and_return(['[::1]','[::2]'])}
|
||||
it { should run.with_params(['::1','[::2]','::3']).and_return(['[::1]','[::2]','[::3]'])}
|
||||
it { should run.with_params(['192.168.0.1','[::2]']).and_return(['192.168.0.1','[::2]'])}
|
||||
it { should run.with_params(['192.168.0.1','::2']).and_return(['192.168.0.1','[::2]'])}
|
||||
end
|
|
@ -0,0 +1,157 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'os_database_connection' do
|
||||
|
||||
it 'refuses String' do
|
||||
is_expected.to run.with_params('foo').\
|
||||
and_raise_error(Puppet::ParseError, /Requires an hash/)
|
||||
end
|
||||
|
||||
it 'refuses Array' do
|
||||
is_expected.to run.with_params(['foo']).\
|
||||
and_raise_error(Puppet::ParseError, /Requires an hash/)
|
||||
end
|
||||
|
||||
it 'refuses without at least one argument' do
|
||||
is_expected.to run.with_params().\
|
||||
and_raise_error(Puppet::ParseError, /Wrong number of arguments/)
|
||||
end
|
||||
|
||||
it 'refuses too many arguments' do
|
||||
is_expected.to run.with_params('foo', 'bar').\
|
||||
and_raise_error(Puppet::ParseError, /Wrong number of arguments/)
|
||||
end
|
||||
|
||||
it 'refuses extra params passed as String' do
|
||||
is_expected.to run.with_params({
|
||||
'dialect' => 'sqlite',
|
||||
'database' => '/var/lib/keystone/keystone.db',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '3306',
|
||||
'extra' => 'charset=utf-8'
|
||||
}).and_raise_error(Puppet::ParseError, /extra should be a Hash/)
|
||||
end
|
||||
|
||||
it 'fails if port is provided with missing host' do
|
||||
is_expected.to run.with_params({
|
||||
'dialect' => 'sqlite',
|
||||
'database' => '/var/lib/keystone/keystone.db',
|
||||
'port' => '3306',
|
||||
'extra' => { 'charset' => 'utf-8' }
|
||||
}).and_raise_error(Puppet::ParseError, /host is required with port/)
|
||||
end
|
||||
|
||||
context 'creates the correct connection URI' do
|
||||
|
||||
it 'with all parameters' do
|
||||
is_expected.to run.with_params({
|
||||
'dialect' => 'mysql',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '3306',
|
||||
'database' => 'test',
|
||||
'username' => 'guest',
|
||||
'password' => 's3cr3t',
|
||||
'extra' => { 'charset' => 'utf-8', 'read_timeout' => '60' }
|
||||
}).and_return('mysql://guest:s3cr3t@127.0.0.1:3306/test?charset=utf-8&read_timeout=60')
|
||||
end
|
||||
|
||||
it 'with all parameters and charset set' do
|
||||
is_expected.to run.with_params({
|
||||
'dialect' => 'mysql',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '3306',
|
||||
'database' => 'test',
|
||||
'username' => 'guest',
|
||||
'password' => 's3cr3t',
|
||||
'charset' => 'utf-8',
|
||||
'extra' => { 'charset' => 'latin1', 'read_timeout' => '60' }
|
||||
}).and_return('mysql://guest:s3cr3t@127.0.0.1:3306/test?charset=utf-8&read_timeout=60')
|
||||
end
|
||||
|
||||
it 'without port' do
|
||||
is_expected.to run.with_params({
|
||||
'dialect' => 'mysql',
|
||||
'host' => '127.0.0.1',
|
||||
'database' => 'test',
|
||||
'username' => 'guest',
|
||||
'password' => 's3cr3t',
|
||||
'extra' => { 'charset' => 'utf-8' }
|
||||
}).and_return('mysql://guest:s3cr3t@127.0.0.1/test?charset=utf-8')
|
||||
end
|
||||
|
||||
it 'without host and port' do
|
||||
is_expected.to run.with_params({
|
||||
'dialect' => 'sqlite',
|
||||
'database' => '/var/lib/keystone/keystone.db',
|
||||
'extra' => { 'charset' => 'utf-8' }
|
||||
}).and_return('sqlite:////var/lib/keystone/keystone.db?charset=utf-8')
|
||||
end
|
||||
|
||||
it 'without username and password' do
|
||||
is_expected.to run.with_params({
|
||||
'dialect' => 'mysql',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '3306',
|
||||
'database' => 'test',
|
||||
'extra' => { 'charset' => 'utf-8' }
|
||||
}).and_return('mysql://127.0.0.1:3306/test?charset=utf-8')
|
||||
end
|
||||
|
||||
it 'with username set to undef' do
|
||||
is_expected.to run.with_params({
|
||||
'dialect' => 'mysql',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '3306',
|
||||
'database' => 'test',
|
||||
'username' => :undef,
|
||||
'extra' => { 'charset' => 'utf-8' }
|
||||
}).and_return('mysql://127.0.0.1:3306/test?charset=utf-8')
|
||||
end
|
||||
|
||||
it 'with username set to an empty string' do
|
||||
is_expected.to run.with_params({
|
||||
'dialect' => 'mysql',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '3306',
|
||||
'database' => 'test',
|
||||
'username' => '',
|
||||
'extra' => { 'charset' => 'utf-8' }
|
||||
}).and_return('mysql://127.0.0.1:3306/test?charset=utf-8')
|
||||
end
|
||||
|
||||
it 'without password' do
|
||||
is_expected.to run.with_params({
|
||||
'dialect' => 'mysql',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '3306',
|
||||
'database' => 'test',
|
||||
'username' => 'guest',
|
||||
'extra' => { 'charset' => 'utf-8' }
|
||||
}).and_return('mysql://guest@127.0.0.1:3306/test?charset=utf-8')
|
||||
end
|
||||
|
||||
it 'with password set to undef' do
|
||||
is_expected.to run.with_params({
|
||||
'dialect' => 'mysql',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '3306',
|
||||
'database' => 'test',
|
||||
'username' => 'guest',
|
||||
'password' => :undef,
|
||||
'extra' => { 'charset' => 'utf-8' }
|
||||
}).and_return('mysql://guest@127.0.0.1:3306/test?charset=utf-8')
|
||||
end
|
||||
|
||||
it 'with password set to an empty string' do
|
||||
is_expected.to run.with_params({
|
||||
'dialect' => 'mysql',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '3306',
|
||||
'database' => 'test',
|
||||
'username' => 'guest',
|
||||
'password' => '',
|
||||
'extra' => { 'charset' => 'utf-8' }
|
||||
}).and_return('mysql://guest@127.0.0.1:3306/test?charset=utf-8')
|
||||
end
|
||||
end
|
||||
end
|
|
@ -0,0 +1,324 @@
|
|||
require 'spec_helper'
|
||||
|
||||
describe 'os_transport_url' do
|
||||
|
||||
it 'refuses String' do
|
||||
is_expected.to run.with_params('foo').\
|
||||
and_raise_error(Puppet::ParseError, /Requires an hash/)
|
||||
end
|
||||
|
||||
it 'refuses Array' do
|
||||
is_expected.to run.with_params(['foo']).\
|
||||
and_raise_error(Puppet::ParseError, /Requires an hash/)
|
||||
end
|
||||
|
||||
it 'refuses without at least one argument' do
|
||||
is_expected.to run.with_params().\
|
||||
and_raise_error(ArgumentError, /Wrong number of arguments/)
|
||||
end
|
||||
|
||||
it 'refuses too many arguments' do
|
||||
is_expected.to run.with_params('foo', 'bar').\
|
||||
and_raise_error(ArgumentError, /Wrong number of arguments/)
|
||||
end
|
||||
|
||||
it 'refuses hosts params passed as String' do
|
||||
is_expected.to run.with_params({
|
||||
'transport'=> 'rabbit',
|
||||
'hosts' => '127.0.0.1',
|
||||
}).and_raise_error(Puppet::ParseError, /hosts should be a Array/)
|
||||
end
|
||||
|
||||
it 'fails if missing host' do
|
||||
is_expected.to run.with_params({
|
||||
'transport'=> 'rabbit',
|
||||
}).and_raise_error(Puppet::ParseError, /host or hosts is required/)
|
||||
end
|
||||
|
||||
context 'creates the correct transport URI' do
|
||||
|
||||
it 'with a single host array for hosts' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'hosts' => [ '127.0.0.1' ],
|
||||
'port' => '5672',
|
||||
'username' => 'guest',
|
||||
'password' => 's3cr3t',
|
||||
'virtual_host' => 'virt',
|
||||
'ssl' => '1',
|
||||
'query' => { 'read_timeout' => '60' },
|
||||
}).and_return('rabbit://guest:s3cr3t@127.0.0.1:5672/virt?read_timeout=60&ssl=1')
|
||||
end
|
||||
|
||||
it 'with a single host array for hosts and integer port' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'hosts' => [ '127.0.0.1' ],
|
||||
'port' => 5672,
|
||||
'username' => 'guest',
|
||||
'password' => 's3cr3t',
|
||||
'virtual_host' => 'virt',
|
||||
'ssl' => '1',
|
||||
'query' => { 'read_timeout' => '60' },
|
||||
}).and_return('rabbit://guest:s3cr3t@127.0.0.1:5672/virt?read_timeout=60&ssl=1')
|
||||
end
|
||||
|
||||
it 'with all params for a single host' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '5672',
|
||||
'username' => 'guest',
|
||||
'password' => 's3cr3t',
|
||||
'virtual_host' => 'virt',
|
||||
'ssl' => '1',
|
||||
'query' => { 'read_timeout' => '60' },
|
||||
}).and_return('rabbit://guest:s3cr3t@127.0.0.1:5672/virt?read_timeout=60&ssl=1')
|
||||
end
|
||||
|
||||
it 'with all params for a single host and integer port' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => 5672,
|
||||
'username' => 'guest',
|
||||
'password' => 's3cr3t',
|
||||
'virtual_host' => 'virt',
|
||||
'ssl' => '1',
|
||||
'query' => { 'read_timeout' => '60' },
|
||||
}).and_return('rabbit://guest:s3cr3t@127.0.0.1:5672/virt?read_timeout=60&ssl=1')
|
||||
end
|
||||
|
||||
it 'with only required params for a single host' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'host' => '127.0.0.1',
|
||||
}).and_return('rabbit://127.0.0.1/')
|
||||
end
|
||||
|
||||
it 'with a single ipv6 address' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'host' => 'fe80::ca5b:76ff:fe4b:be3b',
|
||||
'port' => '5672',
|
||||
}).and_return('rabbit://[fe80::ca5b:76ff:fe4b:be3b]:5672/')
|
||||
end
|
||||
|
||||
it 'with a single ipv6 address and integer port' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'host' => 'fe80::ca5b:76ff:fe4b:be3b',
|
||||
'port' => 5672,
|
||||
}).and_return('rabbit://[fe80::ca5b:76ff:fe4b:be3b]:5672/')
|
||||
end
|
||||
|
||||
it 'with all params with multiple hosts' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'hosts' => ['1.1.1.1', '2.2.2.2'],
|
||||
'port' => '5672',
|
||||
'username' => 'guest',
|
||||
'password' => 's3cr3t',
|
||||
'virtual_host' => 'virt',
|
||||
'query' => { 'read_timeout' => '60' },
|
||||
}).and_return('rabbit://guest:s3cr3t@1.1.1.1:5672,guest:s3cr3t@2.2.2.2:5672/virt?read_timeout=60')
|
||||
end
|
||||
|
||||
it 'with all params with multiple hosts and integer port' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'hosts' => ['1.1.1.1', '2.2.2.2'],
|
||||
'port' => 5672,
|
||||
'username' => 'guest',
|
||||
'password' => 's3cr3t',
|
||||
'virtual_host' => 'virt',
|
||||
'query' => { 'read_timeout' => '60' },
|
||||
}).and_return('rabbit://guest:s3cr3t@1.1.1.1:5672,guest:s3cr3t@2.2.2.2:5672/virt?read_timeout=60')
|
||||
end
|
||||
|
||||
it 'with only required params for multiple hosts' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'hosts' => [ '1.1.1.1', '2.2.2.2' ],
|
||||
'port' => '5672',
|
||||
'username' => 'guest',
|
||||
'password' => 's3cr3t',
|
||||
}).and_return('rabbit://guest:s3cr3t@1.1.1.1:5672,guest:s3cr3t@2.2.2.2:5672/')
|
||||
end
|
||||
|
||||
it 'with multiple ipv6 hosts' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'hosts' => [ 'fe80::ca5b:76ff:fe4b:be3b', 'fe80::ca5b:76ff:fe4b:be3c' ],
|
||||
'port' => '5672',
|
||||
'username' => 'guest',
|
||||
'password' => 's3cr3t',
|
||||
}).and_return('rabbit://guest:s3cr3t@[fe80::ca5b:76ff:fe4b:be3b]:5672,guest:s3cr3t@[fe80::ca5b:76ff:fe4b:be3c]:5672/')
|
||||
end
|
||||
|
||||
it 'with a mix of ipv4 and ipv6 hosts' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'hosts' => [ 'fe80::ca5b:76ff:fe4b:be3b', '1.1.1.1' ],
|
||||
'port' => '5672',
|
||||
'username' => 'guest',
|
||||
'password' => 's3cr3t',
|
||||
}).and_return('rabbit://guest:s3cr3t@[fe80::ca5b:76ff:fe4b:be3b]:5672,guest:s3cr3t@1.1.1.1:5672/')
|
||||
end
|
||||
|
||||
it 'without port' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'host' => '127.0.0.1',
|
||||
'username' => 'guest',
|
||||
'password' => 's3cr3t',
|
||||
'virtual_host' => 'virt',
|
||||
'query' => { 'read_timeout' => '60' },
|
||||
}).and_return('rabbit://guest:s3cr3t@127.0.0.1/virt?read_timeout=60')
|
||||
end
|
||||
|
||||
it 'without port and query' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'host' => '127.0.0.1',
|
||||
'username' => 'guest',
|
||||
'password' => 's3cr3t',
|
||||
'virtual_host' => 'virt',
|
||||
}).and_return('rabbit://guest:s3cr3t@127.0.0.1/virt')
|
||||
end
|
||||
|
||||
it 'without username and password' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '5672',
|
||||
'virtual_host' => 'virt',
|
||||
'query' => { 'read_timeout' => '60' },
|
||||
}).and_return('rabbit://127.0.0.1:5672/virt?read_timeout=60')
|
||||
end
|
||||
|
||||
it 'with username set to undef' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '5672',
|
||||
'username' => :undef,
|
||||
'virtual_host' => 'virt',
|
||||
'query' => { 'read_timeout' => '60' },
|
||||
}).and_return('rabbit://127.0.0.1:5672/virt?read_timeout=60')
|
||||
end
|
||||
|
||||
it 'with username set to an empty string' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '5672',
|
||||
'username' => '',
|
||||
'virtual_host' => 'virt',
|
||||
'query' => { 'read_timeout' => '60' },
|
||||
}).and_return('rabbit://127.0.0.1:5672/virt?read_timeout=60')
|
||||
end
|
||||
|
||||
it 'without password' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '5672',
|
||||
'username' => 'guest',
|
||||
'virtual_host' => 'virt',
|
||||
'query' => { 'read_timeout' => '60' },
|
||||
}).and_return('rabbit://guest@127.0.0.1:5672/virt?read_timeout=60')
|
||||
end
|
||||
|
||||
it 'with password set to undef' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '5672',
|
||||
'username' => 'guest',
|
||||
'password' => :undef,
|
||||
'virtual_host' => 'virt',
|
||||
'query' => { 'read_timeout' => '60' },
|
||||
}).and_return('rabbit://guest@127.0.0.1:5672/virt?read_timeout=60')
|
||||
end
|
||||
|
||||
it 'with password set to an empty string' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '5672',
|
||||
'username' => 'guest',
|
||||
'password' => '',
|
||||
'virtual_host' => 'virt',
|
||||
'query' => { 'read_timeout' => '60' },
|
||||
}).and_return('rabbit://guest@127.0.0.1:5672/virt?read_timeout=60')
|
||||
end
|
||||
|
||||
it 'with ssl overrides ssl in quert hash' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '5672',
|
||||
'username' => 'guest',
|
||||
'password' => '',
|
||||
'virtual_host' => 'virt',
|
||||
'ssl' => '1',
|
||||
'query' => { 'read_timeout' => '60' , 'ssl' => '0'},
|
||||
}).and_return('rabbit://guest@127.0.0.1:5672/virt?read_timeout=60&ssl=1')
|
||||
end
|
||||
|
||||
it 'with ssl as boolean string' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '5672',
|
||||
'username' => 'guest',
|
||||
'password' => '',
|
||||
'virtual_host' => 'virt',
|
||||
'ssl' => 'true',
|
||||
'query' => { 'read_timeout' => '60' },
|
||||
}).and_return('rabbit://guest@127.0.0.1:5672/virt?read_timeout=60&ssl=1')
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '5672',
|
||||
'username' => 'guest',
|
||||
'password' => '',
|
||||
'virtual_host' => 'virt',
|
||||
'ssl' => 'false',
|
||||
'query' => { 'read_timeout' => '60' },
|
||||
}).and_return('rabbit://guest@127.0.0.1:5672/virt?read_timeout=60&ssl=0')
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '5672',
|
||||
'username' => 'guest',
|
||||
'password' => '',
|
||||
'virtual_host' => 'virt',
|
||||
'ssl' => 'True',
|
||||
'query' => { 'read_timeout' => '60' },
|
||||
}).and_return('rabbit://guest@127.0.0.1:5672/virt?read_timeout=60&ssl=1')
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'rabbit',
|
||||
'host' => '127.0.0.1',
|
||||
'port' => '5672',
|
||||
'username' => 'guest',
|
||||
'password' => '',
|
||||
'virtual_host' => 'virt',
|
||||
'ssl' => 'False',
|
||||
'query' => { 'read_timeout' => '60' },
|
||||
}).and_return('rabbit://guest@127.0.0.1:5672/virt?read_timeout=60&ssl=0')
|
||||
end
|
||||
|
||||
it 'with alternative transport and single host array for hosts' do
|
||||
is_expected.to run.with_params({
|
||||
'transport' => 'amqp',
|
||||
'hosts' => [ '127.0.0.1' ],
|
||||
'port' => '5672',
|
||||
'username' => 'guest',
|
||||
'password' => 's3cr3t',
|
||||
}).and_return('amqp://guest:s3cr3t@127.0.0.1:5672/')
|
||||
end
|
||||
|
||||
end
|
||||
end
|
|
@ -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
|
|
@ -0,0 +1,10 @@
|
|||
require 'puppetlabs_spec_helper/module_spec_helper'
|
||||
require 'shared_examples'
|
||||
require 'puppet-openstack_spec_helper/facts'
|
||||
|
||||
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
|
||||
|
||||
at_exit { RSpec::Puppet::Coverage.report! }
|
|
@ -0,0 +1 @@
|
|||
require 'puppet-openstack_spec_helper/beaker_spec_helper'
|
|
@ -0,0 +1,241 @@
|
|||
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
|
||||
|
||||
context 'with a nonexistent file' do
|
||||
it 'should get default rcfile when no environment or openrc file' do
|
||||
ENV.clear
|
||||
mock = "export OS_USERNAME='user'\nexport OS_PASSWORD='secret'\nexport OS_PROJECT_NAME='project'\nexport OS_AUTH_URL='http://127.0.0.1:5000'"
|
||||
filename = '/root/openrc'
|
||||
|
||||
File.expects(:exists?).with("#{ENV['HOME']}/openrc").returns(false)
|
||||
File.expects(:exists?).with(filename).returns(true)
|
||||
File.expects(:open).with(filename).returns(StringIO.new(mock))
|
||||
|
||||
expect(klass.get_os_vars_from_rcfile("#{ENV['HOME']}/openrc")).to eq({
|
||||
'OS_USERNAME' => 'user',
|
||||
'OS_PASSWORD' => 'secret',
|
||||
'OS_PROJECT_NAME' => 'project',
|
||||
'OS_AUTH_URL' => 'http://127.0.0.1:5000'
|
||||
})
|
||||
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
|
|
@ -0,0 +1,160 @@
|
|||
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'
|
||||
creds.region_name = 'Region1'
|
||||
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',
|
||||
'OS_REGION_NAME' => 'Region1',
|
||||
})
|
||||
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
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue