From: Martin Zobel-Helas Date: Wed, 1 Jul 2015 18:30:41 +0000 (+0000) Subject: try again, with puppetforge modules, correctly included now X-Git-Url: https://git.adam-barratt.org.uk/?a=commitdiff_plain;h=4631045ebb77ee8622f6fa09277a50c372bcc02e;p=mirror%2Fdsa-puppet.git try again, with puppetforge modules, correctly included now Signed-off-by: Martin Zobel-Helas --- diff --git a/3rdparty/Puppetfile b/3rdparty/Puppetfile index 17df6001b..29f9da5e4 100644 --- a/3rdparty/Puppetfile +++ b/3rdparty/Puppetfile @@ -12,3 +12,16 @@ mod 'elasticsearch/elasticsearch', '0.9.5' mod 'nanliu/staging', '1.0.3' # OpenStack +mod 'stackforge/keystone', '5.1.0' +mod 'puppetlabs/apache', '1.5.0' +mod 'stackforge/openstacklib', '5.1.0' +mod 'aimonb/aviator', '0.5.1' +mod 'stackforge/glance', '5.1.0' +mod 'stackforge/cinder', '5.1.0' +mod 'dprince/qpid', '1.0.2' +mod 'stackforge/nova', '5.1.0' +mod 'duritong/sysctl', '0.0.11' +mod 'stackforge/neutron', '5.1.0' +mod 'stackforge/vswitch', '1.1.0' +mod 'stackforge/horizon', '5.1.0' +mod 'saz/memcached', '2.8.1' diff --git a/3rdparty/modules/apache/CHANGELOG.md b/3rdparty/modules/apache/CHANGELOG.md new file mode 100644 index 000000000..7a722a8a9 --- /dev/null +++ b/3rdparty/modules/apache/CHANGELOG.md @@ -0,0 +1,528 @@ +##2015-06-11 - Supported Release 1.5.0 +### Summary +This release primarily adds Suse compatibility. It also adds a handful of other +parameters for greater configuration control. + +### Features +- Add `apache::lib_path` parameter +- Add `apache::service_restart` parameter +- Add `apache::vhost::geoip_enable` parameter +- Add `apache::mod::geoip` class +- Add `apache::mod::remoteip` class +- Add parameters to `apache::mod::expires` class +- Add `index_style_sheet` handling to `apache::vhost::directories` +- Add some compatibility for SLES 11 +- Add `apache::mod::ssl::ssl_sessioncachetimeout` parameter +- Add `apache::mod::ssl::ssl_cryptodevice` parameter +- Add `apache::mod::ssl::ssl_honorcipherorder` parameter +- Add `apache::mod::userdir::options` parameter + +### Bugfixes +- Document `apache::user` parameter +- Document `apache::group` parameter +- Fix apache::dev on FreeBSD +- Fix proxy\_connect on apache >= 2.2 +- Validate log levels better +- Fix `apache::apache_name` for package and vhost +- Fix Debian Jessie mod\_prefork package name +- Fix alias module being declared even when vhost is absent +- Fix proxy\_pass\_match handling in vhost's proxy template +- Fix userdir access permissions +- Fix issue where the module was trying to use systemd on Amazon Linux. + +##2015-04-28 - Supported Release 1.4.1 + +This release corrects a metadata issue that has been present since release 1.2.0. The refactoring of `apache::vhost` to use `puppetlabs-concat` requires a version of concat newer than the version required in PE. If you are using PE 3.3.0 or earlier you will need to use version 1.1.1 or earlier of the `puppetlabs-apache` module. + +##2015-03-17 - Supported Release 1.4.0 +###Summary + +This release fixes the issue where the docroot was still managed even if the default vhosts were disabled and has many other features and bugfixes including improved support for 'deny' and 'require' as arrays in the 'directories' parameter under `apache::vhost` + +####Features +- New parameters to `apache` + - `default_charset` + - `default_type` +- New parameters to `apache::vhost` + - `proxy_error_override` + - `passenger_app_env` (MODULES-1776) + - `proxy_dest_match` + - `proxy_dest_reverse_match` + - `proxy_pass_match` + - `no_proxy_uris_match` +- New parameters to `apache::mod::passenger` + - `passenger_app_env` + - `passenger_min_instances` +- New parameter to `apache::mod::alias` + - `icons_options` +- New classes added under `apache::mod::*` + - `authn_file` + - `authz_default` + - `authz_user` +- Added support for 'deny' as an array in 'directories' under `apache::vhost` +- Added support for RewriteMap +- Improved support for FreeBSD. (Note: If using apache < 2.4.12, see the discussion [here](https://github.com/puppetlabs/puppetlabs-apache/pull/1030)) +- Added check for deprecated options in directories and fail when they are unsupported +- Added gentoo compatibility +- Added proper array support for `require` in the `directories` parameter in `apache::vhost` +- Added support for `setenv` inside proxy locations + +###Bugfixes +- Fix issue in `apache::vhost` that was preventing the scriptalias fragment from being included (MODULES-1784) +- Install required `mod_ldap` package for EL7 (MODULES-1779) +- Change default value of `maxrequestworkers` in `apache::mod::event` to be a multiple of the default `ThreadsPerChild` of 25. +- Use the correct `mod_prefork` package name for trusty and jessie +- Don't manage docroot when default vhosts are disabled +- Ensure resources notify `Class['Apache::Service']` instead of `Service['httpd']` (MODULES-1829) +- Change the loadfile name for `mod_passenger` so `mod_proxy` will load by default before `mod_passenger` +- Remove old Debian work-around that removed `passenger_extra.conf` + +##2015-02-17 - Supported Release 1.3.0 +###Summary + +This release has many new features and bugfixes, including the ability to optionally not trigger service restarts on config changes. + +####Features +- New parameters - `apache` + - `service_manage` + - `use_optional_includes` +- New parameters - `apache::service` + - `service_manage` +- New parameters - `apache::vhost` + - `access_logs` + - `php_flags` + - `php_values` + - `modsec_disable_vhost` + - `modsec_disable_ids` + - `modsec_disable_ips` + - `modsec_body_limit` +- Improved FreeBSD support +- Add ability to omit priority prefix if `$priority` is set to false +- Add `apache::security::rule_link` define +- Improvements to `apache::mod::*` + - Add `apache::mod::auth_cas` class + - Add `threadlimit`, `listenbacklog`, `maxrequestworkers`, `maxconnectionsperchild` parameters to `apache::mod::event` + - Add `apache::mod::filter` class + - Add `root_group` to `apache::mod::php` + - Add `apache::mod::proxy_connect` class + - Add `apache::mod::security` class + - Add `ssl_pass_phrase_dialog` and `ssl_random_seed_bytes parameters to `apache::mod::ssl` (MODULES-1719) + - Add `status_path` parameter to `apache::mod::status` + - Add `apache_version` parameter to `apache::mod::version` + - Add `package_name` and `mod_path` parameters to `apache::mod::wsgi` (MODULES-1458) +- Improved SCL support + - Add support for specifying the docroot +- Updated `_directories.erb` to add support for SetEnv +- Support multiple access log directives (MODULES-1382) +- Add passenger support for Debian Jessie +- Add support for not having puppet restart the apache service (MODULES-1559) + +####Bugfixes +- For apache 2.4 `mod_itk` requires `mod_prefork` (MODULES-825) +- Allow SSLCACertificatePath to be unset in `apache::vhost` (MODULES-1457) +- Load fcgid after unixd on RHEL7 +- Allow disabling default vhost for Apache 2.4 +- Test fixes +- `mod_version` is now built-in (MODULES-1446) +- Sort LogFormats for idempotency +- `allow_encoded_slashes` was omitted from `apache::vhost` +- Fix documentation bug (MODULES-1403, MODULES-1510) +- Sort `wsgi_script_aliases` for idempotency (MODULES-1384) +- lint fixes +- Fix automatic version detection for Debian Jessie +- Fix error docs and icons path for RHEL7-based systems (MODULES-1554) +- Sort php_* hashes for idempotency (MODULES-1680) +- Ensure `mod::setenvif` is included if needed (MODULES-1696) +- Fix indentation in `vhost/_directories.erb` template (MODULES-1688) +- Create symlinks on all distros if `vhost_enable_dir` is specified + +##2014-09-30 - Supported Release 1.2.0 +###Summary + +This release features many improvements and bugfixes, including several new defines, a reworking of apache::vhost for more extensibility, and many new parameters for more customization. This release also includes improved support for strict variables and the future parser. + +####Features +- Convert apache::vhost to use concat for easier extensions +- Test improvements +- Synchronize files with modulesync +- Strict variable and future parser support +- Added apache::custom_config defined type to allow validation of configs before they are created +- Added bool2httpd function to convert true/false to apache 'On' and 'Off'. Intended for internal use in the module. +- Improved SCL support + - allow overriding of the mod_ssl package name +- Add support for reverse_urls/ProxyPassReverse in apache::vhost +- Add satisfy directive in apache::vhost::directories +- Add apache::fastcgi::server defined type +- New parameters - apache + - allow_encoded_slashes + - apache_name + - conf_dir + - default_ssl_crl_check + - docroot + - logroot_mode + - purge_vhost_dir +- New parameters - apache::vhost + - add_default_charset + - allow_encoded_slashes + - logroot_ensure + - logroot_mode + - manage_docroot + - passenger_app_root + - passenger_min_instances + - passenger_pre_start + - passenger_ruby + - passenger_start_timeout + - proxy_preserve_host + - redirectmatch_dest + - ssl_crl_check + - wsgi_chunked_request + - wsgi_pass_authorization +- Add support for ScriptAlias and ScriptAliasMatch in the apache::vhost::aliases parameter +- Add support for rewrites in the apache::vhost::directories parameter +- If the service_ensure parameter in apache::service is set to anything other than true, false, running, or stopped, ensure will not be passed to the service resource, allowing for the service to not be managed by puppet +- Turn of SSLv3 by default +- Improvements to apache::mod* + - Add restrict_access parameter to apache::mod::info + - Add force_language_priority and language_priority parameters to apache::mod::negotiation + - Add threadlimit parameter to apache::mod::worker + - Add content, template, and source parameters to apache::mod::php + - Add mod_authz_svn support via the authz_svn_enabled parameter in apache::mod::dav_svn + - Add loadfile_name parameter to apache::mod + - Add apache::mod::deflate class + - Add options parameter to apache::mod::fcgid + - Add timeouts parameter to apache::mod::reqtimeout + - Add apache::mod::shib + - Add apache_version parameter to apache::mod::ldap + - Add magic_file parameter to apache::mod::mime_magic + - Add apache_version parameter to apache::mod::pagespeed + - Add passenger_default_ruby parameter to apache::mod::passenger + - Add content, template, and source parameters to apache::mod::php + - Add apache_version parameter to apache::mod::proxy + - Add loadfiles parameter to apache::mod::proxy_html + - Add ssl_protocol and package_name parameters to apache::mod::ssl + - Add apache_version parameter to apache::mod::status + - Add apache_version parameter to apache::mod::userdir + - Add apache::mod::version class + +####Bugfixes +- Set osfamily defaults for wsgi_socket_prefix +- Support multiple balancermembers with the same url +- Validate apache::vhost::custom_fragment +- Add support for itk with mod_php +- Allow apache::vhost::ssl_certs_dir to not be set +- Improved passenger support for Debian +- Improved 2.4 support without mod_access_compat +- Support for more than one 'Allow from'-directive in _directories.erb +- Don't load systemd on Amazon linux based on CentOS6 with apache 2.4 +- Fix missing newline in ModPagespeed filter and memcached servers directive +- Use interpolated strings instead of numbers where required by future parser +- Make auth_require take precedence over default with apache 2.4 +- Lint fixes +- Set default for php_admin_flags and php_admin_values to be empty hash instead of empty array +- Correct typo in mod::pagespeed +- spec_helper fixes +- Install mod packages before dealing with the configuration +- Use absolute scope to check class definition in apache::mod::php +- Fix dependency loop in apache::vhost +- Properly scope variables in the inline template in apache::balancer +- Documentation clarification, typos, and formatting +- Set apache::mod::ssl::ssl_mutex to default for debian on apache >= 2.4 +- Strict variables fixes +- Add authn_core mode to Ubuntu trusty defaults +- Keep default loadfile for authz_svn on Debian +- Remove '.conf' from the site-include regexp for better Ubuntu/Debian support +- Load unixd before fcgid for EL7 +- Fix RedirectMatch rules +- Fix misleading error message in apache::version + +####Known Bugs +* By default, the version of Apache that ships with Ubuntu 10.04 does not work with `wsgi_import_script`. +* SLES is unsupported. + +##2014-07-15 - Supported Release 1.1.1 +###Summary + +This release merely updates metadata.json so the module can be uninstalled and +upgraded via the puppet module command. + +## 2014-04-14 Supported Release 1.1.0 + +###Summary + +This release primarily focuses on extending the httpd 2.4 support, tested +through adding RHEL7 and Ubuntu 14.04 support. It also includes Passenger +4 support, as well as several new modules and important bugfixes. + +####Features + +- Add support for RHEL7 and Ubuntu 14.04 +- More complete apache24 support +- Passenger 4 support +- Add support for max_keepalive_requests and log_formats parameters +- Add mod_pagespeed support +- Add mod_speling support +- Added several parameters for mod_passenger +- Added ssl_cipher parameter to apache::mod::ssl +- Improved examples in documentation +- Added docroot_mode, action, and suexec_user_group parameters to apache::vhost +- Add support for custom extensions for mod_php +- Improve proxy_html support for Debian + +####Bugfixes + +- Remove NameVirtualHost directive for apache >= 2.4 +- Order proxy_set option so it doesn't change between runs +- Fix inverted SSL compression +- Fix missing ensure on concat::fragment resources +- Fix bad dependencies in apache::mod and apache::mod::mime + +####Known Bugs +* By default, the version of Apache that ships with Ubuntu 10.04 does not work with `wsgi_import_script`. +* SLES is unsupported. + +## 2014-03-04 Supported Release 1.0.1 +###Summary + +This is a supported release. This release removes a testing symlink that can +cause trouble on systems where /var is on a seperate filesystem from the +modulepath. + +####Features +####Bugfixes +####Known Bugs +* By default, the version of Apache that ships with Ubuntu 10.04 does not work with `wsgi_import_script`. +* SLES is unsupported. + +## 2014-03-04 Supported Release 1.0.0 +###Summary + +This is a supported release. This release introduces Apache 2.4 support for +Debian and RHEL based osfamilies. + +####Features + +- Add apache24 support +- Add rewrite_base functionality to rewrites +- Updated README documentation +- Add WSGIApplicationGroup and WSGIImportScript directives + +####Bugfixes + +- Replace mutating hashes with merge() for Puppet 3.5 +- Fix WSGI import_script and mod_ssl issues on Lucid + +####Known Bugs +* By default, the version of Apache that ships with Ubuntu 10.04 does not work with `wsgi_import_script`. +* SLES is unsupported. + +--- + +## 2014-01-31 Release 0.11.0 +### Summary: + +This release adds preliminary support for Windows compatibility and multiple rewrite support. + +#### Backwards-incompatible Changes: + +- The rewrite_rule parameter is deprecated in favor of the new rewrite parameter + and will be removed in a future release. + +#### Features: + +- add Match directive +- quote paths for windows compatibility +- add auth_group_file option to README.md +- allow AuthGroupFile directive for vhosts +- Support Header directives in vhost context +- Don't purge mods-available dir when separate enable dir is used +- Fix the servername used in log file name +- Added support for mod_include +- Remove index parameters. +- Support environment variable control for CustomLog +- added redirectmatch support +- Setting up the ability to do multiple rewrites and conditions. +- Convert spec tests to beaker. +- Support php_admin_(flag|value)s + +#### Bugfixes: + +- directories are either a Hash or an Array of Hashes +- Configure Passenger in separate .conf file on RH so PassengerRoot isn't lost +- (docs) Update list of `apache::mod::[name]` classes +- (docs) Fix apache::namevirtualhost example call style +- Fix $ports_file reference in apache::listen. +- Fix $ports_file reference in Namevirtualhost. + + +## 2013-12-05 Release 0.10.0 +### Summary: + +This release adds FreeBSD osfamily support and various other improvements to some mods. + +#### Features: + +- Add suPHP_UserGroup directive to directory context +- Add support for ScriptAliasMatch directives +- Set SSLOptions StdEnvVars in server context +- No implicit entry for ScriptAlias path +- Add support for overriding ErrorDocument +- Add support for AliasMatch directives +- Disable default "allow from all" in vhost-directories +- Add WSGIPythonPath as an optional parameter to mod_wsgi. +- Add mod_rpaf support +- Add directives: IndexOptions, IndexOrderDefault +- Add ability to include additional external configurations in vhost +- need to use the provider variable not the provider key value from the directory hash for matches +- Support for FreeBSD and few other features +- Add new params to apache::mod::mime class +- Allow apache::mod to specify module id and path +- added $server_root parameter +- Add Allow and ExtendedStatus support to mod_status +- Expand vhost/_directories.pp directive support +- Add initial support for nss module (no directives in vhost template yet) +- added peruser and event mpms +- added $service_name parameter +- add parameter for TraceEnable +- Make LogLevel configurable for server and vhost +- Add documentation about $ip +- Add ability to pass ip (instead of wildcard) in default vhost files + +#### Bugfixes: + +- Don't listen on port or set NameVirtualHost for non-existent vhost +- only apply Directory defaults when provider is a directory +- Working mod_authnz_ldap support on Debian/Ubuntu + +## 2013-09-06 Release 0.9.0 +### Summary: +This release adds more parameters to the base apache class and apache defined +resource to make the module more flexible. It also adds or enhances SuPHP, +WSGI, and Passenger mod support, and support for the ITK mpm module. + +#### Backwards-incompatible Changes: +- Remove many default mods that are not normally needed. +- Remove `rewrite_base` `apache::vhost` parameter; did not work anyway. +- Specify dependencies on stdlib >=2.4.0 (this was already the case, but +making explicit) +- Deprecate `a2mod` in favor of the `apache::mod::*` classes and `apache::mod` +defined resource. + +#### Features: +- `apache` class + - Add `httpd_dir` parameter to change the location of the configuration + files. + - Add `logroot` parameter to change the logroot + - Add `ports_file` parameter to changes the `ports.conf` file location + - Add `keepalive` parameter to enable persistent connections + - Add `keepalive_timeout` parameter to change the timeout + - Update `default_mods` to be able to take an array of mods to enable. +- `apache::vhost` + - Add `wsgi_daemon_process`, `wsgi_daemon_process_options`, + `wsgi_process_group`, and `wsgi_script_aliases` parameters for per-vhost + WSGI configuration. + - Add `access_log_syslog` parameter to enable syslogging. + - Add `error_log_syslog` parameter to enable syslogging of errors. + - Add `directories` hash parameter. Please see README for documentation. + - Add `sslproxyengine` parameter to enable SSLProxyEngine + - Add `suphp_addhandler`, `suphp_engine`, and `suphp_configpath` for + configuring SuPHP. + - Add `custom_fragment` parameter to allow for arbitrary apache + configuration injection. (Feature pull requests are prefered over using + this, but it is available in a pinch.) +- Add `apache::mod::suphp` class for configuring SuPHP. +- Add `apache::mod::itk` class for configuring ITK mpm module. +- Update `apache::mod::wsgi` class for global WSGI configuration with +`wsgi_socket_prefix` and `wsgi_python_home` parameters. +- Add README.passenger.md to document the `apache::mod::passenger` usage. +Added `passenger_high_performance`, `passenger_pool_idle_time`, +`passenger_max_requests`, `passenger_stat_throttle_rate`, `rack_autodetect`, +and `rails_autodetect` parameters. +- Separate the httpd service resource into a new `apache::service` class for +dependency chaining of `Class['apache'] -> ~> +Class['apache::service']` +- Added `apache::mod::proxy_balancer` class for `apache::balancer` + +#### Bugfixes: +- Change dependency to puppetlabs-concat +- Fix ruby 1.9 bug for `a2mod` +- Change servername to be `$::hostname` if there is no `$::fqdn` +- Make `/etc/ssl/certs` the default ssl certs directory for RedHat non-5. +- Make `php` the default php package for RedHat non-5. +- Made `aliases` able to take a single alias hash instead of requiring an +array. + +## 2013-07-26 Release 0.8.1 +#### Bugfixes: +- Update `apache::mpm_module` detection for worker/prefork +- Update `apache::mod::cgi` and `apache::mod::cgid` detection for +worker/prefork + +## 2013-07-16 Release 0.8.0 +#### Features: +- Add `servername` parameter to `apache` class +- Add `proxy_set` parameter to `apache::balancer` define + +#### Bugfixes: +- Fix ordering for multiple `apache::balancer` clusters +- Fix symlinking for sites-available on Debian-based OSs +- Fix dependency ordering for recursive confdir management +- Fix `apache::mod::*` to notify the service on config change +- Documentation updates + +## 2013-07-09 Release 0.7.0 +#### Changes: +- Essentially rewrite the module -- too many to list +- `apache::vhost` has many abilities -- see README.md for details +- `apache::mod::*` classes provide httpd mod-loading capabilities +- `apache` base class is much more configurable + +#### Bugfixes: +- Many. And many more to come + +## 2013-03-2 Release 0.6.0 +- update travis tests (add more supported versions) +- add access log_parameter +- make purging of vhost dir configurable + +## 2012-08-24 Release 0.4.0 +#### Changes: +- `include apache` is now required when using `apache::mod::*` + +#### Bugfixes: +- Fix syntax for validate_re +- Fix formatting in vhost template +- Fix spec tests such that they pass + +##2012-05-08 Puppet Labs - 0.0.4 +* e62e362 Fix broken tests for ssl, vhost, vhost::* +* 42c6363 Changes to match style guide and pass puppet-lint without error +* 42bc8ba changed name => path for file resources in order to name namevar by it's name +* 72e13de One end too much +* 0739641 style guide fixes: 'true' <> true, $operatingsystem needs to be $::operatingsystem, etc. +* 273f94d fix tests +* a35ede5 (#13860) Make a2enmod/a2dismo commands optional +* 98d774e (#13860) Autorequire Package['httpd'] +* 05fcec5 (#13073) Add missing puppet spec tests +* 541afda (#6899) Remove virtual a2mod definition +* 976cb69 (#13072) Move mod python and wsgi package names to params +* 323915a (#13060) Add .gitignore to repo +* fdf40af (#13060) Remove pkg directory from source tree +* fd90015 Add LICENSE file and update the ModuleFile +* d3d0d23 Re-enable local php class +* d7516c7 Make management of firewalls configurable for vhosts +* 60f83ba Explicitly lookup scope of apache_name in templates. +* f4d287f (#12581) Add explicit ordering for vdir directory +* 88a2ac6 (#11706) puppetlabs-apache depends on puppetlabs-firewall +* a776a8b (#11071) Fix to work with latest firewall module +* 2b79e8b (#11070) Add support for Scientific Linux +* 405b3e9 Fix for a2mod +* 57b9048 Commit apache::vhost::redirect Manifest +* 8862d01 Commit apache::vhost::proxy Manifest +* d5c1fd0 Commit apache::mod::wsgi Manifest +* a825ac7 Commit apache::mod::python Manifest +* b77062f Commit Templates +* 9a51b4a Vhost File Declarations +* 6cf7312 Defaults for Parameters +* 6a5b11a Ensure installed +* f672e46 a2mod fix +* 8a56ee9 add pthon support to apache diff --git a/3rdparty/modules/apache/CONTRIBUTING.md b/3rdparty/modules/apache/CONTRIBUTING.md new file mode 100644 index 000000000..f1cbde4bb --- /dev/null +++ b/3rdparty/modules/apache/CONTRIBUTING.md @@ -0,0 +1,220 @@ +Checklist (and a short version for the impatient) +================================================= + + * Commits: + + - Make commits of logical units. + + - Check for unnecessary whitespace with "git diff --check" before + committing. + + - Commit using Unix line endings (check the settings around "crlf" in + git-config(1)). + + - Do not check in commented out code or unneeded files. + + - The first line of the commit message should be a short + description (50 characters is the soft limit, excluding ticket + number(s)), and should skip the full stop. + + - Associate the issue in the message. The first line should include + the issue number in the form "(#XXXX) Rest of message". + + - The body should provide a meaningful commit message, which: + + - uses the imperative, present tense: "change", not "changed" or + "changes". + + - includes motivation for the change, and contrasts its + implementation with the previous behavior. + + - Make sure that you have tests for the bug you are fixing, or + feature you are adding. + + - Make sure the test suites passes after your commit: + `bundle exec rspec spec/acceptance` More information on [testing](#Testing) below + + - When introducing a new feature, make sure it is properly + documented in the README.md + + * Submission: + + * Pre-requisites: + + - Make sure you have a [GitHub account](https://github.com/join) + + - [Create a ticket](https://tickets.puppetlabs.com/secure/CreateIssue!default.jspa), or [watch the ticket](https://tickets.puppetlabs.com/browse/) you are patching for. + + * Preferred method: + + - Fork the repository on GitHub. + + - Push your changes to a topic branch in your fork of the + repository. (the format ticket/1234-short_description_of_change is + usually preferred for this project). + + - Submit a pull request to the repository in the puppetlabs + organization. + +The long version +================ + + 1. Make separate commits for logically separate changes. + + Please break your commits down into logically consistent units + which include new or changed tests relevant to the rest of the + change. The goal of doing this is to make the diff easier to + read for whoever is reviewing your code. In general, the easier + your diff is to read, the more likely someone will be happy to + review it and get it into the code base. + + If you are going to refactor a piece of code, please do so as a + separate commit from your feature or bug fix changes. + + We also really appreciate changes that include tests to make + sure the bug is not re-introduced, and that the feature is not + accidentally broken. + + Describe the technical detail of the change(s). If your + description starts to get too long, that is a good sign that you + probably need to split up your commit into more finely grained + pieces. + + Commits which plainly describe the things which help + reviewers check the patch and future developers understand the + code are much more likely to be merged in with a minimum of + bike-shedding or requested changes. Ideally, the commit message + would include information, and be in a form suitable for + inclusion in the release notes for the version of Puppet that + includes them. + + Please also check that you are not introducing any trailing + whitespace or other "whitespace errors". You can do this by + running "git diff --check" on your changes before you commit. + + 2. Sending your patches + + To submit your changes via a GitHub pull request, we _highly_ + recommend that you have them on a topic branch, instead of + directly on "master". + It makes things much easier to keep track of, especially if + you decide to work on another thing before your first change + is merged in. + + GitHub has some pretty good + [general documentation](http://help.github.com/) on using + their site. They also have documentation on + [creating pull requests](http://help.github.com/send-pull-requests/). + + In general, after pushing your topic branch up to your + repository on GitHub, you can switch to the branch in the + GitHub UI and click "Pull Request" towards the top of the page + in order to open a pull request. + + + 3. Update the related GitHub issue. + + If there is a GitHub issue associated with the change you + submitted, then you should update the ticket to include the + location of your branch, along with any other commentary you + may wish to make. + +Testing +======= + +Getting Started +--------------- + +Our puppet modules provide [`Gemfile`](./Gemfile)s which can tell a ruby +package manager such as [bundler](http://bundler.io/) what Ruby packages, +or Gems, are required to build, develop, and test this software. + +Please make sure you have [bundler installed](http://bundler.io/#getting-started) +on your system, then use it to install all dependencies needed for this project, +by running + +```shell +% bundle install +Fetching gem metadata from https://rubygems.org/........ +Fetching gem metadata from https://rubygems.org/.. +Using rake (10.1.0) +Using builder (3.2.2) +-- 8><-- many more --><8 -- +Using rspec-system-puppet (2.2.0) +Using serverspec (0.6.3) +Using rspec-system-serverspec (1.0.0) +Using bundler (1.3.5) +Your bundle is complete! +Use `bundle show [gemname]` to see where a bundled gem is installed. +``` + +NOTE some systems may require you to run this command with sudo. + +If you already have those gems installed, make sure they are up-to-date: + +```shell +% bundle update +``` + +With all dependencies in place and up-to-date we can now run the tests: + +```shell +% rake spec +``` + +This will execute all the [rspec tests](http://rspec-puppet.com/) tests +under [spec/defines](./spec/defines), [spec/classes](./spec/classes), +and so on. rspec tests may have the same kind of dependencies as the +module they are testing. While the module defines in its [Modulefile](./Modulefile), +rspec tests define them in [.fixtures.yml](./fixtures.yml). + +Some puppet modules also come with [beaker](https://github.com/puppetlabs/beaker) +tests. These tests spin up a virtual machine under +[VirtualBox](https://www.virtualbox.org/)) with, controlling it with +[Vagrant](http://www.vagrantup.com/) to actually simulate scripted test +scenarios. In order to run these, you will need both of those tools +installed on your system. + +You can run them by issuing the following command + +```shell +% rake spec_clean +% rspec spec/acceptance +``` + +This will now download a pre-fabricated image configured in the [default node-set](./spec/acceptance/nodesets/default.yml), +install puppet, copy this module and install its dependencies per [spec/spec_helper_acceptance.rb](./spec/spec_helper_acceptance.rb) +and then run all the tests under [spec/acceptance](./spec/acceptance). + +Writing Tests +------------- + +XXX getting started writing tests. + +If you have commit access to the repository +=========================================== + +Even if you have commit access to the repository, you will still need to +go through the process above, and have someone else review and merge +in your changes. The rule is that all changes must be reviewed by a +developer on the project (that did not write the code) to ensure that +all changes go through a code review process. + +Having someone other than the author of the topic branch recorded as +performing the merge is the record that they performed the code +review. + + +Additional Resources +==================== + +* [Getting additional help](http://puppetlabs.com/community/get-help) + +* [Writing tests](http://projects.puppetlabs.com/projects/puppet/wiki/Development_Writing_Tests) + +* [Patchwork](https://patchwork.puppetlabs.com) + +* [General GitHub documentation](http://help.github.com/) + +* [GitHub pull request documentation](http://help.github.com/send-pull-requests/) + diff --git a/3rdparty/modules/apache/Gemfile b/3rdparty/modules/apache/Gemfile new file mode 100644 index 000000000..2b1b7cd8d --- /dev/null +++ b/3rdparty/modules/apache/Gemfile @@ -0,0 +1,47 @@ +source ENV['GEM_SOURCE'] || "https://rubygems.org" + +def location_for(place, fake_version = nil) + if place =~ /^(git:[^#]*)#(.*)/ + [fake_version, { :git => $1, :branch => $2, :require => false }].compact + elsif place =~ /^file:\/\/(.*)/ + ['>= 0', { :path => File.expand_path($1), :require => false }] + else + [place, { :require => false }] + end +end + +group :development, :unit_tests do + gem 'rspec-core', '3.1.7', :require => false + gem 'puppetlabs_spec_helper', :require => false + gem 'simplecov', :require => false + gem 'puppet_facts', :require => false + gem 'json', :require => false +end + +group :system_tests do + if beaker_version = ENV['BEAKER_VERSION'] + gem 'beaker', *location_for(beaker_version) + end + if beaker_rspec_version = ENV['BEAKER_RSPEC_VERSION'] + gem 'beaker-rspec', *location_for(beaker_rspec_version) + else + gem 'beaker-rspec', :require => false + end + gem 'serverspec', :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 diff --git a/3rdparty/modules/apache/LICENSE b/3rdparty/modules/apache/LICENSE new file mode 100644 index 000000000..8961ce8a6 --- /dev/null +++ b/3rdparty/modules/apache/LICENSE @@ -0,0 +1,15 @@ +Copyright (C) 2012 Puppet Labs Inc + +Puppet Labs can be contacted at: info@puppetlabs.com + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/3rdparty/modules/apache/README.md b/3rdparty/modules/apache/README.md new file mode 100644 index 000000000..087bbc869 --- /dev/null +++ b/3rdparty/modules/apache/README.md @@ -0,0 +1,2695 @@ +#apache + +####Table of Contents + +1. [Overview - What is the apache module?](#overview) +2. [Module Description - What does the module do?](#module-description) +3. [Setup - The basics of getting started with apache](#setup) + * [Beginning with apache - Installation](#beginning-with-apache) + * [Configure a virtual host - Basic options for getting started](#configure-a-virtual-host) +4. [Usage - The classes and defined types available for configuration](#usage) + * [Classes and Defined Types](#classes-and-defined-types) + * [Class: apache](#class-apache) + * [Defined Type: apache::custom_config](#defined-type-apachecustom_config) + * [Class: apache::default_mods](#class-apachedefault_mods) + * [Defined Type: apache::mod](#defined-type-apachemod) + * [Classes: apache::mod::*](#classes-apachemodname) + * [Class: apache::mod::alias](#class-apachemodalias) + * [Class: apache::mod::event](#class-apachemodevent) + * [Class: apache::mod::geoip](#class-apachemodgeoip) + * [Class: apache::mod::info](#class-apachemodinfo) + * [Class: apache::mod::pagespeed](#class-apachemodpagespeed) + * [Class: apache::mod::php](#class-apachemodphp) + * [Class: apache::mod::ssl](#class-apachemodssl) + * [Class: apache::mod::status](#class-apachemodstatus) + * [Class: apache::mod::expires](#class-apachemodexpires) + * [Class: apache::mod::wsgi](#class-apachemodwsgi) + * [Class: apache::mod::fcgid](#class-apachemodfcgid) + * [Class: apache::mod::negotiation](#class-apachemodnegotiation) + * [Class: apache::mod::deflate](#class-apachemoddeflate) + * [Class: apache::mod::reqtimeout](#class-apachemodreqtimeout) + * [Class: apache::mod::security](#class-modsecurity) + * [Class: apache::mod::version](#class-apachemodversion) + * [Defined Type: apache::vhost](#defined-type-apachevhost) + * [Parameter: `directories` for apache::vhost](#parameter-directories-for-apachevhost) + * [SSL parameters for apache::vhost](#ssl-parameters-for-apachevhost) + * [Defined Type: apache::fastcgi::server](#defined-type-fastcgi-server) + * [Virtual Host Examples - Demonstrations of some configuration options](#virtual-host-examples) + * [Load Balancing](#load-balancing) + * [Defined Type: apache::balancer](#defined-type-apachebalancer) + * [Defined Type: apache::balancermember](#defined-type-apachebalancermember) + * [Examples - Load balancing with exported and non-exported resources](#examples) +5. [Reference - An under-the-hood peek at what the module is doing and how](#reference) + * [Classes](#classes) + * [Public Classes](#public-classes) + * [Private Classes](#private-classes) + * [Defined Types](#defined-types) + * [Public Defined Types](#public-defined-types) + * [Private Defined Types](#private-defined-types) + * [Templates](#templates) +6. [Limitations - OS compatibility, etc.](#limitations) +7. [Development - Guide for contributing to the module](#development) + * [Contributing to the apache module](#contributing) + * [Running tests - A quick guide](#running-tests) + +##Overview + +The apache module allows you to set up virtual hosts and manage web services with minimal effort. + +##Module Description + +Apache is a widely-used web server, and this module provides a simplified way of creating configurations to manage your infrastructure. This includes the ability to configure and manage a range of different virtual host setups, as well as a streamlined way to install and configure Apache modules. + +##Setup + +**What apache affects:** + +* configuration files and directories (created and written to) + * **WARNING**: Configurations that are *not* managed by Puppet will be purged. +* package/service/configuration files for Apache +* Apache modules +* virtual hosts +* listened-to ports +* `/etc/make.conf` on FreeBSD and Gentoo +* depends on module 'gentoo/puppet-portage' for Gentoo + +###Beginning with Apache + +To install Apache with the default parameters + +```puppet + class { 'apache': } +``` + +The defaults are determined by your operating system (e.g. Debian systems have one set of defaults, and RedHat systems have another, as do FreeBSD and Gentoo systems). These defaults work well in a testing environment, but are not suggested for production. To establish customized parameters + +```puppet + class { 'apache': + default_mods => false, + default_confd_files => false, + } +``` + +###Configure a virtual host + +Declaring the `apache` class creates a default virtual host by setting up a vhost on port 80, listening on all interfaces and serving `$apache::docroot`. + +```puppet + class { 'apache': } +``` + +To configure a very basic, name-based virtual host + +```puppet + apache::vhost { 'first.example.com': + port => '80', + docroot => '/var/www/first', + } +``` + +*Note:* The default priority is 15. If nothing matches this priority, the alphabetically first name-based vhost is used. This is also true if you pass a higher priority and no names match anything else. + +A slightly more complicated example, changes the docroot owner/group from the default 'root' + +```puppet + apache::vhost { 'second.example.com': + port => '80', + docroot => '/var/www/second', + docroot_owner => 'third', + docroot_group => 'third', + } +``` + +To set up a virtual host with SSL and default SSL certificates + +```puppet + apache::vhost { 'ssl.example.com': + port => '443', + docroot => '/var/www/ssl', + ssl => true, + } +``` + +To set up a virtual host with SSL and specific SSL certificates + +```puppet + apache::vhost { 'fourth.example.com': + port => '443', + docroot => '/var/www/fourth', + ssl => true, + ssl_cert => '/etc/ssl/fourth.example.com.cert', + ssl_key => '/etc/ssl/fourth.example.com.key', + } +``` + +Virtual hosts listen on '*' by default. To listen on a specific IP address + +```puppet + apache::vhost { 'subdomain.example.com': + ip => '127.0.0.1', + port => '80', + docroot => '/var/www/subdomain', + } +``` + +To set up a virtual host with a wildcard alias for the subdomain mapped to a same-named directory, for example: `http://example.com.loc` to `/var/www/example.com` + +```puppet + apache::vhost { 'subdomain.loc': + vhost_name => '*', + port => '80', + virtual_docroot => '/var/www/%-2+', + docroot => '/var/www', + serveraliases => ['*.loc',], + } +``` + +To set up a virtual host with suPHP + +```puppet + apache::vhost { 'suphp.example.com': + port => '80', + docroot => '/home/appuser/myphpapp', + suphp_addhandler => 'x-httpd-php', + suphp_engine => 'on', + suphp_configpath => '/etc/php5/apache2', + directories => { path => '/home/appuser/myphpapp', + 'suphp' => { user => 'myappuser', group => 'myappgroup' }, + } + } +``` + +To set up a virtual host with WSGI + +```puppet + apache::vhost { 'wsgi.example.com': + port => '80', + docroot => '/var/www/pythonapp', + wsgi_application_group => '%{GLOBAL}', + wsgi_daemon_process => 'wsgi', + wsgi_daemon_process_options => { + processes => '2', + threads => '15', + display-name => '%{GROUP}', + }, + wsgi_import_script => '/var/www/demo.wsgi', + wsgi_import_script_options => + { process-group => 'wsgi', application-group => '%{GLOBAL}' }, + wsgi_process_group => 'wsgi', + wsgi_script_aliases => { '/' => '/var/www/demo.wsgi' }, + } +``` + +Starting in Apache 2.2.16, HTTPD supports [FallbackResource](https://httpd.apache.org/docs/current/mod/mod_dir.html#fallbackresource), a simple replacement for common RewriteRules. + +```puppet + apache::vhost { 'wordpress.example.com': + port => '80', + docroot => '/var/www/wordpress', + fallbackresource => '/index.php', + } +``` + +Please note that the 'disabled' argument to FallbackResource is only supported since Apache 2.2.24. + +See a list of all [virtual host parameters](#defined-type-apachevhost). See an extensive list of [virtual host examples](#virtual-host-examples). + +##Usage + +###Classes and Defined Types + +This module modifies Apache configuration files and directories and purges any configuration not managed by Puppet. Configuration of Apache should be managed by Puppet, as non-Puppet configuration files can cause unexpected failures. + +It is possible to temporarily disable full Puppet management by setting the [`purge_configs`](#purge_configs) parameter within the base `apache` class to 'false'. This option should only be used as a temporary means of saving and relocating customized configurations. See the [`purge_configs` parameter](#purge_configs) for more information. + +####Class: `apache` + +The apache module's primary class, `apache`, guides the basic setup of Apache on your system. + +You can establish a default vhost in this class, the `vhost` class, or both. You can add additional vhost configurations for specific virtual hosts using a declaration of the `vhost` type. + +**Parameters within `apache`:** + +#####`allow_encoded_slashes` + +This sets the server default for the [`AllowEncodedSlashes` declaration](http://httpd.apache.org/docs/current/mod/core.html#allowencodedslashes) which modifies the responses to URLs with `\` and `/` characters. The default is undefined, which omits the declaration from the server configuration and select the Apache default setting of `Off`. Allowed values are: `on`, `off` or `nodecode`. + +#####`apache_version` + +Configures the behavior of the module templates, package names, and default mods by setting the Apache version. Default is determined by the class `apache::version` using the OS family and release. It should not be configured manually without special reason. + +#####`conf_dir` + +Changes the location of the configuration directory the main configuration file is placed in. Defaults to '/etc/httpd/conf' on RedHat, '/etc/apache2' on Debian, '/usr/local/etc/apache22' on FreeBSD, and '/etc/apache2' on Gentoo. + +#####`confd_dir` + +Changes the location of the configuration directory your custom configuration files are placed in. Defaults to '/etc/httpd/conf' on RedHat, '/etc/apache2/conf.d' on Debian, '/usr/local/etc/apache22' on FreeBSD, and '/etc/apache2/conf.d' on Gentoo. + +#####`conf_template` + +Overrides the template used for the main apache configuration file. Defaults to 'apache/httpd.conf.erb'. + +*Note:* Using this parameter is potentially risky, as the module has been built for a minimal configuration file with the configuration primarily coming from conf.d/ entries. + +#####`default_charset` + +If defined, the value will be set as `AddDefaultCharset` in the main configuration file. It is undefined by default. + +#####`default_confd_files` + +Generates default set of include-able Apache configuration files under `${apache::confd_dir}` directory. These configuration files correspond to what is usually installed with the Apache package on a given platform. + +#####`default_mods` + +Sets up Apache with default settings based on your OS. Valid values are 'true', 'false', or an array of mod names. + +Defaults to 'true', which includes the default [HTTPD mods](https://github.com/puppetlabs/puppetlabs-apache/blob/master/manifests/default_mods.pp). + +If false, it only includes the mods required to make HTTPD work, and any other mods can be declared on their own. + +If an array, the apache module includes the array of mods listed. + +#####`default_ssl_ca` + +The default certificate authority, which is automatically set to 'undef'. This default works out of the box but must be updated with your specific certificate information before being used in production. + +#####`default_ssl_cert` + +The default SSL certification, which is automatically set based on your operating system ('/etc/pki/tls/certs/localhost.crt' for RedHat, '/etc/ssl/certs/ssl-cert-snakeoil.pem' for Debian, '/usr/local/etc/apache22/server.crt' for FreeBSD, and '/etc/ssl/apache2/server.crt' for Gentoo). This default works out of the box but must be updated with your specific certificate information before being used in production. + +#####`default_ssl_chain` + +The default SSL chain, which is automatically set to 'undef'. This default works out of the box but must be updated with your specific certificate information before being used in production. + +#####`default_ssl_crl` + +The default certificate revocation list to use, which is automatically set to 'undef'. This default works out of the box but must be updated with your specific certificate information before being used in production. + +#####`default_ssl_crl_path` + +The default certificate revocation list path, which is automatically set to 'undef'. This default works out of the box but must be updated with your specific certificate information before being used in production. + +#####`default_ssl_crl_check` + +Sets the default certificate revocation check level via the [SSLCARevocationCheck directive](http://httpd.apache.org/docs/current/mod/mod_ssl.html#sslcarevocationcheck), which is automatically set to 'undef'. This default works out of the box but must be specified when using CRLs in production. Only applicable to Apache 2.4 or higher, the value is ignored on older versions. + +#####`default_ssl_key` + +The default SSL key, which is automatically set based on your operating system ('/etc/pki/tls/private/localhost.key' for RedHat, '/etc/ssl/private/ssl-cert-snakeoil.key' for Debian, '/usr/local/etc/apache22/server.key' for FreeBSD, and '/etc/ssl/apache2/server.key' for Gentoo). This default works out of the box but must be updated with your specific certificate information before being used in production. + +#####`default_ssl_vhost` + +Sets up a default SSL virtual host. Defaults to 'false'. If set to 'true', sets up the following vhost: + +```puppet + apache::vhost { 'default-ssl': + port => 443, + ssl => true, + docroot => $docroot, + scriptalias => $scriptalias, + serveradmin => $serveradmin, + access_log_file => "ssl_${access_log_file}", + } +``` + +SSL vhosts only respond to HTTPS queries. + +#####`default_type` + +(Apache httpd 2.2 only) MIME content-type that will be sent if the server cannot determine a type in any other way. This directive has been deprecated in Apache httpd 2.4, and only exists there for backwards compatibility of configuration files. + +#####`default_vhost` + +Sets up a default virtual host. Defaults to 'true', set to 'false' to set up [customized virtual hosts](#configure-a-virtual-host). + +#####`docroot` + +Changes the location of the default [Documentroot](https://httpd.apache.org/docs/current/mod/core.html#documentroot). Defaults to '/var/www/html' on RedHat, '/var/www' on Debian, '/usr/local/www/apache22/data' on FreeBSD, and '/var/www/localhost/htdocs' on Gentoo. + +#####`error_documents` + +Enables custom error documents. Defaults to 'false'. + +#####`group` + +Changes the group that Apache will answer requests as. The parent process will continue to be run as root, but resource accesses by child processes will be done under this group. By default, puppet will attempt to manage this group as a resource under `::apache`. If this is not what you want, set [`manage_group`](#manage_group) to 'false'. Defaults to the OS-specific default user for apache, as detected in `::apache::params`. + +#####`httpd_dir` + +Changes the base location of the configuration directories used for the apache service. This is useful for specially repackaged HTTPD builds, but might have unintended consequences when used in combination with the default distribution packages. Defaults to '/etc/httpd' on RedHat, '/etc/apache2' on Debian, '/usr/local/etc/apache22' on FreeBSD, and '/etc/apache2' on Gentoo. + +#####`keepalive` + +Enables persistent connections. + +#####`keepalive_timeout` + +Sets the amount of time the server waits for subsequent requests on a persistent connection. Defaults to '15'. + +#####`max_keepalive_requests` + +Sets the limit of the number of requests allowed per connection when KeepAlive is on. Defaults to '100'. + +#####`lib_path` + +Specifies the location where apache module files are stored. It should not be configured manually without special reason. + +#####`loadfile_name` + +Sets the file name for the module loadfile. Should be in the format \*.load. This can be used to set the module load order. + +#####`log_level` + +Changes the verbosity level of the error log. Defaults to 'warn'. Valid values are 'emerg', 'alert', 'crit', 'error', 'warn', 'notice', 'info', or 'debug'. + +#####`log_formats` + +Define additional [LogFormats](https://httpd.apache.org/docs/current/mod/mod_log_config.html#logformat). This is done in a Hash: + +```puppet + $log_formats = { vhost_common => '%v %h %l %u %t \"%r\" %>s %b' } +``` + +There are a number of predefined LogFormats in the httpd.conf that Puppet writes out: + +```httpd +LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined +LogFormat "%h %l %u %t \"%r\" %>s %b" common +LogFormat "%{Referer}i -> %U" referer +LogFormat "%{User-agent}i" agent +``` + +If your `$log_formats` contains one of those, they will be overwritten with **your** definition. + +#####`logroot` + +Changes the directory where Apache log files for the virtual host are placed. Defaults to '/var/log/httpd' on RedHat, '/var/log/apache2' on Debian, '/var/log/apache22' on FreeBSD, and '/var/log/apache2' on Gentoo. + +#####`logroot_mode` + +Overrides the mode the default logroot directory is set to ($::apache::logroot). Defaults to undef. Do NOT give people write access to the directory the logs are stored +in without being aware of the consequences; see http://httpd.apache.org/docs/2.4/logs.html#security for details. + +#####`manage_group` + +Setting this to 'false' stops the group resource from being created. This is for when you have a group, created from another Puppet module, you want to use to run Apache. Without this parameter, attempting to use a previously established group would result in a duplicate resource error. + +#####`manage_user` + +Setting this to 'false' stops the user resource from being created. This is for instances when you have a user, created from another Puppet module, you want to use to run Apache. Without this parameter, attempting to use a previously established user would result in a duplicate resource error. + +#####`mod_dir` + +Changes the location of the configuration directory your Apache modules configuration files are placed in. Defaults to '/etc/httpd/conf.d' for RedHat, '/etc/apache2/mods-available' for Debian, '/usr/local/etc/apache22/Modules' for FreeBSD, and '/etc/apache2/modules.d' on Gentoo. + +#####`mpm_module` + +Determines which MPM is loaded and configured for the HTTPD process. Valid values are 'event', 'itk', 'peruser', 'prefork', 'worker', or 'false'. Defaults to 'prefork' on RedHat, FreeBSD and Gentoo, and 'worker' on Debian. Must be set to 'false' to explicitly declare the following classes with custom parameters: + +* `apache::mod::event` +* `apache::mod::itk` +* `apache::mod::peruser` +* `apache::mod::prefork` +* `apache::mod::worker` + +*Note:* Switching between different MPMs on FreeBSD is possible but quite difficult. Before changing `$mpm_module` you must uninstall all packages that depend on your currently-installed Apache. + +#####`package_ensure` + +Allows control over the package ensure attribute. Can be 'present','absent', or a version string. + +#####`ports_file` + +Changes the name of the file containing Apache ports configuration. Default is `${conf_dir}/ports.conf`. + +#####`purge_configs` + +Removes all other Apache configs and vhosts, defaults to 'true'. Setting this to 'false' is a stopgap measure to allow the apache module to coexist with existing or otherwise-managed configuration. It is recommended that you move your configuration entirely to resources within this module. + +#####`purge_vhost_configs` + +If `vhost_dir` != `confd_dir`, this controls the removal of any configurations that are not managed by Puppet within `vhost_dir`. It defaults to the value of `purge_configs`. Setting this to false is a stopgap measure to allow the apache module to coexist with existing or otherwise unmanaged configurations within `vhost_dir` + +#####`sendfile` + +Makes Apache use the Linux kernel sendfile to serve static files. Defaults to 'On'. + +#####`serveradmin` + +Sets the server administrator. Defaults to 'root@localhost'. + +#####`servername` + +Sets the server name. Defaults to `fqdn` provided by Facter. + +#####`server_root` + +Sets the root directory in which the server resides. Defaults to '/etc/httpd' on RedHat, '/etc/apache2' on Debian, '/usr/local' on FreeBSD, and '/var/www' on Gentoo. + +#####`server_signature` + +Configures a trailing footer line under server-generated documents. More information about [ServerSignature](http://httpd.apache.org/docs/current/mod/core.html#serversignature). Defaults to 'On'. + +#####`server_tokens` + +Controls how much information Apache sends to the browser about itself and the operating system. More information about [ServerTokens](http://httpd.apache.org/docs/current/mod/core.html#servertokens). Defaults to 'OS'. + +#####`service_enable` + +Determines whether the HTTPD service is enabled when the machine is booted. Defaults to 'true'. + +#####`service_ensure` + +Determines whether the service should be running. Valid values are 'true', 'false', 'running', or 'stopped' when Puppet should manage the service. Any other value sets ensure to 'false' for the Apache service, which is useful when you want to let the service be managed by some other application like Pacemaker. Defaults to 'running'. + +#####`service_name` + +Name of the Apache service to run. Defaults to: 'httpd' on RedHat, 'apache2' on Debian and Gentoo, and 'apache22' on FreeBSD. + +#####`service_manage` + +Determines whether the HTTPD service state is managed by Puppet . Defaults to 'true'. + +#####`service_restart` + +Determines whether the HTTPD service restart command should be anything other than the default managed by Puppet. Defaults to undef. + + +#####`trace_enable` + +Controls how TRACE requests per RFC 2616 are handled. More information about [TraceEnable](http://httpd.apache.org/docs/current/mod/core.html#traceenable). Defaults to 'On'. + +#####`vhost_dir` + +Changes the location of the configuration directory your virtual host configuration files are placed in. Defaults to 'etc/httpd/conf.d' on RedHat, '/etc/apache2/sites-available' on Debian, '/usr/local/etc/apache22/Vhosts' on FreeBSD, and '/etc/apache2/vhosts.d' on Gentoo. + +#####`user` + +Changes the user that Apache will answer requests as. The parent process will continue to be run as root, but resource accesses by child processes will be done under this user. By default, puppet will attept to manage this user as a resource under `::apache`. If this is not what you want, set [`manage_user`](#manage_user) to 'false'. Defaults to the OS-specific default user for apache, as detected in `::apache::params`. + +#####`apache_name` + +The name of the Apache package to install. This is automatically detected in `::apache::params`. You might need to override this if you are using a non-standard Apache package, such as those from Red Hat's software collections. + +####Defined Type: `apache::custom_config` + +Allows you to create custom configs for Apache. The configuration files are only added to the Apache confd dir if the file is valid. An error is raised during the Puppet run if the file is invalid and `$verify_config` is `true`. + +```puppet + apache::custom_config { 'test': + content => '# Test', + } +``` + +**Parameters within `apache::custom_config`:** + +#####`ensure` + +Specify whether the configuration file is present or absent. Defaults to 'present'. Valid values are 'present' and 'absent'. + +#####`confdir` + +The directory to place the configuration file in. Defaults to `$::apache::confd_dir`. + +#####`content` + +The content of the configuration file. Only one of `$content` and `$source` can be specified. + +#####`priority` + +The priority of the configuration file, used for ordering. Defaults to '25'. + +Pass priority `false` to omit the priority prefix in file names. + +#####`source` + +The source of the configuration file. Only one of `$content` and `$source` can be specified. + +#####`verify_command` + +The command to use to verify the configuration file. It should use a fully qualified command. Defaults to '/usr/sbin/apachectl -t'. The `$verify_command` is only used if `$verify_config` is `true`. If the `$verify_command` fails, the configuration file is deleted, the Apache service is not notified, and an error is raised during the Puppet run. + +#####`verify_config` + +Boolean to specify whether the configuration file should be validated before the Apache service is notified. Defaults to `true`. + +####Class: `apache::default_mods` + +Installs default Apache modules based on what OS you are running. + +```puppet + class { 'apache::default_mods': } +``` + +####Defined Type: `apache::mod` + +Used to enable arbitrary Apache HTTPD modules for which there is no specific `apache::mod::[name]` class. The `apache::mod` defined type also installs the required packages to enable the module, if any. + +```puppet + apache::mod { 'rewrite': } + apache::mod { 'ldap': } +``` + +####Classes: `apache::mod::[name]` + +There are many `apache::mod::[name]` classes within this module that can be declared using `include`: + +* `actions` +* `alias`(see [`apache::mod::alias`](#class-apachemodalias) below) +* `auth_basic` +* `auth_cas`* (see [`apache::mod::auth_cas`](#class-apachemodauthcas) below) +* `auth_kerb` +* `authn_core` +* `authn_file` +* `authnz_ldap`* +* `authz_default` +* `authz_user` +* `autoindex` +* `cache` +* `cgi` +* `cgid` +* `dav` +* `dav_fs` +* `dav_svn`* +* `deflate` +* `dev` +* `dir`* +* `disk_cache` +* `event`(see [`apache::mod::event`](#class-apachemodevent) below) +* `expires` +* `fastcgi` +* `fcgid` +* `filter` +* `headers` +* `include` +* `info`* +* `itk` +* `ldap` +* `mime` +* `mime_magic`* +* `negotiation` +* `nss`* +* `pagespeed` (see [`apache::mod::pagespeed`](#class-apachemodpagespeed) below) +* `passenger`* +* `perl` +* `peruser` +* `php` (requires [`mpm_module`](#mpm_module) set to `prefork`) +* `prefork`* +* `proxy`* +* `proxy_ajp` +* `proxy_balancer` +* `proxy_html` +* `proxy_http` +* `python` +* `reqtimeout` +* `remoteip`* +* `rewrite` +* `rpaf`* +* `setenvif` +* `security` +* `shib`* (see [`apache::mod::shib`](#class-apachemodshib) below) +* `speling` +* `ssl`* (see [`apache::mod::ssl`](#class-apachemodssl) below) +* `status`* (see [`apache::mod::status`](#class-apachemodstatus) below) +* `suphp` +* `userdir`* +* `vhost_alias` +* `worker`* +* `wsgi` (see [`apache::mod::wsgi`](#class-apachemodwsgi) below) +* `xsendfile` + +Modules noted with a * indicate that the module has settings and, thus, a template that includes parameters. These parameters control the module's configuration. Most of the time, these parameters do not require any configuration or attention. + +The modules mentioned above, and other Apache modules that have templates, cause template files to be dropped along with the mod install. The module will not work without the template. Any module without a template installs the package but drops no files. + +###Class: `apache::mod::alias` + +Installs and manages the alias module. + +Full Documentation for alias is available from [Apache](https://httpd.apache.org/docs/current/mod/mod_alias.html). + +To disable directory listing for the icons directory: +```puppet + class { 'apache::mod::alias': + icons_options => 'None', + } +``` + +####Class: `apache::mod::event` + +Installs and manages mpm_event module. + +Full Documentation for mpm_event is available from [Apache](https://httpd.apache.org/docs/current/mod/event.html). + +To configure the event thread limit: + +```puppet + class {'apache::mod::event': + $threadlimit => '128', + } +``` + +####Class: `apache::mod::auth_cas` + +Installs and manages mod_auth_cas. The parameters `cas_login_url` and `cas_validate_url` are required. + +Full documentation on mod_auth_cas is available from [JASIG](https://github.com/Jasig/mod_auth_cas). + +####Class: `apache::mod::geoip` + +Installs and manages mod_geoip. + +Full documentation on mod_geoip is available from [MaxMind](http://dev.maxmind.com/geoip/legacy/mod_geoip2/). + +These are the default settings: + +```puppet + class {'apache::mod::geoip': + $enable => false, + $db_file => '/usr/share/GeoIP/GeoIP.dat', + $flag => 'Standard', + $output => 'All', + } +``` + +The parameter `db_file` can be a single directory or a hash of directories. + +####Class: `apache::mod::info` + +Installs and manages mod_info which provides a comprehensive overview of the server configuration. + +Full documentation for mod_info is available from [Apache](https://httpd.apache.org/docs/current/mod/mod_info.html). + +These are the default settings: + +```puppet + $allow_from = ['127.0.0.1','::1'], + $apache_version = $::apache::apache_version, + $restrict_access = true, +``` + +To set the addresses that are allowed to access /server-info add the following: + +```puppet + class {'apache::mod::info': + allow_from => [ + '10.10.36', + '10.10.38', + '127.0.0.1', + ], + } +``` + +To disable the access restrictions add the following: + +```puppet + class {'apache::mod::info': + restrict_access => false, + } +``` + +It is not recommended to leave this set to false though it can be very useful for testing. For this reason, you can insert this setting in your normal code to temporarily disable the restrictions like so: + +```puppet + class {'apache::mod::info': + restrict_access => false, # false disables the block below + allow_from => [ + '10.10.36', + '10.10.38', + '127.0.0.1', + ], + } +``` + +####Class: `apache::mod::pagespeed` + +Installs and manages mod_pagespeed, which is a Google module that rewrites web pages to reduce latency and bandwidth. + +This module does *not* manage the software repositories needed to automatically install the +mod-pagespeed-stable package. The module does however require that the package be installed, +or be installable using the system's default package provider. You should ensure that this +pre-requisite is met or declaring `apache::mod::pagespeed` causes the Puppet run to fail. + +These are the defaults: + +```puppet + class { 'apache::mod::pagespeed': + inherit_vhost_config => 'on', + filter_xhtml => false, + cache_path => '/var/cache/mod_pagespeed/', + log_dir => '/var/log/pagespeed', + memcache_servers => [], + rewrite_level => 'CoreFilters', + disable_filters => [], + enable_filters => [], + forbid_filters => [], + rewrite_deadline_per_flush_ms => 10, + additional_domains => undef, + file_cache_size_kb => 102400, + file_cache_clean_interval_ms => 3600000, + lru_cache_per_process => 1024, + lru_cache_byte_limit => 16384, + css_flatten_max_bytes => 2048, + css_inline_max_bytes => 2048, + css_image_inline_max_bytes => 2048, + image_inline_max_bytes => 2048, + js_inline_max_bytes => 2048, + css_outline_min_bytes => 3000, + js_outline_min_bytes => 3000, + inode_limit => 500000, + image_max_rewrites_at_once => 8, + num_rewrite_threads => 4, + num_expensive_rewrite_threads => 4, + collect_statistics => 'on', + statistics_logging => 'on', + allow_view_stats => [], + allow_pagespeed_console => [], + allow_pagespeed_message => [], + message_buffer_size => 100000, + additional_configuration => { } + } +``` + +Full documentation for mod_pagespeed is available from [Google](http://modpagespeed.com). + +####Class: `apache::mod::php` + +Installs and configures mod_php. The defaults are OS-dependant. + +Overriding the package name: +```puppet + class {'::apache::mod::php': + package_name => "php54-php", + path => "${::apache::params::lib_path}/libphp54-php5.so", + } +``` + +Overriding the default configuartion: +```puppet + class {'::apache::mod::php': + source => 'puppet:///modules/apache/my_php.conf', + } +``` + +or +```puppet + class {'::apache::mod::php': + template => 'apache/php.conf.erb', + } +``` + +or + +```puppet + class {'::apache::mod::php': + content => ' +AddHandler php5-script .php +AddType text/html .php', + } +``` +####Class: `apache::mod::shib` + +Installs the [Shibboleth](http://shibboleth.net/) module for Apache which allows the use of SAML2 Single-Sign-On (SSO) authentication by Shibboleth Identity Providers and Shibboleth Federations. This class only installs and configures the Apache components of a Shibboleth Service Provider (a web application that consumes Shibboleth SSO identities). The Shibboleth configuration can be managed manually, with Puppet, or using a [Shibboleth Puppet Module](https://github.com/aethylred/puppet-shibboleth). + +Defining this class enables the Shibboleth specific parameters in `apache::vhost` instances. + +####Class: `apache::mod::ssl` + +Installs Apache SSL capabilities and uses the ssl.conf.erb template. These are the defaults: + +```puppet + class { 'apache::mod::ssl': + ssl_compression => false, + ssl_cryptodevice => 'builtin', + ssl_options => [ 'StdEnvVars' ], + ssl_cipher => 'HIGH:MEDIUM:!aNULL:!MD5', + ssl_honorcipherorder => 'On', + ssl_protocol => [ 'all', '-SSLv2', '-SSLv3' ], + ssl_pass_phrase_dialog => 'builtin', + ssl_random_seed_bytes => '512', + ssl_sessioncachetimeout => '300', + } +``` + +To *use* SSL with a virtual host, you must either set the`default_ssl_vhost` parameter in `::apache` to 'true' or set the `ssl` parameter in `apache::vhost` to 'true'. + +####Class: `apache::mod::status` + +Installs Apache mod_status and uses the status.conf.erb template. These are the defaults: + +```puppet + class { 'apache::mod::status': + allow_from => ['127.0.0.1','::1'], + extended_status => 'On', + status_path => '/server-status', +){ + + + } +``` + +####Class: `apache::mod::expires` + +Installs Apache mod_expires and uses the expires.conf.erb template. These are the defaults: + +```puppet + class { 'apache::mod::expires': + expires_active => true, + expires_default => undef, + expires_by_type => undef, +){ + + + } +``` + +`expires_by_type` is an array of Hashes, describing a set of types and their expire times: + +```puppet + class { 'apache::mod::expires': + expires_by_type => [ + { 'text/json' => 'access plus 1 month' }, + { 'text/html' => 'access plus 1 year' }, + ] + } +``` + +####Class: `apache::mod::wsgi` + +Enables Python support in the WSGI module. To use, simply `include 'apache::mod::wsgi'`. + +For customized parameters, which tell Apache how Python is currently configured on the operating system, + +```puppet + class { 'apache::mod::wsgi': + wsgi_socket_prefix => "\${APACHE_RUN_DIR}WSGI", + wsgi_python_home => '/path/to/venv', + wsgi_python_path => '/path/to/venv/site-packages', + } +``` + +To specify an alternate mod\_wsgi package name to install and the name of the module .so it provides, +(e.g. a "python27-mod\_wsgi" package that provides "python27-mod_wsgi.so" in the default module directory): + +```puppet + class { 'apache::mod::wsgi': + wsgi_socket_prefix => "\${APACHE_RUN_DIR}WSGI", + wsgi_python_home => '/path/to/venv', + wsgi_python_path => '/path/to/venv/site-packages', + package_name => 'python27-mod_wsgi', + mod_path => 'python27-mod_wsgi.so', + } +``` + +If ``mod_path`` does not contain "/", it will be prefixed by the default module path +for your OS; otherwise, it will be used literally. + +More information about [WSGI](http://modwsgi.readthedocs.org/en/latest/). + +####Class: `apache::mod::fcgid` + +Installs and configures mod_fcgid. + +The class makes no effort to list all available options, but rather uses an options hash to allow for ultimate flexibility: + +```puppet + class { 'apache::mod::fcgid': + options => { + 'FcgidIPCDir' => '/var/run/fcgidsock', + 'SharememPath' => '/var/run/fcgid_shm', + 'AddHandler' => 'fcgid-script .fcgi', + }, + } +``` + +For a full list op options, see the [official mod_fcgid documentation](https://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html). + +It is also possible to set the FcgidWrapper per directory per vhost. You must ensure the fcgid module is loaded because there is no auto loading. + +```puppet + include apache::mod::fcgid + apache::vhost { 'example.org': + docroot => '/var/www/html', + directories => { + path => '/var/www/html', + fcgiwrapper => { + command => '/usr/local/bin/fcgiwrapper', + } + }, + } +``` + +See [FcgidWrapper documentation](https://httpd.apache.org/mod_fcgid/mod/mod_fcgid.html#fcgidwrapper) for more information. + +####Class: `apache::mod::negotiation` + +Installs and configures mod_negotiation. If there are not provided any +parameter, default apache mod_negotiation configuration is done. + +```puppet + class { '::apache::mod::negotiation': + force_language_priority => 'Prefer', + language_priority => [ 'es', 'en', 'ca', 'cs', 'da', 'de', 'el', 'eo' ], + } +``` + +**Parameters within `apache::mod::negotiation`:** + +#####`force_language_priority` + +A string that sets the `ForceLanguagePriority` option. Defaults to `Prefer Fallback`. + +#####`language_priority` + +An array of languages to set the `LanguagePriority` option of the module. + +####Class: `apache::mod::deflate` + +Installs and configures mod_deflate. If no parameters are provided, a default configuration is applied. + +```puppet + class { '::apache::mod::deflate': + types => [ 'text/html', 'text/css' ], + notes => { + 'Input' => 'instream', + 'Ratio' => 'ratio', + }, + } +``` + +#####`types` + +An array of mime types to be deflated. + +#####`notes` + +A hash where the key represents the type and the value represents the note name. + + +####Class: `apache::mod::reqtimeout` + +Installs and configures mod_reqtimeout. Defaults to recommended apache +mod_reqtimeout configuration. + +```puppet + class { '::apache::mod::reqtimeout': + timeouts => ['header=20-40,MinRate=500', 'body=20,MinRate=500'], + } +``` + +####Class: `apache::mod::version` + +This wrapper around mod_version warns on Debian and Ubuntu systems with Apache httpd 2.4 +about loading mod_version, as on these platforms it's already built-in. + +```puppet + include '::apache::mod::version' +``` + +#####`timeouts` + +A string or an array that sets the `RequestReadTimeout` option. Defaults to +`['header=20-40,MinRate=500', 'body=20,MinRate=500']`. + + +####Class: `apache::mod::security` + +Installs and configures mod_security. Defaults to enabled and running on all +vhosts. + +```puppet + include '::apache::mod::security' +``` + +#####`crs_package` + +Name of package to install containing crs rules + +#####`modsec_dir` + +Directory to install the modsec configuration and activated rules links into + +#####`activated_rules` + +Array of rules from the modsec_crs_path to activate by symlinking to +${modsec_dir}/activated_rules. + +#####`allowed_methods` + +HTTP methods allowed by mod_security + +#####`content_types` + +Content-types allowed by mod_security + +#####`restricted_extensions` + +Extensions prohibited by mod_security + +#####`restricted_headers` + +Headers restricted by mod_security + + +####Defined Type: `apache::vhost` + +The Apache module allows a lot of flexibility in the setup and configuration of virtual hosts. This flexibility is due, in part, to `vhost` being a defined resource type, which allows it to be evaluated multiple times with different parameters. + +The `vhost` defined type allows you to have specialized configurations for virtual hosts that have requirements outside the defaults. You can set up a default vhost within the base `::apache` class, as well as set a customized vhost as default. Your customized vhost (priority 10) will be privileged over the base class vhost (15). + +The `vhost` defined type uses `concat::fragment` to build the configuration file, so if you want to inject custom fragments for pieces of the configuration not supported by default by the defined type, you can add a custom fragment. For the `order` parameter for the custom fragment, the `vhost` defined type uses multiples of 10, so any order that isn't a multiple of 10 should work. + +```puppet + apache::vhost { "example.com": + docroot => '/var/www/html', + priority => '25', + } + concat::fragment { "example.com-my_custom_fragment": + target => '25-example.com.conf', + order => 11, + content => '# my custom comment', + } +``` + +If you have a series of specific configurations and do not want a base `::apache` class default vhost, make sure to set the base class `default_vhost` to 'false'. + +```puppet + class { 'apache': + default_vhost => false, + } +``` + +**Parameters within `apache::vhost`:** + +#####`access_log` + +Specifies whether `*_access.log` directives (`*_file`,`*_pipe`, or `*_syslog`) should be configured. Setting the value to 'false' chooses none. Defaults to 'true'. + +#####`access_log_file` + +Sets the `*_access.log` filename that is placed in `$logroot`. Given a vhost, example.com, it defaults to 'example.com_ssl.log' for SSL vhosts and 'example.com_access.log' for non-SSL vhosts. + +#####`access_log_pipe` + +Specifies a pipe to send access log messages to. Defaults to 'undef'. + +#####`access_log_syslog` + +Sends all access log messages to syslog. Defaults to 'undef'. + +#####`access_log_format` + +Specifies the use of either a LogFormat nickname or a custom format string for the access log. Defaults to 'combined'. See [these examples](http://httpd.apache.org/docs/current/mod/mod_log_config.html). + +#####`access_log_env_var` + +Specifies that only requests with particular environment variables be logged. Defaults to 'undef'. + +#####`add_default_charset` + +Sets [AddDefaultCharset](http://httpd.apache.org/docs/current/mod/core.html#adddefaultcharset), a default value for the media charset, which is added to text/plain and text/html responses. + +#####`add_listen` + +Determines whether the vhost creates a Listen statement. The default value is 'true'. + +Setting `add_listen` to 'false' stops the vhost from creating a Listen statement, and this is important when you combine vhosts that are not passed an `ip` parameter with vhosts that *are* passed the `ip` parameter. + +#####`use_optional_includes` + +Specifies if for apache > 2.4 it should use IncludeOptional instead of Include for `additional_includes`. Defaults to 'false'. + +#####`additional_includes` + +Specifies paths to additional static, vhost-specific Apache configuration files. Useful for implementing a unique, custom configuration not supported by this module. Can be an array. Defaults to '[]'. + +#####`aliases` + +Passes a list of hashes to the vhost to create Alias, AliasMatch, ScriptAlias or ScriptAliasMatch directives as per the [mod_alias documentation](http://httpd.apache.org/docs/current/mod/mod_alias.html). These hashes are formatted as follows: + +```puppet +aliases => [ + { aliasmatch => '^/image/(.*)\.jpg$', + path => '/files/jpg.images/$1.jpg', + }, + { alias => '/image', + path => '/ftp/pub/image', + }, + { scriptaliasmatch => '^/cgi-bin(.*)', + path => '/usr/local/share/cgi-bin$1', + }, + { scriptalias => '/nagios/cgi-bin/', + path => '/usr/lib/nagios/cgi-bin/', + }, + { alias => '/nagios', + path => '/usr/share/nagios/html', + }, +], +``` + +For `alias`, `aliasmatch`, `scriptalias` and `scriptaliasmatch` to work, each needs a corresponding context, such as `` or ``. The directives are created in the order specified in the `aliases` parameter. As described in the [`mod_alias` documentation](http://httpd.apache.org/docs/current/mod/mod_alias.html), more specific `alias`, `aliasmatch`, `scriptalias` or `scriptaliasmatch` parameters should come before the more general ones to avoid shadowing. + +*Note*: Using the `aliases` parameter is preferred over the `scriptaliases` parameter since here the order of the various alias directives among each other can be controlled precisely. Defining ScriptAliases using the `scriptaliases` parameter means *all* ScriptAlias directives will come after *all* Alias directives, which can lead to Alias directives shadowing ScriptAlias directives. This is often problematic, for example in case of Nagios. + +*Note:* If `apache::mod::passenger` is loaded and `PassengerHighPerformance => true` is set, then Alias might have issues honoring the `PassengerEnabled => off` statement. See [this article](http://www.conandalton.net/2010/06/passengerenabled-off-not-working.html) for details. + +#####`allow_encoded_slashes` + +This sets the [`AllowEncodedSlashes` declaration](http://httpd.apache.org/docs/current/mod/core.html#allowencodedslashes) for the vhost, overriding the server default. This modifies the vhost responses to URLs with `\` and `/` characters. The default is undefined, which omits the declaration from the server configuration and select the Apache default setting of `Off`. Allowed values are: `on`, `off` or `nodecode`. + +#####`block` + +Specifies the list of things Apache blocks access to. The default is an empty set, '[]'. Currently, the only option is 'scm', which blocks web access to .svn, .git and .bzr directories. + +#####`custom_fragment` + +Passes a string of custom configuration directives to be placed at the end of the vhost configuration. Defaults to 'undef'. + +#####`default_vhost` + +Sets a given `apache::vhost` as the default to serve requests that do not match any other `apache::vhost` definitions. The default value is 'false'. + +#####`directories` + +See the [`directories` section](#parameter-directories-for-apachevhost). + +#####`directoryindex` + +Sets the list of resources to look for when a client requests an index of the directory by specifying a '/' at the end of the directory name. [DirectoryIndex](http://httpd.apache.org/docs/current/mod/mod_dir.html#directoryindex) has more information. Defaults to 'undef'. + +#####`docroot` + +Provides the +[DocumentRoot](http://httpd.apache.org/docs/current/mod/core.html#documentroot) +directive, which identifies the directory Apache serves files from. Required. + +#####`docroot_group` + +Sets group access to the docroot directory. Defaults to 'root'. + +#####`docroot_owner` + +Sets individual user access to the docroot directory. Defaults to 'root'. + +#####`docroot_mode` + +Sets access permissions of the docroot directory. Defaults to 'undef'. + +#####`manage_docroot` + +Whether to manage to docroot directory at all. Defaults to 'true'. + +#####`error_log` + +Specifies whether `*_error.log` directives should be configured. Defaults to 'true'. + +#####`error_log_file` + +Points to the `*_error.log` file. Given a vhost, example.com, it defaults to 'example.com_ssl_error.log' for SSL vhosts and 'example.com_access_error.log' for non-SSL vhosts. + +#####`error_log_pipe` + +Specifies a pipe to send error log messages to. Defaults to 'undef'. + +#####`error_log_syslog` + +Sends all error log messages to syslog. Defaults to 'undef'. + +#####`error_documents` + +A list of hashes which can be used to override the [ErrorDocument](https://httpd.apache.org/docs/current/mod/core.html#errordocument) settings for this vhost. Defaults to '[]'. Example: + +```puppet + apache::vhost { 'sample.example.net': + error_documents => [ + { 'error_code' => '503', 'document' => '/service-unavail' }, + { 'error_code' => '407', 'document' => 'https://example.com/proxy/login' }, + ], + } +``` + +#####`ensure` + +Specifies if the vhost file is present or absent. Defaults to 'present'. + +#####`fallbackresource` + +Sets the [FallbackResource](http://httpd.apache.org/docs/current/mod/mod_dir.html#fallbackresource) directive, which specifies an action to take for any URL that doesn't map to anything in your filesystem and would otherwise return 'HTTP 404 (Not Found)'. Valid values must either begin with a / or be 'disabled'. Defaults to 'undef'. + +#####`headers` + +Adds lines to replace, merge, or remove response headers. See [Header](http://httpd.apache.org/docs/current/mod/mod_headers.html#header) for more information. Can be an array. Defaults to 'undef'. + +#####`ip` + +Sets the IP address the vhost listens on. Defaults to listen on all IPs. + +#####`ip_based` + +Enables an [IP-based](http://httpd.apache.org/docs/current/vhosts/ip-based.html) vhost. This parameter inhibits the creation of a NameVirtualHost directive, since those are used to funnel requests to name-based vhosts. Defaults to 'false'. + +#####`itk` + +Configures [ITK](http://mpm-itk.sesse.net/) in a hash. Keys can be: + +* user + group +* `assignuseridexpr` +* `assigngroupidexpr` +* `maxclientvhost` +* `nice` +* `limituidrange` (Linux 3.5.0 or newer) +* `limitgidrange` (Linux 3.5.0 or newer) + +Usage typically looks like: + +```puppet + apache::vhost { 'sample.example.net': + docroot => '/path/to/directory', + itk => { + user => 'someuser', + group => 'somegroup', + }, + } +``` + +#####`logroot` + +Specifies the location of the virtual host's logfiles. Defaults to '/var/log//'. + +#####`$logroot_ensure` + +Determines whether or not to remove the logroot directory for a virtual host. Valid values are 'directory', or 'absent'. + +#####`logroot_mode` + +Overrides the mode the logroot directory is set to. Defaults to undef. Do NOT give people write access to the directory the logs are stored +in without being aware of the consequences; see http://httpd.apache.org/docs/2.4/logs.html#security for details. + +#####`log_level` + +Specifies the verbosity of the error log. Defaults to 'warn' for the global server configuration and can be overridden on a per-vhost basis. Valid values are 'emerg', 'alert', 'crit', 'error', 'warn', 'notice', 'info' or 'debug'. + +######`modsec_body_limit` + +Configures the maximum request body size (in bytes) ModSecurity will accept for buffering + +######`modsec_disable_vhost` + +Boolean. Only valid if apache::mod::security is included. Used to disable mod_security on an individual vhost. Only relevant if apache::mod::security is included. + +######`modsec_disable_ids` + +Array of mod_security IDs to remove from the vhost. Also takes a hash allowing removal of an ID from a specific location. + +```puppet + apache::vhost { 'sample.example.net': + modsec_disable_ids => [ 90015, 90016 ], + } +``` + +```puppet + apache::vhost { 'sample.example.net': + modsec_disable_ids => { '/location1' => [ 90015, 90016 ] }, + } +``` + +######`modsec_disable_ips` + +Array of IPs to exclude from mod_security rule matching + +#####`no_proxy_uris` + +Specifies URLs you do not want to proxy. This parameter is meant to be used in combination with [`proxy_dest`](#proxy_dest). + +#####`no_proxy_uris_match` + +This directive is equivalent to `no_proxy_uris`, but takes regular expressions. + +#####`proxy_preserve_host` + +Sets the [ProxyPreserveHost Directive](http://httpd.apache.org/docs/2.2/mod/mod_proxy.html#proxypreservehost). true Enables the Host: line from an incoming request to be proxied to the host instead of hostname . false sets this option to off (default). + +#####`proxy_error_override` + +Sets the [ProxyErrorOverride Directive](http://httpd.apache.org/docs/2.2/mod/mod_proxy.html#proxyerroroverride). This directive controls whether apache should override error pages for proxied content. This option is off by default. + +#####`options` + +Sets the [Options](http://httpd.apache.org/docs/current/mod/core.html#options) for the specified virtual host. Defaults to '['Indexes','FollowSymLinks','MultiViews']', as demonstrated below: + +```puppet + apache::vhost { 'site.name.fdqn': + … + options => ['Indexes','FollowSymLinks','MultiViews'], + } +``` + +*Note:* If you use [`directories`](#parameter-directories-for-apachevhost), 'Options', 'Override', and 'DirectoryIndex' are ignored because they are parameters within `directories`. + +#####`override` + +Sets the overrides for the specified virtual host. Accepts an array of [AllowOverride](http://httpd.apache.org/docs/current/mod/core.html#allowoverride) arguments. Defaults to '[none]'. + +#####`passenger_app_root` + +Sets [PassengerRoot](https://www.phusionpassenger.com/documentation/Users%20guide%20Apache.html#PassengerAppRoot), the location of the Passenger application root if different from the DocumentRoot. + +#####`passenger_app_env` + +Sets [PassengerAppEnv](https://www.phusionpassenger.com/documentation/Users%20guide%20Apache.html#PassengerAppEnv), the environment for the Passenger application. If not specifies, defaults to the global setting or 'production'. + +#####`passenger_ruby` + +Sets [PassengerRuby](https://www.phusionpassenger.com/documentation/Users%20guide%20Apache.html#PassengerRuby) on this virtual host, the Ruby interpreter to use for the application. + +#####`passenger_min_instances` + +Sets [PassengerMinInstances](https://www.phusionpassenger.com/documentation/Users%20guide%20Apache.html#PassengerMinInstances), the minimum number of application processes to run. + +#####`passenger_start_timeout` + +Sets [PassengerStartTimeout](https://www.phusionpassenger.com/documentation/Users%20guide%20Apache.html#_passengerstarttimeout_lt_seconds_gt), the timeout for the application startup. + +#####`passenger_pre_start` + +Sets [PassengerPreStart](https://www.phusionpassenger.com/documentation/Users%20guide%20Apache.html#PassengerPreStart), the URL of the application if pre-starting is required. + +#####`php_flags & values` + +Allows per-vhost setting [`php_value`s or `php_flag`s](http://php.net/manual/en/configuration.changes.php). These flags or values can be overwritten by a user or an application. Defaults to '{}'. + +#####`php_admin_flags & values` + +Allows per-vhost setting [`php_admin_value`s or `php_admin_flag`s](http://php.net/manual/en/configuration.changes.php). These flags or values cannot be overwritten by a user or an application. Defaults to '{}'. + +#####`port` + +Sets the port the host is configured on. The module's defaults ensure the host listens on port 80 for non-SSL vhosts and port 443 for SSL vhosts. The host only listens on the port set in this parameter. + +#####`priority` + +Sets the relative load-order for Apache HTTPD VirtualHost configuration files. Defaults to '25'. + +If nothing matches the priority, the first name-based vhost is used. Likewise, passing a higher priority causes the alphabetically first name-based vhost to be used if no other names match. + +*Note:* You should not need to use this parameter. However, if you do use it, be aware that the `default_vhost` parameter for `apache::vhost` passes a priority of '15'. + +Pass priority `false` to omit the priority prefix in file names. + +#####`proxy_dest` + +Specifies the destination address of a [ProxyPass](http://httpd.apache.org/docs/current/mod/mod_proxy.html#proxypass) configuration. Defaults to 'undef'. + +#####`proxy_pass` + +Specifies an array of `path => URI` for a [ProxyPass](http://httpd.apache.org/docs/current/mod/mod_proxy.html#proxypass) configuration. Defaults to 'undef'. Optionally parameters can be added as an array. + +```puppet +apache::vhost { 'site.name.fdqn': + … + proxy_pass => [ + { 'path' => '/a', 'url' => 'http://backend-a/' }, + { 'path' => '/b', 'url' => 'http://backend-b/' }, + { 'path' => '/c', 'url' => 'http://backend-a/c', 'params' => {'max'=>20, 'ttl'=>120, 'retry'=>300}}, + { 'path' => '/l', 'url' => 'http://backend-xy', + 'reverse_urls' => ['http://backend-x', 'http://backend-y'] }, + { 'path' => '/d', 'url' => 'http://backend-a/d', + 'params' => { 'retry' => '0', 'timeout' => '5' }, }, + { 'path' => '/e', 'url' => 'http://backend-a/e', + 'keywords' => ['nocanon', 'interpolate'] }, + { 'path' => '/f', 'url' => 'http://backend-f/', + 'setenv' => ['proxy-nokeepalive 1','force-proxy-request-1.0 1']}, + ], +} +``` + +`reverse_urls` is optional and can be an array or a string. It is useful when used with `mod_proxy_balancer`. +`params` is an optional parameter. It allows to provide the ProxyPass key=value parameters (Connection settings). +`setenv` is optional and is an array to set environment variables for the proxy directive, for details see http://httpd.apache.org/docs/current/mod/mod_proxy.html#envsettings + +#####`proxy_dest_match` + +This directive is equivalent to proxy_dest, but takes regular expressions, see [ProxyPassMatch](http://httpd.apache.org/docs/current/mod/mod_proxy.html#proxypassmatch) for details. + +#####`proxy_dest_reverse_match` + +Allows you to pass a ProxyPassReverse if `proxy_dest_match` is specified. See [ProxyPassReverse](http://httpd.apache.org/docs/current/mod/mod_proxy.html#proxypassreverse) for details. + +#####`proxy_pass_match` + +This directive is equivalent to proxy_pass, but takes regular expressions, see [ProxyPassMatch](http://httpd.apache.org/docs/current/mod/mod_proxy.html#proxypassmatch) for details. + +#####`rack_base_uris` + +Specifies the resource identifiers for a rack configuration. The file paths specified are listed as rack application roots for [Phusion Passenger](http://www.modrails.com/documentation/Users%20guide%20Apache.html#_railsbaseuri_and_rackbaseuri) in the _rack.erb template. Defaults to 'undef'. + +#####`redirect_dest` + +Specifies the address to redirect to. Defaults to 'undef'. + +#####`redirect_source` + +Specifies the source URIs that redirect to the destination specified in `redirect_dest`. If more than one item for redirect is supplied, the source and destination must be the same length, and the items are order-dependent. + +```puppet + apache::vhost { 'site.name.fdqn': + … + redirect_source => ['/images','/downloads'], + redirect_dest => ['http://img.example.com/','http://downloads.example.com/'], + } +``` + +#####`redirect_status` + +Specifies the status to append to the redirect. Defaults to 'undef'. + +```puppet + apache::vhost { 'site.name.fdqn': + … + redirect_status => ['temp','permanent'], + } +``` + +#####`redirectmatch_regexp` & `redirectmatch_status` & `redirectmatch_dest` + +Determines which server status should be raised for a given regular expression and where to forward the user to. Entered as arrays. Defaults to 'undef'. + +```puppet + apache::vhost { 'site.name.fdqn': + … + redirectmatch_status => ['404','404'], + redirectmatch_regexp => ['\.git(/.*|$)/','\.svn(/.*|$)'], + redirectmatch_dest => ['http://www.example.com/1','http://www.example.com/2'], + } +``` + +#####`request_headers` + +Modifies collected [request headers](http://httpd.apache.org/docs/current/mod/mod_headers.html#requestheader) in various ways, including adding additional request headers, removing request headers, etc. Defaults to 'undef'. + +```puppet + apache::vhost { 'site.name.fdqn': + … + request_headers => [ + 'append MirrorID "mirror 12"', + 'unset MirrorID', + ], + } +``` + +#####`rewrites` + +Creates URL rewrite rules. Expects an array of hashes, and the hash keys can be any of 'comment', 'rewrite_base', 'rewrite_cond', 'rewrite_rule' or 'rewrite_map'. Defaults to 'undef'. + +For example, you can specify that anyone trying to access index.html is served welcome.html + +```puppet + apache::vhost { 'site.name.fdqn': + … + rewrites => [ { rewrite_rule => ['^index\.html$ welcome.html'] } ] + } +``` + +The parameter allows rewrite conditions that, when true, execute the associated rule. For instance, if you wanted to rewrite URLs only if the visitor is using IE + +```puppet + apache::vhost { 'site.name.fdqn': + … + rewrites => [ + { + comment => 'redirect IE', + rewrite_cond => ['%{HTTP_USER_AGENT} ^MSIE'], + rewrite_rule => ['^index\.html$ welcome.html'], + }, + ], + } +``` + +You can also apply multiple conditions. For instance, rewrite index.html to welcome.html only when the browser is Lynx or Mozilla (version 1 or 2) + +```puppet + apache::vhost { 'site.name.fdqn': + … + rewrites => [ + { + comment => 'Lynx or Mozilla v1/2', + rewrite_cond => ['%{HTTP_USER_AGENT} ^Lynx/ [OR]', '%{HTTP_USER_AGENT} ^Mozilla/[12]'], + rewrite_rule => ['^index\.html$ welcome.html'], + }, + ], + } +``` + +Multiple rewrites and conditions are also possible + +```puppet + apache::vhost { 'site.name.fdqn': + … + rewrites => [ + { + comment => 'Lynx or Mozilla v1/2', + rewrite_cond => ['%{HTTP_USER_AGENT} ^Lynx/ [OR]', '%{HTTP_USER_AGENT} ^Mozilla/[12]'], + rewrite_rule => ['^index\.html$ welcome.html'], + }, + { + comment => 'Internet Explorer', + rewrite_cond => ['%{HTTP_USER_AGENT} ^MSIE'], + rewrite_rule => ['^index\.html$ /index.IE.html [L]'], + }, + { + rewrite_base => /apps/, + rewrite_rule => ['^index\.cgi$ index.php', '^index\.html$ index.php', '^index\.asp$ index.html'], + }, + { comment => 'Rewrite to lower case', + rewrite_cond => ['%{REQUEST_URI} [A-Z]'], + rewrite_map => ['lc int:tolower'], + rewrite_rule => ['(.*) ${lc:$1} [R=301,L]'], + }, + ], + } +``` + +Refer to the [`mod_rewrite` documentation](http://httpd.apache.org/docs/current/mod/mod_rewrite.html) for more details on what is possible with rewrite rules and conditions. + +#####`scriptalias` + +Defines a directory of CGI scripts to be aliased to the path '/cgi-bin', for example: '/usr/scripts'. Defaults to 'undef'. + +#####`scriptaliases` + +*Note*: This parameter is deprecated in favour of the `aliases` parameter. + +Passes an array of hashes to the vhost to create either ScriptAlias or ScriptAliasMatch statements as per the [`mod_alias` documentation](http://httpd.apache.org/docs/current/mod/mod_alias.html). These hashes are formatted as follows: + +```puppet + scriptaliases => [ + { + alias => '/myscript', + path => '/usr/share/myscript', + }, + { + aliasmatch => '^/foo(.*)', + path => '/usr/share/fooscripts$1', + }, + { + aliasmatch => '^/bar/(.*)', + path => '/usr/share/bar/wrapper.sh/$1', + }, + { + alias => '/neatscript', + path => '/usr/share/neatscript', + }, + ] +``` + +The ScriptAlias and ScriptAliasMatch directives are created in the order specified. As with [Alias and AliasMatch](#aliases) directives, more specific aliases should come before more general ones to avoid shadowing. + +#####`serveradmin` + +Specifies the email address Apache displays when it renders one of its error pages. Defaults to 'undef'. + +#####`serveraliases` + +Sets the [ServerAliases](http://httpd.apache.org/docs/current/mod/core.html#serveralias) of the site. Defaults to '[]'. + +#####`servername` + +Sets the servername corresponding to the hostname you connect to the virtual host at. Defaults to the title of the resource. + +#####`setenv` + +Used by HTTPD to set environment variables for vhosts. Defaults to '[]'. + +Example: + +```puppet + apache::vhost { 'setenv.example.com': + setenv => ['SPECIAL_PATH /foo/bin'], + } +``` + +#####`setenvif` + +Used by HTTPD to conditionally set environment variables for vhosts. Defaults to '[]'. + +#####`suphp_addhandler`, `suphp_configpath`, & `suphp_engine` + +Set up a virtual host with [suPHP](http://suphp.org/DocumentationView.html?file=apache/CONFIG). + +`suphp_addhandler` defaults to 'php5-script' on RedHat and FreeBSD, and 'x-httpd-php' on Debian and Gentoo. + +`suphp_configpath` defaults to 'undef' on RedHat and FreeBSD, and '/etc/php5/apache2' on Debian and Gentoo. + +`suphp_engine` allows values 'on' or 'off'. Defaults to 'off' + +To set up a virtual host with suPHP + +```puppet + apache::vhost { 'suphp.example.com': + port => '80', + docroot => '/home/appuser/myphpapp', + suphp_addhandler => 'x-httpd-php', + suphp_engine => 'on', + suphp_configpath => '/etc/php5/apache2', + directories => { path => '/home/appuser/myphpapp', + 'suphp' => { user => 'myappuser', group => 'myappgroup' }, + } + } +``` + +#####`vhost_name` + +Enables name-based virtual hosting. If no IP is passed to the virtual host, but the vhost is assigned a port, then the vhost name is 'vhost_name:port'. If the virtual host has no assigned IP or port, the vhost name is set to the title of the resource. Defaults to '*'. + +#####`virtual_docroot` + +Sets up a virtual host with a wildcard alias subdomain mapped to a directory with the same name. For example, 'http://example.com' would map to '/var/www/example.com'. Defaults to 'false'. + +```puppet + apache::vhost { 'subdomain.loc': + vhost_name => '*', + port => '80', + virtual_docroot' => '/var/www/%-2+', + docroot => '/var/www', + serveraliases => ['*.loc',], + } +``` + +#####`wsgi_daemon_process`, `wsgi_daemon_process_options`, `wsgi_process_group`, `wsgi_script_aliases`, & `wsgi_pass_authorization` + +Set up a virtual host with [WSGI](https://code.google.com/p/modwsgi/). + +`wsgi_daemon_process` sets the name of the WSGI daemon. It is a hash, accepting [these keys](http://modwsgi.readthedocs.org/en/latest/configuration-directives/WSGIDaemonProcess.html), and it defaults to 'undef'. + +`wsgi_daemon_process_options` is optional and defaults to 'undef'. + +`wsgi_process_group` sets the group ID the virtual host runs under. Defaults to 'undef'. + +`wsgi_script_aliases` requires a hash of web paths to filesystem .wsgi paths. Defaults to 'undef'. + +`wsgi_pass_authorization` the WSGI application handles authorisation instead of Apache when set to 'On'. For more information see [here] (http://modwsgi.readthedocs.org/en/latest/configuration-directives/WSGIPassAuthorization.html). Defaults to 'undef' where apache sets the defaults setting to 'Off'. + +`wsgi_chunked_request` enables support for chunked requests. Defaults to 'undef'. + +To set up a virtual host with WSGI + +```puppet + apache::vhost { 'wsgi.example.com': + port => '80', + docroot => '/var/www/pythonapp', + wsgi_daemon_process => 'wsgi', + wsgi_daemon_process_options => + { processes => '2', + threads => '15', + display-name => '%{GROUP}', + }, + wsgi_process_group => 'wsgi', + wsgi_script_aliases => { '/' => '/var/www/demo.wsgi' }, + wsgi_chunked_request => 'On', + } +``` + +####Parameter `directories` for `apache::vhost` + +The `directories` parameter within the `apache::vhost` class passes an array of hashes to the vhost to create [Directory](http://httpd.apache.org/docs/current/mod/core.html#directory), [File](http://httpd.apache.org/docs/current/mod/core.html#files), and [Location](http://httpd.apache.org/docs/current/mod/core.html#location) directive blocks. These blocks take the form, '< Directory /path/to/directory>...< /Directory>'. + +The `path` key sets the path for the directory, files, and location blocks. Its value must be a path for the 'directory', 'files', and 'location' providers, or a regex for the 'directorymatch', 'filesmatch', or 'locationmatch' providers. Each hash passed to `directories` **must** contain `path` as one of the keys. + +The `provider` key is optional. If missing, this key defaults to 'directory'. Valid values for `provider` are 'directory', 'files', 'location', 'directorymatch', 'filesmatch', or 'locationmatch'. If you set `provider` to 'directorymatch', it uses the keyword 'DirectoryMatch' in the Apache config file. + +General `directories` usage looks something like + +```puppet + apache::vhost { 'files.example.net': + docroot => '/var/www/files', + directories => [ + { 'path' => '/var/www/files', + 'provider' => 'files', + 'deny' => 'from all' + }, + ], + } +``` + +*Note:* At least one directory should match the `docroot` parameter. After you start declaring directories, `apache::vhost` assumes that all required Directory blocks will be declared. If not defined, a single default Directory block is created that matches the `docroot` parameter. + +Available handlers, represented as keys, should be placed within the `directory`, `files`, or `location` hashes. This looks like + +```puppet + apache::vhost { 'sample.example.net': + docroot => '/path/to/directory', + directories => [ { path => '/path/to/directory', handler => value } ], +} +``` + +Any handlers you do not set in these hashes are considered 'undefined' within Puppet and are not added to the virtual host, resulting in the module using their default values. Supported handlers are: + +######`addhandlers` + +Sets [AddHandler](http://httpd.apache.org/docs/current/mod/mod_mime.html#addhandler) directives, which map filename extensions to the specified handler. Accepts a list of hashes, with `extensions` serving to list the extensions being managed by the handler, and takes the form: `{ handler => 'handler-name', extensions => ['extension']}`. + +```puppet + apache::vhost { 'sample.example.net': + docroot => '/path/to/directory', + directories => [ + { path => '/path/to/directory', + addhandlers => [{ handler => 'cgi-script', extensions => ['.cgi']}], + }, + ], + } +``` + +######`allow` + +Sets an [Allow](http://httpd.apache.org/docs/2.2/mod/mod_authz_host.html#allow) directive, which groups authorizations based on hostnames or IPs. **Deprecated:** This parameter is being deprecated due to a change in Apache. It only works with Apache 2.2 and lower. You can use it as a single string for one rule or as an array for more than one. + +```puppet + apache::vhost { 'sample.example.net': + docroot => '/path/to/directory', + directories => [ + { path => '/path/to/directory', + allow => 'from example.org', + }, + ], + } +``` + +######`allow_override` + +Sets the types of directives allowed in [.htaccess](http://httpd.apache.org/docs/current/mod/core.html#allowoverride) files. Accepts an array. + +```puppet + apache::vhost { 'sample.example.net': + docroot => '/path/to/directory', + directories => [ + { path => '/path/to/directory', + allow_override => ['AuthConfig', 'Indexes'], + }, + ], + } +``` + +######`auth_basic_authoritative` + +Sets the value for [AuthBasicAuthoritative](https://httpd.apache.org/docs/current/mod/mod_auth_basic.html#authbasicauthoritative), which determines whether authorization and authentication are passed to lower level Apache modules. + +######`auth_basic_fake` + +Sets the value for [AuthBasicFake](http://httpd.apache.org/docs/current/mod/mod_auth_basic.html#authbasicfake), which statically configures authorization credentials for a given directive block. + +######`auth_basic_provider` + +Sets the value for [AuthBasicProvider] (http://httpd.apache.org/docs/current/mod/mod_auth_basic.html#authbasicprovider), which sets the authentication provider for a given location. + +######`auth_digest_algorithm` + +Sets the value for [AuthDigestAlgorithm](http://httpd.apache.org/docs/current/mod/mod_auth_digest.html#authdigestalgorithm), which selects the algorithm used to calculate the challenge and response hashes. + +######`auth_digest_domain` + +Sets the value for [AuthDigestDomain](http://httpd.apache.org/docs/current/mod/mod_auth_digest.html#authdigestdomain), which allows you to specify one or more URIs in the same protection space for digest authentication. + +######`auth_digest_nonce_lifetime` + +Sets the value for [AuthDigestNonceLifetime](http://httpd.apache.org/docs/current/mod/mod_auth_digest.html#authdigestnoncelifetime), which controls how long the server nonce is valid. + +######`auth_digest_provider` + +Sets the value for [AuthDigestProvider](http://httpd.apache.org/docs/current/mod/mod_auth_digest.html#authdigestprovider), which sets the authentication provider for a given location. + +######`auth_digest_qop` + +Sets the value for [AuthDigestQop](http://httpd.apache.org/docs/current/mod/mod_auth_digest.html#authdigestqop), which determines the quality-of-protection to use in digest authentication. + +######`auth_digest_shmem_size` + +Sets the value for [AuthAuthDigestShmemSize](http://httpd.apache.org/docs/current/mod/mod_auth_digest.html#authdigestshmemsize), which defines the amount of shared memory allocated to the server for keeping track of clients. + +######`auth_group_file` + +Sets the value for [AuthGroupFile](https://httpd.apache.org/docs/current/mod/mod_authz_groupfile.html#authgroupfile), which sets the name of the text file containing the list of user groups for authorization. + +######`auth_name` + +Sets the value for [AuthName](http://httpd.apache.org/docs/current/mod/mod_authn_core.html#authname), which sets the name of the authorization realm. + +######`auth_require` + +Sets the entity name you're requiring to allow access. Read more about [Require](http://httpd.apache.org/docs/current/mod/mod_authz_host.html#requiredirectives). + +######`auth_type` + +Sets the value for [AuthType](http://httpd.apache.org/docs/current/mod/mod_authn_core.html#authtype), which guides the type of user authentication. + +######`auth_user_file` + +Sets the value for [AuthUserFile](http://httpd.apache.org/docs/current/mod/mod_authn_file.html#authuserfile), which sets the name of the text file containing the users/passwords for authentication. + +######`custom_fragment` + +Pass a string of custom configuration directives to be placed at the end of the directory configuration. + +```puppet + apache::vhost { 'monitor': + … + directories => [ + { + path => '/path/to/directory', + custom_fragment => ' + + SetHandler balancer-manager + Order allow,deny + Allow from all + + + SetHandler server-status + Order allow,deny + Allow from all + + ProxyStatus On', + }, + ] + } +``` + +######`deny` + +Sets a [Deny](http://httpd.apache.org/docs/2.2/mod/mod_authz_host.html#deny) directive, specifying which hosts are denied access to the server. **Deprecated:** This parameter is being deprecated due to a change in Apache. It only works with Apache 2.2 and lower. You can use it as a single string for one rule or as an array for more than one. + +```puppet + apache::vhost { 'sample.example.net': + docroot => '/path/to/directory', + directories => [ + { path => '/path/to/directory', + deny => 'from example.org', + }, + ], + } +``` + +######`error_documents` + +An array of hashes used to override the [ErrorDocument](https://httpd.apache.org/docs/current/mod/core.html#errordocument) settings for the directory. + +```puppet + apache::vhost { 'sample.example.net': + directories => [ + { path => '/srv/www', + error_documents => [ + { 'error_code' => '503', + 'document' => '/service-unavail', + }, + ], + }, + ], + } +``` + +######`geoip_enable` + +Sets the [GeoIPEnable](http://dev.maxmind.com/geoip/legacy/mod_geoip2/#Configuration) directive. +Note that you must declare `class {'apache::mod::geoip': }` before using this directive. + +```puppet + apache::vhost { 'first.example.com': + docroot => '/var/www/first', + directories => [ + { path => '/var/www/first', + geoip_enable => true, + }, + ], + } +``` + +######`headers` + +Adds lines for [Header](http://httpd.apache.org/docs/current/mod/mod_headers.html#header) directives. + +```puppet + apache::vhost { 'sample.example.net': + docroot => '/path/to/directory', + directories => { + path => '/path/to/directory', + headers => 'Set X-Robots-Tag "noindex, noarchive, nosnippet"', + }, + } +``` + +######`index_options` + +Allows configuration settings for [directory indexing](http://httpd.apache.org/docs/current/mod/mod_autoindex.html#indexoptions). + +```puppet + apache::vhost { 'sample.example.net': + docroot => '/path/to/directory', + directories => [ + { path => '/path/to/directory', + directoryindex => 'disabled', # this is needed on Apache 2.4 or mod_autoindex doesn't work + options => ['Indexes','FollowSymLinks','MultiViews'], + index_options => ['IgnoreCase', 'FancyIndexing', 'FoldersFirst', 'NameWidth=*', 'DescriptionWidth=*', 'SuppressHTMLPreamble'], + }, + ], + } +``` + +######`index_order_default` + +Sets the [default ordering](http://httpd.apache.org/docs/current/mod/mod_autoindex.html#indexorderdefault) of the directory index. + +```puppet + apache::vhost { 'sample.example.net': + docroot => '/path/to/directory', + directories => [ + { path => '/path/to/directory', + order => 'Allow,Deny', + index_order_default => ['Descending', 'Date'], + }, + ], + } +``` + +######`index_style_sheet` + +Sets the [IndexStyleSheet](http://httpd.apache.org/docs/current/mod/mod_autoindex.html#indexstylesheet) which adds a CSS stylesheet to the directory index. + +```puppet + apache::vhost { 'sample.example.net': + docroot => '/path/to/directory', + directories => [ + { path => '/path/to/directory', + options => ['Indexes','FollowSymLinks','MultiViews'], + index_options => ['FancyIndexing'], + index_style_sheet => '/styles/style.css', + }, + ], + } +``` + +######`options` + +Lists the [Options](http://httpd.apache.org/docs/current/mod/core.html#options) for the given Directory block. + +```puppet + apache::vhost { 'sample.example.net': + docroot => '/path/to/directory', + directories => [ + { path => '/path/to/directory', + options => ['Indexes','FollowSymLinks','MultiViews'], + }, + ], + } +``` + +######`order` + +Sets the order of processing Allow and Deny statements as per [Apache core documentation](http://httpd.apache.org/docs/2.2/mod/mod_authz_host.html#order). **Deprecated:** This parameter is being deprecated due to a change in Apache. It only works with Apache 2.2 and lower. + +```puppet + apache::vhost { 'sample.example.net': + docroot => '/path/to/directory', + directories => [ + { path => '/path/to/directory', + order => 'Allow,Deny', + }, + ], + } +``` + +######`passenger_enabled` + +Sets the value for the [PassengerEnabled](http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerEnabled) directory to 'on' or 'off'. Requires `apache::mod::passenger` to be included. + +```puppet + apache::vhost { 'sample.example.net': + docroot => '/path/to/directory', + directories => [ + { path => '/path/to/directory', + passenger_enabled => 'on', + }, + ], + } +``` + +*Note:* Be aware that there is an [issue](http://www.conandalton.net/2010/06/passengerenabled-off-not-working.html) using the PassengerEnabled directive with the PassengerHighPerformance directive. + +######`php_value` and `php_flag` + +`php_value` sets the value of the directory, and `php_flag` uses a boolean to configure the directory. Further information can be found [here](http://php.net/manual/en/configuration.changes.php). + +######`php_admin_value` and `php_admin_flag` + +`php_admin_value` sets the value of the directory, and `php_admin_flag` uses a boolean to configure the directory. Further information can be found [here](http://php.net/manual/en/configuration.changes.php). + + +######`satisfy` + +Sets a `Satisfy` directive as per the [Apache Core documentation](http://httpd.apache.org/docs/2.2/mod/core.html#satisfy). **Deprecated:** This parameter is being deprecated due to a change in Apache. It only works with Apache 2.2 and lower. + +```puppet + apache::vhost { 'sample.example.net': + docroot => '/path/to/directory', + directories => [ + { path => '/path/to/directory', + satisfy => 'Any', + } + ], + } +``` + +######`sethandler` + +Sets a `SetHandler` directive as per the [Apache Core documentation](http://httpd.apache.org/docs/2.2/mod/core.html#sethandler). An example: + +```puppet + apache::vhost { 'sample.example.net': + docroot => '/path/to/directory', + directories => [ + { path => '/path/to/directory', + sethandler => 'None', + } + ], + } +``` + +######`rewrites` + +Creates URL [`rewrites`](#rewrites) rules in vhost directories. Expects an array of hashes, and the hash keys can be any of 'comment', 'rewrite_base', 'rewrite_cond', or 'rewrite_rule'. + +```puppet + apache::vhost { 'secure.example.net': + docroot => '/path/to/directory', + directories => [ + { path => '/path/to/directory', + rewrites => [ { comment => 'Permalink Rewrites', + rewrite_base => '/' + }, + { rewrite_rule => [ '^index\.php$ - [L]' ] + }, + { rewrite_cond => [ '%{REQUEST_FILENAME} !-f', + '%{REQUEST_FILENAME} !-d', + ], + rewrite_rule => [ '. /index.php [L]' ], + } + ], + }, + ], + } +``` + +***Note*** If you include rewrites in your directories make sure you are also including `apache::mod::rewrite`. You may also want to consider setting the rewrites using the `rewrites` parameter in `apache::vhost` rather than setting the rewrites in the vhost directories. + +######`shib_request_setting` + +Allows an valid content setting to be set or altered for the application request. This command takes two parameters, the name of the content setting, and the value to set it to.Check the Shibboleth [content setting documentation](https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPContentSettings) for valid settings. This key is disabled if `apache::mod::shib` is not defined. Check the [`mod_shib` documentation](https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPApacheConfig#NativeSPApacheConfig-Server/VirtualHostOptions) for more details. + +```puppet + apache::vhost { 'secure.example.net': + docroot => '/path/to/directory', + directories => [ + { path => '/path/to/directory', + shib_require_setting => 'requiresession 1', + shib_use_headers => 'On', + }, + ], + } +``` + +######`shib_use_headers` + +When set to 'On' this turns on the use of request headers to publish attributes to applications. Valid values for this key is 'On' or 'Off', and the default value is 'Off'. This key is disabled if `apache::mod::shib` is not defined. Check the [`mod_shib` documentation](https://wiki.shibboleth.net/confluence/display/SHIB2/NativeSPApacheConfig#NativeSPApacheConfig-Server/VirtualHostOptions) for more details. + +######`ssl_options` + +String or list of [SSLOptions](https://httpd.apache.org/docs/current/mod/mod_ssl.html#ssloptions), which configure SSL engine run-time options. This handler takes precedence over SSLOptions set in the parent block of the vhost. + +```puppet + apache::vhost { 'secure.example.net': + docroot => '/path/to/directory', + directories => [ + { path => '/path/to/directory', + ssl_options => '+ExportCertData', + }, + { path => '/path/to/different/dir', + ssl_options => [ '-StdEnvVars', '+ExportCertData'], + }, + ], + } +``` + +######`suphp` + +A hash containing the 'user' and 'group' keys for the [suPHP_UserGroup](http://www.suphp.org/DocumentationView.html?file=apache/CONFIG) setting. It must be used with `suphp_engine => on` in the vhost declaration, and can only be passed within `directories`. + +```puppet + apache::vhost { 'secure.example.net': + docroot => '/path/to/directory', + directories => [ + { path => '/path/to/directory', + suphp => + { user => 'myappuser', + group => 'myappgroup', + }, + }, + ], + } +``` + +####SSL parameters for `apache::vhost` + +All of the SSL parameters for `::vhost` default to whatever is set in the base `apache` class. Use the below parameters to tweak individual SSL settings for specific vhosts. + +#####`ssl` + +Enables SSL for the virtual host. SSL vhosts only respond to HTTPS queries. Valid values are 'true' or 'false'. Defaults to 'false'. + +#####`ssl_ca` + +Specifies the SSL certificate authority. Defaults to 'undef'. + +#####`ssl_cert` + +Specifies the SSL certification. Defaults are based on your OS: '/etc/pki/tls/certs/localhost.crt' for RedHat, '/etc/ssl/certs/ssl-cert-snakeoil.pem' for Debian, '/usr/local/etc/apache22/server.crt' for FreeBSD, and '/etc/ssl/apache2/server.crt' on Gentoo. + +#####`ssl_protocol` + +Specifies [SSLProtocol](http://httpd.apache.org/docs/current/mod/mod_ssl.html#sslprotocol). Expects an array of accepted protocols. Defaults to 'all', '-SSLv2', '-SSLv3'. + +#####`ssl_cipher` + +Specifies [SSLCipherSuite](http://httpd.apache.org/docs/current/mod/mod_ssl.html#sslciphersuite). Defaults to 'HIGH:MEDIUM:!aNULL:!MD5'. + +#####`ssl_honorcipherorder` + +Sets [SSLHonorCipherOrder](http://httpd.apache.org/docs/current/mod/mod_ssl.html#sslhonorcipherorder), which is used to prefer the server's cipher preference order. Defaults to 'On' in the base `apache` config. + +#####`ssl_certs_dir` + +Specifies the location of the SSL certification directory. Defaults to '/etc/ssl/certs' on Debian, '/etc/pki/tls/certs' on RedHat, '/usr/local/etc/apache22' on FreeBSD, and '/etc/ssl/apache2' on Gentoo. + +#####`ssl_chain` + +Specifies the SSL chain. Defaults to 'undef'. (This default works out of the box, but it must be updated in the base `apache` class with your specific certificate information before being used in production.) + +#####`ssl_crl` + +Specifies the certificate revocation list to use. Defaults to 'undef'. (This default works out of the box but must be updated in the base `apache` class with your specific certificate information before being used in production.) + +#####`ssl_crl_path` + +Specifies the location of the certificate revocation list. Defaults to 'undef'. (This default works out of the box but must be updated in the base `apache` class with your specific certificate information before being used in production.) + +#####`ssl_crl_check` + +Sets the certificate revocation check level via the [SSLCARevocationCheck directive](http://httpd.apache.org/docs/current/mod/mod_ssl.html#sslcarevocationcheck), defaults to 'undef'. This default works out of the box but must be specified when using CRLs in production. Only applicable to Apache 2.4 or higher; the value is ignored on older versions. + +#####`ssl_key` + +Specifies the SSL key. Defaults are based on your operating system: '/etc/pki/tls/private/localhost.key' for RedHat, '/etc/ssl/private/ssl-cert-snakeoil.key' for Debian, '/usr/local/etc/apache22/server.key' for FreeBSD, and '/etc/ssl/apache2/server.key' on Gentoo. (This default works out of the box but must be updated in the base `apache` class with your specific certificate information before being used in production.) + +#####`ssl_verify_client` + +Sets the [SSLVerifyClient](http://httpd.apache.org/docs/current/mod/mod_ssl.html#sslverifyclient) directive, which sets the certificate verification level for client authentication. Valid values are: 'none', 'optional', 'require', and 'optional_no_ca'. Defaults to 'undef'. + +```puppet + apache::vhost { 'sample.example.net': + … + ssl_verify_client => 'optional', + } +``` + +#####`ssl_verify_depth` + +Sets the [SSLVerifyDepth](http://httpd.apache.org/docs/current/mod/mod_ssl.html#sslverifydepth) directive, which specifies the maximum depth of CA certificates in client certificate verification. Defaults to 'undef'. + +```puppet + apache::vhost { 'sample.example.net': + … + ssl_verify_depth => 1, + } +``` + +#####`ssl_options` + +Sets the [SSLOptions](http://httpd.apache.org/docs/current/mod/mod_ssl.html#ssloptions) directive, which configures various SSL engine run-time options. This is the global setting for the given vhost and can be a string or an array. Defaults to 'undef'. + +A string: + +```puppet + apache::vhost { 'sample.example.net': + … + ssl_options => '+ExportCertData', + } +``` + +An array: + +```puppet + apache::vhost { 'sample.example.net': + … + ssl_options => [ '+StrictRequire', '+ExportCertData' ], + } +``` + +#####`ssl_proxyengine` + +Specifies whether or not to use [SSLProxyEngine](http://httpd.apache.org/docs/current/mod/mod_ssl.html#sslproxyengine). Valid values are 'true' and 'false'. Defaults to 'false'. + +####Defined Type: FastCGI Server + +This type is intended for use with mod_fastcgi. It allows you to define one or more external FastCGI servers to handle specific file types. + +Ex: + +```puppet +apache::fastcgi::server { 'php': + host => '127.0.0.1:9000', + timeout => 15, + flush => false, + faux_path => '/var/www/php.fcgi', + fcgi_alias => '/php.fcgi', + file_type => 'application/x-httpd-php' +} +``` + +Within your virtual host, you can then configure the specified file type to be handled by the fastcgi server specified above. + +```puppet +apache::vhost { 'www': + ... + custom_fragment => 'AddType application/x-httpd-php .php' + ... +} +``` + +#####`host` + +The hostname or IP address and TCP port number (1-65535) of the FastCGI server. + +#####`timeout` + +The number of seconds of FastCGI application inactivity allowed before the request is aborted and the event is logged (at the error LogLevel). The inactivity timer applies only as long as a connection is pending with the FastCGI application. If a request is queued to an application, but the application doesn't respond (by writing and flushing) within this period, the request is aborted. If communication is complete with the application but incomplete with the client (the response is buffered), the timeout does not apply. + +#####`flush` + +Force a write to the client as data is received from the application. By default, mod_fastcgi buffers data in order to free the application as quickly as possible. + +#####`faux_path` + +`faux_path` does not have to exist in the local filesystem. URIs that Apache resolves to this filename are handled by this external FastCGI application. + +#####`alias` + +A unique alias. This is used internally to link the action with the FastCGI server. + +#####`file_type` + +The MIME-type of the file to be processed by the FastCGI server. + +###Virtual Host Examples + +The apache module allows you to set up pretty much any configuration of virtual host you might need. This section addresses some common configurations, but look at the [Tests section](https://github.com/puppetlabs/puppetlabs-apache/tree/master/tests) for even more examples. + +Configure a vhost with a server administrator + +```puppet + apache::vhost { 'third.example.com': + port => '80', + docroot => '/var/www/third', + serveradmin => 'admin@example.com', + } +``` + +- - - + +Set up a vhost with aliased servers + +```puppet + apache::vhost { 'sixth.example.com': + serveraliases => [ + 'sixth.example.org', + 'sixth.example.net', + ], + port => '80', + docroot => '/var/www/fifth', + } +``` + +- - - + +Configure a vhost with a cgi-bin + +```puppet + apache::vhost { 'eleventh.example.com': + port => '80', + docroot => '/var/www/eleventh', + scriptalias => '/usr/lib/cgi-bin', + } +``` + +- - - + +Set up a vhost with a rack configuration + +```puppet + apache::vhost { 'fifteenth.example.com': + port => '80', + docroot => '/var/www/fifteenth', + rack_base_uris => ['/rackapp1', '/rackapp2'], + } +``` + +- - - + +Set up a mix of SSL and non-SSL vhosts at the same domain + +```puppet + #The non-ssl vhost + apache::vhost { 'first.example.com non-ssl': + servername => 'first.example.com', + port => '80', + docroot => '/var/www/first', + } + + #The SSL vhost at the same domain + apache::vhost { 'first.example.com ssl': + servername => 'first.example.com', + port => '443', + docroot => '/var/www/first', + ssl => true, + } +``` + +- - - + +Configure a vhost to redirect non-SSL connections to SSL + +```puppet + apache::vhost { 'sixteenth.example.com non-ssl': + servername => 'sixteenth.example.com', + port => '80', + docroot => '/var/www/sixteenth', + redirect_status => 'permanent', + redirect_dest => 'https://sixteenth.example.com/' + } + apache::vhost { 'sixteenth.example.com ssl': + servername => 'sixteenth.example.com', + port => '443', + docroot => '/var/www/sixteenth', + ssl => true, + } +``` + +- - - + +Set up IP-based vhosts on any listen port and have them respond to requests on specific IP addresses. In this example, we set listening on ports 80 and 81. This is required because the example vhosts are not declared with a port parameter. + +```puppet + apache::listen { '80': } + apache::listen { '81': } +``` + +Then we set up the IP-based vhosts + +```puppet + apache::vhost { 'first.example.com': + ip => '10.0.0.10', + docroot => '/var/www/first', + ip_based => true, + } + apache::vhost { 'second.example.com': + ip => '10.0.0.11', + docroot => '/var/www/second', + ip_based => true, + } +``` + +- - - + +Configure a mix of name-based and IP-based vhosts. First, we add two IP-based vhosts on 10.0.0.10, one SSL and one non-SSL + +```puppet + apache::vhost { 'The first IP-based vhost, non-ssl': + servername => 'first.example.com', + ip => '10.0.0.10', + port => '80', + ip_based => true, + docroot => '/var/www/first', + } + apache::vhost { 'The first IP-based vhost, ssl': + servername => 'first.example.com', + ip => '10.0.0.10', + port => '443', + ip_based => true, + docroot => '/var/www/first-ssl', + ssl => true, + } +``` + +Then, we add two name-based vhosts listening on 10.0.0.20 + +```puppet + apache::vhost { 'second.example.com': + ip => '10.0.0.20', + port => '80', + docroot => '/var/www/second', + } + apache::vhost { 'third.example.com': + ip => '10.0.0.20', + port => '80', + docroot => '/var/www/third', + } +``` + +If you want to add two name-based vhosts so that they answer on either 10.0.0.10 or 10.0.0.20, you **MUST** declare `add_listen => 'false'` to disable the otherwise automatic 'Listen 80', as it conflicts with the preceding IP-based vhosts. + +```puppet + apache::vhost { 'fourth.example.com': + port => '80', + docroot => '/var/www/fourth', + add_listen => false, + } + apache::vhost { 'fifth.example.com': + port => '80', + docroot => '/var/www/fifth', + add_listen => false, + } +``` + +###Load Balancing + +####Defined Type: `apache::balancer` + +`apache::balancer` creates an Apache balancer cluster. Each balancer cluster needs one or more balancer members, which are declared with [`apache::balancermember`](#defined-type-apachebalancermember). + +One `apache::balancer` defined resource should be defined for each Apache load balanced set of servers. The `apache::balancermember` resources for all balancer members can be exported and collected on a single Apache load balancer server using exported resources. + +**Parameters within `apache::balancer`:** + +#####`name` + +Sets the balancer cluster's title. This parameter also sets the title of the conf.d file. + +#####`proxy_set` + +Configures key-value pairs as [ProxySet](http://httpd.apache.org/docs/current/mod/mod_proxy.html#proxyset) lines. Accepts a hash, and defaults to '{}'. + +#####`collect_exported` + +Determines whether or not to use exported resources. Valid values 'true' and 'false', defaults to 'true'. + +If you statically declare all of your backend servers, you should set this to 'false' to rely on existing declared balancer member resources. Also make sure to use `apache::balancermember` with array arguments. + +If you wish to dynamically declare your backend servers via [exported resources](http://docs.puppetlabs.com/guides/exported_resources.html) collected on a central node, you must set this parameter to 'true' in order to collect the exported balancer member resources that were exported by the balancer member nodes. + +If you choose not to use exported resources, all balancer members will be configured in a single Puppet run. If you are using exported resources, Puppet has to run on the balanced nodes, then run on the balancer. + +####Defined Type: `apache::balancermember` + +Defines members of [mod_proxy_balancer](http://httpd.apache.org/docs/current/mod/mod_proxy_balancer.html), which sets up a balancer member inside a listening service configuration block in etc/apache/apache.cfg on the load balancer. + +**Parameters within `apache::balancermember`:** + +#####`name` + +Sets the title of the resource. This name also sets the name of the concat fragment. + +#####`balancer_cluster` + +Sets the Apache service's instance name. This must match the name of a declared `apache::balancer` resource. Required. + +#####`url` + +Specifies the URL used to contact the balancer member server. Defaults to 'http://${::fqdn}/'. + +#####`options` + +An array of [options](http://httpd.apache.org/docs/2.2/mod/mod_proxy.html#balancermember) to be specified after the URL. Accepts any key-value pairs available to [ProxyPass](http://httpd.apache.org/docs/2.2/mod/mod_proxy.html#proxypass). + +####Examples + +To load balance with exported resources, export the `balancermember` from the balancer member + +```puppet + @@apache::balancermember { "${::fqdn}-puppet00": + balancer_cluster => 'puppet00', + url => "ajp://${::fqdn}:8009" + options => ['ping=5', 'disablereuse=on', 'retry=5', 'ttl=120'], + } +``` + +Then, on the proxy server, create the balancer cluster + +```puppet + apache::balancer { 'puppet00': } +``` + +To load balance without exported resources, declare the following on the proxy + +```puppet + apache::balancer { 'puppet00': } + apache::balancermember { "${::fqdn}-puppet00": + balancer_cluster => 'puppet00', + url => "ajp://${::fqdn}:8009" + options => ['ping=5', 'disablereuse=on', 'retry=5', 'ttl=120'], + } +``` + +Then declare `apache::balancer` and `apache::balancermember` on the proxy server. + +If you need to use ProxySet in the balancer config + +```puppet + apache::balancer { 'puppet01': + proxy_set => {'stickysession' => 'JSESSIONID'}, + } +``` + +##Reference + +###Classes + +####Public Classes + +* [`apache`](#class-apache): Guides the basic setup of Apache. +* `apache::dev`: Installs Apache development libraries. (*Note:* On FreeBSD, you must declare `apache::package` or `apache` before `apache::dev`.) +* [`apache::mod::[name]`](#classes-apachemodname): Enables specific Apache HTTPD modules. + +####Private Classes + +* `apache::confd::no_accf`: Creates the no-accf.conf configuration file in conf.d, required by FreeBSD's Apache 2.4. +* `apache::default_confd_files`: Includes conf.d files for FreeBSD. +* `apache::default_mods`: Installs the Apache modules required to run the default configuration. +* `apache::package`: Installs and configures basic Apache packages. +* `apache::params`: Manages Apache parameters. +* `apache::service`: Manages the Apache daemon. + +###Defined Types + +####Public Defined Types + +* `apache::balancer`: Creates an Apache balancer cluster. +* `apache::balancermember`: Defines members of [mod_proxy_balancer](http://httpd.apache.org/docs/current/mod/mod_proxy_balancer.html). +* `apache::listen`: Based on the title, controls which ports Apache binds to for listening. Adds [Listen](http://httpd.apache.org/docs/current/bind.html) directives to ports.conf in the Apache HTTPD configuration directory. Titles take the form '', ':', or ':'. +* `apache::mod`: Used to enable arbitrary Apache HTTPD modules for which there is no specific `apache::mod::[name]` class. +* `apache::namevirtualhost`: Enables name-based hosting of a virtual host. Adds all [NameVirtualHost](http://httpd.apache.org/docs/current/vhosts/name-based.html) directives to the `ports.conf` file in the Apache HTTPD configuration directory. Titles take the form '\*', '*:', '\_default_:, '', or ':'. +* `apache::vhost`: Allows specialized configurations for virtual hosts that have requirements outside the defaults. + +####Private Defined Types + +* `apache::peruser::multiplexer`: Enables the [Peruser](http://www.freebsd.org/cgi/url.cgi?ports/www/apache22-peruser-mpm/pkg-descr) module for FreeBSD only. +* `apache::peruser::processor`: Enables the [Peruser](http://www.freebsd.org/cgi/url.cgi?ports/www/apache22-peruser-mpm/pkg-descr) module for FreeBSD only. +* `apache::security::file_link`: Links the activated_rules from apache::mod::security to the respective CRS rules on disk. + +###Templates + +The Apache module relies heavily on templates to enable the `vhost` and `apache::mod` defined types. These templates are built based on Facter facts around your operating system. Unless explicitly called out, most templates are not meant for configuration. + +##Limitations + +###Ubuntu 10.04 + +The `apache::vhost::WSGIImportScript` parameter creates a statement inside the VirtualHost which is unsupported on older versions of Apache, causing this to fail. This will be remedied in a future refactoring. + +###RHEL/CentOS 5 + +The `apache::mod::passenger` and `apache::mod::proxy_html` classes are untested since repositories are missing compatible packages. + +###RHEL/CentOS 7 + +The `apache::mod::passenger` class is untested as the repository does not have packages for EL7 yet. The fact that passenger packages aren't available also makes us unable to test the `rack_base_uri` parameter in `apache::vhost`. + +###General + +This module is CI tested on Centos 5 & 6, Ubuntu 12.04 & 14.04, Debian 7, and RHEL 5, 6 & 7 platforms against both the OSS and Enterprise version of Puppet. + +The module contains support for other distributions and operating systems, such as FreeBSD, Gentoo and Amazon Linux, but is not formally tested on those and regressions can occur. + +###SELinux and Custom Paths + +If you are running with SELinux in enforcing mode and want to use custom paths for your `logroot`, `mod_dir`, `vhost_dir`, and `docroot`, you need to manage the context for the files yourself. + +Something along the lines of: + +```puppet + exec { 'set_apache_defaults': + command => 'semanage fcontext -a -t httpd_sys_content_t "/custom/path(/.*)?"', + path => '/bin:/usr/bin/:/sbin:/usr/sbin', + require => Package['policycoreutils-python'], + } + package { 'policycoreutils-python': ensure => installed } + exec { 'restorecon_apache': + command => 'restorecon -Rv /apache_spec', + path => '/bin:/usr/bin/:/sbin:/usr/sbin', + before => Class['Apache::Service'], + require => Class['apache'], + } + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + file { '/custom/path': ensure => directory, } + file { '/custom/path/include': ensure => present, content => '#additional_includes' } + apache::vhost { 'test.server': + docroot => '/custom/path', + additional_includes => '/custom/path/include', + } +``` + +You need to set the contexts using `semanage fcontext` not `chcon` because `file {...}` resources reset the context to the values in the database if the resource isn't specifying the context. + +###FreeBSD + +In order to use this module on FreeBSD, you *must* use apache24-2.4.12 (www/apache24) or newer. + +##Development + +###Contributing + +Puppet Labs modules on the Puppet Forge are open projects, and community contributions are essential for keeping them great. We can’t access the huge number of platforms and myriad of hardware, software, and deployment configurations that Puppet is intended to serve. + +We want to keep it as easy as possible to contribute changes so that our modules work in your environment. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things. + +Read the complete module [contribution guide](https://docs.puppetlabs.com/forge/contributing.html) + +###Running tests + +This project contains tests for both [rspec-puppet](http://rspec-puppet.com/) and [beaker-rspec](https://github.com/puppetlabs/beaker-rspec) to verify functionality. For in-depth information please see their respective documentation. + +Quickstart: + +####Ruby > 1.8.7 + +``` + gem install bundler + bundle install + bundle exec rake spec + bundle exec rspec spec/acceptance + RS_DEBUG=yes bundle exec rspec spec/acceptance +``` + +####Ruby = 1.8.7 + +``` + gem install bundler + bundle install --without system_tests + bundle exec rake spec +``` diff --git a/3rdparty/modules/apache/README.passenger.md b/3rdparty/modules/apache/README.passenger.md new file mode 100644 index 000000000..5b33d2909 --- /dev/null +++ b/3rdparty/modules/apache/README.passenger.md @@ -0,0 +1,287 @@ +# Passenger + +Just enabling the Passenger module is insufficient for the use of Passenger in +production. Passenger should be tunable to better fit the environment in which +it is run while being aware of the resources it required. + +To this end the Apache passenger module has been modified to apply system wide +Passenger tuning declarations to `passenger.conf`. Declarations specific to a +virtual host should be passed through when defining a `vhost` (e.g. +`rack_base_uris` parameter on the `apache::vhost` type, check `README.md`). + +Also, general apache module loading parameters can be supplied to enable using +a customized passenger module in place of a default-package-based version of +the module. + +# Operating system support and Passenger versions + +The most important configuration directive for the Apache Passenger module is +`PassengerRoot`. Its value depends on the Passenger version used (2.x, 3.x or +4.x) and on the operating system package from which the Apache Passenger module +is installed. + +The following table summarises the current *default versions* and +`PassengerRoot` settings for the operating systems supported by +puppetlabs-apache: + +OS | Passenger version | `PassengerRoot` +---------------- | ------------------ | ---------------- +Debian 7 | 3.0.13 | /usr +Debian 8 | 4.0.53 | /usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini +Ubuntu 12.04 | 2.2.11 | /usr +Ubuntu 14.04 | 4.0.37 | /usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini +RHEL with EPEL6 | 3.0.21 | /usr/lib/ruby/gems/1.8/gems/passenger-3.0.21 + +As mentioned in `README.md` there are no compatible packages available for +RHEL/CentOS 5 or RHEL/CentOS 7. + +## Configuration files and locations on RHEL/CentOS + +Notice two important points: + +1. The Passenger version packaged in the EPEL repositories may change over time. +2. The value of `PassengerRoot` depends on the Passenger version installed. + +To prevent the puppetlabs-apache module from having to keep up with these +package versions the Passenger configuration files installed by the +packages are left untouched by this module. All configuration is placed in an +extra configuration file managed by puppetlabs-apache. + +This means '/etc/httpd/conf.d/passenger.conf' is installed by the +`mod_passenger` package and contains correct values for `PassengerRoot` and +`PassengerRuby`. Puppet will ignore this file. Additional configuration +directives as described in the remainder of this document are placed in +'/etc/httpd/conf.d/passenger_extra.conf', managed by Puppet. + +This pertains *only* to RHEL/CentOS, *not* Debian and Ubuntu. + +## Third-party and custom Passenger packages and versions + +The Passenger version distributed by the default OS packages may be too old to +be useful. Newer versions may be installed via Gems, from source or from +third-party OS packages. + +Most notably the Passenger developers officially provide Debian packages for a +variety of Debian and Ubuntu releases in the [Passenger APT +repository](https://oss-binaries.phusionpassenger.com/apt/passenger). Read more +about [installing these packages in the offical user +guide](http://www.modrails.com/documentation/Users%20guide%20Apache.html#install_on_debian_ubuntu). + +If you install custom Passenger packages and newer version make sure to set the +directives `PassengerRoot`, `PassengerRuby` and/or `PassengerDefaultRuby` +correctly, or Passenger and Apache will fail to function properly. + +For Passenger 4.x packages on Debian and Ubuntu the `PassengerRoot` directive +should almost universally be set to +`/usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini`. + +# Parameters for `apache::mod::passenger` + +The following class parameters configure Passenger in a global, server-wide +context. + +Example: + +```puppet +class { 'apache::mod::passenger': + passenger_root => '/usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini', + passenger_default_ruby => '/usr/bin/ruby1.9.3', + passenger_high_performance => 'on', + rails_autodetect => 'off', + mod_lib_path => '/usr/lib/apache2/custom_modules', +} +``` + +The general form is using the all lower-case version of the configuration +directive, with underscores instead of CamelCase. + +## Parameters used with passenger.conf + +If you pass a default value to `apache::mod::passenger` it will be ignored and +not passed through to the configuration file. + +### passenger_root + +The location to the Phusion Passenger root directory. This configuration option +is essential to Phusion Passenger, and allows Phusion Passenger to locate its +own data files. + +The default depends on the Passenger version and the means of installation. See +the above section on operating system support, versions and packages for more +information. + +http://www.modrails.com/documentation/Users%20guide%20Apache.html#_passengerroot_lt_directory_gt + +### passenger_default_ruby + +This option specifies the default Ruby interpreter to use for web apps as well +as for all sorts of internal Phusion Passenger helper scripts, e.g. the one +used by PassengerPreStart. + +This directive was introduced in Passenger 4.0.0 and will not work in versions +< 4.x. Do not set this parameter if your Passenger version is older than 4.0.0. + +Defaults to `undef` for all operating systems except Ubuntu 14.04, where it is +set to '/usr/bin/ruby'. + +http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerDefaultRuby + +### passenger_ruby + +This directive is the same as `passenger_default_ruby` for Passenger versions +< 4.x and must be used instead of `passenger_default_ruby` for such versions. + +It makes no sense to set `PassengerRuby` for Passenger >= 4.x. That +directive should only be used to override the value of `PassengerDefaultRuby` +on a non-global context, i.e. in ``, ``, `` +and so on. + +Defaults to `/usr/bin/ruby` for all supported operating systems except Ubuntu +14.04, where it is set to `undef`. + +http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerRuby + +### passenger_high_performance + +Default is `off`. When turned `on` Passenger runs in a higher performance mode +that can be less compatible with other Apache modules. + +http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerHighPerformance + +### passenger_max_pool_size + +Sets the maximum number of Passenger application processes that may +simultaneously run. The default value is 6. + +http://www.modrails.com/documentation/Users%20guide%20Apache.html#_passengermaxpoolsize_lt_integer_gt + +### passenger_pool_idle_time + +The maximum number of seconds a Passenger Application process will be allowed +to remain idle before being shut down. The default value is 300. + +http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerPoolIdleTime + +### passenger_max_requests + +The maximum number of request a Passenger application will process before being +restarted. The default value is 0, which indicates that a process will only +shut down if the Pool Idle Time (see above) expires. + +http://www.modrails.com/documentation/Users%20guide%20Apache.html#PassengerMaxRequests + +### passenger_stat_throttle_rate + +Sets how often Passenger performs file system checks, at most once every _x_ +seconds. Default is 0, which means the checks are performed with every request. + +http://www.modrails.com/documentation/Users%20guide%20Apache.html#_passengerstatthrottlerate_lt_integer_gt + +### rack_autodetect + +Should Passenger automatically detect if the document root of a virtual host is +a Rack application. Not set by default (`undef`). Note that this directive has +been removed in Passenger 4.0.0 and `PassengerEnabled` should be used instead. +Use this directive only on Passenger < 4.x. + +http://www.modrails.com/documentation/Users%20guide%20Apache.html#_rackautodetect_lt_on_off_gt + +### rails_autodetect + +Should Passenger automatically detect if the document root of a virtual host is +a Rails application. Not set by default (`undef`). Note that this directive +has been removed in Passenger 4.0.0 and `PassengerEnabled` should be used +instead. Use this directive only on Passenger < 4.x. + +http://www.modrails.com/documentation/Users%20guide%20Apache.html#_railsautodetect_lt_on_off_gt + +### passenger_use_global_queue + +Allows toggling of PassengerUseGlobalQueue. NOTE: PassengerUseGlobalQueue is +the default in Passenger 4.x and the versions >= 4.x have disabled this +configuration option altogether. Use with caution. + +### passenger_app_env + +Sets the global default `PassengerAppEnv` for Passenger applications. Not set by +default (`undef`) and thus defaults to Passenger's built-in value of 'production'. +This directive can be overridden in an `apache::vhost` resource. + +https://www.phusionpassenger.com/documentation/Users%20guide%20Apache.html#PassengerAppEnv + +## Parameters used to load the module + +Unlike the tuning parameters specified above, the following parameters are only +used when loading customized passenger modules. + +### mod_package + +Allows overriding the default package name used for the passenger module +package. + +### mod_package_ensure + +Allows overriding the package installation setting used by puppet when +installing the passenger module. The default is 'present'. + +### mod_id + +Allows overriding the value used by apache to identify the passenger module. +The default is 'passenger_module'. + +### mod_lib_path + +Allows overriding the directory path used by apache when loading the passenger +module. The default is the value of `$apache::params::lib_path`. + +### mod_lib + +Allows overriding the library file name used by apache when loading the +passenger module. The default is 'mod_passenger.so'. + +### mod_path + +Allows overriding the full path to the library file used by apache when loading +the passenger module. The default is the concatenation of the `mod_lib_path` +and `mod_lib` parameters. + +# Dependencies + +RedHat-based systems will need to configure additional package repositories in +order to install Passenger, specifically: + +* [Extra Packages for Enterprise Linux](https://fedoraproject.org/wiki/EPEL) +* [Phusion Passenger](http://passenger.stealthymonkeys.com) + +Configuration of these repositories is beyond the scope of this module and is +left to the user. + +# Attribution + +The Passenger tuning parameters for the `apache::mod::passenger` Puppet class +was modified by Aaron Hicks (hicksa@landcareresearch.co.nz) for work on the +NeSI Project and the Tuakiri New Zealand Access Federation as a fork from the +PuppetLabs Apache module on GitHub. + +* https://github.com/puppetlabs/puppetlabs-apache +* https://github.com/nesi/puppetlabs-apache +* http://www.nesi.org.nz// +* https://tuakiri.ac.nz/confluence/display/Tuakiri/Home + +# Copyright and License + +Copyright (C) 2012 [Puppet Labs](https://www.puppetlabs.com/) Inc + +Puppet Labs can be contacted at: info@puppetlabs.com + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/3rdparty/modules/apache/Rakefile b/3rdparty/modules/apache/Rakefile new file mode 100644 index 000000000..416807dad --- /dev/null +++ b/3rdparty/modules/apache/Rakefile @@ -0,0 +1,11 @@ +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' + +PuppetLint.configuration.fail_on_warnings = true +PuppetLint.configuration.send('relative') +PuppetLint.configuration.send('disable_80chars') +PuppetLint.configuration.send('disable_class_inherits_from_params_class') +PuppetLint.configuration.send('disable_documentation') +PuppetLint.configuration.send('disable_single_quote_string_with_variables') +PuppetLint.configuration.send('disable_only_variable_string') +PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"] diff --git a/3rdparty/modules/apache/checksums.json b/3rdparty/modules/apache/checksums.json new file mode 100644 index 000000000..f409fe01e --- /dev/null +++ b/3rdparty/modules/apache/checksums.json @@ -0,0 +1,298 @@ +{ + "CHANGELOG.md": "ddab29429292bf0d0d5676b62b97e794", + "CONTRIBUTING.md": "e2b8e8e433fc76b3798b7fe435f49375", + "Gemfile": "e62c96457cdaab2a09f1a37479ea6351", + "LICENSE": "b3f8a01d8699078d82e8c3c992307517", + "README.md": "5778028848917e410777c5a8e4971882", + "README.passenger.md": "1d15d1a56b36de464cb5baf54da9ddec", + "Rakefile": "ed3db0e49f5fcb381a19542c08ec473f", + "files/httpd": "295f5e924afe6f752d29327e73fe6d0a", + "lib/puppet/parser/functions/bool2httpd.rb": "05d5deeb6e0c31acee7c55b249ec8e06", + "lib/puppet/parser/functions/validate_apache_log_level.rb": "d75bc4ef17ff5c9a1f94dd3948e733d1", + "lib/puppet/provider/a2mod/a2mod.rb": "d986d8e8373f3f31c97359381c180628", + "lib/puppet/provider/a2mod/gentoo.rb": "2492d446adbb68f678e86a75eb7ff3bd", + "lib/puppet/provider/a2mod/modfix.rb": "b689a1c83c9ccd8590399c67f3e588e5", + "lib/puppet/provider/a2mod/redhat.rb": "c39b80e75e7d0666def31c2a6cdedb0b", + "lib/puppet/provider/a2mod.rb": "03ed73d680787dd126ea37a03be0b236", + "lib/puppet/type/a2mod.rb": "9042ccc045bfeecca28bebb834114f05", + "manifests/balancer.pp": "59ae0052030a0b077192f697a5b42e9e", + "manifests/balancermember.pp": "8f44f65124330b7e9b49a7100f86fe6d", + "manifests/confd/no_accf.pp": "406d0ca41c3b90f83740ca218dc3f484", + "manifests/custom_config.pp": "7948ab43ba405cb396f2fd8bb169a1b9", + "manifests/default_confd_files.pp": "86fdbe5773abb7c2da26db096973865c", + "manifests/default_mods/load.pp": "bc0b3b65edd1ba6178c09672352f9bce", + "manifests/default_mods.pp": "1a6b9907cccb539d22a6eeb2c233e572", + "manifests/dev.pp": "9329a07cf67feee12f91cb79b8060663", + "manifests/fastcgi/server.pp": "a47073f4447baef318c823f93b5f59ee", + "manifests/init.pp": "51d8043cbbe0aaed1ad02ef6d4d22b53", + "manifests/listen.pp": "f7e224cba3b8021f90511af4f43d8b1f", + "manifests/mod/actions.pp": "ec2a5d1cf54790204750f9b67938d230", + "manifests/mod/alias.pp": "67c9413d52bf2fbfbf256755477a8c9d", + "manifests/mod/auth_basic.pp": "dffef6ff10145393cb78fcaa27220c53", + "manifests/mod/auth_cas.pp": "a20c718cc3ffab32f7c72f42160a5602", + "manifests/mod/auth_kerb.pp": "08d536cb13281db3b9ed9a966ad431fd", + "manifests/mod/authn_core.pp": "4db773ddbc0d875230085782d4521951", + "manifests/mod/authn_file.pp": "eeb11513490beee901574746faaeabdf", + "manifests/mod/authnz_ldap.pp": "e3f91908be35306a488b44c55608b2a0", + "manifests/mod/authz_default.pp": "a3274a3174e79138ca16acd9e653364c", + "manifests/mod/authz_user.pp": "d446c90c44304594206bd2a0112be625", + "manifests/mod/autoindex.pp": "05112ccb06dc218f9a7b937767a6ea2d", + "manifests/mod/cache.pp": "b56d68b9401ba3e02a1f2fe55cdfbcca", + "manifests/mod/cgi.pp": "558a0350d1e8634a706543e0c6e28687", + "manifests/mod/cgid.pp": "bafc08448218bbb76c85b9ec2de05a98", + "manifests/mod/dav.pp": "9df80d36dd609be9032a8260aa9d10c1", + "manifests/mod/dav_fs.pp": "4528673b6e8d0af6935d9d630028b9f0", + "manifests/mod/dav_svn.pp": "f021fe8048deaa06759cd0b96b450363", + "manifests/mod/deflate.pp": "3dc2dbb0dfde703f47d1dc4993ef5b94", + "manifests/mod/dev.pp": "42673bab60b6fc0f3aa6e2357ec0a27c", + "manifests/mod/dir.pp": "8e577c570ba5e835c4f82232a1c01a4e", + "manifests/mod/disk_cache.pp": "379031f640bea89ee0978b0e95bf5ddd", + "manifests/mod/event.pp": "0d70f0733492c6c192e5ba6f6b3f3698", + "manifests/mod/expires.pp": "069783635a7a4f97af535cc149da6589", + "manifests/mod/fastcgi.pp": "237ff6ebc17c35ee2e3c82d2e19cd442", + "manifests/mod/fcgid.pp": "61bec2b414dd7e13315c06ff637699fc", + "manifests/mod/filter.pp": "b0039f3ae932b1204994ef2180dd76d2", + "manifests/mod/geoip.pp": "73f5822a4df6d25c088c9ca4947e25cd", + "manifests/mod/headers.pp": "ef3de538a0a4c9406236faf43eb89710", + "manifests/mod/include.pp": "a3b66eda88e38d90825c16b834bacd8d", + "manifests/mod/info.pp": "bad325232ff8038449dcafc11ff37ca1", + "manifests/mod/itk.pp": "5dea86531cd543d26436bfae4a357481", + "manifests/mod/ldap.pp": "367f13080f78b3e8527172cbb8a2fd4a", + "manifests/mod/mime.pp": "9d13abceb29f36c2f6c3a5a71a77561f", + "manifests/mod/mime_magic.pp": "481e016b74b0649bfdcbb32104a62054", + "manifests/mod/negotiation.pp": "6860ed514001b9f3f6945c78d250fd32", + "manifests/mod/nss.pp": "9d1573a9af62cc17cb9b8e322cf2a2b7", + "manifests/mod/pagespeed.pp": "2638c14081f8065bc8940b8d47782cc3", + "manifests/mod/passenger.pp": "41ff48aa1b9447d17af693062777744e", + "manifests/mod/perl.pp": "0bc488e1ac33e4e8987e0b07aa909682", + "manifests/mod/peruser.pp": "70cdb0592f53ec17f06365812e3e59c9", + "manifests/mod/php.pp": "628b672c8a28d1ebd43bedde63a5dfd3", + "manifests/mod/prefork.pp": "1dd2f9b1dfc702138401ca9b923548b4", + "manifests/mod/proxy.pp": "39e224390d43ffe082ff60fba2b97fc4", + "manifests/mod/proxy_ajp.pp": "073e2406aea7822750d4c21f02d8ac80", + "manifests/mod/proxy_balancer.pp": "6d16440ba6bed5427b331b6c6abf4063", + "manifests/mod/proxy_connect.pp": "574df18a67e478a3be903238ade3d334", + "manifests/mod/proxy_html.pp": "1a8ef7d17e65954aab303e3547e02f22", + "manifests/mod/proxy_http.pp": "0db1b26f8b4036b0d46ba86b7eaac561", + "manifests/mod/python.pp": "15f03d79e45737fdf0afca9665706b88", + "manifests/mod/remoteip.pp": "7fa5b92322df550f58421b24a53dbb01", + "manifests/mod/reqtimeout.pp": "aee3d869e6ca6eed18071c8d2aa97aff", + "manifests/mod/rewrite.pp": "292f2d6ce2078fa9df7f686105ea7b95", + "manifests/mod/rpaf.pp": "4844d717d6577aee8a788a7fbdc5e8dd", + "manifests/mod/security.pp": "9289d90560550a265d290a6fa17a1d76", + "manifests/mod/setenvif.pp": "b2ae43541bf1df5374187339e50a081f", + "manifests/mod/shib.pp": "3e2d3b5bf864fd292fa30f7c98d449f6", + "manifests/mod/speling.pp": "fa89a82933d30d2ebfe11e3ad9966bd1", + "manifests/mod/ssl.pp": "ecd2a08d79abf747e0d6aa38fbd9ccb9", + "manifests/mod/status.pp": "0b24de931fd8d54b2db0e3d16f0d0d8c", + "manifests/mod/suexec.pp": "2a8671856a0ece597e9b57867dc35e76", + "manifests/mod/suphp.pp": "6905059571fa21b7de957fd90540acff", + "manifests/mod/userdir.pp": "bbe716e8ff38815a51cc4eaaa0c1e4df", + "manifests/mod/version.pp": "6cb31057ebffa796f95642cc95f9499d", + "manifests/mod/vhost_alias.pp": "ee1225a748daaf50aca39a6d93fb8470", + "manifests/mod/worker.pp": "f80e8e73fb24da6e086aa478a0aff88f", + "manifests/mod/wsgi.pp": "0377fe287e51f4a396bd15b47f2628cc", + "manifests/mod/xsendfile.pp": "fba06f05a19c466654aca5ecaa705bf0", + "manifests/mod.pp": "7bd6b6d02b9a390a4021412e6825bfcb", + "manifests/mpm.pp": "32ed668ad674ed01a4b1c53e480a34be", + "manifests/namevirtualhost.pp": "67618d40112e4ddc1b46f64af2a5e875", + "manifests/package.pp": "2fdf95e2b20d6ab17f7adaf36a29ef7f", + "manifests/params.pp": "f570751b43092db18ec4dc6e7a6514a6", + "manifests/peruser/multiplexer.pp": "0ea75341b7a93e55bcfb431a93b1a6c9", + "manifests/peruser/processor.pp": "62f0ad5ed2ec36dadc7f40ad2a9e1bb9", + "manifests/php.pp": "9c9d07e12bf5d112b0b54f5bd69046fc", + "manifests/proxy.pp": "7c8515b88406922e148322ee15044b29", + "manifests/python.pp": "ddef4cd73850fdc2dc126d4579c30adf", + "manifests/security/rule_link.pp": "4635131018b0c5cd5f57ecea9f708b65", + "manifests/service.pp": "e0821dac17ef2bc00068ceae06bc17d9", + "manifests/ssl.pp": "173f3d6a7fd2b5f4100c4ff03d84e13b", + "manifests/version.pp": "bcc947740e4357cbdc9a1d54f44305c7", + "manifests/vhost.pp": "f028edcda9a1ab5a1e03e09d5c31973a", + "metadata.json": "8193f69f2b0ef0bc81ba32ed6240abfe", + "spec/acceptance/apache_parameters_spec.rb": "2bf2a24853b723af816d1543b57ec390", + "spec/acceptance/apache_ssl_spec.rb": "9813a93162e56c80b9eb6c286084437a", + "spec/acceptance/class_spec.rb": "7fc50a2b9f8deb588c1c3bb318a25f53", + "spec/acceptance/custom_config_spec.rb": "7982e71cd9a786536cb55fef618ac857", + "spec/acceptance/default_mods_spec.rb": "32826e1a7f6b99511b2937ab37b8f5cd", + "spec/acceptance/itk_spec.rb": "45401fe10b565ee9bf86900346a51a85", + "spec/acceptance/mod_dav_svn_spec.rb": "921cddd8b1f7f506859aaaae6cfd2c8a", + "spec/acceptance/mod_deflate_spec.rb": "cc2d1a68c6c53b17b1b9642e3fa2631f", + "spec/acceptance/mod_fcgid_spec.rb": "514cfb3b6bc81ddd0417271be8925956", + "spec/acceptance/mod_mime_spec.rb": "d753fad7136ef4c4b9034b32f0ddbcf8", + "spec/acceptance/mod_negotiation_spec.rb": "9d83d468dc13b179791fd4360c465aaf", + "spec/acceptance/mod_pagespeed_spec.rb": "0cc476dde6ba35804bb550b2b6f8e168", + "spec/acceptance/mod_passenger_spec.rb": "4b6f750448df7469c84b3cc57418244f", + "spec/acceptance/mod_php_spec.rb": "a91b953539eba21e64e9ddeee4a37f21", + "spec/acceptance/mod_proxy_html_spec.rb": "649c2bf1f251900fac5e9c81930aa6fd", + "spec/acceptance/mod_security_spec.rb": "a0b520040b23cd7591535469dc46b4a9", + "spec/acceptance/mod_suphp_spec.rb": "1e675ae7fcdbba8b1abbd1a96b59a060", + "spec/acceptance/nodesets/centos-59-x64.yml": "57eb3e471b9042a8ea40978c467f8151", + "spec/acceptance/nodesets/centos-64-x64-pe.yml": "ec075d95760df3d4702abea1ce0a829b", + "spec/acceptance/nodesets/centos-64-x64.yml": "d65958bdf25fb31eb4838fd984b555df", + "spec/acceptance/nodesets/centos-65-x64.yml": "3e5c36e6aa5a690229e720f4048bb8af", + "spec/acceptance/nodesets/centos-70-x64.yml": "0ae796256280ca157abc98f7cb492ea4", + "spec/acceptance/nodesets/debian-607-x64.yml": "52f42f3b8fc507a5fc825977d62665a3", + "spec/acceptance/nodesets/debian-70rc1-x64.yml": "717aa92150ebe3fca718807c7c93126f", + "spec/acceptance/nodesets/debian-73-i386.yml": "40aeb7ceab29148bb98a1e2bd51aba86", + "spec/acceptance/nodesets/debian-73-x64.yml": "df78f357e1bd0f7f9818d552eeb35026", + "spec/acceptance/nodesets/default.yml": "d65958bdf25fb31eb4838fd984b555df", + "spec/acceptance/nodesets/fedora-18-x64.yml": "9c907e4416a5fd487ff30a672a6b1c9e", + "spec/acceptance/nodesets/ubuntu-server-10044-x64.yml": "75e86400b7889888dc0781c0ae1a1297", + "spec/acceptance/nodesets/ubuntu-server-12042-x64.yml": "d30d73e34cd50b043c7d14e305955269", + "spec/acceptance/nodesets/ubuntu-server-1310-x64.yml": "9deb39279e104d765179b471c6ebb3a2", + "spec/acceptance/nodesets/ubuntu-server-1404-x64.yml": "5f0aed10098ac5b78e4217bb27c7aaf0", + "spec/acceptance/prefork_worker_spec.rb": "0994c75d9f6aab28040c86c2ae4e4eac", + "spec/acceptance/service_spec.rb": "24ce3caa9990b2f06ac98c7c438e1d5c", + "spec/acceptance/unsupported_spec.rb": "ecb65438d469b70dd7c611414f535771", + "spec/acceptance/version.rb": "bedfcffe1a6f47824defd167f1d3330e", + "spec/acceptance/vhost_spec.rb": "8ebc59432b65517c52ec44b280b25c75", + "spec/classes/apache_spec.rb": "93766ec34eece2ce419dad6d18f55017", + "spec/classes/dev_spec.rb": "549f0e09b6b0c2b8f612b44150d8d357", + "spec/classes/mod/alias_spec.rb": "cb7fa1744b0624ec6d04d6dba80bccda", + "spec/classes/mod/auth_cas_spec.rb": "34af1e2489fe7f805c760c40b2bc3f5b", + "spec/classes/mod/auth_kerb_spec.rb": "56066a4060352f76efdad26fe51b2e20", + "spec/classes/mod/authnz_ldap_spec.rb": "ce2f5fb517d4cc760c913fe131b1550f", + "spec/classes/mod/dav_svn_spec.rb": "6cf5fbd5e73c455f0f5afa01561cc704", + "spec/classes/mod/deflate_spec.rb": "a5b6afd416cbad17f21d5c86c83c3485", + "spec/classes/mod/dev_spec.rb": "78d215d7ef3a8e2df3e8789eb75fc4ca", + "spec/classes/mod/dir_spec.rb": "555e4b21a18422034b8b16560a1034a1", + "spec/classes/mod/event_spec.rb": "d8d0bd5dee8a4bf2dcd709326dfdd4e2", + "spec/classes/mod/expires_spec.rb": "a9ff97bcca20bb17102efd88ea0462e6", + "spec/classes/mod/fastcgi_spec.rb": "76ac8328da6c2fe1e126d8dcdcdb5519", + "spec/classes/mod/fcgid_spec.rb": "9868eb000373bdf6c6536ef4a205b62e", + "spec/classes/mod/info_spec.rb": "4b829ceca7c9b90c3eefafa391eb8e80", + "spec/classes/mod/itk_spec.rb": "437d4e4e776e082db051c99cb05a1058", + "spec/classes/mod/mime_magic_spec.rb": "8291c37b89f9d50f58fa94ab9cbb1bfe", + "spec/classes/mod/mime_spec.rb": "5e527739b595f9b0638ce384648c3187", + "spec/classes/mod/negotiation_spec.rb": "f1b10fe931b96f72f5d0eaf86354fce9", + "spec/classes/mod/pagespeed_spec.rb": "482d0dc3ebf002155d3c728d2043bcac", + "spec/classes/mod/passenger_spec.rb": "99c37bdde76f36760363a373f00cb72d", + "spec/classes/mod/perl_spec.rb": "11fb2ae842e64d467ccf70813ef3de7d", + "spec/classes/mod/peruser_spec.rb": "c379ce85a997789856b12c27957bf994", + "spec/classes/mod/php_spec.rb": "a88c78ba9bf9dd190c93617257d1ad15", + "spec/classes/mod/prefork_spec.rb": "d82f0f25691ba019b912cd000dbb845f", + "spec/classes/mod/proxy_connect_spec.rb": "bc0d0d6328288cd91d84ac9de66e9019", + "spec/classes/mod/proxy_html_spec.rb": "893bfa8dba37e63a24229e28cc74d073", + "spec/classes/mod/python_spec.rb": "45736e6305ca541ba29f997b8e7dd0ef", + "spec/classes/mod/remoteip_spec.rb": "e8840c791f3561c6d466040b888551ed", + "spec/classes/mod/reqtimeout_spec.rb": "cee7de04531d3fb49d75f8f8a7c2b493", + "spec/classes/mod/rpaf_spec.rb": "1845e640c44f8daeeffb13b29a26da84", + "spec/classes/mod/security_spec.rb": "a6c7526a69306c1993376e9e0646354f", + "spec/classes/mod/shib_spec.rb": "18107e156dd4682f59ddcc33c0dfc0d7", + "spec/classes/mod/speling_spec.rb": "4727fbb92f074e0cf3911e6cffe3322f", + "spec/classes/mod/ssl_spec.rb": "1a73d2c7a6df42ee0278dbf7c73c2a0b", + "spec/classes/mod/status_spec.rb": "1c7520050c8bed47492acd51588be52d", + "spec/classes/mod/suphp_spec.rb": "0c4d625a64124e7c9c14ea2b68dc7ebe", + "spec/classes/mod/worker_spec.rb": "a9049f0c44ac3593a750eaa6b5c2185c", + "spec/classes/mod/wsgi_spec.rb": "532da8779e878372ff29b51dfaefceea", + "spec/classes/params_spec.rb": "7bb6270f0338de41e1c34bd77cd844b7", + "spec/classes/service_spec.rb": "2d0abb70fc2b14f37121f6f7a683cc68", + "spec/defines/balancermember_spec.rb": "6071ddc9a56be6ecccfade6e233fb34b", + "spec/defines/custom_config_spec.rb": "a4beeb334685da5ac26bc5673587d0f9", + "spec/defines/fastcgi_server_spec.rb": "5798af8e6380d05f3ab38f4788b5c47c", + "spec/defines/mod_spec.rb": "a71fbfa5d62e9118a84c08138de9a248", + "spec/defines/modsec_link_spec.rb": "3421b21f8234637dd1c32ebcf89e44c3", + "spec/defines/vhost_spec.rb": "9da72619300e74e83327e882aa90119e", + "spec/spec.opts": "a600ded995d948e393fbe2320ba8e51c", + "spec/spec_helper.rb": "eb7ec6afb39e2282e62f2ebf69712707", + "spec/spec_helper_acceptance.rb": "8b602f7f655936386092fa12257034f0", + "spec/unit/provider/a2mod/gentoo_spec.rb": "8cf6574e75a4a7e8ff5a92d75a8d7ea8", + "spec/unit/puppet/parser/functions/bool2httpd_spec.rb": "3c47a968139400e5b81af8650f2d0e21", + "spec/unit/puppet/parser/functions/validate_apache_log_level.rb": "8f558fd81d1655e9ab20896152eca512", + "templates/confd/no-accf.conf.erb": "a614f28c4b54370e4fa88403dfe93eb0", + "templates/fastcgi/server.erb": "482ce7a72a08f21e3592e584178d5917", + "templates/httpd.conf.erb": "e468ccb373f653065f9f9296ea963b03", + "templates/listen.erb": "6286aa08f9e28caee54b1e1ee031b9d6", + "templates/mod/alias.conf.erb": "71028c659b7d1784c0e9f373846c8457", + "templates/mod/auth_cas.conf.erb": "74595985c3b0f9df1aaa0ad5dd7a7906", + "templates/mod/authnz_ldap.conf.erb": "12c9a1482694ddad3143e5eef03fb531", + "templates/mod/autoindex.conf.erb": "2421a3c6df32c7e38c2a7a22afdf5728", + "templates/mod/cgid.conf.erb": "f8ce27d60bc495bab16de2696ebb2fd0", + "templates/mod/dav_fs.conf.erb": "10c1131168e35319e22b3fbfe51aebfd", + "templates/mod/deflate.conf.erb": "e866ecf2bfe8e42ea984267f569723db", + "templates/mod/dir.conf.erb": "2485da78a2506c14bf51dde38dd03360", + "templates/mod/disk_cache.conf.erb": "7d3e7a5ee3bd7b6a839924b06a60667f", + "templates/mod/event.conf.erb": "469ef574b0ae1728203002a52f3d5a3b", + "templates/mod/expires.conf.erb": "7a77f8b1d50c53ee77a6cb798c51a2b9", + "templates/mod/fastcgi.conf.erb": "ab125b9bfdc494b621eec41587bf6101", + "templates/mod/fcgid.conf.erb": "1780c7808bb3811deaf0007c890df4dc", + "templates/mod/geoip.conf.erb": "069a4cb95c32f9fb1bc48617c21c1c31", + "templates/mod/info.conf.erb": "dd434aca2b3693c425a2c252a2c39f46", + "templates/mod/itk.conf.erb": "eff84b78e4f2f8c5c3a2e9fc4b8aad16", + "templates/mod/ldap.conf.erb": "57a006daca5fdacc094a872f9f0a4535", + "templates/mod/load.erb": "01132434e6101080c41548b0ba7e57d8", + "templates/mod/mime.conf.erb": "8f953519790a5900369fb656054cae35", + "templates/mod/mime_magic.conf.erb": "db7ac6bbf365d016852744d339c12d16", + "templates/mod/mpm_event.conf.erb": "80097a19d063a4f973465d9ef5c0c0bf", + "templates/mod/negotiation.conf.erb": "a2f0fb40cd038cb17bedc2b84d9f48ea", + "templates/mod/nss.conf.erb": "688c134cb37159a92cf85010ea3c67e6", + "templates/mod/pagespeed.conf.erb": "0d1ba456a798d1404205b7fbdee3294e", + "templates/mod/passenger.conf.erb": "1ae6254dd2f9c209e4fa373b5eefe804", + "templates/mod/peruser.conf.erb": "c4f4054aee899249ea6fef5a9e5c14ff", + "templates/mod/php5.conf.erb": "e92f4b41e71318d35f44859b71999887", + "templates/mod/prefork.conf.erb": "f9ec5a7eaea78a19b04fa69f8acd8a84", + "templates/mod/proxy.conf.erb": "7eef34af57278ea572b267cff9fb6631", + "templates/mod/proxy_html.conf.erb": "69c9ce9b7f24e1337065f1ce26b057a0", + "templates/mod/remoteip.conf.erb": "5e3fae3bb4532d351d3860652215af92", + "templates/mod/reqtimeout.conf.erb": "314ef068b786ae5afded290a8b6eab15", + "templates/mod/rpaf.conf.erb": "5447539c083ae54f3a9e93c1ac8c988b", + "templates/mod/security.conf.erb": "1bd891bb3ed76e493a48c06b53a468f5", + "templates/mod/security_crs.conf.erb": "0533f947d1d418774213bc9eb0444358", + "templates/mod/setenvif.conf.erb": "c7ede4173da1915b7ec088201f030c28", + "templates/mod/ssl.conf.erb": "312a0337c1f6ae1af80ddbd08177ef69", + "templates/mod/status.conf.erb": "9e959900ac58c8de34783886efeebce7", + "templates/mod/suphp.conf.erb": "05bb7b3ea23976b032ce405bfd4edd18", + "templates/mod/userdir.conf.erb": "ae083ac8bf569a3db2a01ba8ecf30790", + "templates/mod/worker.conf.erb": "a590811ec67bb7c8a3d3dcf7b442e226", + "templates/mod/wsgi.conf.erb": "9a416fa3b71be0795679069809686300", + "templates/namevirtualhost.erb": "fbfca19a639e18e6c477e191344ac8ae", + "templates/ports_header.erb": "afe35cb5747574b700ebaa0f0b3a626e", + "templates/vhost/_access_log.erb": "a0c804cb6fc03e5c573f9bfbcf73d9c6", + "templates/vhost/_action.erb": "a004dfcac2e63cef65cf8aa0e270b636", + "templates/vhost/_additional_includes.erb": "630083ded68174663e79eadf0491c0a8", + "templates/vhost/_aliases.erb": "6412f695e911feac18986da38f290dae", + "templates/vhost/_allow_encoded_slashes.erb": "37dee0b6fe9287342a10b533955dff81", + "templates/vhost/_block.erb": "cab4365316621b4e06cd1258abeb1d23", + "templates/vhost/_charsets.erb": "d152b6a7815e9edc0fe9bf9acbe2f1ec", + "templates/vhost/_custom_fragment.erb": "67a4475275ec9208e6421b047b9ed7f4", + "templates/vhost/_directories.erb": "a586e7cffdb3de18cf54752bbe36f23f", + "templates/vhost/_docroot.erb": "1cd82546a85458b1e117ca24f06d4691", + "templates/vhost/_error_document.erb": "81d3007c1301a5c5f244c082cfee9de2", + "templates/vhost/_fallbackresource.erb": "e6c103bee7f6f76b10f244fc9fd1cd3b", + "templates/vhost/_fastcgi.erb": "d07c41eae32671b38b5dba14724c14cc", + "templates/vhost/_file_footer.erb": "e27b2525783e590ca1820f1e2118285d", + "templates/vhost/_file_header.erb": "9502d6f3c9cc29c66c08ef94eb27f9fb", + "templates/vhost/_header.erb": "9eb9d4075f288183d8224ddec5b2f126", + "templates/vhost/_itk.erb": "8bf90b9855a9277f7a665b10f6c57fe9", + "templates/vhost/_logging.erb": "5bc4cbb1bc8a292acc0ba0420f96ca4e", + "templates/vhost/_passenger.erb": "6b8f937fffe27e65f9aa72e950c4dbfc", + "templates/vhost/_php.erb": "0be13b20951791db0f09c328e13b7eaf", + "templates/vhost/_php_admin.erb": "107a57e9e7b3f86d1abcf743f672a292", + "templates/vhost/_proxy.erb": "08406c6676346d26b2a8d93b20884858", + "templates/vhost/_rack.erb": "ebe187c1bdc81eec9c8e0d9026120b18", + "templates/vhost/_redirect.erb": "639e170cafa9e703ab38797c8fc3030b", + "templates/vhost/_requestheader.erb": "db1b0cdda069ae809b5b83b0871ef991", + "templates/vhost/_rewrite.erb": "63a86545cd1c1a8e9e8518dd270deb3e", + "templates/vhost/_scriptalias.erb": "98713f33cca15b22c749bd35ea9a7b41", + "templates/vhost/_security.erb": "58cd0f606e104be456dea0b5d52212e8", + "templates/vhost/_serveralias.erb": "95fed45853629924467aefc271d5b396", + "templates/vhost/_serversignature.erb": "9bf5a458783ab459e5043e1cdf671fa7", + "templates/vhost/_setenv.erb": "818f65d2936be12a24e59079e28f8f47", + "templates/vhost/_ssl.erb": "af6a1e1b3811a59e19ca11856511d032", + "templates/vhost/_suexec.erb": "f2b3f9b9ff8fbac4e468e02cd824675a", + "templates/vhost/_suphp.erb": "a1c4a5e4461adbfce870df0abd158b59", + "templates/vhost/_wsgi.erb": "c4ea9a97580489edc6b589ac46816462", + "tests/apache.pp": "819cf9116ffd349e6757e1926d11ca2f", + "tests/dev.pp": "9f5727f69f536538f8d840fad0852308", + "tests/init.pp": "4eac4a7ef68499854c54a78879e25535", + "tests/mod_load_params.pp": "5981af4d625a906fce1cedeb3f70cb90", + "tests/mods.pp": "0085911ba562b7e56ad8d793099c9240", + "tests/mods_custom.pp": "9afd068edce0538b5c55a3bc19f9c24a", + "tests/php.pp": "60e7939034d531dd6b95af35338bcbe7", + "tests/vhost.pp": "eafb5f9d792b110921879a648b506796", + "tests/vhost_directories.pp": "b4e6b5a596e5bae122233652b9a33e32", + "tests/vhost_ip_based.pp": "7d9f7b6976de7488ab6ff0a6e647fc73", + "tests/vhost_proxypass.pp": "59b87f88943aa809578288e26b41aade", + "tests/vhost_ssl.pp": "9f3716bc15a9a6760f1d6cc3bf8ce8ac", + "tests/vhosts_without_listen.pp": "a6692104056a56517b4365bcc816e7f4" +} \ No newline at end of file diff --git a/3rdparty/modules/apache/files/httpd b/3rdparty/modules/apache/files/httpd new file mode 100644 index 000000000..d65a8d445 --- /dev/null +++ b/3rdparty/modules/apache/files/httpd @@ -0,0 +1,24 @@ +# Configuration file for the httpd service. + +# +# The default processing model (MPM) is the process-based +# 'prefork' model. A thread-based model, 'worker', is also +# available, but does not work with some modules (such as PHP). +# The service must be stopped before changing this variable. +# +#HTTPD=/usr/sbin/httpd.worker + +# +# To pass additional options (for instance, -D definitions) to the +# httpd binary at startup, set OPTIONS here. +# +#OPTIONS= +#OPTIONS=-DDOWN + +# +# By default, the httpd process is started in the C locale; to +# change the locale in which the server runs, the HTTPD_LANG +# variable can be set. +# +#HTTPD_LANG=C +export SHORTHOST=`hostname -s` diff --git a/3rdparty/modules/apache/lib/puppet/parser/functions/bool2httpd.rb b/3rdparty/modules/apache/lib/puppet/parser/functions/bool2httpd.rb new file mode 100644 index 000000000..5fb79f6f5 --- /dev/null +++ b/3rdparty/modules/apache/lib/puppet/parser/functions/bool2httpd.rb @@ -0,0 +1,30 @@ +Puppet::Parser::Functions::newfunction(:bool2httpd, :type => :rvalue, :doc => <<-EOS +Transform a supposed boolean to On or Off. Pass all other values through. +Given a nil value (undef), bool2httpd will return 'Off' + +Example: + + $trace_enable = false + $server_signature = 'mail' + + bool2httpd($trace_enable) + # => 'Off' + bool2httpd($server_signature) + # => 'mail' + bool2httpd(undef) + # => 'Off' + +EOS +) do |args| + raise(Puppet::ParseError, "bool2httpd() wrong number of arguments. Given: #{args.size} for 1)") if args.size != 1 + + arg = args[0] + + if arg.nil? or arg == false or arg =~ /false/i or arg == :undef + return 'Off' + elsif arg == true or arg =~ /true/i + return 'On' + end + + return arg.to_s +end diff --git a/3rdparty/modules/apache/lib/puppet/parser/functions/validate_apache_log_level.rb b/3rdparty/modules/apache/lib/puppet/parser/functions/validate_apache_log_level.rb new file mode 100644 index 000000000..8a1ade0be --- /dev/null +++ b/3rdparty/modules/apache/lib/puppet/parser/functions/validate_apache_log_level.rb @@ -0,0 +1,27 @@ +module Puppet::Parser::Functions + newfunction(:validate_apache_log_level, :doc => <<-'ENDHEREDOC') do |args| + Perform simple validation of a string against the list of known log + levels as per http://httpd.apache.org/docs/current/mod/core.html#loglevel + validate_apache_loglevel('info') + + Modules maybe specified with their own levels like these: + validate_apache_loglevel('warn ssl:info') + validate_apache_loglevel('warn mod_ssl.c:info') + validate_apache_loglevel('warn ssl_module:info') + + Expected to be used from the main or vhost. + + Might be used from directory too later as apaceh supports that + + ENDHEREDOC + if (args.size != 1) then + raise Puppet::ParseError, ("validate_apache_loglevel(): wrong number of arguments (#{args.length}; must be 1)") + end + + log_level = args[0] + msg = "Log level '${log_level}' is not one of the supported Apache HTTP Server log levels." + + raise Puppet::ParseError, (msg) unless log_level =~ Regexp.compile('(emerg|alert|crit|error|warn|notice|info|debug|trace[1-8])') + + end +end diff --git a/3rdparty/modules/apache/lib/puppet/provider/a2mod.rb b/3rdparty/modules/apache/lib/puppet/provider/a2mod.rb new file mode 100644 index 000000000..670aca3d0 --- /dev/null +++ b/3rdparty/modules/apache/lib/puppet/provider/a2mod.rb @@ -0,0 +1,34 @@ +class Puppet::Provider::A2mod < Puppet::Provider + def self.prefetch(mods) + instances.each do |prov| + if mod = mods[prov.name] + mod.provider = prov + end + end + end + + def flush + @property_hash.clear + end + + def properties + if @property_hash.empty? + @property_hash = query || {:ensure => :absent} + @property_hash[:ensure] = :absent if @property_hash.empty? + end + @property_hash.dup + end + + def query + self.class.instances.each do |mod| + if mod.name == self.name or mod.name.downcase == self.name + return mod.properties + end + end + nil + end + + def exists? + properties[:ensure] != :absent + end +end diff --git a/3rdparty/modules/apache/lib/puppet/provider/a2mod/a2mod.rb b/3rdparty/modules/apache/lib/puppet/provider/a2mod/a2mod.rb new file mode 100644 index 000000000..e257a579e --- /dev/null +++ b/3rdparty/modules/apache/lib/puppet/provider/a2mod/a2mod.rb @@ -0,0 +1,35 @@ +require 'puppet/provider/a2mod' + +Puppet::Type.type(:a2mod).provide(:a2mod, :parent => Puppet::Provider::A2mod) do + desc "Manage Apache 2 modules on Debian and Ubuntu" + + optional_commands :encmd => "a2enmod" + optional_commands :discmd => "a2dismod" + commands :apache2ctl => "apache2ctl" + + confine :osfamily => :debian + defaultfor :operatingsystem => [:debian, :ubuntu] + + def self.instances + modules = apache2ctl("-M").lines.collect { |line| + m = line.match(/(\w+)_module \(shared\)$/) + m[1] if m + }.compact + + modules.map do |mod| + new( + :name => mod, + :ensure => :present, + :provider => :a2mod + ) + end + end + + def create + encmd resource[:name] + end + + def destroy + discmd resource[:name] + end +end diff --git a/3rdparty/modules/apache/lib/puppet/provider/a2mod/gentoo.rb b/3rdparty/modules/apache/lib/puppet/provider/a2mod/gentoo.rb new file mode 100644 index 000000000..07319dfdc --- /dev/null +++ b/3rdparty/modules/apache/lib/puppet/provider/a2mod/gentoo.rb @@ -0,0 +1,116 @@ +require 'puppet/util/filetype' +Puppet::Type.type(:a2mod).provide(:gentoo, :parent => Puppet::Provider) do + desc "Manage Apache 2 modules on Gentoo" + + confine :operatingsystem => :gentoo + defaultfor :operatingsystem => :gentoo + + attr_accessor :property_hash + + def create + @property_hash[:ensure] = :present + end + + def exists? + (!(@property_hash[:ensure].nil?) and @property_hash[:ensure] == :present) + end + + def destroy + @property_hash[:ensure] = :absent + end + + def flush + self.class.flush + end + + class << self + attr_reader :conf_file + end + + def self.clear + @mod_resources = [] + @modules = [] + @other_args = "" + end + + def self.initvars + @conf_file = "/etc/conf.d/apache2" + @filetype = Puppet::Util::FileType.filetype(:flat).new(conf_file) + @mod_resources = [] + @modules = [] + @other_args = "" + end + + self.initvars + + # Retrieve an array of all existing modules + def self.modules + if @modules.length <= 0 + # Locate the APACHE_OPTS variable + records = filetype.read.split(/\n/) + apache2_opts = records.grep(/^\s*APACHE2_OPTS=/).first + + # Extract all defines + while apache2_opts.sub!(/-D\s+(\w+)/, '') + @modules << $1.downcase + end + + # Hang on to any remaining options. + if apache2_opts.match(/APACHE2_OPTS="(.+)"/) + @other_args = $1.strip + end + + @modules.sort!.uniq! + end + + @modules + end + + def self.prefetch(resources={}) + # Match resources with existing providers + instances.each do |provider| + if resource = resources[provider.name] + resource.provider = provider + end + end + + # Store all resources using this provider for flushing + resources.each do |name, resource| + @mod_resources << resource + end + end + + def self.instances + modules.map {|mod| new(:name => mod, :provider => :gentoo, :ensure => :present)} + end + + def self.flush + + mod_list = modules + mods_to_remove = @mod_resources.select {|mod| mod.should(:ensure) == :absent}.map {|mod| mod[:name]} + mods_to_add = @mod_resources.select {|mod| mod.should(:ensure) == :present}.map {|mod| mod[:name]} + + mod_list -= mods_to_remove + mod_list += mods_to_add + mod_list.sort!.uniq! + + if modules != mod_list + opts = @other_args + " " + opts << mod_list.map {|mod| "-D #{mod.upcase}"}.join(" ") + opts.strip! + opts.gsub!(/\s+/, ' ') + + apache2_opts = %Q{APACHE2_OPTS="#{opts}"} + Puppet.debug("Writing back \"#{apache2_opts}\" to #{conf_file}") + + records = filetype.read.split(/\n/) + + opts_index = records.find_index {|i| i.match(/^\s*APACHE2_OPTS/)} + records[opts_index] = apache2_opts + + filetype.backup + filetype.write(records.join("\n")) + @modules = mod_list + end + end +end diff --git a/3rdparty/modules/apache/lib/puppet/provider/a2mod/modfix.rb b/3rdparty/modules/apache/lib/puppet/provider/a2mod/modfix.rb new file mode 100644 index 000000000..8f35b2e4a --- /dev/null +++ b/3rdparty/modules/apache/lib/puppet/provider/a2mod/modfix.rb @@ -0,0 +1,12 @@ +Puppet::Type.type(:a2mod).provide :modfix do + desc "Dummy provider for A2mod. + + Fake nil resources when there is no crontab binary available. Allows + puppetd to run on a bootstrapped machine before a Cron package has been + installed. Workaround for: http://projects.puppetlabs.com/issues/2384 + " + + def self.instances + [] + end +end \ No newline at end of file diff --git a/3rdparty/modules/apache/lib/puppet/provider/a2mod/redhat.rb b/3rdparty/modules/apache/lib/puppet/provider/a2mod/redhat.rb new file mode 100644 index 000000000..ea5494cb4 --- /dev/null +++ b/3rdparty/modules/apache/lib/puppet/provider/a2mod/redhat.rb @@ -0,0 +1,60 @@ +require 'puppet/provider/a2mod' + +Puppet::Type.type(:a2mod).provide(:redhat, :parent => Puppet::Provider::A2mod) do + desc "Manage Apache 2 modules on RedHat family OSs" + + commands :apachectl => "apachectl" + + confine :osfamily => :redhat + defaultfor :osfamily => :redhat + + require 'pathname' + + # modpath: Path to default apache modules directory /etc/httpd/mod.d + # modfile: Path to module load configuration file; Default: resides under modpath directory + # libfile: Path to actual apache module library. Added in modfile LoadModule + + attr_accessor :modfile, :libfile + class << self + attr_accessor :modpath + def preinit + @modpath = "/etc/httpd/mod.d" + end + end + + self.preinit + + def create + File.open(modfile,'w') do |f| + f.puts "LoadModule #{resource[:identifier]} #{libfile}" + end + end + + def destroy + File.delete(modfile) + end + + def self.instances + modules = apachectl("-M").lines.collect { |line| + m = line.match(/(\w+)_module \(shared\)$/) + m[1] if m + }.compact + + modules.map do |mod| + new( + :name => mod, + :ensure => :present, + :provider => :redhat + ) + end + end + + def modfile + modfile ||= "#{self.class.modpath}/#{resource[:name]}.load" + end + + # Set libfile path: If absolute path is passed, then maintain it. Else, make it default from 'modules' dir. + def libfile + libfile = Pathname.new(resource[:lib]).absolute? ? resource[:lib] : "modules/#{resource[:lib]}" + end +end diff --git a/3rdparty/modules/apache/lib/puppet/type/a2mod.rb b/3rdparty/modules/apache/lib/puppet/type/a2mod.rb new file mode 100644 index 000000000..07a911e5e --- /dev/null +++ b/3rdparty/modules/apache/lib/puppet/type/a2mod.rb @@ -0,0 +1,30 @@ +Puppet::Type.newtype(:a2mod) do + @doc = "Manage Apache 2 modules" + + ensurable + + newparam(:name) do + Puppet.warning "The a2mod provider is deprecated, please use apache::mod instead" + desc "The name of the module to be managed" + + isnamevar + + end + + newparam(:lib) do + desc "The name of the .so library to be loaded" + + defaultto { "mod_#{@resource[:name]}.so" } + end + + newparam(:identifier) do + desc "Module identifier string used by LoadModule. Default: module-name_module" + + # http://httpd.apache.org/docs/2.2/mod/module-dict.html#ModuleIdentifier + + defaultto { "#{resource[:name]}_module" } + end + + autorequire(:package) { catalog.resource(:package, 'httpd')} + +end diff --git a/3rdparty/modules/apache/manifests/balancer.pp b/3rdparty/modules/apache/manifests/balancer.pp new file mode 100644 index 000000000..765dae629 --- /dev/null +++ b/3rdparty/modules/apache/manifests/balancer.pp @@ -0,0 +1,82 @@ +# == Define Resource Type: apache::balancer +# +# This type will create an apache balancer cluster file inside the conf.d +# directory. Each balancer cluster needs one or more balancer members (that can +# be declared with the apache::balancermember defined resource type). Using +# storeconfigs, you can export the apache::balancermember resources on all +# balancer members, and then collect them on a single apache load balancer +# server. +# +# === Requirement/Dependencies: +# +# Currently requires the puppetlabs/concat module on the Puppet Forge and uses +# storeconfigs on the Puppet Master to export/collect resources from all +# balancer members. +# +# === Parameters +# +# [*name*] +# The namevar of the defined resource type is the balancer clusters name. +# This name is also used in the name of the conf.d file +# +# [*proxy_set*] +# Hash, default empty. If given, each key-value pair will be used as a ProxySet +# line in the configuration. +# +# [*collect_exported*] +# Boolean, default 'true'. True means 'collect exported @@balancermember +# resources' (for the case when every balancermember node exports itself), +# false means 'rely on the existing declared balancermember resources' (for the +# case when you know the full set of balancermembers in advance and use +# apache::balancermember with array arguments, which allows you to deploy +# everything in 1 run) +# +# +# === Examples +# +# Exporting the resource for a balancer member: +# +# apache::balancer { 'puppet00': } +# +define apache::balancer ( + $proxy_set = {}, + $collect_exported = true, +) { + include ::apache::mod::proxy_balancer + + $target = "${::apache::params::confd_dir}/balancer_${name}.conf" + + concat { $target: + owner => '0', + group => '0', + mode => '0644', + notify => Class['Apache::Service'], + } + + concat::fragment { "00-${name}-header": + ensure => present, + target => $target, + order => '01', + content => "\n", + } + + if $collect_exported { + Apache::Balancermember <<| balancer_cluster == $name |>> + } + # else: the resources have been created and they introduced their + # concat fragments. We don't have to do anything about them. + + concat::fragment { "01-${name}-proxyset": + ensure => present, + target => $target, + order => '19', + content => inline_template("<% @proxy_set.keys.sort.each do |key| %> Proxyset <%= key %>=<%= @proxy_set[key] %>\n<% end %>"), + } + + concat::fragment { "01-${name}-footer": + ensure => present, + target => $target, + order => '20', + content => "\n", + } +} diff --git a/3rdparty/modules/apache/manifests/balancermember.pp b/3rdparty/modules/apache/manifests/balancermember.pp new file mode 100644 index 000000000..459081a71 --- /dev/null +++ b/3rdparty/modules/apache/manifests/balancermember.pp @@ -0,0 +1,53 @@ +# == Define Resource Type: apache::balancermember +# +# This type will setup a balancer member inside a listening service +# configuration block in /etc/apache/apache.cfg on the load balancer. +# currently it only has the ability to specify the instance name, url and an +# array of options. More features can be added as needed. The best way to +# implement this is to export this resource for all apache balancer member +# servers, and then collect them on the main apache load balancer. +# +# === Requirement/Dependencies: +# +# Currently requires the puppetlabs/concat module on the Puppet Forge and +# uses storeconfigs on the Puppet Master to export/collect resources +# from all balancer members. +# +# === Parameters +# +# [*name*] +# The title of the resource is arbitrary and only utilized in the concat +# fragment name. +# +# [*balancer_cluster*] +# The apache service's instance name (or, the title of the apache::balancer +# resource). This must match up with a declared apache::balancer resource. +# +# [*url*] +# The url used to contact the balancer member server. +# +# [*options*] +# An array of options to be specified after the url. +# +# === Examples +# +# Exporting the resource for a balancer member: +# +# @@apache::balancermember { 'apache': +# balancer_cluster => 'puppet00', +# url => "ajp://${::fqdn}:8009" +# options => ['ping=5', 'disablereuse=on', 'retry=5', 'ttl=120'], +# } +# +define apache::balancermember( + $balancer_cluster, + $url = "http://${::fqdn}/", + $options = [], +) { + + concat::fragment { "BalancerMember ${name}": + ensure => present, + target => "${::apache::params::confd_dir}/balancer_${balancer_cluster}.conf", + content => inline_template(" BalancerMember ${url} <%= @options.join ' ' %>\n"), + } +} diff --git a/3rdparty/modules/apache/manifests/confd/no_accf.pp b/3rdparty/modules/apache/manifests/confd/no_accf.pp new file mode 100644 index 000000000..f35c0c8b9 --- /dev/null +++ b/3rdparty/modules/apache/manifests/confd/no_accf.pp @@ -0,0 +1,10 @@ +class apache::confd::no_accf { + # Template uses no variables + file { 'no-accf.conf': + ensure => 'file', + path => "${::apache::confd_dir}/no-accf.conf", + content => template('apache/confd/no-accf.conf.erb'), + require => Exec["mkdir ${::apache::confd_dir}"], + before => File[$::apache::confd_dir], + } +} diff --git a/3rdparty/modules/apache/manifests/custom_config.pp b/3rdparty/modules/apache/manifests/custom_config.pp new file mode 100644 index 000000000..ceb1fd077 --- /dev/null +++ b/3rdparty/modules/apache/manifests/custom_config.pp @@ -0,0 +1,67 @@ +# See README.md for usage information +define apache::custom_config ( + $ensure = 'present', + $confdir = $::apache::confd_dir, + $content = undef, + $priority = '25', + $source = undef, + $verify_command = $::apache::params::verify_command, + $verify_config = true, +) { + + if $content and $source { + fail('Only one of $content and $source can be specified.') + } + + if $ensure == 'present' and ! $content and ! $source { + fail('One of $content and $source must be specified.') + } + + validate_re($ensure, '^(present|absent)$', + "${ensure} is not supported for ensure. + Allowed values are 'present' and 'absent'.") + + validate_bool($verify_config) + + if $priority { + $priority_prefix = "${priority}-" + } else { + $priority_prefix = '' + } + + ## Apache include does not always work with spaces in the filename + $filename_middle = regsubst($name, ' ', '_', 'G') + $filename = "${priority_prefix}${filename_middle}.conf" + + if ! $verify_config or $ensure == 'absent' { + $notifies = Class['Apache::Service'] + } else { + $notifies = undef + } + + file { "apache_${name}": + ensure => $ensure, + path => "${confdir}/${filename}", + content => $content, + source => $source, + require => Package['httpd'], + notify => $notifies, + } + + if $ensure == 'present' and $verify_config { + exec { "service notify for ${name}": + command => $verify_command, + subscribe => File["apache_${name}"], + refreshonly => true, + notify => Class['Apache::Service'], + before => Exec["remove ${name} if invalid"], + } + + exec { "remove ${name} if invalid": + command => "/bin/rm ${confdir}/${filename}", + unless => $verify_command, + subscribe => File["apache_${name}"], + refreshonly => true, + } + } +} diff --git a/3rdparty/modules/apache/manifests/default_confd_files.pp b/3rdparty/modules/apache/manifests/default_confd_files.pp new file mode 100644 index 000000000..c06b30c83 --- /dev/null +++ b/3rdparty/modules/apache/manifests/default_confd_files.pp @@ -0,0 +1,15 @@ +class apache::default_confd_files ( + $all = true, +) { + # The rest of the conf.d/* files only get loaded if we want them + if $all { + case $::osfamily { + 'freebsd': { + include ::apache::confd::no_accf + } + default: { + # do nothing + } + } + } +} diff --git a/3rdparty/modules/apache/manifests/default_mods.pp b/3rdparty/modules/apache/manifests/default_mods.pp new file mode 100644 index 000000000..9e3c2c69a --- /dev/null +++ b/3rdparty/modules/apache/manifests/default_mods.pp @@ -0,0 +1,173 @@ +class apache::default_mods ( + $all = true, + $mods = undef, + $apache_version = $::apache::apache_version +) { + # These are modules required to run the default configuration. + # They are not configurable at this time, so we just include + # them to make sure it works. + case $::osfamily { + 'redhat': { + ::apache::mod { 'log_config': } + if versioncmp($apache_version, '2.4') >= 0 { + # Lets fork it + # Do not try to load mod_systemd on RHEL/CentOS 6 SCL. + if ( !($::osfamily == 'redhat' and versioncmp($::operatingsystemrelease, '7.0') == -1) and !($::operatingsystem == 'Amazon') ) { + ::apache::mod { 'systemd': } + } + ::apache::mod { 'unixd': } + } + } + 'freebsd': { + ::apache::mod { 'log_config': } + ::apache::mod { 'unixd': } + } + 'Suse': { + ::apache::mod { 'log_config': } + } + default: {} + } + case $::osfamily { + 'gentoo': {} + default: { + ::apache::mod { 'authz_host': } + } + } + # The rest of the modules only get loaded if we want all modules enabled + if $all { + case $::osfamily { + 'debian': { + include ::apache::mod::authn_core + include ::apache::mod::reqtimeout + } + 'redhat': { + include ::apache::mod::actions + include ::apache::mod::authn_core + include ::apache::mod::cache + include ::apache::mod::mime + include ::apache::mod::mime_magic + include ::apache::mod::rewrite + include ::apache::mod::speling + include ::apache::mod::suexec + include ::apache::mod::version + include ::apache::mod::vhost_alias + ::apache::mod { 'auth_digest': } + ::apache::mod { 'authn_anon': } + ::apache::mod { 'authn_dbm': } + ::apache::mod { 'authz_dbm': } + ::apache::mod { 'authz_owner': } + ::apache::mod { 'expires': } + ::apache::mod { 'ext_filter': } + ::apache::mod { 'include': } + ::apache::mod { 'logio': } + ::apache::mod { 'substitute': } + ::apache::mod { 'usertrack': } + + if versioncmp($apache_version, '2.4') < 0 { + ::apache::mod { 'authn_alias': } + ::apache::mod { 'authn_default': } + } + } + 'freebsd': { + include ::apache::mod::actions + include ::apache::mod::authn_core + include ::apache::mod::cache + include ::apache::mod::disk_cache + include ::apache::mod::headers + include ::apache::mod::info + include ::apache::mod::mime_magic + include ::apache::mod::reqtimeout + include ::apache::mod::rewrite + include ::apache::mod::userdir + include ::apache::mod::version + include ::apache::mod::vhost_alias + include ::apache::mod::speling + include ::apache::mod::filter + + ::apache::mod { 'asis': } + ::apache::mod { 'auth_digest': } + ::apache::mod { 'auth_form': } + ::apache::mod { 'authn_anon': } + ::apache::mod { 'authn_dbm': } + ::apache::mod { 'authn_socache': } + ::apache::mod { 'authz_dbd': } + ::apache::mod { 'authz_dbm': } + ::apache::mod { 'authz_owner': } + ::apache::mod { 'dumpio': } + ::apache::mod { 'expires': } + ::apache::mod { 'file_cache': } + ::apache::mod { 'imagemap':} + ::apache::mod { 'include': } + ::apache::mod { 'logio': } + ::apache::mod { 'request': } + ::apache::mod { 'session': } + ::apache::mod { 'unique_id': } + } + default: {} + } + case $::apache::mpm_module { + 'prefork': { + include ::apache::mod::cgi + } + 'worker': { + include ::apache::mod::cgid + } + default: { + # do nothing + } + } + include ::apache::mod::alias + include ::apache::mod::authn_file + include ::apache::mod::autoindex + include ::apache::mod::dav + include ::apache::mod::dav_fs + include ::apache::mod::deflate + include ::apache::mod::dir + include ::apache::mod::mime + include ::apache::mod::negotiation + include ::apache::mod::setenvif + ::apache::mod { 'auth_basic': } + + if versioncmp($apache_version, '2.4') >= 0 { + # filter is needed by mod_deflate + include ::apache::mod::filter + + # authz_core is needed for 'Require' directive + ::apache::mod { 'authz_core': + id => 'authz_core_module', + } + + # lots of stuff seems to break without access_compat + ::apache::mod { 'access_compat': } + } else { + include ::apache::mod::authz_default + } + + include ::apache::mod::authz_user + + ::apache::mod { 'authz_groupfile': } + ::apache::mod { 'env': } + } elsif $mods { + ::apache::default_mods::load { $mods: } + + if versioncmp($apache_version, '2.4') >= 0 { + # authz_core is needed for 'Require' directive + ::apache::mod { 'authz_core': + id => 'authz_core_module', + } + + # filter is needed by mod_deflate + include ::apache::mod::filter + } + } else { + if versioncmp($apache_version, '2.4') >= 0 { + # authz_core is needed for 'Require' directive + ::apache::mod { 'authz_core': + id => 'authz_core_module', + } + + # filter is needed by mod_deflate + include ::apache::mod::filter + } + } +} diff --git a/3rdparty/modules/apache/manifests/default_mods/load.pp b/3rdparty/modules/apache/manifests/default_mods/load.pp new file mode 100644 index 000000000..356e9fa00 --- /dev/null +++ b/3rdparty/modules/apache/manifests/default_mods/load.pp @@ -0,0 +1,8 @@ +# private define +define apache::default_mods::load ($module = $title) { + if defined("apache::mod::${module}") { + include "::apache::mod::${module}" + } else { + ::apache::mod { $module: } + } +} diff --git a/3rdparty/modules/apache/manifests/dev.pp b/3rdparty/modules/apache/manifests/dev.pp new file mode 100644 index 000000000..b1947e934 --- /dev/null +++ b/3rdparty/modules/apache/manifests/dev.pp @@ -0,0 +1,10 @@ +class apache::dev { + include ::apache::params + $packages = $::apache::params::dev_packages + if $packages { # FreeBSD doesn't have dev packages to install + package { $packages: + ensure => present, + require => Package['httpd'], + } + } +} diff --git a/3rdparty/modules/apache/manifests/fastcgi/server.pp b/3rdparty/modules/apache/manifests/fastcgi/server.pp new file mode 100644 index 000000000..afc7c8860 --- /dev/null +++ b/3rdparty/modules/apache/manifests/fastcgi/server.pp @@ -0,0 +1,24 @@ +define apache::fastcgi::server ( + $host = '127.0.0.1:9000', + $timeout = 15, + $flush = false, + $faux_path = "/var/www/${name}.fcgi", + $fcgi_alias = "/${name}.fcgi", + $file_type = 'application/x-httpd-php' +) { + include apache::mod::fastcgi + + Apache::Mod['fastcgi'] -> Apache::Fastcgi::Server[$title] + + file { "fastcgi-pool-${name}.conf": + ensure => present, + path => "${::apache::confd_dir}/fastcgi-pool-${name}.conf", + owner => 'root', + group => $::apache::params::root_group, + mode => '0644', + content => template('apache/fastcgi/server.erb'), + require => Exec["mkdir ${::apache::confd_dir}"], + before => File[$::apache::confd_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/init.pp b/3rdparty/modules/apache/manifests/init.pp new file mode 100644 index 000000000..9e6da9813 --- /dev/null +++ b/3rdparty/modules/apache/manifests/init.pp @@ -0,0 +1,386 @@ +# Class: apache +# +# This class installs Apache +# +# Parameters: +# +# Actions: +# - Install Apache +# - Manage Apache service +# +# Requires: +# +# Sample Usage: +# +class apache ( + $apache_name = $::apache::params::apache_name, + $service_name = $::apache::params::service_name, + $default_mods = true, + $default_vhost = true, + $default_charset = undef, + $default_confd_files = true, + $default_ssl_vhost = false, + $default_ssl_cert = $::apache::params::default_ssl_cert, + $default_ssl_key = $::apache::params::default_ssl_key, + $default_ssl_chain = undef, + $default_ssl_ca = undef, + $default_ssl_crl_path = undef, + $default_ssl_crl = undef, + $default_ssl_crl_check = undef, + $default_type = 'none', + $ip = undef, + $service_enable = true, + $service_manage = true, + $service_ensure = 'running', + $service_restart = undef, + $purge_configs = true, + $purge_vhost_dir = undef, + $purge_vdir = false, + $serveradmin = 'root@localhost', + $sendfile = 'On', + $error_documents = false, + $timeout = '120', + $httpd_dir = $::apache::params::httpd_dir, + $server_root = $::apache::params::server_root, + $conf_dir = $::apache::params::conf_dir, + $confd_dir = $::apache::params::confd_dir, + $vhost_dir = $::apache::params::vhost_dir, + $vhost_enable_dir = $::apache::params::vhost_enable_dir, + $mod_dir = $::apache::params::mod_dir, + $mod_enable_dir = $::apache::params::mod_enable_dir, + $mpm_module = $::apache::params::mpm_module, + $lib_path = $::apache::params::lib_path, + $conf_template = $::apache::params::conf_template, + $servername = $::apache::params::servername, + $manage_user = true, + $manage_group = true, + $user = $::apache::params::user, + $group = $::apache::params::group, + $keepalive = $::apache::params::keepalive, + $keepalive_timeout = $::apache::params::keepalive_timeout, + $max_keepalive_requests = $::apache::params::max_keepalive_requests, + $logroot = $::apache::params::logroot, + $logroot_mode = $::apache::params::logroot_mode, + $log_level = $::apache::params::log_level, + $log_formats = {}, + $ports_file = $::apache::params::ports_file, + $docroot = $::apache::params::docroot, + $apache_version = $::apache::version::default, + $server_tokens = 'OS', + $server_signature = 'On', + $trace_enable = 'On', + $allow_encoded_slashes = undef, + $package_ensure = 'installed', + $use_optional_includes = $::apache::params::use_optional_includes, +) inherits ::apache::params { + validate_bool($default_vhost) + validate_bool($default_ssl_vhost) + validate_bool($default_confd_files) + # true/false is sufficient for both ensure and enable + validate_bool($service_enable) + validate_bool($service_manage) + validate_bool($use_optional_includes) + + $valid_mpms_re = $apache_version ? { + '2.4' => '(event|itk|peruser|prefork|worker)', + default => '(event|itk|prefork|worker)' + } + + if $mpm_module { + validate_re($mpm_module, $valid_mpms_re) + } + + if $allow_encoded_slashes { + validate_re($allow_encoded_slashes, '(^on$|^off$|^nodecode$)', "${allow_encoded_slashes} is not permitted for allow_encoded_slashes. Allowed values are 'on', 'off' or 'nodecode'.") + } + + # NOTE: on FreeBSD it's mpm module's responsibility to install httpd package. + # NOTE: the same strategy may be introduced for other OSes. For this, you + # should delete the 'if' block below and modify all MPM modules' manifests + # such that they include apache::package class (currently event.pp, itk.pp, + # peruser.pp, prefork.pp, worker.pp). + if $::osfamily != 'FreeBSD' { + package { 'httpd': + ensure => $package_ensure, + name => $apache_name, + notify => Class['Apache::Service'], + } + } + validate_re($sendfile, [ '^[oO]n$' , '^[oO]ff$' ]) + + # declare the web server user and group + # Note: requiring the package means the package ought to create them and not puppet + validate_bool($manage_user) + if $manage_user { + user { $user: + ensure => present, + gid => $group, + require => Package['httpd'], + } + } + validate_bool($manage_group) + if $manage_group { + group { $group: + ensure => present, + require => Package['httpd'] + } + } + + validate_apache_log_level($log_level) + + class { '::apache::service': + service_name => $service_name, + service_enable => $service_enable, + service_manage => $service_manage, + service_ensure => $service_ensure, + service_restart => $service_restart, + } + + # Deprecated backwards-compatibility + if $purge_vdir { + warning('Class[\'apache\'] parameter purge_vdir is deprecated in favor of purge_configs') + $purge_confd = $purge_vdir + } else { + $purge_confd = $purge_configs + } + + # Set purge vhostd appropriately + if $purge_vhost_dir == undef { + $purge_vhostd = $purge_confd + } else { + $purge_vhostd = $purge_vhost_dir + } + + Exec { + path => '/bin:/sbin:/usr/bin:/usr/sbin', + } + + exec { "mkdir ${confd_dir}": + creates => $confd_dir, + require => Package['httpd'], + } + file { $confd_dir: + ensure => directory, + recurse => true, + purge => $purge_confd, + notify => Class['Apache::Service'], + require => Package['httpd'], + } + + if ! defined(File[$mod_dir]) { + exec { "mkdir ${mod_dir}": + creates => $mod_dir, + require => Package['httpd'], + } + # Don't purge available modules if an enable dir is used + $purge_mod_dir = $purge_configs and !$mod_enable_dir + file { $mod_dir: + ensure => directory, + recurse => true, + purge => $purge_mod_dir, + notify => Class['Apache::Service'], + require => Package['httpd'], + } + } + + if $mod_enable_dir and ! defined(File[$mod_enable_dir]) { + $mod_load_dir = $mod_enable_dir + exec { "mkdir ${mod_enable_dir}": + creates => $mod_enable_dir, + require => Package['httpd'], + } + file { $mod_enable_dir: + ensure => directory, + recurse => true, + purge => $purge_configs, + notify => Class['Apache::Service'], + require => Package['httpd'], + } + } else { + $mod_load_dir = $mod_dir + } + + if ! defined(File[$vhost_dir]) { + exec { "mkdir ${vhost_dir}": + creates => $vhost_dir, + require => Package['httpd'], + } + file { $vhost_dir: + ensure => directory, + recurse => true, + purge => $purge_vhostd, + notify => Class['Apache::Service'], + require => Package['httpd'], + } + } + + if $vhost_enable_dir and ! defined(File[$vhost_enable_dir]) { + $vhost_load_dir = $vhost_enable_dir + exec { "mkdir ${vhost_load_dir}": + creates => $vhost_load_dir, + require => Package['httpd'], + } + file { $vhost_enable_dir: + ensure => directory, + recurse => true, + purge => $purge_vhostd, + notify => Class['Apache::Service'], + require => Package['httpd'], + } + } else { + $vhost_load_dir = $vhost_dir + } + + concat { $ports_file: + owner => 'root', + group => $::apache::params::root_group, + mode => '0644', + notify => Class['Apache::Service'], + require => Package['httpd'], + } + concat::fragment { 'Apache ports header': + ensure => present, + target => $ports_file, + content => template('apache/ports_header.erb') + } + + if $::apache::conf_dir and $::apache::params::conf_file { + case $::osfamily { + 'debian': { + $pidfile = "\${APACHE_PID_FILE}" + $error_log = 'error.log' + $scriptalias = '/usr/lib/cgi-bin' + $access_log_file = 'access.log' + } + 'redhat': { + $pidfile = 'run/httpd.pid' + $error_log = 'error_log' + $scriptalias = '/var/www/cgi-bin' + $access_log_file = 'access_log' + } + 'freebsd': { + $pidfile = '/var/run/httpd.pid' + $error_log = 'httpd-error.log' + $scriptalias = '/usr/local/www/apache24/cgi-bin' + $access_log_file = 'httpd-access.log' + } 'gentoo': { + $pidfile = '/run/apache2.pid' + $error_log = 'error.log' + $error_documents_path = '/usr/share/apache2/error' + $scriptalias = '/var/www/localhost/cgi-bin' + $access_log_file = 'access.log' + + ::portage::makeconf { 'apache2_modules': + content => $default_mods, + } + file { [ + '/etc/apache2/modules.d/.keep_www-servers_apache-2', + '/etc/apache2/vhosts.d/.keep_www-servers_apache-2' + ]: + ensure => absent, + require => Package['httpd'], + } + } + 'Suse': { + $pidfile = '/var/run/httpd2.pid' + $error_log = 'error.log' + $scriptalias = '/usr/lib/cgi-bin' + $access_log_file = 'access.log' + } + default: { + fail("Unsupported osfamily ${::osfamily}") + } + } + + $apxs_workaround = $::osfamily ? { + 'freebsd' => true, + default => false + } + + # Template uses: + # - $pidfile + # - $user + # - $group + # - $logroot + # - $error_log + # - $sendfile + # - $mod_dir + # - $ports_file + # - $confd_dir + # - $vhost_dir + # - $error_documents + # - $error_documents_path + # - $apxs_workaround + # - $keepalive + # - $keepalive_timeout + # - $max_keepalive_requests + # - $server_root + # - $server_tokens + # - $server_signature + # - $trace_enable + file { "${::apache::conf_dir}/${::apache::params::conf_file}": + ensure => file, + content => template($conf_template), + notify => Class['Apache::Service'], + require => Package['httpd'], + } + + # preserve back-wards compatibility to the times when default_mods was + # only a boolean value. Now it can be an array (too) + if is_array($default_mods) { + class { '::apache::default_mods': + all => false, + mods => $default_mods, + } + } else { + class { '::apache::default_mods': + all => $default_mods, + } + } + class { '::apache::default_confd_files': + all => $default_confd_files + } + if $mpm_module { + class { "::apache::mod::${mpm_module}": } + } + + $default_vhost_ensure = $default_vhost ? { + true => 'present', + false => 'absent' + } + $default_ssl_vhost_ensure = $default_ssl_vhost ? { + true => 'present', + false => 'absent' + } + + ::apache::vhost { 'default': + ensure => $default_vhost_ensure, + port => 80, + docroot => $docroot, + scriptalias => $scriptalias, + serveradmin => $serveradmin, + access_log_file => $access_log_file, + priority => '15', + ip => $ip, + logroot_mode => $logroot_mode, + manage_docroot => $default_vhost, + } + $ssl_access_log_file = $::osfamily ? { + 'freebsd' => $access_log_file, + default => "ssl_${access_log_file}", + } + ::apache::vhost { 'default-ssl': + ensure => $default_ssl_vhost_ensure, + port => 443, + ssl => true, + docroot => $docroot, + scriptalias => $scriptalias, + serveradmin => $serveradmin, + access_log_file => $ssl_access_log_file, + priority => '15', + ip => $ip, + logroot_mode => $logroot_mode, + manage_docroot => $default_ssl_vhost, + } + } +} diff --git a/3rdparty/modules/apache/manifests/listen.pp b/3rdparty/modules/apache/manifests/listen.pp new file mode 100644 index 000000000..e6a8a3c76 --- /dev/null +++ b/3rdparty/modules/apache/manifests/listen.pp @@ -0,0 +1,10 @@ +define apache::listen { + $listen_addr_port = $name + + # Template uses: $listen_addr_port + concat::fragment { "Listen ${listen_addr_port}": + ensure => present, + target => $::apache::ports_file, + content => template('apache/listen.erb'), + } +} diff --git a/3rdparty/modules/apache/manifests/mod.pp b/3rdparty/modules/apache/manifests/mod.pp new file mode 100644 index 000000000..920114a7c --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod.pp @@ -0,0 +1,165 @@ +define apache::mod ( + $package = undef, + $package_ensure = 'present', + $lib = undef, + $lib_path = $::apache::lib_path, + $id = undef, + $path = undef, + $loadfile_name = undef, + $loadfiles = undef, +) { + if ! defined(Class['apache']) { + fail('You must include the apache base class before using any apache defined resources') + } + + $mod = $name + #include apache #This creates duplicate resources in rspec-puppet + $mod_dir = $::apache::mod_dir + + # Determine if we have special lib + $mod_libs = $::apache::params::mod_libs + if $lib { + $_lib = $lib + } elsif has_key($mod_libs, $mod) { # 2.6 compatibility hack + $_lib = $mod_libs[$mod] + } else { + $_lib = "mod_${mod}.so" + } + + # Determine if declaration specified a path to the module + if $path { + $_path = $path + } else { + $_path = "${lib_path}/${_lib}" + } + + if $id { + $_id = $id + } else { + $_id = "${mod}_module" + } + + if $loadfile_name { + $_loadfile_name = $loadfile_name + } else { + $_loadfile_name = "${mod}.load" + } + + # Determine if we have a package + $mod_packages = $::apache::params::mod_packages + if $package { + $_package = $package + } elsif has_key($mod_packages, $mod) { # 2.6 compatibility hack + $_package = $mod_packages[$mod] + } else { + $_package = undef + } + if $_package and ! defined(Package[$_package]) { + # note: FreeBSD/ports uses apxs tool to activate modules; apxs clutters + # httpd.conf with 'LoadModule' directives; here, by proper resource + # ordering, we ensure that our version of httpd.conf is reverted after + # the module gets installed. + $package_before = $::osfamily ? { + 'freebsd' => [ + File[$_loadfile_name], + File["${::apache::conf_dir}/${::apache::params::conf_file}"] + ], + default => File[$_loadfile_name], + } + # if there are any packages, they should be installed before the associated conf file + Package[$_package] -> File<| title == "${mod}.conf" |> + # $_package may be an array + package { $_package: + ensure => $package_ensure, + require => Package['httpd'], + before => $package_before, + } + } + + file { $_loadfile_name: + ensure => file, + path => "${mod_dir}/${_loadfile_name}", + owner => 'root', + group => $::apache::params::root_group, + mode => '0644', + content => template('apache/mod/load.erb'), + require => [ + Package['httpd'], + Exec["mkdir ${mod_dir}"], + ], + before => File[$mod_dir], + notify => Class['apache::service'], + } + + if $::osfamily == 'Debian' { + $enable_dir = $::apache::mod_enable_dir + file{ "${_loadfile_name} symlink": + ensure => link, + path => "${enable_dir}/${_loadfile_name}", + target => "${mod_dir}/${_loadfile_name}", + owner => 'root', + group => $::apache::params::root_group, + mode => '0644', + require => [ + File[$_loadfile_name], + Exec["mkdir ${enable_dir}"], + ], + before => File[$enable_dir], + notify => Class['apache::service'], + } + # Each module may have a .conf file as well, which should be + # defined in the class apache::mod::module + # Some modules do not require this file. + if defined(File["${mod}.conf"]) { + file{ "${mod}.conf symlink": + ensure => link, + path => "${enable_dir}/${mod}.conf", + target => "${mod_dir}/${mod}.conf", + owner => 'root', + group => $::apache::params::root_group, + mode => '0644', + require => [ + File["${mod}.conf"], + Exec["mkdir ${enable_dir}"], + ], + before => File[$enable_dir], + notify => Class['apache::service'], + } + } + } elsif $::osfamily == 'Suse' { + $enable_dir = $::apache::mod_enable_dir + file{ "${_loadfile_name} symlink": + ensure => link, + path => "${enable_dir}/${_loadfile_name}", + target => "${mod_dir}/${_loadfile_name}", + owner => 'root', + group => $::apache::params::root_group, + mode => '0644', + require => [ + File[$_loadfile_name], + Exec["mkdir ${enable_dir}"], + ], + before => File[$enable_dir], + notify => Class['apache::service'], + } + # Each module may have a .conf file as well, which should be + # defined in the class apache::mod::module + # Some modules do not require this file. + if defined(File["${mod}.conf"]) { + file{ "${mod}.conf symlink": + ensure => link, + path => "${enable_dir}/${mod}.conf", + target => "${mod_dir}/${mod}.conf", + owner => 'root', + group => $::apache::params::root_group, + mode => '0644', + require => [ + File["${mod}.conf"], + Exec["mkdir ${enable_dir}"], + ], + before => File[$enable_dir], + notify => Class['apache::service'], + } + } + } +} diff --git a/3rdparty/modules/apache/manifests/mod/actions.pp b/3rdparty/modules/apache/manifests/mod/actions.pp new file mode 100644 index 000000000..3b60f297f --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/actions.pp @@ -0,0 +1,3 @@ +class apache::mod::actions { + apache::mod { 'actions': } +} diff --git a/3rdparty/modules/apache/manifests/mod/alias.pp b/3rdparty/modules/apache/manifests/mod/alias.pp new file mode 100644 index 000000000..2f078f645 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/alias.pp @@ -0,0 +1,27 @@ +class apache::mod::alias( + $apache_version = $apache::apache_version, + $icons_options = 'Indexes MultiViews', +) { + $ver24 = versioncmp($apache_version, '2.4') >= 0 + + $icons_path = $::osfamily ? { + 'debian' => '/usr/share/apache2/icons', + 'Suse' => '/usr/share/apache2/icons', + 'redhat' => $ver24 ? { + true => '/usr/share/httpd/icons', + default => '/var/www/icons', + }, + 'freebsd' => '/usr/local/www/apache24/icons', + 'gentoo' => '/usr/share/apache2/icons', + } + apache::mod { 'alias': } + # Template uses $icons_path + file { 'alias.conf': + ensure => file, + path => "${::apache::mod_dir}/alias.conf", + content => template('apache/mod/alias.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/auth_basic.pp b/3rdparty/modules/apache/manifests/mod/auth_basic.pp new file mode 100644 index 000000000..cacfafa4d --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/auth_basic.pp @@ -0,0 +1,3 @@ +class apache::mod::auth_basic { + ::apache::mod { 'auth_basic': } +} diff --git a/3rdparty/modules/apache/manifests/mod/auth_cas.pp b/3rdparty/modules/apache/manifests/mod/auth_cas.pp new file mode 100644 index 000000000..5b13af66a --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/auth_cas.pp @@ -0,0 +1,48 @@ +class apache::mod::auth_cas ( + $cas_login_url, + $cas_validate_url, + $cas_cookie_path = $::apache::params::cas_cookie_path, + $cas_version = 2, + $cas_debug = 'Off', + $cas_validate_depth = undef, + $cas_certificate_path = undef, + $cas_proxy_validate_url = undef, + $cas_root_proxied_as = undef, + $cas_cookie_entropy = undef, + $cas_timeout = undef, + $cas_idle_timeout = undef, + $cas_cache_clean_interval = undef, + $cas_cookie_domain = undef, + $cas_cookie_http_only = undef, + $cas_authoritative = undef, + $suppress_warning = false, +) { + + validate_string($cas_login_url, $cas_validate_url, $cas_cookie_path) + + if $::osfamily == 'RedHat' and ! $suppress_warning { + warning('RedHat distributions do not have Apache mod_auth_cas in their default package repositories.') + } + + ::apache::mod { 'auth_cas': } + + file { $cas_cookie_path: + ensure => directory, + before => File['auth_cas.conf'], + mode => '0750', + owner => $apache::user, + group => $apache::group, + } + + # Template uses + # - All variables beginning with cas_ + file { 'auth_cas.conf': + ensure => file, + path => "${::apache::mod_dir}/auth_cas.conf", + content => template('apache/mod/auth_cas.conf.erb'), + require => [ Exec["mkdir ${::apache::mod_dir}"], ], + before => File[$::apache::mod_dir], + notify => Class['Apache::Service'], + } + +} diff --git a/3rdparty/modules/apache/manifests/mod/auth_kerb.pp b/3rdparty/modules/apache/manifests/mod/auth_kerb.pp new file mode 100644 index 000000000..6b53262a1 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/auth_kerb.pp @@ -0,0 +1,5 @@ +class apache::mod::auth_kerb { + ::apache::mod { 'auth_kerb': } +} + + diff --git a/3rdparty/modules/apache/manifests/mod/authn_core.pp b/3rdparty/modules/apache/manifests/mod/authn_core.pp new file mode 100644 index 000000000..c5ce5b107 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/authn_core.pp @@ -0,0 +1,7 @@ +class apache::mod::authn_core( + $apache_version = $::apache::apache_version +) { + if versioncmp($apache_version, '2.4') >= 0 { + ::apache::mod { 'authn_core': } + } +} diff --git a/3rdparty/modules/apache/manifests/mod/authn_file.pp b/3rdparty/modules/apache/manifests/mod/authn_file.pp new file mode 100644 index 000000000..bc787244a --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/authn_file.pp @@ -0,0 +1,3 @@ +class apache::mod::authn_file { + ::apache::mod { 'authn_file': } +} diff --git a/3rdparty/modules/apache/manifests/mod/authnz_ldap.pp b/3rdparty/modules/apache/manifests/mod/authnz_ldap.pp new file mode 100644 index 000000000..b75369ffc --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/authnz_ldap.pp @@ -0,0 +1,19 @@ +class apache::mod::authnz_ldap ( + $verifyServerCert = true, +) { + include '::apache::mod::ldap' + ::apache::mod { 'authnz_ldap': } + + validate_bool($verifyServerCert) + + # Template uses: + # - $verifyServerCert + file { 'authnz_ldap.conf': + ensure => file, + path => "${::apache::mod_dir}/authnz_ldap.conf", + content => template('apache/mod/authnz_ldap.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/authz_default.pp b/3rdparty/modules/apache/manifests/mod/authz_default.pp new file mode 100644 index 000000000..23edd9b5a --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/authz_default.pp @@ -0,0 +1,3 @@ +class apache::mod::authz_default { + ::apache::mod { 'authz_default': } +} diff --git a/3rdparty/modules/apache/manifests/mod/authz_user.pp b/3rdparty/modules/apache/manifests/mod/authz_user.pp new file mode 100644 index 000000000..948a3e2c9 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/authz_user.pp @@ -0,0 +1,3 @@ +class apache::mod::authz_user { + ::apache::mod { 'authz_user': } +} diff --git a/3rdparty/modules/apache/manifests/mod/autoindex.pp b/3rdparty/modules/apache/manifests/mod/autoindex.pp new file mode 100644 index 000000000..c0969a814 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/autoindex.pp @@ -0,0 +1,12 @@ +class apache::mod::autoindex { + ::apache::mod { 'autoindex': } + # Template uses no variables + file { 'autoindex.conf': + ensure => file, + path => "${::apache::mod_dir}/autoindex.conf", + content => template('apache/mod/autoindex.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/cache.pp b/3rdparty/modules/apache/manifests/mod/cache.pp new file mode 100644 index 000000000..4ab9f44ba --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/cache.pp @@ -0,0 +1,3 @@ +class apache::mod::cache { + ::apache::mod { 'cache': } +} diff --git a/3rdparty/modules/apache/manifests/mod/cgi.pp b/3rdparty/modules/apache/manifests/mod/cgi.pp new file mode 100644 index 000000000..91352e8c8 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/cgi.pp @@ -0,0 +1,10 @@ +class apache::mod::cgi { + case $::osfamily { + 'FreeBSD': {} + default: { + Class['::apache::mod::prefork'] -> Class['::apache::mod::cgi'] + } + } + + ::apache::mod { 'cgi': } +} diff --git a/3rdparty/modules/apache/manifests/mod/cgid.pp b/3rdparty/modules/apache/manifests/mod/cgid.pp new file mode 100644 index 000000000..8946f652b --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/cgid.pp @@ -0,0 +1,28 @@ +class apache::mod::cgid { + case $::osfamily { + 'FreeBSD': {} + default: { + Class['::apache::mod::worker'] -> Class['::apache::mod::cgid'] + } + } + + # Debian specifies it's cgid sock path, but RedHat uses the default value + # with no config file + $cgisock_path = $::osfamily ? { + 'debian' => "\${APACHE_RUN_DIR}/cgisock", + 'freebsd' => 'cgisock', + default => undef, + } + ::apache::mod { 'cgid': } + if $cgisock_path { + # Template uses $cgisock_path + file { 'cgid.conf': + ensure => file, + path => "${::apache::mod_dir}/cgid.conf", + content => template('apache/mod/cgid.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } + } +} diff --git a/3rdparty/modules/apache/manifests/mod/dav.pp b/3rdparty/modules/apache/manifests/mod/dav.pp new file mode 100644 index 000000000..ade9c0809 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/dav.pp @@ -0,0 +1,3 @@ +class apache::mod::dav { + ::apache::mod { 'dav': } +} diff --git a/3rdparty/modules/apache/manifests/mod/dav_fs.pp b/3rdparty/modules/apache/manifests/mod/dav_fs.pp new file mode 100644 index 000000000..af037e32d --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/dav_fs.pp @@ -0,0 +1,20 @@ +class apache::mod::dav_fs { + $dav_lock = $::osfamily ? { + 'debian' => "\${APACHE_LOCK_DIR}/DAVLock", + 'freebsd' => '/usr/local/var/DavLock', + default => '/var/lib/dav/lockdb', + } + + Class['::apache::mod::dav'] -> Class['::apache::mod::dav_fs'] + ::apache::mod { 'dav_fs': } + + # Template uses: $dav_lock + file { 'dav_fs.conf': + ensure => file, + path => "${::apache::mod_dir}/dav_fs.conf", + content => template('apache/mod/dav_fs.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/dav_svn.pp b/3rdparty/modules/apache/manifests/mod/dav_svn.pp new file mode 100644 index 000000000..6e70598d0 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/dav_svn.pp @@ -0,0 +1,20 @@ +class apache::mod::dav_svn ( + $authz_svn_enabled = false, +) { + Class['::apache::mod::dav'] -> Class['::apache::mod::dav_svn'] + include ::apache::mod::dav + ::apache::mod { 'dav_svn': } + + if $::osfamily == 'Debian' and ($::operatingsystemmajrelease != '6' and $::operatingsystemmajrelease != '10.04' and $::operatingsystemrelease != '10.04') { + $loadfile_name = undef + } else { + $loadfile_name = 'dav_svn_authz_svn.load' + } + + if $authz_svn_enabled { + ::apache::mod { 'authz_svn': + loadfile_name => $loadfile_name, + require => Apache::Mod['dav_svn'], + } + } +} diff --git a/3rdparty/modules/apache/manifests/mod/deflate.pp b/3rdparty/modules/apache/manifests/mod/deflate.pp new file mode 100644 index 000000000..9b8d43621 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/deflate.pp @@ -0,0 +1,24 @@ +class apache::mod::deflate ( + $types = [ + 'text/html text/plain text/xml', + 'text/css', + 'application/x-javascript application/javascript application/ecmascript', + 'application/rss+xml' + ], + $notes = { + 'Input' => 'instream', + 'Output' => 'outstream', + 'Ratio' => 'ratio' + } +) { + ::apache::mod { 'deflate': } + + file { 'deflate.conf': + ensure => file, + path => "${::apache::mod_dir}/deflate.conf", + content => template('apache/mod/deflate.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/dev.pp b/3rdparty/modules/apache/manifests/mod/dev.pp new file mode 100644 index 000000000..5abdedd36 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/dev.pp @@ -0,0 +1,5 @@ +class apache::mod::dev { + # Development packages are not apache modules + warning('apache::mod::dev is deprecated; please use apache::dev') + include ::apache::dev +} diff --git a/3rdparty/modules/apache/manifests/mod/dir.pp b/3rdparty/modules/apache/manifests/mod/dir.pp new file mode 100644 index 000000000..6243a1bb7 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/dir.pp @@ -0,0 +1,21 @@ +# Note: this sets the global DirectoryIndex directive, it may be necessary to consider being able to modify the apache::vhost to declare DirectoryIndex statements in a vhost configuration +# Parameters: +# - $indexes provides a string for the DirectoryIndex directive http://httpd.apache.org/docs/current/mod/mod_dir.html#directoryindex +class apache::mod::dir ( + $dir = 'public_html', + $indexes = ['index.html','index.html.var','index.cgi','index.pl','index.php','index.xhtml'], +) { + validate_array($indexes) + ::apache::mod { 'dir': } + + # Template uses + # - $indexes + file { 'dir.conf': + ensure => file, + path => "${::apache::mod_dir}/dir.conf", + content => template('apache/mod/dir.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/disk_cache.pp b/3rdparty/modules/apache/manifests/mod/disk_cache.pp new file mode 100644 index 000000000..2b9d8a910 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/disk_cache.pp @@ -0,0 +1,31 @@ +class apache::mod::disk_cache { + $cache_root = $::osfamily ? { + 'debian' => '/var/cache/apache2/mod_disk_cache', + 'redhat' => '/var/cache/mod_proxy', + 'freebsd' => '/var/cache/mod_disk_cache', + 'gentoo' => '/var/cache/apache2/mod_disk_cache', + } + + $mod_name = $::osfamily ? { + 'FreeBSD' => 'cache_disk', + default => 'disk_cache', + } + + if $::osfamily != 'FreeBSD' { + # FIXME: investigate why disk_cache was dependent on proxy + # NOTE: on FreeBSD disk_cache is compiled by default but proxy is not + Class['::apache::mod::proxy'] -> Class['::apache::mod::disk_cache'] + } + Class['::apache::mod::cache'] -> Class['::apache::mod::disk_cache'] + + apache::mod { $mod_name: } + # Template uses $cache_proxy + file { 'disk_cache.conf': + ensure => file, + path => "${::apache::mod_dir}/disk_cache.conf", + content => template('apache/mod/disk_cache.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/event.pp b/3rdparty/modules/apache/manifests/mod/event.pp new file mode 100644 index 000000000..389120cb7 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/event.pp @@ -0,0 +1,71 @@ +class apache::mod::event ( + $startservers = '2', + $maxclients = '150', + $minsparethreads = '25', + $maxsparethreads = '75', + $threadsperchild = '25', + $maxrequestsperchild = '0', + $serverlimit = '25', + $apache_version = $::apache::apache_version, + $threadlimit = '64', + $listenbacklog = '511', + $maxrequestworkers = '250', + $maxconnectionsperchild = '0', +) { + if defined(Class['apache::mod::itk']) { + fail('May not include both apache::mod::event and apache::mod::itk on the same node') + } + if defined(Class['apache::mod::peruser']) { + fail('May not include both apache::mod::event and apache::mod::peruser on the same node') + } + if defined(Class['apache::mod::prefork']) { + fail('May not include both apache::mod::event and apache::mod::prefork on the same node') + } + if defined(Class['apache::mod::worker']) { + fail('May not include both apache::mod::event and apache::mod::worker on the same node') + } + File { + owner => 'root', + group => $::apache::params::root_group, + mode => '0644', + } + + # Template uses: + # - $startservers + # - $maxclients + # - $minsparethreads + # - $maxsparethreads + # - $threadsperchild + # - $maxrequestsperchild + # - $serverlimit + file { "${::apache::mod_dir}/event.conf": + ensure => file, + content => template('apache/mod/event.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } + + case $::osfamily { + 'redhat': { + if versioncmp($apache_version, '2.4') >= 0 { + apache::mpm{ 'event': + apache_version => $apache_version, + } + } + } + 'debian','freebsd' : { + apache::mpm{ 'event': + apache_version => $apache_version, + } + } + 'gentoo': { + ::portage::makeconf { 'apache2_mpms': + content => 'event', + } + } + default: { + fail("Unsupported osfamily ${::osfamily}") + } + } +} diff --git a/3rdparty/modules/apache/manifests/mod/expires.pp b/3rdparty/modules/apache/manifests/mod/expires.pp new file mode 100644 index 000000000..10542916a --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/expires.pp @@ -0,0 +1,20 @@ +class apache::mod::expires ( + $expires_active = true, + $expires_default = undef, + $expires_by_type = undef, +) { + ::apache::mod { 'expires': } + + # Template uses + # $expires_active + # $expires_default + # $expires_by_type + file { 'expires.conf': + ensure => file, + path => "${::apache::mod_dir}/expires.conf", + content => template('apache/mod/expires.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/fastcgi.pp b/3rdparty/modules/apache/manifests/mod/fastcgi.pp new file mode 100644 index 000000000..1f7e5df4f --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/fastcgi.pp @@ -0,0 +1,24 @@ +class apache::mod::fastcgi { + + # Debian specifies it's fastcgi lib path, but RedHat uses the default value + # with no config file + $fastcgi_lib_path = $::apache::params::fastcgi_lib_path + + ::apache::mod { 'fastcgi': } + + if $fastcgi_lib_path { + # Template uses: + # - $fastcgi_server + # - $fastcgi_socket + # - $fastcgi_dir + file { 'fastcgi.conf': + ensure => file, + path => "${::apache::mod_dir}/fastcgi.conf", + content => template('apache/mod/fastcgi.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } + } + +} diff --git a/3rdparty/modules/apache/manifests/mod/fcgid.pp b/3rdparty/modules/apache/manifests/mod/fcgid.pp new file mode 100644 index 000000000..a143c2b43 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/fcgid.pp @@ -0,0 +1,24 @@ +class apache::mod::fcgid( + $options = {}, +) { + if $::osfamily == 'RedHat' and $::operatingsystemmajrelease == '7' { + $loadfile_name = 'unixd_fcgid.load' + } else { + $loadfile_name = undef + } + + ::apache::mod { 'fcgid': + loadfile_name => $loadfile_name + } + + # Template uses: + # - $options + file { 'fcgid.conf': + ensure => file, + path => "${::apache::mod_dir}/fcgid.conf", + content => template('apache/mod/fcgid.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/filter.pp b/3rdparty/modules/apache/manifests/mod/filter.pp new file mode 100644 index 000000000..26dc488b3 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/filter.pp @@ -0,0 +1,3 @@ +class apache::mod::filter { + ::apache::mod { 'filter': } +} diff --git a/3rdparty/modules/apache/manifests/mod/geoip.pp b/3rdparty/modules/apache/manifests/mod/geoip.pp new file mode 100644 index 000000000..4e87cb96a --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/geoip.pp @@ -0,0 +1,29 @@ +class apache::mod::geoip ( + $enable = false, + $db_file = '/usr/share/GeoIP/GeoIP.dat', + $flag = 'Standard', + $output = 'All', + $enable_utf8 = undef, + $scan_proxy_headers = undef, + $use_last_xforwarededfor_ip = undef, +) { + ::apache::mod { 'geoip': } + + # Template uses: + # - enable + # - db_file + # - flag + # - output + # - enable_utf8 + # - scan_proxy_headers + # - use_last_xforwarededfor_ip + file { 'geoip.conf': + ensure => file, + path => "${::apache::mod_dir}/geoip.conf", + content => template('apache/mod/geoip.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } + +} diff --git a/3rdparty/modules/apache/manifests/mod/headers.pp b/3rdparty/modules/apache/manifests/mod/headers.pp new file mode 100644 index 000000000..d18c5e279 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/headers.pp @@ -0,0 +1,3 @@ +class apache::mod::headers { + ::apache::mod { 'headers': } +} diff --git a/3rdparty/modules/apache/manifests/mod/include.pp b/3rdparty/modules/apache/manifests/mod/include.pp new file mode 100644 index 000000000..edbe81f32 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/include.pp @@ -0,0 +1,3 @@ +class apache::mod::include { + ::apache::mod { 'include': } +} diff --git a/3rdparty/modules/apache/manifests/mod/info.pp b/3rdparty/modules/apache/manifests/mod/info.pp new file mode 100644 index 000000000..f0d03eb0f --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/info.pp @@ -0,0 +1,18 @@ +class apache::mod::info ( + $allow_from = ['127.0.0.1','::1'], + $apache_version = $::apache::apache_version, + $restrict_access = true, +){ + apache::mod { 'info': } + # Template uses + # $allow_from + # $apache_version + file { 'info.conf': + ensure => file, + path => "${::apache::mod_dir}/info.conf", + content => template('apache/mod/info.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/itk.pp b/3rdparty/modules/apache/manifests/mod/itk.pp new file mode 100644 index 000000000..2be7d832d --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/itk.pp @@ -0,0 +1,60 @@ +class apache::mod::itk ( + $startservers = '8', + $minspareservers = '5', + $maxspareservers = '20', + $serverlimit = '256', + $maxclients = '256', + $maxrequestsperchild = '4000', + $apache_version = $::apache::apache_version, +) { + if defined(Class['apache::mod::event']) { + fail('May not include both apache::mod::itk and apache::mod::event on the same node') + } + if defined(Class['apache::mod::peruser']) { + fail('May not include both apache::mod::itk and apache::mod::peruser on the same node') + } + if versioncmp($apache_version, '2.4') < 0 { + if defined(Class['apache::mod::prefork']) { + fail('May not include both apache::mod::itk and apache::mod::prefork on the same node') + } + } + if defined(Class['apache::mod::worker']) { + fail('May not include both apache::mod::itk and apache::mod::worker on the same node') + } + File { + owner => 'root', + group => $::apache::params::root_group, + mode => '0644', + } + + # Template uses: + # - $startservers + # - $minspareservers + # - $maxspareservers + # - $serverlimit + # - $maxclients + # - $maxrequestsperchild + file { "${::apache::mod_dir}/itk.conf": + ensure => file, + content => template('apache/mod/itk.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } + + case $::osfamily { + 'debian', 'freebsd': { + apache::mpm{ 'itk': + apache_version => $apache_version, + } + } + 'gentoo': { + ::portage::makeconf { 'apache2_mpms': + content => 'itk', + } + } + default: { + fail("Unsupported osfamily ${::osfamily}") + } + } +} diff --git a/3rdparty/modules/apache/manifests/mod/ldap.pp b/3rdparty/modules/apache/manifests/mod/ldap.pp new file mode 100644 index 000000000..fbd56d539 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/ldap.pp @@ -0,0 +1,14 @@ +class apache::mod::ldap ( + $apache_version = $::apache::apache_version, +){ + ::apache::mod { 'ldap': } + # Template uses $apache_version + file { 'ldap.conf': + ensure => file, + path => "${::apache::mod_dir}/ldap.conf", + content => template('apache/mod/ldap.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/mime.pp b/3rdparty/modules/apache/manifests/mod/mime.pp new file mode 100644 index 000000000..86000d167 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/mime.pp @@ -0,0 +1,21 @@ +class apache::mod::mime ( + $mime_support_package = $::apache::params::mime_support_package, + $mime_types_config = $::apache::params::mime_types_config, +) { + apache::mod { 'mime': } + # Template uses $mime_types_config + file { 'mime.conf': + ensure => file, + path => "${::apache::mod_dir}/mime.conf", + content => template('apache/mod/mime.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } + if $mime_support_package { + package { $mime_support_package: + ensure => 'installed', + before => File['mime.conf'], + } + } +} diff --git a/3rdparty/modules/apache/manifests/mod/mime_magic.pp b/3rdparty/modules/apache/manifests/mod/mime_magic.pp new file mode 100644 index 000000000..c057b01f5 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/mime_magic.pp @@ -0,0 +1,14 @@ +class apache::mod::mime_magic ( + $magic_file = "${::apache::conf_dir}/magic" +) { + apache::mod { 'mime_magic': } + # Template uses $magic_file + file { 'mime_magic.conf': + ensure => file, + path => "${::apache::mod_dir}/mime_magic.conf", + content => template('apache/mod/mime_magic.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/negotiation.pp b/3rdparty/modules/apache/manifests/mod/negotiation.pp new file mode 100644 index 000000000..02a3a0e64 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/negotiation.pp @@ -0,0 +1,25 @@ +class apache::mod::negotiation ( + $force_language_priority = 'Prefer Fallback', + $language_priority = [ 'en', 'ca', 'cs', 'da', 'de', 'el', 'eo', 'es', 'et', + 'fr', 'he', 'hr', 'it', 'ja', 'ko', 'ltz', 'nl', 'nn', + 'no', 'pl', 'pt', 'pt-BR', 'ru', 'sv', 'zh-CN', + 'zh-TW' ], +) { + if !is_array($force_language_priority) and !is_string($force_language_priority) { + fail('force_languague_priority must be a string or array of strings') + } + if !is_array($language_priority) and !is_string($language_priority) { + fail('force_languague_priority must be a string or array of strings') + } + + ::apache::mod { 'negotiation': } + # Template uses no variables + file { 'negotiation.conf': + ensure => file, + path => "${::apache::mod_dir}/negotiation.conf", + content => template('apache/mod/negotiation.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/nss.pp b/3rdparty/modules/apache/manifests/mod/nss.pp new file mode 100644 index 000000000..132b41b3f --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/nss.pp @@ -0,0 +1,25 @@ +class apache::mod::nss ( + $transfer_log = "${::apache::params::logroot}/access.log", + $error_log = "${::apache::params::logroot}/error.log", + $passwd_file = undef +) { + include ::apache::mod::mime + + apache::mod { 'nss': } + + $httpd_dir = $::apache::httpd_dir + + # Template uses: + # $transfer_log + # $error_log + # $http_dir + # passwd_file + file { 'nss.conf': + ensure => file, + path => "${::apache::mod_dir}/nss.conf", + content => template('apache/mod/nss.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/pagespeed.pp b/3rdparty/modules/apache/manifests/mod/pagespeed.pp new file mode 100644 index 000000000..588849c47 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/pagespeed.pp @@ -0,0 +1,55 @@ +class apache::mod::pagespeed ( + $inherit_vhost_config = 'on', + $filter_xhtml = false, + $cache_path = '/var/cache/mod_pagespeed/', + $log_dir = '/var/log/pagespeed', + $memcache_servers = [], + $rewrite_level = 'CoreFilters', + $disable_filters = [], + $enable_filters = [], + $forbid_filters = [], + $rewrite_deadline_per_flush_ms = 10, + $additional_domains = undef, + $file_cache_size_kb = 102400, + $file_cache_clean_interval_ms = 3600000, + $lru_cache_per_process = 1024, + $lru_cache_byte_limit = 16384, + $css_flatten_max_bytes = 2048, + $css_inline_max_bytes = 2048, + $css_image_inline_max_bytes = 2048, + $image_inline_max_bytes = 2048, + $js_inline_max_bytes = 2048, + $css_outline_min_bytes = 3000, + $js_outline_min_bytes = 3000, + $inode_limit = 500000, + $image_max_rewrites_at_once = 8, + $num_rewrite_threads = 4, + $num_expensive_rewrite_threads = 4, + $collect_statistics = 'on', + $statistics_logging = 'on', + $allow_view_stats = [], + $allow_pagespeed_console = [], + $allow_pagespeed_message = [], + $message_buffer_size = 100000, + $additional_configuration = {}, + $apache_version = $::apache::apache_version, +){ + + $_lib = $::apache::apache_version ? { + '2.4' => 'mod_pagespeed_ap24.so', + default => undef + } + + apache::mod { 'pagespeed': + lib => $_lib, + } + + file { 'pagespeed.conf': + ensure => file, + path => "${::apache::mod_dir}/pagespeed.conf", + content => template('apache/mod/pagespeed.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/passenger.pp b/3rdparty/modules/apache/manifests/mod/passenger.pp new file mode 100644 index 000000000..03cce4d89 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/passenger.pp @@ -0,0 +1,77 @@ +class apache::mod::passenger ( + $passenger_conf_file = $::apache::params::passenger_conf_file, + $passenger_conf_package_file = $::apache::params::passenger_conf_package_file, + $passenger_high_performance = undef, + $passenger_pool_idle_time = undef, + $passenger_max_requests = undef, + $passenger_stat_throttle_rate = undef, + $rack_autodetect = undef, + $rails_autodetect = undef, + $passenger_root = $::apache::params::passenger_root, + $passenger_ruby = $::apache::params::passenger_ruby, + $passenger_default_ruby = $::apache::params::passenger_default_ruby, + $passenger_max_pool_size = undef, + $passenger_min_instances = undef, + $passenger_use_global_queue = undef, + $passenger_app_env = undef, + $mod_package = undef, + $mod_package_ensure = undef, + $mod_lib = undef, + $mod_lib_path = undef, + $mod_id = undef, + $mod_path = undef, +) { + # Managed by the package, but declare it to avoid purging + if $passenger_conf_package_file { + file { 'passenger_package.conf': + path => "${::apache::mod_dir}/${passenger_conf_package_file}", + } + } + + $_package = $mod_package + $_package_ensure = $mod_package_ensure + $_lib = $mod_lib + if $::osfamily == 'FreeBSD' { + if $mod_lib_path { + $_lib_path = $mod_lib_path + } else { + $_lib_path = "${passenger_root}/buildout/apache2" + } + } else { + $_lib_path = $mod_lib_path + } + + $_id = $mod_id + $_path = $mod_path + ::apache::mod { 'passenger': + package => $_package, + package_ensure => $_package_ensure, + lib => $_lib, + lib_path => $_lib_path, + id => $_id, + path => $_path, + loadfile_name => 'zpassenger.load', + } + + # Template uses: + # - $passenger_root + # - $passenger_ruby + # - $passenger_default_ruby + # - $passenger_max_pool_size + # - $passenger_min_instances + # - $passenger_high_performance + # - $passenger_max_requests + # - $passenger_stat_throttle_rate + # - $passenger_use_global_queue + # - $passenger_app_env + # - $rack_autodetect + # - $rails_autodetect + file { 'passenger.conf': + ensure => file, + path => "${::apache::mod_dir}/${passenger_conf_file}", + content => template('apache/mod/passenger.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/perl.pp b/3rdparty/modules/apache/manifests/mod/perl.pp new file mode 100644 index 000000000..b57f25fd5 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/perl.pp @@ -0,0 +1,3 @@ +class apache::mod::perl { + ::apache::mod { 'perl': } +} diff --git a/3rdparty/modules/apache/manifests/mod/peruser.pp b/3rdparty/modules/apache/manifests/mod/peruser.pp new file mode 100644 index 000000000..b6a8015f9 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/peruser.pp @@ -0,0 +1,76 @@ +class apache::mod::peruser ( + $minspareprocessors = '2', + $minprocessors = '2', + $maxprocessors = '10', + $maxclients = '150', + $maxrequestsperchild = '1000', + $idletimeout = '120', + $expiretimeout = '120', + $keepalive = 'Off', +) { + + case $::osfamily { + 'freebsd' : { + fail("Unsupported osfamily ${::osfamily}") + } + default: { + if $::osfamily == 'gentoo' { + ::portage::makeconf { 'apache2_mpms': + content => 'peruser', + } + } + + if defined(Class['apache::mod::event']) { + fail('May not include both apache::mod::peruser and apache::mod::event on the same node') + } + if defined(Class['apache::mod::itk']) { + fail('May not include both apache::mod::peruser and apache::mod::itk on the same node') + } + if defined(Class['apache::mod::prefork']) { + fail('May not include both apache::mod::peruser and apache::mod::prefork on the same node') + } + if defined(Class['apache::mod::worker']) { + fail('May not include both apache::mod::peruser and apache::mod::worker on the same node') + } + File { + owner => 'root', + group => $::apache::params::root_group, + mode => '0644', + } + + $mod_dir = $::apache::mod_dir + + # Template uses: + # - $minspareprocessors + # - $minprocessors + # - $maxprocessors + # - $maxclients + # - $maxrequestsperchild + # - $idletimeout + # - $expiretimeout + # - $keepalive + # - $mod_dir + file { "${::apache::mod_dir}/peruser.conf": + ensure => file, + content => template('apache/mod/peruser.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } + file { "${::apache::mod_dir}/peruser": + ensure => directory, + require => File[$::apache::mod_dir], + } + file { "${::apache::mod_dir}/peruser/multiplexers": + ensure => directory, + require => File["${::apache::mod_dir}/peruser"], + } + file { "${::apache::mod_dir}/peruser/processors": + ensure => directory, + require => File["${::apache::mod_dir}/peruser"], + } + + ::apache::peruser::multiplexer { '01-default': } + } + } +} diff --git a/3rdparty/modules/apache/manifests/mod/php.pp b/3rdparty/modules/apache/manifests/mod/php.pp new file mode 100644 index 000000000..1d1274f3b --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/php.pp @@ -0,0 +1,62 @@ +class apache::mod::php ( + $package_name = undef, + $package_ensure = 'present', + $path = undef, + $extensions = ['.php'], + $content = undef, + $template = 'apache/mod/php5.conf.erb', + $source = undef, + $root_group = $::apache::params::root_group, +) inherits apache::params { + + if defined(Class['::apache::mod::prefork']) { + Class['::apache::mod::prefork']->File['php5.conf'] + } + elsif defined(Class['::apache::mod::itk']) { + Class['::apache::mod::itk']->File['php5.conf'] + } + else { + fail('apache::mod::php requires apache::mod::prefork or apache::mod::itk; please enable mpm_module => \'prefork\' or mpm_module => \'itk\' on Class[\'apache\']') + } + validate_array($extensions) + + if $source and ($content or $template != 'apache/mod/php5.conf.erb') { + warning('source and content or template parameters are provided. source parameter will be used') + } elsif $content and $template != 'apache/mod/php5.conf.erb' { + warning('content and template parameters are provided. content parameter will be used') + } + + $manage_content = $source ? { + undef => $content ? { + undef => template($template), + default => $content, + }, + default => undef, + } + + ::apache::mod { 'php5': + package => $package_name, + package_ensure => $package_ensure, + path => $path, + } + + include ::apache::mod::mime + include ::apache::mod::dir + Class['::apache::mod::mime'] -> Class['::apache::mod::dir'] -> Class['::apache::mod::php'] + + # Template uses $extensions + file { 'php5.conf': + ensure => file, + path => "${::apache::mod_dir}/php5.conf", + owner => 'root', + group => $root_group, + mode => '0644', + content => $manage_content, + source => $source, + require => [ + Exec["mkdir ${::apache::mod_dir}"], + ], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/prefork.pp b/3rdparty/modules/apache/manifests/mod/prefork.pp new file mode 100644 index 000000000..91567de11 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/prefork.pp @@ -0,0 +1,77 @@ +class apache::mod::prefork ( + $startservers = '8', + $minspareservers = '5', + $maxspareservers = '20', + $serverlimit = '256', + $maxclients = '256', + $maxrequestsperchild = '4000', + $apache_version = $::apache::apache_version, +) { + if defined(Class['apache::mod::event']) { + fail('May not include both apache::mod::prefork and apache::mod::event on the same node') + } + if versioncmp($apache_version, '2.4') < 0 { + if defined(Class['apache::mod::itk']) { + fail('May not include both apache::mod::prefork and apache::mod::itk on the same node') + } + } + if defined(Class['apache::mod::peruser']) { + fail('May not include both apache::mod::prefork and apache::mod::peruser on the same node') + } + if defined(Class['apache::mod::worker']) { + fail('May not include both apache::mod::prefork and apache::mod::worker on the same node') + } + File { + owner => 'root', + group => $::apache::params::root_group, + mode => '0644', + } + + # Template uses: + # - $startservers + # - $minspareservers + # - $maxspareservers + # - $serverlimit + # - $maxclients + # - $maxrequestsperchild + file { "${::apache::mod_dir}/prefork.conf": + ensure => file, + content => template('apache/mod/prefork.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } + + case $::osfamily { + 'redhat': { + if versioncmp($apache_version, '2.4') >= 0 { + ::apache::mpm{ 'prefork': + apache_version => $apache_version, + } + } + else { + file_line { '/etc/sysconfig/httpd prefork enable': + ensure => present, + path => '/etc/sysconfig/httpd', + line => '#HTTPD=/usr/sbin/httpd.worker', + match => '#?HTTPD=/usr/sbin/httpd.worker', + require => Package['httpd'], + notify => Class['apache::service'], + } + } + } + 'debian', 'freebsd', 'Suse' : { + ::apache::mpm{ 'prefork': + apache_version => $apache_version, + } + } + 'gentoo': { + ::portage::makeconf { 'apache2_mpms': + content => 'prefork', + } + } + default: { + fail("Unsupported osfamily ${::osfamily}") + } + } +} diff --git a/3rdparty/modules/apache/manifests/mod/proxy.pp b/3rdparty/modules/apache/manifests/mod/proxy.pp new file mode 100644 index 000000000..8c685d55b --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/proxy.pp @@ -0,0 +1,16 @@ +class apache::mod::proxy ( + $proxy_requests = 'Off', + $allow_from = undef, + $apache_version = $::apache::apache_version, +) { + ::apache::mod { 'proxy': } + # Template uses $proxy_requests, $apache_version + file { 'proxy.conf': + ensure => file, + path => "${::apache::mod_dir}/proxy.conf", + content => template('apache/mod/proxy.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/proxy_ajp.pp b/3rdparty/modules/apache/manifests/mod/proxy_ajp.pp new file mode 100644 index 000000000..a011a1789 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/proxy_ajp.pp @@ -0,0 +1,4 @@ +class apache::mod::proxy_ajp { + Class['::apache::mod::proxy'] -> Class['::apache::mod::proxy_ajp'] + ::apache::mod { 'proxy_ajp': } +} diff --git a/3rdparty/modules/apache/manifests/mod/proxy_balancer.pp b/3rdparty/modules/apache/manifests/mod/proxy_balancer.pp new file mode 100644 index 000000000..5a0768d8d --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/proxy_balancer.pp @@ -0,0 +1,10 @@ +class apache::mod::proxy_balancer { + + include ::apache::mod::proxy + include ::apache::mod::proxy_http + + Class['::apache::mod::proxy'] -> Class['::apache::mod::proxy_balancer'] + Class['::apache::mod::proxy_http'] -> Class['::apache::mod::proxy_balancer'] + ::apache::mod { 'proxy_balancer': } + +} diff --git a/3rdparty/modules/apache/manifests/mod/proxy_connect.pp b/3rdparty/modules/apache/manifests/mod/proxy_connect.pp new file mode 100644 index 000000000..7adef1f89 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/proxy_connect.pp @@ -0,0 +1,8 @@ +class apache::mod::proxy_connect ( + $apache_version = $::apache::apache_version, +) { + if versioncmp($apache_version, '2.2') >= 0 { + Class['::apache::mod::proxy'] -> Class['::apache::mod::proxy_connect'] + ::apache::mod { 'proxy_connect': } + } +} diff --git a/3rdparty/modules/apache/manifests/mod/proxy_html.pp b/3rdparty/modules/apache/manifests/mod/proxy_html.pp new file mode 100644 index 000000000..8b910c251 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/proxy_html.pp @@ -0,0 +1,37 @@ +class apache::mod::proxy_html { + Class['::apache::mod::proxy'] -> Class['::apache::mod::proxy_html'] + Class['::apache::mod::proxy_http'] -> Class['::apache::mod::proxy_html'] + + # Add libxml2 + case $::osfamily { + /RedHat|FreeBSD|Gentoo/: { + ::apache::mod { 'xml2enc': } + $loadfiles = undef + } + 'Debian': { + $gnu_path = $::hardwaremodel ? { + 'i686' => 'i386', + default => $::hardwaremodel, + } + $loadfiles = $::apache::params::distrelease ? { + '6' => ['/usr/lib/libxml2.so.2'], + '10' => ['/usr/lib/libxml2.so.2'], + default => ["/usr/lib/${gnu_path}-linux-gnu/libxml2.so.2"], + } + } + } + + ::apache::mod { 'proxy_html': + loadfiles => $loadfiles, + } + + # Template uses $icons_path + file { 'proxy_html.conf': + ensure => file, + path => "${::apache::mod_dir}/proxy_html.conf", + content => template('apache/mod/proxy_html.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/proxy_http.pp b/3rdparty/modules/apache/manifests/mod/proxy_http.pp new file mode 100644 index 000000000..1579e68ee --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/proxy_http.pp @@ -0,0 +1,4 @@ +class apache::mod::proxy_http { + Class['::apache::mod::proxy'] -> Class['::apache::mod::proxy_http'] + ::apache::mod { 'proxy_http': } +} diff --git a/3rdparty/modules/apache/manifests/mod/python.pp b/3rdparty/modules/apache/manifests/mod/python.pp new file mode 100644 index 000000000..e326c8d75 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/python.pp @@ -0,0 +1,5 @@ +class apache::mod::python { + ::apache::mod { 'python': } +} + + diff --git a/3rdparty/modules/apache/manifests/mod/remoteip.pp b/3rdparty/modules/apache/manifests/mod/remoteip.pp new file mode 100644 index 000000000..564390e94 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/remoteip.pp @@ -0,0 +1,27 @@ +class apache::mod::remoteip ( + $header = 'X-Forwarded-For', + $proxy_ips = [ '127.0.0.1' ], + $proxies_header = undef, + $trusted_proxy_ips = undef, + $apache_version = $::apache::apache_version +) { + if versioncmp($apache_version, '2.4') < 0 { + fail('mod_remoteip is only available in Apache 2.4') + } + + ::apache::mod { 'remoteip': } + + # Template uses: + # - $header + # - $proxy_ips + # - $proxies_header + # - $trusted_proxy_ips + file { 'remoteip.conf': + ensure => file, + path => "${::apache::mod_dir}/remoteip.conf", + content => template('apache/mod/remoteip.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Service['httpd'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/reqtimeout.pp b/3rdparty/modules/apache/manifests/mod/reqtimeout.pp new file mode 100644 index 000000000..34c96a678 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/reqtimeout.pp @@ -0,0 +1,14 @@ +class apache::mod::reqtimeout ( + $timeouts = ['header=20-40,minrate=500', 'body=10,minrate=500'] +){ + ::apache::mod { 'reqtimeout': } + # Template uses no variables + file { 'reqtimeout.conf': + ensure => file, + path => "${::apache::mod_dir}/reqtimeout.conf", + content => template('apache/mod/reqtimeout.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/rewrite.pp b/3rdparty/modules/apache/manifests/mod/rewrite.pp new file mode 100644 index 000000000..694f0b6f5 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/rewrite.pp @@ -0,0 +1,4 @@ +class apache::mod::rewrite { + include ::apache::params + ::apache::mod { 'rewrite': } +} diff --git a/3rdparty/modules/apache/manifests/mod/rpaf.pp b/3rdparty/modules/apache/manifests/mod/rpaf.pp new file mode 100644 index 000000000..12b86eb8b --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/rpaf.pp @@ -0,0 +1,20 @@ +class apache::mod::rpaf ( + $sethostname = true, + $proxy_ips = [ '127.0.0.1' ], + $header = 'X-Forwarded-For' +) { + ::apache::mod { 'rpaf': } + + # Template uses: + # - $sethostname + # - $proxy_ips + # - $header + file { 'rpaf.conf': + ensure => file, + path => "${::apache::mod_dir}/rpaf.conf", + content => template('apache/mod/rpaf.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/security.pp b/3rdparty/modules/apache/manifests/mod/security.pp new file mode 100644 index 000000000..84e55e292 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/security.pp @@ -0,0 +1,75 @@ +class apache::mod::security ( + $crs_package = $::apache::params::modsec_crs_package, + $activated_rules = $::apache::params::modsec_default_rules, + $modsec_dir = $::apache::params::modsec_dir, + $allowed_methods = 'GET HEAD POST OPTIONS', + $content_types = 'application/x-www-form-urlencoded|multipart/form-data|text/xml|application/xml|application/x-amf', + $restricted_extensions = '.asa/ .asax/ .ascx/ .axd/ .backup/ .bak/ .bat/ .cdx/ .cer/ .cfg/ .cmd/ .com/ .config/ .conf/ .cs/ .csproj/ .csr/ .dat/ .db/ .dbf/ .dll/ .dos/ .htr/ .htw/ .ida/ .idc/ .idq/ .inc/ .ini/ .key/ .licx/ .lnk/ .log/ .mdb/ .old/ .pass/ .pdb/ .pol/ .printer/ .pwd/ .resources/ .resx/ .sql/ .sys/ .vb/ .vbs/ .vbproj/ .vsdisco/ .webinfo/ .xsd/ .xsx/', + $restricted_headers = '/Proxy-Connection/ /Lock-Token/ /Content-Range/ /Translate/ /via/ /if/', +){ + + if $::osfamily == 'FreeBSD' { + fail('FreeBSD is not currently supported') + } + + ::apache::mod { 'security': + id => 'security2_module', + lib => 'mod_security2.so', + } + + ::apache::mod { 'unique_id_module': + id => 'unique_id_module', + lib => 'mod_unique_id.so', + } + + if $crs_package { + package { $crs_package: + ensure => 'latest', + before => File['security.conf'], + } + } + + # Template uses: + # - $modsec_dir + file { 'security.conf': + ensure => file, + content => template('apache/mod/security.conf.erb'), + path => "${::apache::mod_dir}/security.conf", + owner => $::apache::params::user, + group => $::apache::params::group, + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } + + file { $modsec_dir: + ensure => directory, + owner => $::apache::params::user, + group => $::apache::params::group, + mode => '0555', + purge => true, + force => true, + recurse => true, + } + + file { "${modsec_dir}/activated_rules": + ensure => directory, + owner => $::apache::params::user, + group => $::apache::params::group, + mode => '0555', + purge => true, + force => true, + recurse => true, + notify => Class['apache::service'], + } + + file { "${modsec_dir}/security_crs.conf": + ensure => file, + content => template('apache/mod/security_crs.conf.erb'), + require => File[$modsec_dir], + notify => Class['apache::service'], + } + + apache::security::rule_link { $activated_rules: } + +} diff --git a/3rdparty/modules/apache/manifests/mod/setenvif.pp b/3rdparty/modules/apache/manifests/mod/setenvif.pp new file mode 100644 index 000000000..c73102dfb --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/setenvif.pp @@ -0,0 +1,12 @@ +class apache::mod::setenvif { + ::apache::mod { 'setenvif': } + # Template uses no variables + file { 'setenvif.conf': + ensure => file, + path => "${::apache::mod_dir}/setenvif.conf", + content => template('apache/mod/setenvif.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/shib.pp b/3rdparty/modules/apache/manifests/mod/shib.pp new file mode 100644 index 000000000..8ec4c6dd1 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/shib.pp @@ -0,0 +1,15 @@ +class apache::mod::shib ( + $suppress_warning = false, +) { + + if $::osfamily == 'RedHat' and ! $suppress_warning { + warning('RedHat distributions do not have Apache mod_shib in their default package repositories.') + } + + $mod_shib = 'shib2' + + apache::mod {$mod_shib: + id => 'mod_shib', + } + +} \ No newline at end of file diff --git a/3rdparty/modules/apache/manifests/mod/speling.pp b/3rdparty/modules/apache/manifests/mod/speling.pp new file mode 100644 index 000000000..eb46d78f0 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/speling.pp @@ -0,0 +1,3 @@ +class apache::mod::speling { + ::apache::mod { 'speling': } +} diff --git a/3rdparty/modules/apache/manifests/mod/ssl.pp b/3rdparty/modules/apache/manifests/mod/ssl.pp new file mode 100644 index 000000000..4a6b82334 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/ssl.pp @@ -0,0 +1,74 @@ +class apache::mod::ssl ( + $ssl_compression = false, + $ssl_cryptodevice = 'builtin', + $ssl_options = [ 'StdEnvVars' ], + $ssl_cipher = 'HIGH:MEDIUM:!aNULL:!MD5', + $ssl_honorcipherorder = 'On', + $ssl_protocol = [ 'all', '-SSLv2', '-SSLv3' ], + $ssl_pass_phrase_dialog = 'builtin', + $ssl_random_seed_bytes = '512', + $ssl_sessioncachetimeout = '300', + $apache_version = $::apache::apache_version, + $package_name = undef, +) { + $session_cache = $::osfamily ? { + 'debian' => "\${APACHE_RUN_DIR}/ssl_scache(512000)", + 'redhat' => '/var/cache/mod_ssl/scache(512000)', + 'freebsd' => '/var/run/ssl_scache(512000)', + 'gentoo' => '/var/run/ssl_scache(512000)', + } + + case $::osfamily { + 'debian': { + if versioncmp($apache_version, '2.4') >= 0 { + $ssl_mutex = 'default' + } elsif $::operatingsystem == 'Ubuntu' and $::operatingsystemrelease == '10.04' { + $ssl_mutex = 'file:/var/run/apache2/ssl_mutex' + } else { + $ssl_mutex = "file:\${APACHE_RUN_DIR}/ssl_mutex" + } + } + 'redhat': { + $ssl_mutex = 'default' + } + 'freebsd': { + $ssl_mutex = 'default' + } + 'gentoo': { + $ssl_mutex = 'default' + } + default: { + fail("Unsupported osfamily ${::osfamily}") + } + } + + ::apache::mod { 'ssl': + package => $package_name, + } + + if versioncmp($apache_version, '2.4') >= 0 { + ::apache::mod { 'socache_shmcb': } + } + + # Template uses + # + # $ssl_compression + # $ssl_cryptodevice + # $ssl_cipher + # $ssl_honorcipherorder + # $ssl_options + # $session_cache + # $ssl_mutex + # $ssl_random_seed_bytes + # $ssl_sessioncachetimeout + # $apache_version + # + file { 'ssl.conf': + ensure => file, + path => "${::apache::mod_dir}/ssl.conf", + content => template('apache/mod/ssl.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/status.pp b/3rdparty/modules/apache/manifests/mod/status.pp new file mode 100644 index 000000000..4c3f8d9e2 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/status.pp @@ -0,0 +1,46 @@ +# Class: apache::mod::status +# +# This class enables and configures Apache mod_status +# See: http://httpd.apache.org/docs/current/mod/mod_status.html +# +# Parameters: +# - $allow_from is an array of hosts, ip addresses, partial network numbers +# or networks in CIDR notation specifying what hosts can view the special +# /server-status URL. Defaults to ['127.0.0.1', '::1']. +# - $extended_status track and display extended status information. Valid +# values are 'On' or 'Off'. Defaults to 'On'. +# - $status_path is the path assigned to the Location directive which +# defines the URL to access the server status. Defaults to '/server-status'. +# +# Actions: +# - Enable and configure Apache mod_status +# +# Requires: +# - The apache class +# +# Sample Usage: +# +# # Simple usage allowing access from localhost and a private subnet +# class { 'apache::mod::status': +# $allow_from => ['127.0.0.1', '10.10.10.10/24'], +# } +# +class apache::mod::status ( + $allow_from = ['127.0.0.1','::1'], + $extended_status = 'On', + $apache_version = $::apache::apache_version, + $status_path = '/server-status', +){ + validate_array($allow_from) + validate_re(downcase($extended_status), '^(on|off)$', "${extended_status} is not supported for extended_status. Allowed values are 'On' and 'Off'.") + ::apache::mod { 'status': } + # Template uses $allow_from, $extended_status, $apache_version, $status_path + file { 'status.conf': + ensure => file, + path => "${::apache::mod_dir}/status.conf", + content => template('apache/mod/status.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/suexec.pp b/3rdparty/modules/apache/manifests/mod/suexec.pp new file mode 100644 index 000000000..ded013d49 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/suexec.pp @@ -0,0 +1,3 @@ +class apache::mod::suexec { + ::apache::mod { 'suexec': } +} diff --git a/3rdparty/modules/apache/manifests/mod/suphp.pp b/3rdparty/modules/apache/manifests/mod/suphp.pp new file mode 100644 index 000000000..c50beea06 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/suphp.pp @@ -0,0 +1,14 @@ +class apache::mod::suphp ( +){ + ::apache::mod { 'suphp': } + + file {'suphp.conf': + ensure => file, + path => "${::apache::mod_dir}/suphp.conf", + content => template('apache/mod/suphp.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} + diff --git a/3rdparty/modules/apache/manifests/mod/userdir.pp b/3rdparty/modules/apache/manifests/mod/userdir.pp new file mode 100644 index 000000000..4b3d0b8e8 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/userdir.pp @@ -0,0 +1,19 @@ +class apache::mod::userdir ( + $home = '/home', + $dir = 'public_html', + $disable_root = true, + $apache_version = $::apache::apache_version, + $options = [ 'MultiViews', 'Indexes', 'SymLinksIfOwnerMatch', 'IncludesNoExec' ], +) { + ::apache::mod { 'userdir': } + + # Template uses $home, $dir, $disable_root, $apache_version + file { 'userdir.conf': + ensure => file, + path => "${::apache::mod_dir}/userdir.conf", + content => template('apache/mod/userdir.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/mod/version.pp b/3rdparty/modules/apache/manifests/mod/version.pp new file mode 100644 index 000000000..1cc4412e1 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/version.pp @@ -0,0 +1,10 @@ +class apache::mod::version( + $apache_version = $::apache::apache_version +) { + + if ($::osfamily == 'debian' and versioncmp($apache_version, '2.4') >= 0) { + warning("${module_name}: module version_module is built-in and can't be loaded") + } else { + ::apache::mod { 'version': } + } +} diff --git a/3rdparty/modules/apache/manifests/mod/vhost_alias.pp b/3rdparty/modules/apache/manifests/mod/vhost_alias.pp new file mode 100644 index 000000000..30ae122e1 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/vhost_alias.pp @@ -0,0 +1,3 @@ +class apache::mod::vhost_alias { + ::apache::mod { 'vhost_alias': } +} diff --git a/3rdparty/modules/apache/manifests/mod/worker.pp b/3rdparty/modules/apache/manifests/mod/worker.pp new file mode 100644 index 000000000..25925f807 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/worker.pp @@ -0,0 +1,79 @@ +class apache::mod::worker ( + $startservers = '2', + $maxclients = '150', + $minsparethreads = '25', + $maxsparethreads = '75', + $threadsperchild = '25', + $maxrequestsperchild = '0', + $serverlimit = '25', + $threadlimit = '64', + $apache_version = $::apache::apache_version, +) { + if defined(Class['apache::mod::event']) { + fail('May not include both apache::mod::worker and apache::mod::event on the same node') + } + if defined(Class['apache::mod::itk']) { + fail('May not include both apache::mod::worker and apache::mod::itk on the same node') + } + if defined(Class['apache::mod::peruser']) { + fail('May not include both apache::mod::worker and apache::mod::peruser on the same node') + } + if defined(Class['apache::mod::prefork']) { + fail('May not include both apache::mod::worker and apache::mod::prefork on the same node') + } + File { + owner => 'root', + group => $::apache::params::root_group, + mode => '0644', + } + + # Template uses: + # - $startservers + # - $maxclients + # - $minsparethreads + # - $maxsparethreads + # - $threadsperchild + # - $maxrequestsperchild + # - $serverlimit + # - $threadLimit + file { "${::apache::mod_dir}/worker.conf": + ensure => file, + content => template('apache/mod/worker.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } + + case $::osfamily { + 'redhat': { + if versioncmp($apache_version, '2.4') >= 0 { + ::apache::mpm{ 'worker': + apache_version => $apache_version, + } + } + else { + file_line { '/etc/sysconfig/httpd worker enable': + ensure => present, + path => '/etc/sysconfig/httpd', + line => 'HTTPD=/usr/sbin/httpd.worker', + match => '#?HTTPD=/usr/sbin/httpd.worker', + require => Package['httpd'], + notify => Class['apache::service'], + } + } + } + 'debian', 'freebsd', 'Suse': { + ::apache::mpm{ 'worker': + apache_version => $apache_version, + } + } + 'gentoo': { + ::portage::makeconf { 'apache2_mpms': + content => 'worker', + } + } + default: { + fail("Unsupported osfamily ${::osfamily}") + } + } +} diff --git a/3rdparty/modules/apache/manifests/mod/wsgi.pp b/3rdparty/modules/apache/manifests/mod/wsgi.pp new file mode 100644 index 000000000..bff5b46b7 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/wsgi.pp @@ -0,0 +1,41 @@ +class apache::mod::wsgi ( + $wsgi_socket_prefix = $::apache::params::wsgi_socket_prefix, + $wsgi_python_path = undef, + $wsgi_python_home = undef, + $package_name = undef, + $mod_path = undef, +){ + + if ($package_name != undef and $mod_path == undef) or ($package_name == undef and $mod_path != undef) { + fail('apache::mod::wsgi - both package_name and mod_path must be specified!') + } + + if $package_name != undef { + if $mod_path =~ /\// { + $_mod_path = $mod_path + } else { + $_mod_path = "${::apache::lib_path}/${mod_path}" + } + ::apache::mod { 'wsgi': + package => $package_name, + path => $_mod_path, + } + } + else { + ::apache::mod { 'wsgi': } + } + + # Template uses: + # - $wsgi_socket_prefix + # - $wsgi_python_path + # - $wsgi_python_home + file {'wsgi.conf': + ensure => file, + path => "${::apache::mod_dir}/wsgi.conf", + content => template('apache/mod/wsgi.conf.erb'), + require => Exec["mkdir ${::apache::mod_dir}"], + before => File[$::apache::mod_dir], + notify => Class['apache::service'], + } +} + diff --git a/3rdparty/modules/apache/manifests/mod/xsendfile.pp b/3rdparty/modules/apache/manifests/mod/xsendfile.pp new file mode 100644 index 000000000..7c5e88437 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mod/xsendfile.pp @@ -0,0 +1,4 @@ +class apache::mod::xsendfile { + include ::apache::params + ::apache::mod { 'xsendfile': } +} diff --git a/3rdparty/modules/apache/manifests/mpm.pp b/3rdparty/modules/apache/manifests/mpm.pp new file mode 100644 index 000000000..9e7734945 --- /dev/null +++ b/3rdparty/modules/apache/manifests/mpm.pp @@ -0,0 +1,107 @@ +define apache::mpm ( + $lib_path = $::apache::lib_path, + $apache_version = $::apache::apache_version, +) { + if ! defined(Class['apache']) { + fail('You must include the apache base class before using any apache defined resources') + } + + $mpm = $name + $mod_dir = $::apache::mod_dir + + $_lib = "mod_mpm_${mpm}.so" + $_path = "${lib_path}/${_lib}" + $_id = "mpm_${mpm}_module" + + if versioncmp($apache_version, '2.4') >= 0 { + file { "${mod_dir}/${mpm}.load": + ensure => file, + path => "${mod_dir}/${mpm}.load", + content => "LoadModule ${_id} ${_path}\n", + require => [ + Package['httpd'], + Exec["mkdir ${mod_dir}"], + ], + before => File[$mod_dir], + notify => Class['apache::service'], + } + } + + case $::osfamily { + 'debian': { + file { "${::apache::mod_enable_dir}/${mpm}.conf": + ensure => link, + target => "${::apache::mod_dir}/${mpm}.conf", + require => Exec["mkdir ${::apache::mod_enable_dir}"], + before => File[$::apache::mod_enable_dir], + notify => Class['apache::service'], + } + + if versioncmp($apache_version, '2.4') >= 0 { + file { "${::apache::mod_enable_dir}/${mpm}.load": + ensure => link, + target => "${::apache::mod_dir}/${mpm}.load", + require => Exec["mkdir ${::apache::mod_enable_dir}"], + before => File[$::apache::mod_enable_dir], + notify => Class['apache::service'], + } + + if $mpm == 'itk' { + file { "${lib_path}/mod_mpm_itk.so": + ensure => link, + target => "${lib_path}/mpm_itk.so" + } + } + } + + if versioncmp($apache_version, '2.4') < 0 { + package { "apache2-mpm-${mpm}": + ensure => present, + } + } + } + 'freebsd': { + class { '::apache::package': + mpm_module => $mpm + } + } + 'redhat': { + # so we don't fail + } + 'Suse': { + file { "${::apache::mod_enable_dir}/${mpm}.conf": + ensure => link, + target => "${::apache::mod_dir}/${mpm}.conf", + require => Exec["mkdir ${::apache::mod_enable_dir}"], + before => File[$::apache::mod_enable_dir], + notify => Class['apache::service'], + } + + if versioncmp($apache_version, '2.4') >= 0 { + file { "${::apache::mod_enable_dir}/${mpm}.load": + ensure => link, + target => "${::apache::mod_dir}/${mpm}.load", + require => Exec["mkdir ${::apache::mod_enable_dir}"], + before => File[$::apache::mod_enable_dir], + notify => Class['apache::service'], + } + + if $mpm == 'itk' { + file { "${lib_path}/mod_mpm_itk.so": + ensure => link, + target => "${lib_path}/mpm_itk.so" + } + } + } + + if versioncmp($apache_version, '2.4') < 0 { + package { "apache2-${mpm}": + ensure => present, + } + } + } + default: { + fail("Unsupported osfamily ${::osfamily}") + } + } +} diff --git a/3rdparty/modules/apache/manifests/namevirtualhost.pp b/3rdparty/modules/apache/manifests/namevirtualhost.pp new file mode 100644 index 000000000..f8c3a80d8 --- /dev/null +++ b/3rdparty/modules/apache/manifests/namevirtualhost.pp @@ -0,0 +1,10 @@ +define apache::namevirtualhost { + $addr_port = $name + + # Template uses: $addr_port + concat::fragment { "NameVirtualHost ${addr_port}": + ensure => present, + target => $::apache::ports_file, + content => template('apache/namevirtualhost.erb'), + } +} diff --git a/3rdparty/modules/apache/manifests/package.pp b/3rdparty/modules/apache/manifests/package.pp new file mode 100644 index 000000000..728b26010 --- /dev/null +++ b/3rdparty/modules/apache/manifests/package.pp @@ -0,0 +1,65 @@ +class apache::package ( + $ensure = 'present', + $mpm_module = $::apache::params::mpm_module, +) inherits ::apache::params { + + # The base class must be included first because it is used by parameter defaults + if ! defined(Class['apache']) { + fail('You must include the apache base class before using any apache defined resources') + } + + case $::osfamily { + 'FreeBSD': { + case $mpm_module { + 'prefork': { + $set = 'MPM_PREFORK' + $unset = 'MPM_WORKER MPM_EVENT' + } + 'worker': { + $set = 'MPM_WORKER' + $unset = 'MPM_PERFORK MPM_EVENT' + } + 'event': { + $set = 'MPM_EVENT' + $unset = 'MPM_PERFORK MPM_WORKER' + } + 'itk': { + $set = undef + $unset = undef + package { 'www/mod_mpm_itk': + ensure => installed, + } + } + default: { fail("MPM module ${mpm_module} not supported on FreeBSD") } + } + + # Configure ports to have apache build options set correctly + if $set { + file_line { 'apache SET options in /etc/make.conf': + ensure => $ensure, + path => '/etc/make.conf', + line => "apache24_SET_FORCE=${set}", + match => '^apache24_SET_FORCE=.*', + before => Package['httpd'], + } + file_line { 'apache UNSET options in /etc/make.conf': + ensure => $ensure, + path => '/etc/make.conf', + line => "apache24_UNSET_FORCE=${unset}", + match => '^apache24_UNSET_FORCE=.*', + before => Package['httpd'], + } + } + $apache_package = $::apache::apache_name + } + default: { + $apache_package = $::apache::apache_name + } + } + + package { 'httpd': + ensure => $ensure, + name => $apache_package, + notify => Class['Apache::Service'], + } +} diff --git a/3rdparty/modules/apache/manifests/params.pp b/3rdparty/modules/apache/manifests/params.pp new file mode 100644 index 000000000..b5d142136 --- /dev/null +++ b/3rdparty/modules/apache/manifests/params.pp @@ -0,0 +1,483 @@ +# Class: apache::params +# +# This class manages Apache parameters +# +# Parameters: +# - The $user that Apache runs as +# - The $group that Apache runs as +# - The $apache_name is the name of the package and service on the relevant +# distribution +# - The $php_package is the name of the package that provided PHP +# - The $ssl_package is the name of the Apache SSL package +# - The $apache_dev is the name of the Apache development libraries package +# - The $conf_contents is the contents of the Apache configuration file +# +# Actions: +# +# Requires: +# +# Sample Usage: +# +class apache::params inherits ::apache::version { + if($::fqdn) { + $servername = $::fqdn + } else { + $servername = $::hostname + } + + # The default error log level + $log_level = 'warn' + $use_optional_includes = false + + if $::operatingsystem == 'Ubuntu' and $::lsbdistrelease == '10.04' { + $verify_command = '/usr/sbin/apache2ctl -t' + } else { + $verify_command = '/usr/sbin/apachectl -t' + } + if $::osfamily == 'RedHat' or $::operatingsystem == 'amazon' { + $user = 'apache' + $group = 'apache' + $root_group = 'root' + $apache_name = 'httpd' + $service_name = 'httpd' + $httpd_dir = '/etc/httpd' + $server_root = '/etc/httpd' + $conf_dir = "${httpd_dir}/conf" + $confd_dir = "${httpd_dir}/conf.d" + $mod_dir = "${httpd_dir}/conf.d" + $mod_enable_dir = undef + $vhost_dir = "${httpd_dir}/conf.d" + $vhost_enable_dir = undef + $conf_file = 'httpd.conf' + $ports_file = "${conf_dir}/ports.conf" + $logroot = '/var/log/httpd' + $logroot_mode = undef + $lib_path = 'modules' + $mpm_module = 'prefork' + $dev_packages = 'httpd-devel' + $default_ssl_cert = '/etc/pki/tls/certs/localhost.crt' + $default_ssl_key = '/etc/pki/tls/private/localhost.key' + $ssl_certs_dir = '/etc/pki/tls/certs' + $passenger_conf_file = 'passenger_extra.conf' + $passenger_conf_package_file = 'passenger.conf' + $passenger_root = undef + $passenger_ruby = undef + $passenger_default_ruby = undef + $suphp_addhandler = 'php5-script' + $suphp_engine = 'off' + $suphp_configpath = undef + # NOTE: The module for Shibboleth is not available to RH/CentOS without an additional repository. http://wiki.aaf.edu.au/tech-info/sp-install-guide + # NOTE: The auth_cas module isn't available to RH/CentOS without enabling EPEL. + $mod_packages = { + 'auth_cas' => 'mod_auth_cas', + 'auth_kerb' => 'mod_auth_kerb', + 'authnz_ldap' => $::apache::version::distrelease ? { + '7' => 'mod_ldap', + default => 'mod_authz_ldap', + }, + 'fastcgi' => 'mod_fastcgi', + 'fcgid' => 'mod_fcgid', + 'geoip' => 'mod_geoip', + 'ldap' => $::apache::version::distrelease ? { + '7' => 'mod_ldap', + default => undef, + }, + 'pagespeed' => 'mod-pagespeed-stable', + 'passenger' => 'mod_passenger', + 'perl' => 'mod_perl', + 'php5' => $::apache::version::distrelease ? { + '5' => 'php53', + default => 'php', + }, + 'proxy_html' => 'mod_proxy_html', + 'python' => 'mod_python', + 'security' => 'mod_security', + 'shibboleth' => 'shibboleth', + 'ssl' => 'mod_ssl', + 'wsgi' => 'mod_wsgi', + 'dav_svn' => 'mod_dav_svn', + 'suphp' => 'mod_suphp', + 'xsendfile' => 'mod_xsendfile', + 'nss' => 'mod_nss', + 'shib2' => 'shibboleth', + } + $mod_libs = { + 'php5' => 'libphp5.so', + 'nss' => 'libmodnss.so', + } + $conf_template = 'apache/httpd.conf.erb' + $keepalive = 'Off' + $keepalive_timeout = 15 + $max_keepalive_requests = 100 + $fastcgi_lib_path = undef + $mime_support_package = 'mailcap' + $mime_types_config = '/etc/mime.types' + $docroot = '/var/www/html' + $error_documents_path = $::apache::version::distrelease ? { + '7' => '/usr/share/httpd/error', + default => '/var/www/error' + } + if $::osfamily == 'RedHat' { + $wsgi_socket_prefix = '/var/run/wsgi' + } else { + $wsgi_socket_prefix = undef + } + $cas_cookie_path = '/var/cache/mod_auth_cas/' + $modsec_crs_package = 'mod_security_crs' + $modsec_crs_path = '/usr/lib/modsecurity.d' + $modsec_dir = '/etc/httpd/modsecurity.d' + $modsec_default_rules = [ + 'base_rules/modsecurity_35_bad_robots.data', + 'base_rules/modsecurity_35_scanners.data', + 'base_rules/modsecurity_40_generic_attacks.data', + 'base_rules/modsecurity_41_sql_injection_attacks.data', + 'base_rules/modsecurity_50_outbound.data', + 'base_rules/modsecurity_50_outbound_malware.data', + 'base_rules/modsecurity_crs_20_protocol_violations.conf', + 'base_rules/modsecurity_crs_21_protocol_anomalies.conf', + 'base_rules/modsecurity_crs_23_request_limits.conf', + 'base_rules/modsecurity_crs_30_http_policy.conf', + 'base_rules/modsecurity_crs_35_bad_robots.conf', + 'base_rules/modsecurity_crs_40_generic_attacks.conf', + 'base_rules/modsecurity_crs_41_sql_injection_attacks.conf', + 'base_rules/modsecurity_crs_41_xss_attacks.conf', + 'base_rules/modsecurity_crs_42_tight_security.conf', + 'base_rules/modsecurity_crs_45_trojans.conf', + 'base_rules/modsecurity_crs_47_common_exceptions.conf', + 'base_rules/modsecurity_crs_49_inbound_blocking.conf', + 'base_rules/modsecurity_crs_50_outbound.conf', + 'base_rules/modsecurity_crs_59_outbound_blocking.conf', + 'base_rules/modsecurity_crs_60_correlation.conf' + ] + } elsif $::osfamily == 'Debian' { + $user = 'www-data' + $group = 'www-data' + $root_group = 'root' + $apache_name = 'apache2' + $service_name = 'apache2' + $httpd_dir = '/etc/apache2' + $server_root = '/etc/apache2' + $conf_dir = $httpd_dir + $confd_dir = "${httpd_dir}/conf.d" + $mod_dir = "${httpd_dir}/mods-available" + $mod_enable_dir = "${httpd_dir}/mods-enabled" + $vhost_dir = "${httpd_dir}/sites-available" + $vhost_enable_dir = "${httpd_dir}/sites-enabled" + $conf_file = 'apache2.conf' + $ports_file = "${conf_dir}/ports.conf" + $logroot = '/var/log/apache2' + $logroot_mode = undef + $lib_path = '/usr/lib/apache2/modules' + $mpm_module = 'worker' + $default_ssl_cert = '/etc/ssl/certs/ssl-cert-snakeoil.pem' + $default_ssl_key = '/etc/ssl/private/ssl-cert-snakeoil.key' + $ssl_certs_dir = '/etc/ssl/certs' + $suphp_addhandler = 'x-httpd-php' + $suphp_engine = 'off' + $suphp_configpath = '/etc/php5/apache2' + $mod_packages = { + 'auth_cas' => 'libapache2-mod-auth-cas', + 'auth_kerb' => 'libapache2-mod-auth-kerb', + 'dav_svn' => 'libapache2-svn', + 'fastcgi' => 'libapache2-mod-fastcgi', + 'fcgid' => 'libapache2-mod-fcgid', + 'nss' => 'libapache2-mod-nss', + 'pagespeed' => 'mod-pagespeed-stable', + 'passenger' => 'libapache2-mod-passenger', + 'perl' => 'libapache2-mod-perl2', + 'php5' => 'libapache2-mod-php5', + 'proxy_html' => 'libapache2-mod-proxy-html', + 'python' => 'libapache2-mod-python', + 'rpaf' => 'libapache2-mod-rpaf', + 'security' => 'libapache2-modsecurity', + 'suphp' => 'libapache2-mod-suphp', + 'wsgi' => 'libapache2-mod-wsgi', + 'xsendfile' => 'libapache2-mod-xsendfile', + 'shib2' => 'libapache2-mod-shib2', + } + $mod_libs = { + 'php5' => 'libphp5.so', + } + $conf_template = 'apache/httpd.conf.erb' + $keepalive = 'Off' + $keepalive_timeout = 15 + $max_keepalive_requests = 100 + $fastcgi_lib_path = '/var/lib/apache2/fastcgi' + $mime_support_package = 'mime-support' + $mime_types_config = '/etc/mime.types' + $docroot = '/var/www' + $cas_cookie_path = '/var/cache/apache2/mod_auth_cas/' + $modsec_crs_package = 'modsecurity-crs' + $modsec_crs_path = '/usr/share/modsecurity-crs' + $modsec_dir = '/etc/modsecurity' + $modsec_default_rules = [ + 'base_rules/modsecurity_35_bad_robots.data', + 'base_rules/modsecurity_35_scanners.data', + 'base_rules/modsecurity_40_generic_attacks.data', + 'base_rules/modsecurity_41_sql_injection_attacks.data', + 'base_rules/modsecurity_50_outbound.data', + 'base_rules/modsecurity_50_outbound_malware.data', + 'base_rules/modsecurity_crs_20_protocol_violations.conf', + 'base_rules/modsecurity_crs_21_protocol_anomalies.conf', + 'base_rules/modsecurity_crs_23_request_limits.conf', + 'base_rules/modsecurity_crs_30_http_policy.conf', + 'base_rules/modsecurity_crs_35_bad_robots.conf', + 'base_rules/modsecurity_crs_40_generic_attacks.conf', + 'base_rules/modsecurity_crs_41_sql_injection_attacks.conf', + 'base_rules/modsecurity_crs_41_xss_attacks.conf', + 'base_rules/modsecurity_crs_42_tight_security.conf', + 'base_rules/modsecurity_crs_45_trojans.conf', + 'base_rules/modsecurity_crs_47_common_exceptions.conf', + 'base_rules/modsecurity_crs_49_inbound_blocking.conf', + 'base_rules/modsecurity_crs_50_outbound.conf', + 'base_rules/modsecurity_crs_59_outbound_blocking.conf', + 'base_rules/modsecurity_crs_60_correlation.conf' + ] + $error_documents_path = '/usr/share/apache2/error' + if ($::operatingsystem == 'Ubuntu' and versioncmp($::operatingsystemrelease, '13.10') >= 0) or ($::operatingsystem == 'Debian' and versioncmp($::operatingsystemrelease, '8') >= 0) { + $dev_packages = ['libaprutil1-dev', 'libapr1-dev', 'apache2-dev'] + } else { + $dev_packages = ['libaprutil1-dev', 'libapr1-dev', 'apache2-prefork-dev'] + } + + # + # Passenger-specific settings + # + + $passenger_conf_file = 'passenger.conf' + $passenger_conf_package_file = undef + + case $::operatingsystem { + 'Ubuntu': { + case $::lsbdistrelease { + '12.04': { + $passenger_root = '/usr' + $passenger_ruby = '/usr/bin/ruby' + $passenger_default_ruby = undef + } + '14.04': { + $passenger_root = '/usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini' + $passenger_ruby = undef + $passenger_default_ruby = '/usr/bin/ruby' + } + default: { + # The following settings may or may not work on Ubuntu releases not + # supported by this module. + $passenger_root = '/usr' + $passenger_ruby = '/usr/bin/ruby' + $passenger_default_ruby = undef + } + } + } + 'Debian': { + case $::lsbdistcodename { + 'wheezy': { + $passenger_root = '/usr' + $passenger_ruby = '/usr/bin/ruby' + $passenger_default_ruby = undef + } + 'jessie': { + $passenger_root = '/usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini' + $passenger_ruby = undef + $passenger_default_ruby = '/usr/bin/ruby' + } + default: { + # The following settings may or may not work on Debian releases not + # supported by this module. + $passenger_root = '/usr' + $passenger_ruby = '/usr/bin/ruby' + $passenger_default_ruby = undef + } + } + } + } + $wsgi_socket_prefix = undef + } elsif $::osfamily == 'FreeBSD' { + $user = 'www' + $group = 'www' + $root_group = 'wheel' + $apache_name = 'apache24' + $service_name = 'apache24' + $httpd_dir = '/usr/local/etc/apache24' + $server_root = '/usr/local' + $conf_dir = $httpd_dir + $confd_dir = "${httpd_dir}/Includes" + $mod_dir = "${httpd_dir}/Modules" + $mod_enable_dir = undef + $vhost_dir = "${httpd_dir}/Vhosts" + $vhost_enable_dir = undef + $conf_file = 'httpd.conf' + $ports_file = "${conf_dir}/ports.conf" + $logroot = '/var/log/apache24' + $logroot_mode = undef + $lib_path = '/usr/local/libexec/apache24' + $mpm_module = 'prefork' + $dev_packages = undef + $default_ssl_cert = '/usr/local/etc/apache24/server.crt' + $default_ssl_key = '/usr/local/etc/apache24/server.key' + $ssl_certs_dir = '/usr/local/etc/apache24' + $passenger_conf_file = 'passenger.conf' + $passenger_conf_package_file = undef + $passenger_root = '/usr/local/lib/ruby/gems/2.0/gems/passenger-4.0.58' + $passenger_ruby = '/usr/local/bin/ruby' + $passenger_default_ruby = undef + $suphp_addhandler = 'php5-script' + $suphp_engine = 'off' + $suphp_configpath = undef + $mod_packages = { + # NOTE: I list here only modules that are not included in www/apache24 + # NOTE: 'passenger' needs to enable APACHE_SUPPORT in make config + # NOTE: 'php' needs to enable APACHE option in make config + # NOTE: 'dav_svn' needs to enable MOD_DAV_SVN make config + # NOTE: not sure where the shibboleth should come from + 'auth_kerb' => 'www/mod_auth_kerb2', + 'fcgid' => 'www/mod_fcgid', + 'passenger' => 'www/rubygem-passenger', + 'perl' => 'www/mod_perl2', + 'php5' => 'www/mod_php5', + 'proxy_html' => 'www/mod_proxy_html', + 'python' => 'www/mod_python3', + 'wsgi' => 'www/mod_wsgi', + 'dav_svn' => 'devel/subversion', + 'xsendfile' => 'www/mod_xsendfile', + 'rpaf' => 'www/mod_rpaf2', + 'shib2' => 'security/shibboleth2-sp', + } + $mod_libs = { + 'php5' => 'libphp5.so', + } + $conf_template = 'apache/httpd.conf.erb' + $keepalive = 'Off' + $keepalive_timeout = 15 + $max_keepalive_requests = 100 + $fastcgi_lib_path = undef # TODO: revisit + $mime_support_package = 'misc/mime-support' + $mime_types_config = '/usr/local/etc/mime.types' + $wsgi_socket_prefix = undef + $docroot = '/usr/local/www/apache24/data' + $error_documents_path = '/usr/local/www/apache24/error' + } elsif $::osfamily == 'Gentoo' { + $user = 'apache' + $group = 'apache' + $root_group = 'wheel' + $apache_name = 'www-servers/apache' + $service_name = 'apache2' + $httpd_dir = '/etc/apache2' + $server_root = '/var/www' + $conf_dir = $httpd_dir + $confd_dir = "${httpd_dir}/conf.d" + $mod_dir = "${httpd_dir}/modules.d" + $mod_enable_dir = undef + $vhost_dir = "${httpd_dir}/vhosts.d" + $vhost_enable_dir = undef + $conf_file = 'httpd.conf' + $ports_file = "${conf_dir}/ports.conf" + $logroot = '/var/log/apache2' + $logroot_mode = undef + $lib_path = '/usr/lib/apache2/modules' + $mpm_module = 'prefork' + $dev_packages = undef + $default_ssl_cert = '/etc/ssl/apache2/server.crt' + $default_ssl_key = '/etc/ssl/apache2/server.key' + $ssl_certs_dir = '/etc/ssl/apache2' + $passenger_root = '/usr' + $passenger_ruby = '/usr/bin/ruby' + $passenger_conf_file = 'passenger.conf' + $passenger_conf_package_file = undef + $passenger_default_ruby = undef + $suphp_addhandler = 'x-httpd-php' + $suphp_engine = 'off' + $suphp_configpath = '/etc/php5/apache2' + $mod_packages = { + # NOTE: I list here only modules that are not included in www-servers/apache + 'auth_kerb' => 'www-apache/mod_auth_kerb', + 'fcgid' => 'www-apache/mod_fcgid', + 'passenger' => 'www-apache/passenger', + 'perl' => 'www-apache/mod_perl', + 'php5' => 'dev-lang/php', + 'proxy_html' => 'www-apache/mod_proxy_html', + 'proxy_fcgi' => 'www-apache/mod_proxy_fcgi', + 'python' => 'www-apache/mod_python', + 'wsgi' => 'www-apache/mod_wsgi', + 'dav_svn' => 'dev-vcs/subversion', + 'xsendfile' => 'www-apache/mod_xsendfile', + 'rpaf' => 'www-apache/mod_rpaf', + 'xml2enc' => 'www-apache/mod_xml2enc', + } + $mod_libs = { + 'php5' => 'libphp5.so', + } + $conf_template = 'apache/httpd.conf.erb' + $keepalive = 'Off' + $keepalive_timeout = 15 + $max_keepalive_requests = 100 + $fastcgi_lib_path = undef # TODO: revisit + $mime_support_package = 'app-misc/mime-types' + $mime_types_config = '/etc/mime.types' + $wsgi_socket_prefix = undef + $docroot = '/var/www/localhost/htdocs' + $error_documents_path = '/usr/share/apache2/error' + } elsif $::osfamily == 'Suse' { + $user = 'wwwrun' + $group = 'wwwrun' + $root_group = 'root' + $apache_name = 'apache2' + $service_name = 'apache2' + $httpd_dir = '/etc/apache2' + $server_root = '/etc/apache2' + $conf_dir = $httpd_dir + $confd_dir = "${httpd_dir}/conf.d" + $mod_dir = "${httpd_dir}/mods-available" + $mod_enable_dir = "${httpd_dir}/mods-enabled" + $vhost_dir = "${httpd_dir}/sites-available" + $vhost_enable_dir = "${httpd_dir}/sites-enabled" + $conf_file = 'httpd.conf' + $ports_file = "${conf_dir}/ports.conf" + $logroot = '/var/log/apache2' + $logroot_mode = undef + $lib_path = '/usr/lib64/apache2-prefork/' + $mpm_module = 'prefork' + $default_ssl_cert = '/etc/ssl/certs/ssl-cert-snakeoil.pem' + $default_ssl_key = '/etc/ssl/private/ssl-cert-snakeoil.key' + $ssl_certs_dir = '/etc/ssl/certs' + $suphp_addhandler = 'x-httpd-php' + $suphp_engine = 'off' + $suphp_configpath = '/etc/php5/apache2' + $mod_packages = { + 'auth_kerb' => 'apache2-mod_auth_kerb', + 'fcgid' => 'apache2-mod_fcgid', + 'perl' => 'apache2-mod_perl', + 'php5' => 'apache2-mod_php53', + 'python' => 'apache2-mod_python', + } + $mod_libs = { + 'php5' => 'libphp5.so', + } + $conf_template = 'apache/httpd.conf.erb' + $keepalive = 'Off' + $keepalive_timeout = 15 + $max_keepalive_requests = 100 + $fastcgi_lib_path = '/var/lib/apache2/fastcgi' + $mime_support_package = 'aaa_base' + $mime_types_config = '/etc/mime.types' + $docroot = '/srv/www' + $cas_cookie_path = '/var/cache/apache2/mod_auth_cas/' + $error_documents_path = '/usr/share/apache2/error' + $dev_packages = ['libapr-util1-devel', 'libapr1-devel'] + + # + # Passenger-specific settings + # + + $passenger_conf_file = 'passenger.conf' + $passenger_conf_package_file = undef + + $passenger_root = '/usr' + $passenger_ruby = '/usr/bin/ruby' + $passenger_default_ruby = undef + $wsgi_socket_prefix = undef + + } else { + fail("Class['apache::params']: Unsupported osfamily: ${::osfamily}") + } +} diff --git a/3rdparty/modules/apache/manifests/peruser/multiplexer.pp b/3rdparty/modules/apache/manifests/peruser/multiplexer.pp new file mode 100644 index 000000000..97143a1d4 --- /dev/null +++ b/3rdparty/modules/apache/manifests/peruser/multiplexer.pp @@ -0,0 +1,17 @@ +define apache::peruser::multiplexer ( + $user = $::apache::user, + $group = $::apache::group, + $file = undef, +) { + if ! $file { + $filename = "${name}.conf" + } else { + $filename = $file + } + file { "${::apache::mod_dir}/peruser/multiplexers/${filename}": + ensure => file, + content => "Multiplexer ${user} ${group}\n", + require => File["${::apache::mod_dir}/peruser/multiplexers"], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/peruser/processor.pp b/3rdparty/modules/apache/manifests/peruser/processor.pp new file mode 100644 index 000000000..30de61d7c --- /dev/null +++ b/3rdparty/modules/apache/manifests/peruser/processor.pp @@ -0,0 +1,17 @@ +define apache::peruser::processor ( + $user, + $group, + $file = undef, +) { + if ! $file { + $filename = "${name}.conf" + } else { + $filename = $file + } + file { "${::apache::mod_dir}/peruser/processors/${filename}": + ensure => file, + content => "Processor ${user} ${group}\n", + require => File["${::apache::mod_dir}/peruser/processors"], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/php.pp b/3rdparty/modules/apache/manifests/php.pp new file mode 100644 index 000000000..9fa9c682e --- /dev/null +++ b/3rdparty/modules/apache/manifests/php.pp @@ -0,0 +1,18 @@ +# Class: apache::php +# +# This class installs PHP for Apache +# +# Parameters: +# - $php_package +# +# Actions: +# - Install Apache PHP package +# +# Requires: +# +# Sample Usage: +# +class apache::php { + warning('apache::php is deprecated; please use apache::mod::php') + include ::apache::mod::php +} diff --git a/3rdparty/modules/apache/manifests/proxy.pp b/3rdparty/modules/apache/manifests/proxy.pp new file mode 100644 index 000000000..050f36c27 --- /dev/null +++ b/3rdparty/modules/apache/manifests/proxy.pp @@ -0,0 +1,15 @@ +# Class: apache::proxy +# +# This class enabled the proxy module for Apache +# +# Actions: +# - Enables Apache Proxy module +# +# Requires: +# +# Sample Usage: +# +class apache::proxy { + warning('apache::proxy is deprecated; please use apache::mod::proxy') + include ::apache::mod::proxy +} diff --git a/3rdparty/modules/apache/manifests/python.pp b/3rdparty/modules/apache/manifests/python.pp new file mode 100644 index 000000000..723a753f8 --- /dev/null +++ b/3rdparty/modules/apache/manifests/python.pp @@ -0,0 +1,18 @@ +# Class: apache::python +# +# This class installs Python for Apache +# +# Parameters: +# - $php_package +# +# Actions: +# - Install Apache Python package +# +# Requires: +# +# Sample Usage: +# +class apache::python { + warning('apache::python is deprecated; please use apache::mod::python') + include ::apache::mod::python +} diff --git a/3rdparty/modules/apache/manifests/security/rule_link.pp b/3rdparty/modules/apache/manifests/security/rule_link.pp new file mode 100644 index 000000000..a56a2d97f --- /dev/null +++ b/3rdparty/modules/apache/manifests/security/rule_link.pp @@ -0,0 +1,13 @@ +define apache::security::rule_link () { + + $parts = split($title, '/') + $filename = $parts[-1] + + file { $filename: + ensure => 'link', + path => "${::apache::mod::security::modsec_dir}/activated_rules/${filename}", + target => "${::apache::params::modsec_crs_path}/${title}", + require => File["${::apache::mod::security::modsec_dir}/activated_rules"], + notify => Class['apache::service'], + } +} diff --git a/3rdparty/modules/apache/manifests/service.pp b/3rdparty/modules/apache/manifests/service.pp new file mode 100644 index 000000000..708027921 --- /dev/null +++ b/3rdparty/modules/apache/manifests/service.pp @@ -0,0 +1,49 @@ +# Class: apache::service +# +# Manages the Apache daemon +# +# Parameters: +# +# Actions: +# - Manage Apache service +# +# Requires: +# +# Sample Usage: +# +# sometype { 'foo': +# notify => Class['apache::service'], +# } +# +# +class apache::service ( + $service_name = $::apache::params::service_name, + $service_enable = true, + $service_ensure = 'running', + $service_manage = true, + $service_restart = undef +) { + # The base class must be included first because parameter defaults depend on it + if ! defined(Class['apache::params']) { + fail('You must include the apache::params class before using any apache defined resources') + } + validate_bool($service_enable) + validate_bool($service_manage) + + case $service_ensure { + true, false, 'running', 'stopped': { + $_service_ensure = $service_ensure + } + default: { + $_service_ensure = undef + } + } + if $service_manage { + service { 'httpd': + ensure => $_service_ensure, + name => $service_name, + enable => $service_enable, + restart => $service_restart + } + } +} diff --git a/3rdparty/modules/apache/manifests/ssl.pp b/3rdparty/modules/apache/manifests/ssl.pp new file mode 100644 index 000000000..d0b36593d --- /dev/null +++ b/3rdparty/modules/apache/manifests/ssl.pp @@ -0,0 +1,18 @@ +# Class: apache::ssl +# +# This class installs Apache SSL capabilities +# +# Parameters: +# - The $ssl_package name from the apache::params class +# +# Actions: +# - Install Apache SSL capabilities +# +# Requires: +# +# Sample Usage: +# +class apache::ssl { + warning('apache::ssl is deprecated; please use apache::mod::ssl') + include ::apache::mod::ssl +} diff --git a/3rdparty/modules/apache/manifests/version.pp b/3rdparty/modules/apache/manifests/version.pp new file mode 100644 index 000000000..527dc6d38 --- /dev/null +++ b/3rdparty/modules/apache/manifests/version.pp @@ -0,0 +1,45 @@ +# Class: apache::version +# +# Try to automatically detect the version by OS +# +class apache::version { + # This will be 5 or 6 on RedHat, 6 or wheezy on Debian, 12 or quantal on Ubuntu, etc. + $osr_array = split($::operatingsystemrelease,'[\/\.]') + $distrelease = $osr_array[0] + if ! $distrelease { + fail("Class['apache::version']: Unparsable \$::operatingsystemrelease: ${::operatingsystemrelease}") + } + + case $::osfamily { + 'RedHat': { + if ($::operatingsystem == 'Amazon') { + $default = '2.2' + } elsif ($::operatingsystem == 'Fedora' and versioncmp($distrelease, '18') >= 0) or ($::operatingsystem != 'Fedora' and versioncmp($distrelease, '7') >= 0) { + $default = '2.4' + } else { + $default = '2.2' + } + } + 'Debian': { + if $::operatingsystem == 'Ubuntu' and versioncmp($::operatingsystemrelease, '13.10') >= 0 { + $default = '2.4' + } elsif $::operatingsystem == 'Debian' and versioncmp($distrelease, '8') >= 0 { + $default = '2.4' + } else { + $default = '2.2' + } + } + 'FreeBSD': { + $default = '2.4' + } + 'Gentoo': { + $default = '2.4' + } + 'Suse': { + $default = '2.2' + } + default: { + fail("Class['apache::version']: Unsupported osfamily: ${::osfamily}") + } + } +} diff --git a/3rdparty/modules/apache/manifests/vhost.pp b/3rdparty/modules/apache/manifests/vhost.pp new file mode 100644 index 000000000..17f61e313 --- /dev/null +++ b/3rdparty/modules/apache/manifests/vhost.pp @@ -0,0 +1,889 @@ +# See README.md for usage information +define apache::vhost( + $docroot, + $manage_docroot = true, + $virtual_docroot = false, + $port = undef, + $ip = undef, + $ip_based = false, + $add_listen = true, + $docroot_owner = 'root', + $docroot_group = $::apache::params::root_group, + $docroot_mode = undef, + $serveradmin = undef, + $ssl = false, + $ssl_cert = $::apache::default_ssl_cert, + $ssl_key = $::apache::default_ssl_key, + $ssl_chain = $::apache::default_ssl_chain, + $ssl_ca = $::apache::default_ssl_ca, + $ssl_crl_path = $::apache::default_ssl_crl_path, + $ssl_crl = $::apache::default_ssl_crl, + $ssl_crl_check = $::apache::default_ssl_crl_check, + $ssl_certs_dir = $::apache::params::ssl_certs_dir, + $ssl_protocol = undef, + $ssl_cipher = undef, + $ssl_honorcipherorder = undef, + $ssl_verify_client = undef, + $ssl_verify_depth = undef, + $ssl_options = undef, + $ssl_proxyengine = false, + $priority = undef, + $default_vhost = false, + $servername = $name, + $serveraliases = [], + $options = ['Indexes','FollowSymLinks','MultiViews'], + $override = ['None'], + $directoryindex = '', + $vhost_name = '*', + $logroot = $::apache::logroot, + $logroot_ensure = 'directory', + $logroot_mode = undef, + $log_level = undef, + $access_log = true, + $access_log_file = false, + $access_log_pipe = false, + $access_log_syslog = false, + $access_log_format = false, + $access_log_env_var = false, + $access_logs = undef, + $aliases = undef, + $directories = undef, + $error_log = true, + $error_log_file = undef, + $error_log_pipe = undef, + $error_log_syslog = undef, + $error_documents = [], + $fallbackresource = undef, + $scriptalias = undef, + $scriptaliases = [], + $proxy_dest = undef, + $proxy_dest_match = undef, + $proxy_dest_reverse_match = undef, + $proxy_pass = undef, + $proxy_pass_match = undef, + $suphp_addhandler = $::apache::params::suphp_addhandler, + $suphp_engine = $::apache::params::suphp_engine, + $suphp_configpath = $::apache::params::suphp_configpath, + $php_flags = {}, + $php_values = {}, + $php_admin_flags = {}, + $php_admin_values = {}, + $no_proxy_uris = [], + $no_proxy_uris_match = [], + $proxy_preserve_host = false, + $proxy_error_override = false, + $redirect_source = '/', + $redirect_dest = undef, + $redirect_status = undef, + $redirectmatch_status = undef, + $redirectmatch_regexp = undef, + $redirectmatch_dest = undef, + $rack_base_uris = undef, + $headers = undef, + $request_headers = undef, + $rewrites = undef, + $rewrite_base = undef, + $rewrite_rule = undef, + $rewrite_cond = undef, + $setenv = [], + $setenvif = [], + $block = [], + $ensure = 'present', + $wsgi_application_group = undef, + $wsgi_daemon_process = undef, + $wsgi_daemon_process_options = undef, + $wsgi_import_script = undef, + $wsgi_import_script_options = undef, + $wsgi_process_group = undef, + $wsgi_script_aliases = undef, + $wsgi_pass_authorization = undef, + $wsgi_chunked_request = undef, + $custom_fragment = undef, + $itk = undef, + $action = undef, + $fastcgi_server = undef, + $fastcgi_socket = undef, + $fastcgi_dir = undef, + $additional_includes = [], + $apache_version = $::apache::apache_version, + $allow_encoded_slashes = undef, + $suexec_user_group = undef, + $passenger_app_root = undef, + $passenger_app_env = undef, + $passenger_ruby = undef, + $passenger_min_instances = undef, + $passenger_start_timeout = undef, + $passenger_pre_start = undef, + $add_default_charset = undef, + $modsec_disable_vhost = undef, + $modsec_disable_ids = undef, + $modsec_disable_ips = undef, + $modsec_body_limit = undef, +) { + # The base class must be included first because it is used by parameter defaults + if ! defined(Class['apache']) { + fail('You must include the apache base class before using any apache defined resources') + } + + $apache_name = $::apache::apache_name + + validate_re($ensure, '^(present|absent)$', + "${ensure} is not supported for ensure. + Allowed values are 'present' and 'absent'.") + validate_re($suphp_engine, '^(on|off)$', + "${suphp_engine} is not supported for suphp_engine. + Allowed values are 'on' and 'off'.") + validate_bool($ip_based) + validate_bool($access_log) + validate_bool($error_log) + validate_bool($ssl) + validate_bool($default_vhost) + validate_bool($ssl_proxyengine) + if $rewrites { + validate_array($rewrites) + validate_hash($rewrites[0]) + } + + # Input validation begins + + if $suexec_user_group { + validate_re($suexec_user_group, '^\w+ \w+$', + "${suexec_user_group} is not supported for suexec_user_group. Must be 'user group'.") + } + + if $wsgi_pass_authorization { + validate_re(downcase($wsgi_pass_authorization), '^(on|off)$', + "${wsgi_pass_authorization} is not supported for wsgi_pass_authorization. + Allowed values are 'on' and 'off'.") + } + + # Deprecated backwards-compatibility + if $rewrite_base { + warning('Apache::Vhost: parameter rewrite_base is deprecated in favor of rewrites') + } + if $rewrite_rule { + warning('Apache::Vhost: parameter rewrite_rule is deprecated in favor of rewrites') + } + if $rewrite_cond { + warning('Apache::Vhost parameter rewrite_cond is deprecated in favor of rewrites') + } + + if $wsgi_script_aliases { + validate_hash($wsgi_script_aliases) + } + if $wsgi_daemon_process_options { + validate_hash($wsgi_daemon_process_options) + } + if $wsgi_import_script_options { + validate_hash($wsgi_import_script_options) + } + if $itk { + validate_hash($itk) + } + + validate_re($logroot_ensure, '^(directory|absent)$', + "${logroot_ensure} is not supported for logroot_ensure. + Allowed values are 'directory' and 'absent'.") + + if $log_level { + validate_apache_log_level($log_level) + } + + if $access_log_file and $access_log_pipe { + fail("Apache::Vhost[${name}]: 'access_log_file' and 'access_log_pipe' cannot be defined at the same time") + } + + if $error_log_file and $error_log_pipe { + fail("Apache::Vhost[${name}]: 'error_log_file' and 'error_log_pipe' cannot be defined at the same time") + } + + if $fallbackresource { + validate_re($fallbackresource, '^/|disabled', 'Please make sure fallbackresource starts with a / (or is "disabled")') + } + + if $custom_fragment { + validate_string($custom_fragment) + } + + if $allow_encoded_slashes { + validate_re($allow_encoded_slashes, '(^on$|^off$|^nodecode$)', "${allow_encoded_slashes} is not permitted for allow_encoded_slashes. Allowed values are 'on', 'off' or 'nodecode'.") + } + + # Input validation ends + + if $ssl and $ensure == 'present' { + include ::apache::mod::ssl + # Required for the AddType lines. + include ::apache::mod::mime + } + + if $virtual_docroot { + include ::apache::mod::vhost_alias + } + + if $wsgi_daemon_process { + include ::apache::mod::wsgi + } + + if $suexec_user_group { + include ::apache::mod::suexec + } + + if $passenger_app_root or $passenger_app_env or $passenger_ruby or $passenger_min_instances or $passenger_start_timeout or $passenger_pre_start { + include ::apache::mod::passenger + } + + # Configure the defaultness of a vhost + if $priority { + $priority_real = "${priority}-" + } elsif $priority == false { + $priority_real = '' + } elsif $default_vhost { + $priority_real = '10-' + } else { + $priority_real = '25-' + } + + ## Apache include does not always work with spaces in the filename + $filename = regsubst($name, ' ', '_', 'G') + + # This ensures that the docroot exists + # But enables it to be specified across multiple vhost resources + if ! defined(File[$docroot]) and $manage_docroot { + file { $docroot: + ensure => directory, + owner => $docroot_owner, + group => $docroot_group, + mode => $docroot_mode, + require => Package['httpd'], + before => Concat["${priority_real}${filename}.conf"], + } + } + + # Same as above, but for logroot + if ! defined(File[$logroot]) { + file { $logroot: + ensure => $logroot_ensure, + mode => $logroot_mode, + require => Package['httpd'], + before => Concat["${priority_real}${filename}.conf"], + } + } + + + # Is apache::mod::passenger enabled (or apache::mod['passenger']) + $passenger_enabled = defined(Apache::Mod['passenger']) + + # Is apache::mod::shib enabled (or apache::mod['shib2']) + $shibboleth_enabled = defined(Apache::Mod['shib2']) + + if $access_log and !$access_logs { + if $access_log_file { + $_logs_dest = "${logroot}/${access_log_file}" + } elsif $access_log_pipe { + $_logs_dest = $access_log_pipe + } elsif $access_log_syslog { + $_logs_dest = $access_log_syslog + } else { + $_logs_dest = undef + } + $_access_logs = [{ + 'file' => $access_log_file, + 'pipe' => $access_log_pipe, + 'syslog' => $access_log_syslog, + 'format' => $access_log_format, + 'env' => $access_log_env_var + }] + } elsif $access_logs { + if !is_array($access_logs) { + fail("Apache::Vhost[${name}]: access_logs must be an array of hashes") + } + $_access_logs = $access_logs + } + + if $error_log_file { + $error_log_destination = "${logroot}/${error_log_file}" + } elsif $error_log_pipe { + $error_log_destination = $error_log_pipe + } elsif $error_log_syslog { + $error_log_destination = $error_log_syslog + } else { + if $ssl { + $error_log_destination = "${logroot}/${name}_error_ssl.log" + } else { + $error_log_destination = "${logroot}/${name}_error.log" + } + } + + if $ip { + if $port { + $listen_addr_port = "${ip}:${port}" + $nvh_addr_port = "${ip}:${port}" + } else { + $listen_addr_port = undef + $nvh_addr_port = $ip + if ! $servername and ! $ip_based { + fail("Apache::Vhost[${name}]: must pass 'ip' and/or 'port' parameters for name-based vhosts") + } + } + } else { + if $port { + $listen_addr_port = $port + $nvh_addr_port = "${vhost_name}:${port}" + } else { + $listen_addr_port = undef + $nvh_addr_port = $name + if ! $servername { + fail("Apache::Vhost[${name}]: must pass 'ip' and/or 'port' parameters, and/or 'servername' parameter") + } + } + } + if $add_listen { + if $ip and defined(Apache::Listen["${port}"]) { + fail("Apache::Vhost[${name}]: Mixing IP and non-IP Listen directives is not possible; check the add_listen parameter of the apache::vhost define to disable this") + } + if ! defined(Apache::Listen["${listen_addr_port}"]) and $listen_addr_port and $ensure == 'present' { + ::apache::listen { "${listen_addr_port}": } + } + } + if ! $ip_based { + if ! defined(Apache::Namevirtualhost[$nvh_addr_port]) and $ensure == 'present' and (versioncmp($apache_version, '2.4') < 0) { + ::apache::namevirtualhost { $nvh_addr_port: } + } + } + + # Load mod_rewrite if needed and not yet loaded + if $rewrites or $rewrite_cond { + if ! defined(Class['apache::mod::rewrite']) { + include ::apache::mod::rewrite + } + } + + # Load mod_alias if needed and not yet loaded + if ($scriptalias or $scriptaliases != []) or ($redirect_source and $redirect_dest) { + if ! defined(Class['apache::mod::alias']) and ($ensure == 'present') { + include ::apache::mod::alias + } + } + + # Load mod_proxy if needed and not yet loaded + if ($proxy_dest or $proxy_pass or $proxy_pass_match or $proxy_dest_match) { + if ! defined(Class['apache::mod::proxy']) { + include ::apache::mod::proxy + } + if ! defined(Class['apache::mod::proxy_http']) { + include ::apache::mod::proxy_http + } + } + + # Load mod_passenger if needed and not yet loaded + if $rack_base_uris { + if ! defined(Class['apache::mod::passenger']) { + include ::apache::mod::passenger + } + } + + # Load mod_fastci if needed and not yet loaded + if $fastcgi_server and $fastcgi_socket { + if ! defined(Class['apache::mod::fastcgi']) { + include ::apache::mod::fastcgi + } + } + + # Check if mod_headers is required to process $headers/$request_headers + if $headers or $request_headers { + if ! defined(Class['apache::mod::headers']) { + include ::apache::mod::headers + } + } + + if ($setenv and ! empty($setenv)) or ($setenvif and ! empty($setenvif)) { + if ! defined(Class['apache::mod::setenvif']) { + include ::apache::mod::setenvif + } + } + + ## Create a default directory list if none defined + if $directories { + if !is_hash($directories) and !(is_array($directories) and is_hash($directories[0])) { + fail("Apache::Vhost[${name}]: 'directories' must be either a Hash or an Array of Hashes") + } + $_directories = $directories + } else { + $_directory = { + provider => 'directory', + path => $docroot, + options => $options, + allow_override => $override, + directoryindex => $directoryindex, + } + + if versioncmp($apache_version, '2.4') >= 0 { + $_directory_version = { + require => 'all granted', + } + } else { + $_directory_version = { + order => 'allow,deny', + allow => 'from all', + } + } + + $_directories = [ merge($_directory, $_directory_version) ] + } + + ## Create a global LocationMatch if locations aren't defined + if $modsec_disable_ids { + if is_hash($modsec_disable_ids) { + $_modsec_disable_ids = $modsec_disable_ids + } elsif is_array($modsec_disable_ids) { + $_modsec_disable_ids = { '.*' => $modsec_disable_ids } + } else { + fail("Apache::Vhost[${name}]: 'modsec_disable_ids' must be either a Hash of location/IDs or an Array of IDs") + } + } + + concat { "${priority_real}${filename}.conf": + ensure => $ensure, + path => "${::apache::vhost_dir}/${priority_real}${filename}.conf", + owner => 'root', + group => $::apache::params::root_group, + mode => '0644', + order => 'numeric', + require => Package['httpd'], + notify => Class['apache::service'], + } + if $::apache::vhost_enable_dir { + $vhost_enable_dir = $::apache::vhost_enable_dir + $vhost_symlink_ensure = $ensure ? { + present => link, + default => $ensure, + } + file{ "${priority_real}${filename}.conf symlink": + ensure => $vhost_symlink_ensure, + path => "${vhost_enable_dir}/${priority_real}${filename}.conf", + target => "${::apache::vhost_dir}/${priority_real}${filename}.conf", + owner => 'root', + group => $::apache::params::root_group, + mode => '0644', + require => Concat["${priority_real}${filename}.conf"], + notify => Class['apache::service'], + } + } + + # Template uses: + # - $nvh_addr_port + # - $servername + # - $serveradmin + concat::fragment { "${name}-apache-header": + target => "${priority_real}${filename}.conf", + order => 0, + content => template('apache/vhost/_file_header.erb'), + } + + # Template uses: + # - $virtual_docroot + # - $docroot + concat::fragment { "${name}-docroot": + target => "${priority_real}${filename}.conf", + order => 10, + content => template('apache/vhost/_docroot.erb'), + } + + # Template uses: + # - $aliases + if $aliases and ! empty($aliases) { + concat::fragment { "${name}-aliases": + target => "${priority_real}${filename}.conf", + order => 20, + content => template('apache/vhost/_aliases.erb'), + } + } + + # Template uses: + # - $itk + # - $::kernelversion + if $itk and ! empty($itk) { + concat::fragment { "${name}-itk": + target => "${priority_real}${filename}.conf", + order => 30, + content => template('apache/vhost/_itk.erb'), + } + } + + # Template uses: + # - $fallbackresource + if $fallbackresource { + concat::fragment { "${name}-fallbackresource": + target => "${priority_real}${filename}.conf", + order => 40, + content => template('apache/vhost/_fallbackresource.erb'), + } + } + + # Template uses: + # - $allow_encoded_slashes + if $allow_encoded_slashes { + concat::fragment { "${name}-allow_encoded_slashes": + target => "${priority_real}${filename}.conf", + order => 50, + content => template('apache/vhost/_allow_encoded_slashes.erb'), + } + } + + # Template uses: + # - $_directories + # - $docroot + # - $apache_version + # - $suphp_engine + # - $shibboleth_enabled + if $_directories and ! empty($_directories) { + concat::fragment { "${name}-directories": + target => "${priority_real}${filename}.conf", + order => 60, + content => template('apache/vhost/_directories.erb'), + } + } + + # Template uses: + # - $additional_includes + if $additional_includes and ! empty($additional_includes) { + concat::fragment { "${name}-additional_includes": + target => "${priority_real}${filename}.conf", + order => 70, + content => template('apache/vhost/_additional_includes.erb'), + } + } + + # Template uses: + # - $error_log + # - $log_level + # - $error_log_destination + # - $log_level + if $error_log or $log_level { + concat::fragment { "${name}-logging": + target => "${priority_real}${filename}.conf", + order => 80, + content => template('apache/vhost/_logging.erb'), + } + } + + # Template uses no variables + concat::fragment { "${name}-serversignature": + target => "${priority_real}${filename}.conf", + order => 90, + content => template('apache/vhost/_serversignature.erb'), + } + + # Template uses: + # - $access_log + # - $_access_log_env_var + # - $access_log_destination + # - $_access_log_format + # - $_access_log_env_var + # - $access_logs + if $access_log or $access_logs { + concat::fragment { "${name}-access_log": + target => "${priority_real}${filename}.conf", + order => 100, + content => template('apache/vhost/_access_log.erb'), + } + } + + # Template uses: + # - $action + if $action { + concat::fragment { "${name}-action": + target => "${priority_real}${filename}.conf", + order => 110, + content => template('apache/vhost/_action.erb'), + } + } + + # Template uses: + # - $block + # - $apache_version + if $block and ! empty($block) { + concat::fragment { "${name}-block": + target => "${priority_real}${filename}.conf", + order => 120, + content => template('apache/vhost/_block.erb'), + } + } + + # Template uses: + # - $error_documents + if $error_documents and ! empty($error_documents) { + concat::fragment { "${name}-error_document": + target => "${priority_real}${filename}.conf", + order => 130, + content => template('apache/vhost/_error_document.erb'), + } + } + + # Template uses: + # - $proxy_dest + # - $proxy_pass + # - $proxy_pass_match + # - $proxy_preserve_host + # - $no_proxy_uris + if $proxy_dest or $proxy_pass or $proxy_pass_match { + concat::fragment { "${name}-proxy": + target => "${priority_real}${filename}.conf", + order => 140, + content => template('apache/vhost/_proxy.erb'), + } + } + + # Template uses: + # - $rack_base_uris + if $rack_base_uris { + concat::fragment { "${name}-rack": + target => "${priority_real}${filename}.conf", + order => 150, + content => template('apache/vhost/_rack.erb'), + } + } + + # Template uses: + # - $redirect_source + # - $redirect_dest + # - $redirect_status + # - $redirect_dest_a + # - $redirect_source_a + # - $redirect_status_a + # - $redirectmatch_status + # - $redirectmatch_regexp + # - $redirectmatch_dest + # - $redirectmatch_status_a + # - $redirectmatch_regexp_a + # - $redirectmatch_dest + if ($redirect_source and $redirect_dest) or ($redirectmatch_status and $redirectmatch_regexp and $redirectmatch_dest) { + concat::fragment { "${name}-redirect": + target => "${priority_real}${filename}.conf", + order => 160, + content => template('apache/vhost/_redirect.erb'), + } + } + + # Template uses: + # - $rewrites + # - $rewrite_base + # - $rewrite_rule + # - $rewrite_cond + # - $rewrite_map + if $rewrites or $rewrite_rule { + concat::fragment { "${name}-rewrite": + target => "${priority_real}${filename}.conf", + order => 170, + content => template('apache/vhost/_rewrite.erb'), + } + } + + # Template uses: + # - $scriptaliases + # - $scriptalias + if ( $scriptalias or $scriptaliases != [] ) { + concat::fragment { "${name}-scriptalias": + target => "${priority_real}${filename}.conf", + order => 180, + content => template('apache/vhost/_scriptalias.erb'), + } + } + + # Template uses: + # - $serveraliases + if $serveraliases and ! empty($serveraliases) { + concat::fragment { "${name}-serveralias": + target => "${priority_real}${filename}.conf", + order => 190, + content => template('apache/vhost/_serveralias.erb'), + } + } + + # Template uses: + # - $setenv + # - $setenvif + if ($setenv and ! empty($setenv)) or ($setenvif and ! empty($setenvif)) { + concat::fragment { "${name}-setenv": + target => "${priority_real}${filename}.conf", + order => 200, + content => template('apache/vhost/_setenv.erb'), + } + } + + # Template uses: + # - $ssl + # - $ssl_cert + # - $ssl_key + # - $ssl_chain + # - $ssl_certs_dir + # - $ssl_ca + # - $ssl_crl_path + # - $ssl_crl + # - $ssl_crl_check + # - $ssl_proxyengine + # - $ssl_protocol + # - $ssl_cipher + # - $ssl_honorcipherorder + # - $ssl_verify_client + # - $ssl_verify_depth + # - $ssl_options + # - $apache_version + if $ssl { + concat::fragment { "${name}-ssl": + target => "${priority_real}${filename}.conf", + order => 210, + content => template('apache/vhost/_ssl.erb'), + } + } + + # Template uses: + # - $suphp_engine + # - $suphp_addhandler + # - $suphp_configpath + if $suphp_engine == 'on' { + concat::fragment { "${name}-suphp": + target => "${priority_real}${filename}.conf", + order => 220, + content => template('apache/vhost/_suphp.erb'), + } + } + + # Template uses: + # - $php_values + # - $php_flags + if ($php_values and ! empty($php_values)) or ($php_flags and ! empty($php_flags)) { + concat::fragment { "${name}-php": + target => "${priority_real}${filename}.conf", + order => 220, + content => template('apache/vhost/_php.erb'), + } + } + + # Template uses: + # - $php_admin_values + # - $php_admin_flags + if ($php_admin_values and ! empty($php_admin_values)) or ($php_admin_flags and ! empty($php_admin_flags)) { + concat::fragment { "${name}-php_admin": + target => "${priority_real}${filename}.conf", + order => 230, + content => template('apache/vhost/_php_admin.erb'), + } + } + + # Template uses: + # - $headers + if $headers and ! empty($headers) { + concat::fragment { "${name}-header": + target => "${priority_real}${filename}.conf", + order => 240, + content => template('apache/vhost/_header.erb'), + } + } + + # Template uses: + # - $request_headers + if $request_headers and ! empty($request_headers) { + concat::fragment { "${name}-requestheader": + target => "${priority_real}${filename}.conf", + order => 250, + content => template('apache/vhost/_requestheader.erb'), + } + } + + # Template uses: + # - $wsgi_application_group + # - $wsgi_daemon_process + # - $wsgi_daemon_process_options + # - $wsgi_import_script + # - $wsgi_import_script_options + # - $wsgi_process_group + # - $wsgi_script_aliases + # - $wsgi_pass_authorization + if $wsgi_application_group or $wsgi_daemon_process or ($wsgi_import_script and $wsgi_import_script_options) or $wsgi_process_group or ($wsgi_script_aliases and ! empty($wsgi_script_aliases)) or $wsgi_pass_authorization { + concat::fragment { "${name}-wsgi": + target => "${priority_real}${filename}.conf", + order => 260, + content => template('apache/vhost/_wsgi.erb'), + } + } + + # Template uses: + # - $custom_fragment + if $custom_fragment { + concat::fragment { "${name}-custom_fragment": + target => "${priority_real}${filename}.conf", + order => 270, + content => template('apache/vhost/_custom_fragment.erb'), + } + } + + # Template uses: + # - $fastcgi_server + # - $fastcgi_socket + # - $fastcgi_dir + # - $apache_version + if $fastcgi_server or $fastcgi_dir { + concat::fragment { "${name}-fastcgi": + target => "${priority_real}${filename}.conf", + order => 280, + content => template('apache/vhost/_fastcgi.erb'), + } + } + + # Template uses: + # - $suexec_user_group + if $suexec_user_group { + concat::fragment { "${name}-suexec": + target => "${priority_real}${filename}.conf", + order => 290, + content => template('apache/vhost/_suexec.erb'), + } + } + + # Template uses: + # - $passenger_app_root + # - $passenger_app_env + # - $passenger_ruby + # - $passenger_min_instances + # - $passenger_start_timeout + # - $passenger_pre_start + if $passenger_app_root or $passenger_app_env or $passenger_ruby or $passenger_min_instances or $passenger_start_timeout or $passenger_pre_start { + concat::fragment { "${name}-passenger": + target => "${priority_real}${filename}.conf", + order => 300, + content => template('apache/vhost/_passenger.erb'), + } + } + + # Template uses: + # - $add_default_charset + if $add_default_charset { + concat::fragment { "${name}-charsets": + target => "${priority_real}${filename}.conf", + order => 310, + content => template('apache/vhost/_charsets.erb'), + } + } + + # Template uses: + # - $modsec_disable_vhost + # - $modsec_disable_ids + # - $modsec_disable_ips + # - $modsec_body_limit + if $modsec_disable_vhost or $modsec_disable_ids or $modsec_disable_ips { + concat::fragment { "${name}-security": + target => "${priority_real}${filename}.conf", + order => 320, + content => template('apache/vhost/_security.erb') + } + } + + # Template uses no variables + concat::fragment { "${name}-file_footer": + target => "${priority_real}${filename}.conf", + order => 999, + content => template('apache/vhost/_file_footer.erb'), + } +} diff --git a/3rdparty/modules/apache/metadata.json b/3rdparty/modules/apache/metadata.json new file mode 100644 index 000000000..71bad1d35 --- /dev/null +++ b/3rdparty/modules/apache/metadata.json @@ -0,0 +1,79 @@ +{ + "name": "puppetlabs-apache", + "version": "1.5.0", + "author": "puppetlabs", + "summary": "Installs, configures, and manages Apache virtual hosts, web services, and modules.", + "license": "Apache-2.0", + "source": "git://github.com/puppetlabs/puppetlabs-apache.git", + "project_page": "https://github.com/puppetlabs/puppetlabs-apache", + "issues_url": "https://tickets.puppetlabs.com/browse/MODULES", + "operatingsystem_support": [ + { + "operatingsystem": "RedHat", + "operatingsystemrelease": [ + "5", + "6", + "7" + ] + }, + { + "operatingsystem": "CentOS", + "operatingsystemrelease": [ + "5", + "6", + "7" + ] + }, + { + "operatingsystem": "OracleLinux", + "operatingsystemrelease": [ + "6", + "7" + ] + }, + { + "operatingsystem": "Scientific", + "operatingsystemrelease": [ + "5", + "6", + "7" + ] + }, + { + "operatingsystem": "Debian", + "operatingsystemrelease": [ + "6", + "7" + ] + }, + { + "operatingsystem": "SLES", + "operatingsystemrelease": [ + "11 SP1" + ] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": [ + "10.04", + "12.04", + "14.04" + ] + } + ], + "requirements": [ + { + "name": "pe", + "version_requirement": ">= 3.7.0 < 4.0.0" + }, + { + "name": "puppet", + "version_requirement": "3.x" + } + ], + "description": "Module for Apache configuration", + "dependencies": [ + {"name":"puppetlabs/stdlib","version_requirement":">= 2.4.0 < 5.0.0"}, + {"name":"puppetlabs/concat","version_requirement":">= 1.1.1 < 2.0.0"} + ] +} diff --git a/3rdparty/modules/apache/spec/acceptance/apache_parameters_spec.rb b/3rdparty/modules/apache/spec/acceptance/apache_parameters_spec.rb new file mode 100644 index 000000000..4c6fa7f56 --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/apache_parameters_spec.rb @@ -0,0 +1,475 @@ +require 'spec_helper_acceptance' +require_relative './version.rb' + +describe 'apache parameters', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + + # Currently this test only does something on FreeBSD. + describe 'default_confd_files => false' do + it 'doesnt do anything' do + pp = "class { 'apache': default_confd_files => false }" + apply_manifest(pp, :catch_failures => true) + end + + if fact('osfamily') == 'FreeBSD' + describe file("#{$confd_dir}/no-accf.conf.erb") do + it { is_expected.not_to be_file } + end + end + end + describe 'default_confd_files => true' do + it 'copies conf.d files' do + pp = "class { 'apache': default_confd_files => true }" + apply_manifest(pp, :catch_failures => true) + end + + if fact('osfamily') == 'FreeBSD' + describe file("#{$confd_dir}/no-accf.conf.erb") do + it { is_expected.to be_file } + end + end + end + + describe 'when set adds a listen statement' do + it 'applys cleanly' do + pp = "class { 'apache': ip => '10.1.1.1', service_ensure => stopped }" + apply_manifest(pp, :catch_failures => true) + end + + describe file($ports_file) do + it { is_expected.to be_file } + it { is_expected.to contain 'Listen 10.1.1.1' } + end + end + + describe 'service tests => true' do + it 'starts the service' do + pp = <<-EOS + class { 'apache': + service_enable => true, + service_manage => true, + service_ensure => running, + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service($service_name) do + it { is_expected.to be_running } + it { is_expected.to be_enabled } + end + end + + describe 'service tests => false' do + it 'stops the service' do + pp = <<-EOS + class { 'apache': + service_enable => false, + service_ensure => stopped, + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service($service_name) do + it { is_expected.not_to be_running } + it { is_expected.not_to be_enabled } + end + end + + describe 'service manage => false' do + it 'we dont manage the service, so it shouldnt start the service' do + pp = <<-EOS + class { 'apache': + service_enable => true, + service_manage => false, + service_ensure => true, + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service($service_name) do + it { is_expected.not_to be_running } + it { is_expected.not_to be_enabled } + end + end + + describe 'purge parameters => false' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': + purge_configs => false, + purge_vhost_dir => false, + vhost_dir => "#{$confd_dir}.vhosts" + } + EOS + shell("touch #{$confd_dir}/test.conf") + shell("mkdir -p #{$confd_dir}.vhosts && touch #{$confd_dir}.vhosts/test.conf") + apply_manifest(pp, :catch_failures => true) + end + + # Ensure the files didn't disappear. + describe file("#{$confd_dir}/test.conf") do + it { is_expected.to be_file } + end + describe file("#{$confd_dir}.vhosts/test.conf") do + it { is_expected.to be_file } + end + end + + if fact('osfamily') != 'Debian' + describe 'purge parameters => true' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': + purge_configs => true, + purge_vhost_dir => true, + vhost_dir => "#{$confd_dir}.vhosts" + } + EOS + shell("touch #{$confd_dir}/test.conf") + shell("mkdir -p #{$confd_dir}.vhosts && touch #{$confd_dir}.vhosts/test.conf") + apply_manifest(pp, :catch_failures => true) + end + + # File should be gone + describe file("#{$confd_dir}/test.conf") do + it { is_expected.not_to be_file } + end + describe file("#{$confd_dir}.vhosts/test.conf") do + it { is_expected.not_to be_file } + end + end + end + + describe 'serveradmin' do + it 'applies cleanly' do + pp = "class { 'apache': serveradmin => 'test@example.com' }" + apply_manifest(pp, :catch_failures => true) + end + + describe file($vhost) do + it { is_expected.to be_file } + it { is_expected.to contain 'ServerAdmin test@example.com' } + end + end + + describe 'sendfile' do + describe 'setup' do + it 'applies cleanly' do + pp = "class { 'apache': sendfile => 'On' }" + apply_manifest(pp, :catch_failures => true) + end + end + + describe file($conf_file) do + it { is_expected.to be_file } + it { is_expected.to contain 'EnableSendfile On' } + end + + describe 'setup' do + it 'applies cleanly' do + pp = "class { 'apache': sendfile => 'Off' }" + apply_manifest(pp, :catch_failures => true) + end + end + + describe file($conf_file) do + it { is_expected.to be_file } + it { is_expected.to contain 'Sendfile Off' } + end + end + + describe 'error_documents' do + describe 'setup' do + it 'applies cleanly' do + pp = "class { 'apache': error_documents => true }" + apply_manifest(pp, :catch_failures => true) + end + end + + describe file($conf_file) do + it { is_expected.to be_file } + it { is_expected.to contain 'Alias /error/' } + end + end + + describe 'timeout' do + describe 'setup' do + it 'applies cleanly' do + pp = "class { 'apache': timeout => '1234' }" + apply_manifest(pp, :catch_failures => true) + end + end + + describe file($conf_file) do + it { is_expected.to be_file } + it { is_expected.to contain 'Timeout 1234' } + end + end + + describe 'httpd_dir' do + describe 'setup' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': httpd_dir => '/tmp', service_ensure => stopped } + include 'apache::mod::mime' + EOS + apply_manifest(pp, :catch_failures => true) + end + end + + describe file("#{$mod_dir}/mime.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'AddLanguage eo .eo' } + end + end + + describe 'server_root' do + describe 'setup' do + it 'applies cleanly' do + pp = "class { 'apache': server_root => '/tmp/root', service_ensure => stopped }" + apply_manifest(pp, :catch_failures => true) + end + end + + describe file($conf_file) do + it { is_expected.to be_file } + it { is_expected.to contain 'ServerRoot "/tmp/root"' } + end + end + + describe 'confd_dir' do + describe 'setup' do + it 'applies cleanly' do + pp = "class { 'apache': confd_dir => '/tmp/root', service_ensure => stopped, use_optional_includes => true }" + apply_manifest(pp, :catch_failures => true) + end + end + + if $apache_version == '2.4' + describe file($conf_file) do + it { is_expected.to be_file } + it { is_expected.to contain 'IncludeOptional "/tmp/root/*.conf"' } + end + else + describe file($conf_file) do + it { is_expected.to be_file } + it { is_expected.to contain 'Include "/tmp/root/*.conf"' } + end + end + end + + describe 'conf_template' do + describe 'setup' do + it 'applies cleanly' do + pp = "class { 'apache': conf_template => 'another/test.conf.erb', service_ensure => stopped }" + shell("mkdir -p #{default['distmoduledir']}/another/templates") + shell("echo 'testcontent' >> #{default['distmoduledir']}/another/templates/test.conf.erb") + apply_manifest(pp, :catch_failures => true) + end + end + + describe file($conf_file) do + it { is_expected.to be_file } + it { is_expected.to contain 'testcontent' } + end + end + + describe 'servername' do + describe 'setup' do + it 'applies cleanly' do + pp = "class { 'apache': servername => 'test.server', service_ensure => stopped }" + apply_manifest(pp, :catch_failures => true) + end + end + + describe file($conf_file) do + it { is_expected.to be_file } + it { is_expected.to contain 'ServerName "test.server"' } + end + end + + describe 'user' do + describe 'setup' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': + manage_user => true, + manage_group => true, + user => 'testweb', + group => 'testweb', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + end + + describe user('testweb') do + it { is_expected.to exist } + it { is_expected.to belong_to_group 'testweb' } + end + + describe group('testweb') do + it { is_expected.to exist } + end + end + + describe 'logformats' do + describe 'setup' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': + log_formats => { + 'vhost_common' => '%v %h %l %u %t \\\"%r\\\" %>s %b', + 'vhost_combined' => '%v %h %l %u %t \\\"%r\\\" %>s %b \\\"%{Referer}i\\\" \\\"%{User-agent}i\\\"', + } + } + EOS + apply_manifest(pp, :catch_failures => true) + end + end + + describe file($conf_file) do + it { is_expected.to be_file } + it { is_expected.to contain 'LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common' } + it { is_expected.to contain 'LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" vhost_combined' } + end + end + + + describe 'keepalive' do + describe 'setup' do + it 'applies cleanly' do + pp = "class { 'apache': keepalive => 'On', keepalive_timeout => '30', max_keepalive_requests => '200' }" + apply_manifest(pp, :catch_failures => true) + end + end + + describe file($conf_file) do + it { is_expected.to be_file } + it { is_expected.to contain 'KeepAlive On' } + it { is_expected.to contain 'KeepAliveTimeout 30' } + it { is_expected.to contain 'MaxKeepAliveRequests 200' } + end + end + + describe 'logging' do + describe 'setup' do + it 'applies cleanly' do + pp = <<-EOS + if $::osfamily == 'RedHat' and $::selinux { + $semanage_package = $::operatingsystemmajrelease ? { + '5' => 'policycoreutils', + default => 'policycoreutils-python', + } + + package { $semanage_package: ensure => installed } + exec { 'set_apache_defaults': + command => 'semanage fcontext -a -t httpd_log_t "/apache_spec(/.*)?"', + path => '/bin:/usr/bin/:/sbin:/usr/sbin', + require => Package[$semanage_package], + } + exec { 'restorecon_apache': + command => 'restorecon -Rv /apache_spec', + path => '/bin:/usr/bin/:/sbin:/usr/sbin', + before => Service['httpd'], + require => Class['apache'], + } + } + file { '/apache_spec': ensure => directory, } + class { 'apache': logroot => '/apache_spec' } + EOS + apply_manifest(pp, :catch_failures => true) + end + end + + describe file("/apache_spec/#{$error_log}") do + it { is_expected.to be_file } + end + end + + describe 'ports_file' do + it 'applys cleanly' do + pp = <<-EOS + file { '/apache_spec': ensure => directory, } + class { 'apache': + ports_file => '/apache_spec/ports_file', + ip => '10.1.1.1', + service_ensure => stopped + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file('/apache_spec/ports_file') do + it { is_expected.to be_file } + it { is_expected.to contain 'Listen 10.1.1.1' } + end + end + + describe 'server_tokens' do + it 'applys cleanly' do + pp = <<-EOS + class { 'apache': + server_tokens => 'Minor', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file($conf_file) do + it { is_expected.to be_file } + it { is_expected.to contain 'ServerTokens Minor' } + end + end + + describe 'server_signature' do + it 'applys cleanly' do + pp = <<-EOS + class { 'apache': + server_signature => 'testsig', + service_ensure => stopped, + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file($conf_file) do + it { is_expected.to be_file } + it { is_expected.to contain 'ServerSignature testsig' } + end + end + + describe 'trace_enable' do + it 'applys cleanly' do + pp = <<-EOS + class { 'apache': + trace_enable => 'Off', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file($conf_file) do + it { is_expected.to be_file } + it { is_expected.to contain 'TraceEnable Off' } + end + end + + describe 'package_ensure' do + it 'applys cleanly' do + pp = <<-EOS + class { 'apache': + package_ensure => present, + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe package($package_name) do + it { is_expected.to be_installed } + end + end + +end diff --git a/3rdparty/modules/apache/spec/acceptance/apache_ssl_spec.rb b/3rdparty/modules/apache/spec/acceptance/apache_ssl_spec.rb new file mode 100644 index 000000000..f8023fa24 --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/apache_ssl_spec.rb @@ -0,0 +1,100 @@ +require 'spec_helper_acceptance' +require_relative './version.rb' + +case fact('osfamily') +when 'RedHat' + vhostd = '/etc/httpd/conf.d' +when 'Debian' + vhostd = '/etc/apache2/sites-available' +end + +describe 'apache ssl', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + + describe 'ssl parameters' do + it 'runs without error' do + pp = <<-EOS + class { 'apache': + service_ensure => stopped, + default_ssl_vhost => true, + default_ssl_cert => '/tmp/ssl_cert', + default_ssl_key => '/tmp/ssl_key', + default_ssl_chain => '/tmp/ssl_chain', + default_ssl_ca => '/tmp/ssl_ca', + default_ssl_crl_path => '/tmp/ssl_crl_path', + default_ssl_crl => '/tmp/ssl_crl', + default_ssl_crl_check => 'chain', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{vhostd}/15-default-ssl.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'SSLCertificateFile "/tmp/ssl_cert"' } + it { is_expected.to contain 'SSLCertificateKeyFile "/tmp/ssl_key"' } + it { is_expected.to contain 'SSLCertificateChainFile "/tmp/ssl_chain"' } + it { is_expected.to contain 'SSLCACertificateFile "/tmp/ssl_ca"' } + it { is_expected.to contain 'SSLCARevocationPath "/tmp/ssl_crl_path"' } + it { is_expected.to contain 'SSLCARevocationFile "/tmp/ssl_crl"' } + if $apache_version == '2.4' + it { is_expected.to contain 'SSLCARevocationCheck "chain"' } + else + it { is_expected.not_to contain 'SSLCARevocationCheck' } + end + end + end + + describe 'vhost ssl parameters' do + it 'runs without error' do + pp = <<-EOS + class { 'apache': + service_ensure => stopped, + } + + apache::vhost { 'test_ssl': + docroot => '/tmp/test', + ssl => true, + ssl_cert => '/tmp/ssl_cert', + ssl_key => '/tmp/ssl_key', + ssl_chain => '/tmp/ssl_chain', + ssl_ca => '/tmp/ssl_ca', + ssl_crl_path => '/tmp/ssl_crl_path', + ssl_crl => '/tmp/ssl_crl', + ssl_crl_check => 'chain', + ssl_certs_dir => '/tmp', + ssl_protocol => 'test', + ssl_cipher => 'test', + ssl_honorcipherorder => 'test', + ssl_verify_client => 'test', + ssl_verify_depth => 'test', + ssl_options => ['test', 'test1'], + ssl_proxyengine => true, + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{vhostd}/25-test_ssl.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'SSLCertificateFile "/tmp/ssl_cert"' } + it { is_expected.to contain 'SSLCertificateKeyFile "/tmp/ssl_key"' } + it { is_expected.to contain 'SSLCertificateChainFile "/tmp/ssl_chain"' } + it { is_expected.to contain 'SSLCACertificateFile "/tmp/ssl_ca"' } + it { is_expected.to contain 'SSLCARevocationPath "/tmp/ssl_crl_path"' } + it { is_expected.to contain 'SSLCARevocationFile "/tmp/ssl_crl"' } + it { is_expected.to contain 'SSLProxyEngine On' } + it { is_expected.to contain 'SSLProtocol test' } + it { is_expected.to contain 'SSLCipherSuite test' } + it { is_expected.to contain 'SSLHonorCipherOrder test' } + it { is_expected.to contain 'SSLVerifyClient test' } + it { is_expected.to contain 'SSLVerifyDepth test' } + it { is_expected.to contain 'SSLOptions test test1' } + if $apache_version == '2.4' + it { is_expected.to contain 'SSLCARevocationCheck "chain"' } + else + it { is_expected.not_to contain 'SSLCARevocationCheck' } + end + end + end + +end diff --git a/3rdparty/modules/apache/spec/acceptance/class_spec.rb b/3rdparty/modules/apache/spec/acceptance/class_spec.rb new file mode 100644 index 000000000..0a7d67bbb --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/class_spec.rb @@ -0,0 +1,88 @@ +require 'spec_helper_acceptance' + +describe 'apache class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + case fact('osfamily') + when 'RedHat' + package_name = 'httpd' + service_name = 'httpd' + when 'Debian' + package_name = 'apache2' + service_name = 'apache2' + when 'FreeBSD' + package_name = 'apache24' + service_name = 'apache24' + when 'Gentoo' + package_name = 'www-servers/apache' + service_name = 'apache2' + end + + context 'default parameters' do + it 'should work with no errors' do + pp = <<-EOS + class { 'apache': } + EOS + + # Run it twice and test for idempotency + apply_manifest(pp, :catch_failures => true) + expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero + end + + describe package(package_name) do + it { is_expected.to be_installed } + end + + describe service(service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + describe port(80) do + it { should be_listening } + end + end + + context 'custom site/mod dir parameters' do + # Using puppet_apply as a helper + it 'should work with no errors' do + pp = <<-EOS + if $::osfamily == 'RedHat' and $::selinux { + $semanage_package = $::operatingsystemmajrelease ? { + '5' => 'policycoreutils', + default => 'policycoreutils-python', + } + + package { $semanage_package: ensure => installed } + exec { 'set_apache_defaults': + command => 'semanage fcontext -a -t httpd_sys_content_t "/apache_spec(/.*)?"', + path => '/bin:/usr/bin/:/sbin:/usr/sbin', + subscribe => Package[$semanage_package], + refreshonly => true, + } + exec { 'restorecon_apache': + command => 'restorecon -Rv /apache_spec', + path => '/bin:/usr/bin/:/sbin:/usr/sbin', + before => Service['httpd'], + require => Class['apache'], + subscribe => Exec['set_apache_defaults'], + refreshonly => true, + } + } + file { '/apache_spec': ensure => directory, } + file { '/apache_spec/apache_custom': ensure => directory, } + class { 'apache': + mod_dir => '/apache_spec/apache_custom/mods', + vhost_dir => '/apache_spec/apache_custom/vhosts', + } + EOS + + # Run it twice and test for idempotency + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + describe service(service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + end +end diff --git a/3rdparty/modules/apache/spec/acceptance/custom_config_spec.rb b/3rdparty/modules/apache/spec/acceptance/custom_config_spec.rb new file mode 100644 index 000000000..8b59f703f --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/custom_config_spec.rb @@ -0,0 +1,55 @@ +require 'spec_helper_acceptance' +require_relative './version.rb' + +describe 'apache::custom_config define', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + context 'invalid config' do + it 'should not add the config' do + pp = <<-EOS + class { 'apache': } + apache::custom_config { 'acceptance_test': + content => 'INVALID', + } + EOS + + apply_manifest(pp, :expect_failures => true) + end + + describe file("#{$confd_dir}/25-acceptance_test.conf") do + it { is_expected.not_to be_file } + end + end + + context 'valid config' do + it 'should add the config' do + pp = <<-EOS + class { 'apache': } + apache::custom_config { 'acceptance_test': + content => '# just a comment', + } + EOS + + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$confd_dir}/25-acceptance_test.conf") do + it { is_expected.to contain '# just a comment' } + end + end + + describe 'custom_config without priority prefix' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + apache::custom_config { 'prefix_test': + priority => false, + content => '# just a comment', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$confd_dir}/prefix_test.conf") do + it { is_expected.to be_file } + end + end +end diff --git a/3rdparty/modules/apache/spec/acceptance/default_mods_spec.rb b/3rdparty/modules/apache/spec/acceptance/default_mods_spec.rb new file mode 100644 index 000000000..0199f180b --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/default_mods_spec.rb @@ -0,0 +1,123 @@ +require 'spec_helper_acceptance' + +case fact('osfamily') +when 'RedHat' + mod_dir = '/etc/httpd/conf.d' + servicename = 'httpd' +when 'Debian' + mod_dir = '/etc/apache2/mods-available' + servicename = 'apache2' +when 'FreeBSD' + mod_dir = '/usr/local/etc/apache24/Modules' + servicename = 'apache24' +when 'Gentoo' + mod_dir = '/etc/apache2/modules.d' + servicename = 'apache2' +end + +describe 'apache::default_mods class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + describe 'no default mods' do + # Using puppet_apply as a helper + it 'should apply with no errors' do + pp = <<-EOS + class { 'apache': + default_mods => false, + } + EOS + + # Run it twice and test for idempotency + apply_manifest(pp, :catch_failures => true) + expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero + end + + describe service(servicename) do + it { is_expected.to be_running } + end + end + + describe 'no default mods and failing' do + # Using puppet_apply as a helper + it 'should apply with errors' do + pp = <<-EOS + class { 'apache': + default_mods => false, + } + apache::vhost { 'defaults.example.com': + docroot => '/var/www/defaults', + aliases => { + alias => '/css', + path => '/var/www/css', + }, + setenv => 'TEST1 one', + } + EOS + + apply_manifest(pp, { :expect_failures => true }) + end + + # Are these the same? + describe service(servicename) do + it { is_expected.not_to be_running } + end + describe "service #{servicename}" do + it 'should not be running' do + shell("pidof #{servicename}", {:acceptable_exit_codes => 1}) + end + end + end + + describe 'alternative default mods' do + # Using puppet_apply as a helper + it 'should apply with no errors' do + pp = <<-EOS + class { 'apache': + default_mods => [ + 'info', + 'alias', + 'mime', + 'env', + 'expires', + ], + } + apache::vhost { 'defaults.example.com': + docroot => '/var/www/defaults', + aliases => { + alias => '/css', + path => '/var/www/css', + }, + setenv => 'TEST1 one', + } + EOS + + apply_manifest(pp, :catch_failures => true) + shell('sleep 10') + expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero + end + + describe service(servicename) do + it { is_expected.to be_running } + end + end + + describe 'change loadfile name' do + it 'should apply with no errors' do + pp = <<-EOS + class { 'apache': default_mods => false } + ::apache::mod { 'auth_basic': + loadfile_name => 'zz_auth_basic.load', + } + EOS + # Run it twice and test for idempotency + apply_manifest(pp, :catch_failures => true) + expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero + end + + describe service(servicename) do + it { is_expected.to be_running } + end + + describe file("#{mod_dir}/zz_auth_basic.load") do + it { is_expected.to be_file } + end + end +end diff --git a/3rdparty/modules/apache/spec/acceptance/itk_spec.rb b/3rdparty/modules/apache/spec/acceptance/itk_spec.rb new file mode 100644 index 000000000..2dde8f407 --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/itk_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper_acceptance' + +case fact('osfamily') +when 'Debian' + service_name = 'apache2' +when 'FreeBSD' + service_name = 'apache24' +else + # Not implemented yet + service_name = :skip +end + +describe 'apache::mod::itk class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) or service_name.equal? :skip do + describe 'running puppet code' do + # Using puppet_apply as a helper + it 'should work with no errors' do + pp = <<-EOS + class { 'apache': + mpm_module => 'itk', + } + EOS + + # Run it twice and test for idempotency + apply_manifest(pp, :catch_failures => true) + expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero + end + end + + describe service(service_name) do + it { is_expected.to be_running } + it { is_expected.to be_enabled } + end +end diff --git a/3rdparty/modules/apache/spec/acceptance/mod_dav_svn_spec.rb b/3rdparty/modules/apache/spec/acceptance/mod_dav_svn_spec.rb new file mode 100644 index 000000000..10c9b77d7 --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/mod_dav_svn_spec.rb @@ -0,0 +1,62 @@ +require 'spec_helper_acceptance' + +describe 'apache::mod::dav_svn class', :unless => (fact('operatingsystem') == 'OracleLinux' and fact('operatingsystemmajrelease') == '7') do + case fact('osfamily') + when 'Debian' + mod_dir = '/etc/apache2/mods-available' + service_name = 'apache2' + if fact('operatingsystemmajrelease') == '6' or fact('operatingsystemmajrelease') == '10.04' or fact('operatingsystemrelease') == '10.04' + authz_svn_load_file = 'dav_svn_authz_svn.load' + else + authz_svn_load_file = 'authz_svn.load' + end + when 'RedHat' + mod_dir = '/etc/httpd/conf.d' + service_name = 'httpd' + authz_svn_load_file = 'dav_svn_authz_svn.load' + when 'FreeBSD' + mod_dir = '/usr/local/etc/apache24/Modules' + service_name = 'apache24' + authz_svn_load_file = 'dav_svn_authz_svn.load' + end + + context "default dav_svn config" do + it 'succeeds in puppeting dav_svn' do + pp= <<-EOS + class { 'apache': } + include apache::mod::dav_svn + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service(service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + describe file("#{mod_dir}/dav_svn.load") do + it { is_expected.to contain "LoadModule dav_svn_module" } + end + end + + context "dav_svn with enabled authz_svn config" do + it 'succeeds in puppeting dav_svn' do + pp= <<-EOS + class { 'apache': } + class { 'apache::mod::dav_svn': + authz_svn_enabled => true, + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service(service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + describe file("#{mod_dir}/#{authz_svn_load_file}") do + it { is_expected.to contain "LoadModule authz_svn_module" } + end + end +end diff --git a/3rdparty/modules/apache/spec/acceptance/mod_deflate_spec.rb b/3rdparty/modules/apache/spec/acceptance/mod_deflate_spec.rb new file mode 100644 index 000000000..3b505bdbf --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/mod_deflate_spec.rb @@ -0,0 +1,43 @@ +require 'spec_helper_acceptance' + +describe 'apache::mod::deflate class' do + case fact('osfamily') + when 'Debian' + mod_dir = '/etc/apache2/mods-available' + service_name = 'apache2' + when 'RedHat' + mod_dir = '/etc/httpd/conf.d' + service_name = 'httpd' + when 'FreeBSD' + mod_dir = '/usr/local/etc/apache24/Modules' + service_name = 'apache24' + when 'Gentoo' + mod_dir = '/etc/apache2/modules.d' + service_name = 'apache2' + end + + context "default deflate config" do + it 'succeeds in puppeting deflate' do + pp= <<-EOS + class { 'apache': } + include apache::mod::deflate + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service(service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + describe file("#{mod_dir}/deflate.conf") do + it { is_expected.to contain "AddOutputFilterByType DEFLATE text/html text/plain text/xml" } + it { is_expected.to contain "AddOutputFilterByType DEFLATE text/css" } + it { is_expected.to contain "AddOutputFilterByType DEFLATE application/x-javascript application/javascript application/ecmascript" } + it { is_expected.to contain "AddOutputFilterByType DEFLATE application/rss+xml" } + it { is_expected.to contain "DeflateFilterNote Input instream" } + it { is_expected.to contain "DeflateFilterNote Output outstream" } + it { is_expected.to contain "DeflateFilterNote Ratio ratio" } + end + end +end diff --git a/3rdparty/modules/apache/spec/acceptance/mod_fcgid_spec.rb b/3rdparty/modules/apache/spec/acceptance/mod_fcgid_spec.rb new file mode 100644 index 000000000..e99a7f299 --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/mod_fcgid_spec.rb @@ -0,0 +1,57 @@ +require 'spec_helper_acceptance' + +describe 'apache::mod::fcgid class', :unless => (UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) or (fact('operatingsystem') == 'OracleLinux' and fact('operatingsystemmajrelease') == '7')) do + context "default fcgid config", :if => (fact('osfamily') == 'RedHat' and fact('operatingsystemmajrelease') != '5') do + it 'succeeds in puppeting fcgid' do + pp = <<-EOS + class { 'epel': } # mod_fcgid lives in epel + class { 'apache': } + class { 'apache::mod::php': } # For /usr/bin/php-cgi + class { 'apache::mod::fcgid': + options => { + 'FcgidIPCDir' => '/var/run/fcgidsock', + }, + } + apache::vhost { 'fcgid.example.com': + port => '80', + docroot => '/var/www/fcgid', + directories => { + path => '/var/www/fcgid', + options => '+ExecCGI', + addhandlers => { + handler => 'fcgid-script', + extensions => '.php', + }, + fcgiwrapper => { + command => '/usr/bin/php-cgi', + suffix => '.php', + } + }, + } + file { '/var/www/fcgid/index.php': + ensure => file, + owner => 'root', + group => 'root', + content => "\\n", + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service('httpd') do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + it 'should answer to fcgid.example.com' do + shell("/usr/bin/curl -H 'Host: fcgid.example.com' 127.0.0.1:80") do |r| + expect(r.stdout).to match(/^Hello world$/) + expect(r.exit_code).to eq(0) + end + end + + it 'should run a php-cgi process' do + shell("pgrep -u apache php-cgi", :acceptable_exit_codes => [0]) + end + end +end diff --git a/3rdparty/modules/apache/spec/acceptance/mod_mime_spec.rb b/3rdparty/modules/apache/spec/acceptance/mod_mime_spec.rb new file mode 100644 index 000000000..d1886c4bd --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/mod_mime_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper_acceptance' + +describe 'apache::mod::mime class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + case fact('osfamily') + when 'Debian' + mod_dir = '/etc/apache2/mods-available' + service_name = 'apache2' + when 'RedHat' + mod_dir = '/etc/httpd/conf.d' + service_name = 'httpd' + when 'FreeBSD' + mod_dir = '/usr/local/etc/apache24/Modules' + service_name = 'apache24' + when 'Gentoo' + mod_dir = '/etc/apache2/modules.d' + service_name = 'apache2' + end + + context "default mime config" do + it 'succeeds in puppeting mime' do + pp= <<-EOS + class { 'apache': } + include apache::mod::mime + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service(service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + describe file("#{mod_dir}/mime.conf") do + it { is_expected.to contain "AddType application/x-compress .Z" } + end + end +end diff --git a/3rdparty/modules/apache/spec/acceptance/mod_negotiation_spec.rb b/3rdparty/modules/apache/spec/acceptance/mod_negotiation_spec.rb new file mode 100644 index 000000000..a44edbf26 --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/mod_negotiation_spec.rb @@ -0,0 +1,84 @@ +require 'spec_helper_acceptance' + +describe 'apache::mod::negotiation class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + case fact('osfamily') + when 'Debian' + vhost_dir = '/etc/apache2/sites-enabled' + mod_dir = '/etc/apache2/mods-available' + service_name = 'apache2' + when 'RedHat' + vhost_dir = '/etc/httpd/conf.d' + mod_dir = '/etc/httpd/conf.d' + service_name = 'httpd' + when 'FreeBSD' + vhost_dir = '/usr/local/etc/apache24/Vhosts' + mod_dir = '/usr/local/etc/apache24/Modules' + service_name = 'apache24' + when 'Gentoo' + vhost_dir = '/etc/apache2/vhosts.d' + mod_dir = '/etc/apache2/modules.d' + service_name = 'apache2' + end + + context "default negotiation config" do + it 'succeeds in puppeting negotiation' do + pp= <<-EOS + class { '::apache': default_mods => false } + class { '::apache::mod::negotiation': } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{mod_dir}/negotiation.conf") do + it { should contain "LanguagePriority en ca cs da de el eo es et fr he hr it ja ko ltz nl nn no pl pt pt-BR ru sv zh-CN zh-TW +ForceLanguagePriority Prefer Fallback" } + end + + describe service(service_name) do + it { should be_enabled } + it { should be_running } + end + end + + context "with alternative force_language_priority" do + it 'succeeds in puppeting negotiation' do + pp= <<-EOS + class { '::apache': default_mods => false } + class { '::apache::mod::negotiation': + force_language_priority => 'Prefer', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{mod_dir}/negotiation.conf") do + it { should contain "ForceLanguagePriority Prefer" } + end + + describe service(service_name) do + it { should be_enabled } + it { should be_running } + end + end + + context "with alternative language_priority" do + it 'succeeds in puppeting negotiation' do + pp= <<-EOS + class { '::apache': default_mods => false } + class { '::apache::mod::negotiation': + language_priority => [ 'en', 'es' ], + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{mod_dir}/negotiation.conf") do + it { should contain "LanguagePriority en es" } + end + + describe service(service_name) do + it { should be_enabled } + it { should be_running } + end + end +end diff --git a/3rdparty/modules/apache/spec/acceptance/mod_pagespeed_spec.rb b/3rdparty/modules/apache/spec/acceptance/mod_pagespeed_spec.rb new file mode 100644 index 000000000..5fa342e9a --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/mod_pagespeed_spec.rb @@ -0,0 +1,89 @@ +require 'spec_helper_acceptance' + +describe 'apache::mod::pagespeed class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + case fact('osfamily') + when 'Debian' + vhost_dir = '/etc/apache2/sites-enabled' + mod_dir = '/etc/apache2/mods-available' + service_name = 'apache2' + when 'RedHat' + vhost_dir = '/etc/httpd/conf.d' + mod_dir = '/etc/httpd/conf.d' + service_name = 'httpd' + when 'FreeBSD' + vhost_dir = '/usr/local/etc/apache24/Vhosts' + mod_dir = '/usr/local/etc/apache24/Modules' + service_name = 'apache24' + when 'Gentoo' + vhost_dir = '/etc/apache2/vhosts.d' + mod_dir = '/etc/apache2/modules.d' + service_name = 'apache2' + end + + context "default pagespeed config" do + it 'succeeds in puppeting pagespeed' do + pp= <<-EOS + if $::osfamily == 'Debian' { + class { 'apt': } + + apt::source { 'mod-pagespeed': + key => '7FAC5991', + key_server => 'pgp.mit.edu', + location => 'http://dl.google.com/linux/mod-pagespeed/deb/', + release => 'stable', + repos => 'main', + include_src => false, + before => Class['apache'], + } + } elsif $::osfamily == 'RedHat' { + yumrepo { 'mod-pagespeed': + baseurl => "http://dl.google.com/linux/mod-pagespeed/rpm/stable/$::architecture", + enabled => 1, + gpgcheck => 1, + gpgkey => 'https://dl-ssl.google.com/linux/linux_signing_key.pub', + before => Class['apache'], + } + } + + class { 'apache': + mpm_module => 'prefork', + } + class { 'apache::mod::pagespeed': + enable_filters => ['remove_comments'], + disable_filters => ['extend_cache'], + forbid_filters => ['rewrite_javascript'], + } + apache::vhost { 'pagespeed.example.com': + port => '80', + docroot => '/var/www/pagespeed', + } + host { 'pagespeed.example.com': ip => '127.0.0.1', } + file { '/var/www/pagespeed/index.html': + ensure => file, + content => "\n\n\n

Hello World!

\n\n", + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service(service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + describe file("#{mod_dir}/pagespeed.conf") do + it { is_expected.to contain "AddOutputFilterByType MOD_PAGESPEED_OUTPUT_FILTER text/html" } + it { is_expected.to contain "ModPagespeedEnableFilters remove_comments" } + it { is_expected.to contain "ModPagespeedDisableFilters extend_cache" } + it { is_expected.to contain "ModPagespeedForbidFilters rewrite_javascript" } + end + + it 'should answer to pagespeed.example.com and include and be stripped of comments by mod_pagespeed' do + shell("/usr/bin/curl pagespeed.example.com:80") do |r| + expect(r.stdout).to match(//) + expect(r.stdout).not_to match(//) + expect(r.exit_code).to eq(0) + end + end + end +end diff --git a/3rdparty/modules/apache/spec/acceptance/mod_passenger_spec.rb b/3rdparty/modules/apache/spec/acceptance/mod_passenger_spec.rb new file mode 100644 index 000000000..7b2d0da9a --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/mod_passenger_spec.rb @@ -0,0 +1,308 @@ +require 'spec_helper_acceptance' + +describe 'apache::mod::passenger class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + case fact('osfamily') + when 'Debian' + service_name = 'apache2' + mod_dir = '/etc/apache2/mods-available/' + conf_file = "#{mod_dir}passenger.conf" + load_file = "#{mod_dir}zpassenger.load" + + case fact('operatingsystem') + when 'Ubuntu' + case fact('lsbdistrelease') + when '10.04' + passenger_root = '/usr' + passenger_ruby = '/usr/bin/ruby' + when '12.04' + passenger_root = '/usr' + passenger_ruby = '/usr/bin/ruby' + when '14.04' + passenger_root = '/usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini' + passenger_ruby = '/usr/bin/ruby' + passenger_default_ruby = '/usr/bin/ruby' + else + # This may or may not work on Ubuntu releases other than the above + passenger_root = '/usr' + passenger_ruby = '/usr/bin/ruby' + end + when 'Debian' + case fact('lsbdistcodename') + when 'wheezy' + passenger_root = '/usr' + passenger_ruby = '/usr/bin/ruby' + when 'jessie' + passenger_root = '/usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini' + passenger_ruby = '/usr/bin/ruby' + passenger_default_ruby = '/usr/bin/ruby' + else + # This may or may not work on Debian releases other than the above + passenger_root = '/usr' + passenger_ruby = '/usr/bin/ruby' + end + end + + passenger_module_path = '/usr/lib/apache2/modules/mod_passenger.so' + rackapp_user = 'www-data' + rackapp_group = 'www-data' + when 'RedHat' + service_name = 'httpd' + mod_dir = '/etc/httpd/conf.d/' + conf_file = "#{mod_dir}passenger.conf" + load_file = "#{mod_dir}zpassenger.load" + # sometimes installs as 3.0.12, sometimes as 3.0.19 - so just check for the stable part + passenger_root = '/usr/lib/ruby/gems/1.8/gems/passenger-3.0.1' + passenger_ruby = '/usr/bin/ruby' + passenger_tempdir = '/var/run/rubygem-passenger' + passenger_module_path = 'modules/mod_passenger.so' + rackapp_user = 'apache' + rackapp_group = 'apache' + end + + pp_rackapp = <<-EOS + /* a simple ruby rack 'hellow world' app */ + file { '/var/www/passenger': + ensure => directory, + owner => '#{rackapp_user}', + group => '#{rackapp_group}', + require => Class['apache::mod::passenger'], + } + file { '/var/www/passenger/config.ru': + ensure => file, + owner => '#{rackapp_user}', + group => '#{rackapp_group}', + content => "app = proc { |env| [200, { \\"Content-Type\\" => \\"text/html\\" }, [\\"hello world\\"]] }\\nrun app", + require => File['/var/www/passenger'] , + } + apache::vhost { 'passenger.example.com': + port => '80', + docroot => '/var/www/passenger/public', + docroot_group => '#{rackapp_group}' , + docroot_owner => '#{rackapp_user}' , + custom_fragment => "PassengerRuby #{passenger_ruby}\\nRailsEnv development" , + require => File['/var/www/passenger/config.ru'] , + } + host { 'passenger.example.com': ip => '127.0.0.1', } + EOS + + case fact('osfamily') + when 'Debian' + context "default passenger config" do + it 'succeeds in puppeting passenger' do + pp = <<-EOS + /* stock apache and mod_passenger */ + class { 'apache': } + class { 'apache::mod::passenger': } + #{pp_rackapp} + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service(service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + describe file(conf_file) do + it { is_expected.to contain "PassengerRoot \"#{passenger_root}\"" } + + case fact('operatingsystem') + when 'Ubuntu' + case fact('lsbdistrelease') + when '10.04' + it { is_expected.to contain "PassengerRuby \"#{passenger_ruby}\"" } + it { is_expected.not_to contain "/PassengerDefaultRuby/" } + when '12.04' + it { is_expected.to contain "PassengerRuby \"#{passenger_ruby}\"" } + it { is_expected.not_to contain "/PassengerDefaultRuby/" } + when '14.04' + it { is_expected.to contain "PassengerDefaultRuby \"#{passenger_ruby}\"" } + it { is_expected.not_to contain "/PassengerRuby/" } + else + # This may or may not work on Ubuntu releases other than the above + it { is_expected.to contain "PassengerRuby \"#{passenger_ruby}\"" } + it { is_expected.not_to contain "/PassengerDefaultRuby/" } + end + when 'Debian' + case fact('lsbdistcodename') + when 'wheezy' + it { is_expected.to contain "PassengerRuby \"#{passenger_ruby}\"" } + it { is_expected.not_to contain "/PassengerDefaultRuby/" } + when 'jessie' + it { is_expected.to contain "PassengerDefaultRuby \"#{passenger_ruby}\"" } + it { is_expected.not_to contain "/PassengerRuby/" } + else + # This may or may not work on Debian releases other than the above + it { is_expected.to contain "PassengerRuby \"#{passenger_ruby}\"" } + it { is_expected.not_to contain "/PassengerDefaultRuby/" } + end + end + end + + describe file(load_file) do + it { is_expected.to contain "LoadModule passenger_module #{passenger_module_path}" } + end + + it 'should output status via passenger-memory-stats' do + shell("PATH=/usr/bin:$PATH /usr/sbin/passenger-memory-stats") do |r| + expect(r.stdout).to match(/Apache processes/) + expect(r.stdout).to match(/Nginx processes/) + expect(r.stdout).to match(/Passenger processes/) + + # passenger-memory-stats output on newer Debian/Ubuntu verions do not contain + # these two lines + unless ((fact('operatingsystem') == 'Ubuntu' && fact('operatingsystemrelease') == '14.04') or + (fact('operatingsystem') == 'Debian' && fact('operatingsystemrelease') == '8.0')) + expect(r.stdout).to match(/### Processes: [0-9]+/) + expect(r.stdout).to match(/### Total private dirty RSS: [0-9\.]+ MB/) + end + + expect(r.exit_code).to eq(0) + end + end + + # passenger-status fails under stock ubuntu-server-12042-x64 + mod_passenger, + # even when the passenger process is successfully installed and running + unless fact('operatingsystem') == 'Ubuntu' && fact('operatingsystemrelease') == '12.04' + it 'should output status via passenger-status' do + # xml output not available on ubunutu <= 10.04, so sticking with default pool output + shell("PATH=/usr/bin:$PATH /usr/sbin/passenger-status") do |r| + # spacing may vary + expect(r.stdout).to match(/[\-]+ General information [\-]+/) + if fact('operatingsystem') == 'Ubuntu' && fact('operatingsystemrelease') == '14.04' + expect(r.stdout).to match(/Max pool size[ ]+: [0-9]+/) + expect(r.stdout).to match(/Processes[ ]+: [0-9]+/) + expect(r.stdout).to match(/Requests in top-level queue[ ]+: [0-9]+/) + else + expect(r.stdout).to match(/max[ ]+= [0-9]+/) + expect(r.stdout).to match(/count[ ]+= [0-9]+/) + expect(r.stdout).to match(/active[ ]+= [0-9]+/) + expect(r.stdout).to match(/inactive[ ]+= [0-9]+/) + expect(r.stdout).to match(/Waiting on global queue: [0-9]+/) + end + + expect(r.exit_code).to eq(0) + end + end + end + + it 'should answer to passenger.example.com' do + shell("/usr/bin/curl passenger.example.com:80") do |r| + expect(r.stdout).to match(/^hello world<\/b>$/) + expect(r.exit_code).to eq(0) + end + end + + end + + when 'RedHat' + # no fedora 18 passenger package yet, and rhel5 packages only exist for ruby 1.8.5 + unless (fact('operatingsystem') == 'Fedora' and fact('operatingsystemrelease').to_f >= 18) or (fact('osfamily') == 'RedHat' and fact('operatingsystemmajrelease') == '5' and fact('rubyversion') != '1.8.5') + + if fact('osfamily') == 'RedHat' and fact('operatingsystemmajrelease') == '7' + pending('test passenger - RHEL7 packages don\'t exist') + else + context "default passenger config" do + it 'succeeds in puppeting passenger' do + pp = <<-EOS + /* EPEL and passenger repositories */ + class { 'epel': } + exec { 'passenger.repo GPG key': + command => '/usr/bin/curl -o /etc/yum.repos.d/RPM-GPG-KEY-stealthymonkeys.asc http://passenger.stealthymonkeys.com/RPM-GPG-KEY-stealthymonkeys.asc', + creates => '/etc/yum.repos.d/RPM-GPG-KEY-stealthymonkeys.asc', + } + file { 'passenger.repo GPG key': + ensure => file, + path => '/etc/yum.repos.d/RPM-GPG-KEY-stealthymonkeys.asc', + require => Exec['passenger.repo GPG key'], + } + epel::rpm_gpg_key { 'passenger.stealthymonkeys.com': + path => '/etc/yum.repos.d/RPM-GPG-KEY-stealthymonkeys.asc', + require => [ + Class['epel'], + File['passenger.repo GPG key'], + ] + } + $releasever_string = $operatingsystem ? { + 'Scientific' => '6', + default => '$releasever', + } + yumrepo { 'passenger': + baseurl => "http://passenger.stealthymonkeys.com/rhel/${releasever_string}/\\$basearch" , + descr => "Red Hat Enterprise ${releasever_string} - Phusion Passenger", + enabled => 1, + gpgcheck => 1, + gpgkey => 'http://passenger.stealthymonkeys.com/RPM-GPG-KEY-stealthymonkeys.asc', + mirrorlist => 'http://passenger.stealthymonkeys.com/rhel/mirrors', + require => [ + Epel::Rpm_gpg_key['passenger.stealthymonkeys.com'], + ], + } + /* apache and mod_passenger */ + class { 'apache': + require => [ + Class['epel'], + ], + } + class { 'apache::mod::passenger': + require => [ + Yumrepo['passenger'] + ], + } + #{pp_rackapp} + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service(service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + describe file(conf_file) do + it { is_expected.to contain "PassengerRoot #{passenger_root}" } + it { is_expected.to contain "PassengerRuby #{passenger_ruby}" } + it { is_expected.to contain "PassengerTempDir #{passenger_tempdir}" } + end + + describe file(load_file) do + it { is_expected.to contain "LoadModule passenger_module #{passenger_module_path}" } + end + + it 'should output status via passenger-memory-stats' do + shell("/usr/bin/passenger-memory-stats", :pty => true) do |r| + expect(r.stdout).to match(/Apache processes/) + expect(r.stdout).to match(/Nginx processes/) + expect(r.stdout).to match(/Passenger processes/) + expect(r.stdout).to match(/### Processes: [0-9]+/) + expect(r.stdout).to match(/### Total private dirty RSS: [0-9\.]+ MB/) + + expect(r.exit_code).to eq(0) + end + end + + it 'should output status via passenger-status' do + shell("PASSENGER_TMPDIR=/var/run/rubygem-passenger /usr/bin/passenger-status") do |r| + # spacing may vary + r.stdout.should =~ /[\-]+ General information [\-]+/ + r.stdout.should =~ /max[ ]+= [0-9]+/ + r.stdout.should =~ /count[ ]+= [0-9]+/ + r.stdout.should =~ /active[ ]+= [0-9]+/ + r.stdout.should =~ /inactive[ ]+= [0-9]+/ + r.stdout.should =~ /Waiting on global queue: [0-9]+/ + + r.exit_code.should == 0 + end + end + + it 'should answer to passenger.example.com' do + shell("/usr/bin/curl passenger.example.com:80") do |r| + r.stdout.should =~ /^hello world<\/b>$/ + r.exit_code.should == 0 + end + end + end + end + end + end +end diff --git a/3rdparty/modules/apache/spec/acceptance/mod_php_spec.rb b/3rdparty/modules/apache/spec/acceptance/mod_php_spec.rb new file mode 100644 index 000000000..502ec1ddc --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/mod_php_spec.rb @@ -0,0 +1,143 @@ +require 'spec_helper_acceptance' + +describe 'apache::mod::php class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + case fact('osfamily') + when 'Debian' + vhost_dir = '/etc/apache2/sites-enabled' + mod_dir = '/etc/apache2/mods-available' + service_name = 'apache2' + when 'RedHat' + vhost_dir = '/etc/httpd/conf.d' + mod_dir = '/etc/httpd/conf.d' + service_name = 'httpd' + when 'FreeBSD' + vhost_dir = '/usr/local/etc/apache24/Vhosts' + mod_dir = '/usr/local/etc/apache24/Modules' + service_name = 'apache24' + when 'Gentoo' + vhost_dir = '/etc/apache2/vhosts.d' + mod_dir = '/etc/apache2/modules.d' + service_name = 'apache2' + end + + context "default php config" do + it 'succeeds in puppeting php' do + pp= <<-EOS + class { 'apache': + mpm_module => 'prefork', + } + class { 'apache::mod::php': } + apache::vhost { 'php.example.com': + port => '80', + docroot => '/var/www/php', + } + host { 'php.example.com': ip => '127.0.0.1', } + file { '/var/www/php/index.php': + ensure => file, + content => "\\n", + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service(service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + describe file("#{mod_dir}/php5.conf") do + it { is_expected.to contain "DirectoryIndex index.php" } + end + + it 'should answer to php.example.com' do + shell("/usr/bin/curl php.example.com:80") do |r| + expect(r.stdout).to match(/PHP Version/) + expect(r.exit_code).to eq(0) + end + end + end + + context "custom extensions, php_flag, php_value, php_admin_flag, and php_admin_value" do + it 'succeeds in puppeting php' do + pp= <<-EOS + class { 'apache': + mpm_module => 'prefork', + } + class { 'apache::mod::php': + extensions => ['.php','.php5'], + } + apache::vhost { 'php.example.com': + port => '80', + docroot => '/var/www/php', + php_values => { 'include_path' => '.:/usr/share/pear:/usr/bin/php', }, + php_flags => { 'display_errors' => 'on', }, + php_admin_values => { 'open_basedir' => '/var/www/php/:/usr/share/pear/', }, + php_admin_flags => { 'engine' => 'on', }, + } + host { 'php.example.com': ip => '127.0.0.1', } + file { '/var/www/php/index.php5': + ensure => file, + content => "\\n", + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service(service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + describe file("#{vhost_dir}/25-php.example.com.conf") do + it { is_expected.to contain " php_flag display_errors on" } + it { is_expected.to contain " php_value include_path .:/usr/share/pear:/usr/bin/php" } + it { is_expected.to contain " php_admin_flag engine on" } + it { is_expected.to contain " php_admin_value open_basedir /var/www/php/:/usr/share/pear/" } + end + + it 'should answer to php.example.com' do + shell("/usr/bin/curl php.example.com:80") do |r| + expect(r.stdout).to match(/\/usr\/share\/pear\//) + expect(r.exit_code).to eq(0) + end + end + end + + context "provide custom config file" do + it 'succeeds in puppeting php' do + pp= <<-EOS + class {'apache': + mpm_module => 'prefork', + } + class {'apache::mod::php': + content => '# somecontent', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{mod_dir}/php5.conf") do + it { should contain "# somecontent" } + end + end + + context "provide content and template config file" do + it 'succeeds in puppeting php' do + pp= <<-EOS + class {'apache': + mpm_module => 'prefork', + } + class {'apache::mod::php': + content => '# somecontent', + template => 'apache/mod/php5.conf.erb', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{mod_dir}/php5.conf") do + it { should contain "# somecontent" } + end + end + +end diff --git a/3rdparty/modules/apache/spec/acceptance/mod_proxy_html_spec.rb b/3rdparty/modules/apache/spec/acceptance/mod_proxy_html_spec.rb new file mode 100644 index 000000000..e45600089 --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/mod_proxy_html_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper_acceptance' + +describe 'apache::mod::proxy_html class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + case fact('osfamily') + when 'Debian' + service_name = 'apache2' + when 'RedHat' + service_name = 'httpd' + when 'FreeBSD' + service_name = 'apache24' + when 'Gentoo' + service_name = 'apache2' + end + + context "default proxy_html config" do + if fact('osfamily') == 'RedHat' and fact('operatingsystemmajrelease') =~ /(5|6)/ + it 'adds epel' do + pp = "class { 'epel': }" + apply_manifest(pp, :catch_failures => true) + end + end + + it 'succeeds in puppeting proxy_html' do + pp= <<-EOS + class { 'apache': } + class { 'apache::mod::proxy': } + class { 'apache::mod::proxy_http': } + # mod_proxy_html doesn't exist in RHEL5 + if $::osfamily == 'RedHat' and $::operatingsystemmajrelease != '5' { + class { 'apache::mod::proxy_html': } + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service(service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + end +end diff --git a/3rdparty/modules/apache/spec/acceptance/mod_security_spec.rb b/3rdparty/modules/apache/spec/acceptance/mod_security_spec.rb new file mode 100644 index 000000000..60295787e --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/mod_security_spec.rb @@ -0,0 +1,228 @@ +require 'spec_helper_acceptance' + +describe 'apache::mod::security class', :unless => (UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) or (fact('osfamily') == 'Debian' and (fact('lsbdistcodename') == 'squeeze' or fact('lsbdistcodename') == 'lucid' or fact('lsbdistcodename') == 'precise'))) do + case fact('osfamily') + when 'Debian' + mod_dir = '/etc/apache2/mods-available' + service_name = 'apache2' + package_name = 'apache2' + when 'RedHat' + mod_dir = '/etc/httpd/conf.d' + service_name = 'httpd' + package_name = 'httpd' + end + + context "default mod_security config" do + if fact('osfamily') == 'RedHat' and fact('operatingsystemmajrelease') =~ /(5|6)/ + it 'adds epel' do + pp = "class { 'epel': }" + apply_manifest(pp, :catch_failures => true) + end + end + + it 'succeeds in puppeting mod_security' do + pp= <<-EOS + host { 'modsec.example.com': ip => '127.0.0.1', } + class { 'apache': } + class { 'apache::mod::security': } + apache::vhost { 'modsec.example.com': + port => '80', + docroot => '/var/www/html', + } + file { '/var/www/html/index.html': + ensure => file, + content => 'Index page', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service(service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + describe package(package_name) do + it { is_expected.to be_installed } + end + + describe file("#{mod_dir}/security.conf") do + it { is_expected.to contain "mod_security2.c" } + end + + it 'should return index page' do + shell('/usr/bin/curl -A beaker modsec.example.com:80') do |r| + expect(r.stdout).to match(/Index page/) + expect(r.exit_code).to eq(0) + end + end + + it 'should block query with SQL' do + shell '/usr/bin/curl -A beaker -f modsec.example.com:80?SELECT%20*FROM%20mysql.users', :acceptable_exit_codes => [22] + end + + end #default mod_security config + + context "mod_security should allow disabling by vhost" do + it 'succeeds in puppeting mod_security' do + pp= <<-EOS + host { 'modsec.example.com': ip => '127.0.0.1', } + class { 'apache': } + class { 'apache::mod::security': } + apache::vhost { 'modsec.example.com': + port => '80', + docroot => '/var/www/html', + } + file { '/var/www/html/index.html': + ensure => file, + content => 'Index page', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service(service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + describe file("#{mod_dir}/security.conf") do + it { is_expected.to contain "mod_security2.c" } + end + + it 'should block query with SQL' do + shell '/usr/bin/curl -A beaker -f modsec.example.com:80?SELECT%20*FROM%20mysql.users', :acceptable_exit_codes => [22] + end + + it 'should disable mod_security per vhost' do + pp= <<-EOS + class { 'apache': } + class { 'apache::mod::security': } + apache::vhost { 'modsec.example.com': + port => '80', + docroot => '/var/www/html', + modsec_disable_vhost => true, + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + it 'should return index page' do + shell('/usr/bin/curl -A beaker -f modsec.example.com:80?SELECT%20*FROM%20mysql.users') do |r| + expect(r.stdout).to match(/Index page/) + expect(r.exit_code).to eq(0) + end + end + end #mod_security should allow disabling by vhost + + context "mod_security should allow disabling by ip" do + it 'succeeds in puppeting mod_security' do + pp= <<-EOS + host { 'modsec.example.com': ip => '127.0.0.1', } + class { 'apache': } + class { 'apache::mod::security': } + apache::vhost { 'modsec.example.com': + port => '80', + docroot => '/var/www/html', + } + file { '/var/www/html/index.html': + ensure => file, + content => 'Index page', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service(service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + describe file("#{mod_dir}/security.conf") do + it { is_expected.to contain "mod_security2.c" } + end + + it 'should block query with SQL' do + shell '/usr/bin/curl -A beaker -f modsec.example.com:80?SELECT%20*FROM%20mysql.users', :acceptable_exit_codes => [22] + end + + it 'should disable mod_security per vhost' do + pp= <<-EOS + class { 'apache': } + class { 'apache::mod::security': } + apache::vhost { 'modsec.example.com': + port => '80', + docroot => '/var/www/html', + modsec_disable_ips => [ '127.0.0.1' ], + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + it 'should return index page' do + shell('/usr/bin/curl -A beaker modsec.example.com:80') do |r| + expect(r.stdout).to match(/Index page/) + expect(r.exit_code).to eq(0) + end + end + end #mod_security should allow disabling by ip + + context "mod_security should allow disabling by id" do + it 'succeeds in puppeting mod_security' do + pp= <<-EOS + host { 'modsec.example.com': ip => '127.0.0.1', } + class { 'apache': } + class { 'apache::mod::security': } + apache::vhost { 'modsec.example.com': + port => '80', + docroot => '/var/www/html', + } + file { '/var/www/html/index.html': + ensure => file, + content => 'Index page', + } + file { '/var/www/html/index2.html': + ensure => file, + content => 'Page 2', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service(service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + describe file("#{mod_dir}/security.conf") do + it { is_expected.to contain "mod_security2.c" } + end + + it 'should block query with SQL' do + shell '/usr/bin/curl -A beaker -f modsec.example.com:80?SELECT%20*FROM%20mysql.users', :acceptable_exit_codes => [22] + end + + it 'should disable mod_security per vhost' do + pp= <<-EOS + class { 'apache': } + class { 'apache::mod::security': } + apache::vhost { 'modsec.example.com': + port => '80', + docroot => '/var/www/html', + modsec_disable_ids => [ '950007' ], + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + it 'should return index page' do + shell('/usr/bin/curl -A beaker -f modsec.example.com:80?SELECT%20*FROM%20mysql.users') do |r| + expect(r.stdout).to match(/Index page/) + expect(r.exit_code).to eq(0) + end + end + + end #mod_security should allow disabling by id + + +end #apache::mod::security class diff --git a/3rdparty/modules/apache/spec/acceptance/mod_suphp_spec.rb b/3rdparty/modules/apache/spec/acceptance/mod_suphp_spec.rb new file mode 100644 index 000000000..33f57fba6 --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/mod_suphp_spec.rb @@ -0,0 +1,55 @@ +require 'spec_helper_acceptance' + +describe 'apache::mod::suphp class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + case fact('operatingsystem') + when 'Ubuntu' + context "default suphp config" do + it 'succeeds in puppeting suphp' do + pp = <<-EOS +class { 'apache': + mpm_module => 'prefork', +} +host { 'suphp.example.com': ip => '127.0.0.1', } +apache::vhost { 'suphp.example.com': + port => '80', + docroot => '/var/www/suphp', +} +file { '/var/www/suphp/index.php': + ensure => file, + owner => 'daemon', + group => 'daemon', + content => "\\n", + require => File['/var/www/suphp'], + before => Class['apache::mod::php'], +} +class { 'apache::mod::php': } +class { 'apache::mod::suphp': } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service('apache2') do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + it 'should answer to suphp.example.com' do + timeout = 0 + loop do + r = shell('curl suphp.example.com:80') + timeout += 1 + break if r.stdout =~ /^daemon$/ + if timeout > 40 + expect(timeout < 40).to be true + break + end + sleep(1) + end + shell("/usr/bin/curl suphp.example.com:80") do |r| + expect(r.stdout).to match(/^daemon$/) + expect(r.exit_code).to eq(0) + end + end + end + end +end diff --git a/3rdparty/modules/apache/spec/acceptance/nodesets/centos-59-x64.yml b/3rdparty/modules/apache/spec/acceptance/nodesets/centos-59-x64.yml new file mode 100644 index 000000000..2ad90b86a --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/nodesets/centos-59-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + centos-59-x64: + roles: + - master + platform: el-5-x86_64 + box : centos-59-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-59-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: git diff --git a/3rdparty/modules/apache/spec/acceptance/nodesets/centos-64-x64-pe.yml b/3rdparty/modules/apache/spec/acceptance/nodesets/centos-64-x64-pe.yml new file mode 100644 index 000000000..7d9242f1b --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/nodesets/centos-64-x64-pe.yml @@ -0,0 +1,12 @@ +HOSTS: + centos-64-x64: + roles: + - master + - database + - dashboard + platform: el-6-x86_64 + box : centos-64-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: pe diff --git a/3rdparty/modules/apache/spec/acceptance/nodesets/centos-64-x64.yml b/3rdparty/modules/apache/spec/acceptance/nodesets/centos-64-x64.yml new file mode 100644 index 000000000..ce47212a8 --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/nodesets/centos-64-x64.yml @@ -0,0 +1,11 @@ +HOSTS: + centos-64-x64: + roles: + - master + platform: el-6-x86_64 + box : centos-64-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + log_level: debug + type: git diff --git a/3rdparty/modules/apache/spec/acceptance/nodesets/centos-65-x64.yml b/3rdparty/modules/apache/spec/acceptance/nodesets/centos-65-x64.yml new file mode 100644 index 000000000..4e2cb809e --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/nodesets/centos-65-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + centos-65-x64: + roles: + - master + platform: el-6-x86_64 + box : centos-65-x64-vbox436-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-65-x64-virtualbox-nocm.box + hypervisor : vagrant +CONFIG: + type: foss diff --git a/3rdparty/modules/apache/spec/acceptance/nodesets/centos-70-x64.yml b/3rdparty/modules/apache/spec/acceptance/nodesets/centos-70-x64.yml new file mode 100644 index 000000000..2ab005204 --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/nodesets/centos-70-x64.yml @@ -0,0 +1,11 @@ +HOSTS: + centos-70-x64: + roles: + - master + platform: el-7-x86_64 + box : puppetlabs/centos-7.0-64-nocm + box_url : https://vagrantcloud.com/puppetlabs/boxes/centos-7.0-64-nocm + hypervisor : vagrant +CONFIG: + log_level: verbose + type: foss diff --git a/3rdparty/modules/apache/spec/acceptance/nodesets/debian-607-x64.yml b/3rdparty/modules/apache/spec/acceptance/nodesets/debian-607-x64.yml new file mode 100644 index 000000000..e642e0992 --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/nodesets/debian-607-x64.yml @@ -0,0 +1,11 @@ +HOSTS: + debian-607-x64: + roles: + - master + platform: debian-6-amd64 + box : debian-607-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-607-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + log_level: debug + type: git diff --git a/3rdparty/modules/apache/spec/acceptance/nodesets/debian-70rc1-x64.yml b/3rdparty/modules/apache/spec/acceptance/nodesets/debian-70rc1-x64.yml new file mode 100644 index 000000000..cbbbfb2cc --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/nodesets/debian-70rc1-x64.yml @@ -0,0 +1,11 @@ +HOSTS: + debian-70rc1-x64: + roles: + - master + platform: debian-7-amd64 + box : debian-70rc1-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-70rc1-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + log_level: debug + type: git diff --git a/3rdparty/modules/apache/spec/acceptance/nodesets/debian-73-i386.yml b/3rdparty/modules/apache/spec/acceptance/nodesets/debian-73-i386.yml new file mode 100644 index 000000000..a38902d89 --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/nodesets/debian-73-i386.yml @@ -0,0 +1,11 @@ +HOSTS: + debian-73-i386: + roles: + - master + platform: debian-7-i386 + box : debian-73-i386-virtualbox-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-73-i386-virtualbox-nocm.box + hypervisor : vagrant +CONFIG: + log_level: debug + type: git diff --git a/3rdparty/modules/apache/spec/acceptance/nodesets/debian-73-x64.yml b/3rdparty/modules/apache/spec/acceptance/nodesets/debian-73-x64.yml new file mode 100644 index 000000000..f9cf0c9b8 --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/nodesets/debian-73-x64.yml @@ -0,0 +1,11 @@ +HOSTS: + debian-73-x64: + roles: + - master + platform: debian-7-amd64 + box : debian-73-x64-virtualbox-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/debian-73-x64-virtualbox-nocm.box + hypervisor : vagrant +CONFIG: + log_level: debug + type: git diff --git a/3rdparty/modules/apache/spec/acceptance/nodesets/default.yml b/3rdparty/modules/apache/spec/acceptance/nodesets/default.yml new file mode 100644 index 000000000..ce47212a8 --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/nodesets/default.yml @@ -0,0 +1,11 @@ +HOSTS: + centos-64-x64: + roles: + - master + platform: el-6-x86_64 + box : centos-64-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/centos-64-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + log_level: debug + type: git diff --git a/3rdparty/modules/apache/spec/acceptance/nodesets/fedora-18-x64.yml b/3rdparty/modules/apache/spec/acceptance/nodesets/fedora-18-x64.yml new file mode 100644 index 000000000..086cae995 --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/nodesets/fedora-18-x64.yml @@ -0,0 +1,11 @@ +HOSTS: + fedora-18-x64: + roles: + - master + platform: fedora-18-x86_64 + box : fedora-18-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/fedora-18-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + log_level: debug + type: git diff --git a/3rdparty/modules/apache/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml b/3rdparty/modules/apache/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml new file mode 100644 index 000000000..5ca1514e4 --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/nodesets/ubuntu-server-10044-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + ubuntu-server-10044-x64: + roles: + - master + platform: ubuntu-10.04-amd64 + box : ubuntu-server-10044-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-10044-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: foss diff --git a/3rdparty/modules/apache/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml b/3rdparty/modules/apache/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml new file mode 100644 index 000000000..d065b304f --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/nodesets/ubuntu-server-12042-x64.yml @@ -0,0 +1,10 @@ +HOSTS: + ubuntu-server-12042-x64: + roles: + - master + platform: ubuntu-12.04-amd64 + box : ubuntu-server-12042-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-server-12042-x64-vbox4210-nocm.box + hypervisor : vagrant +CONFIG: + type: foss diff --git a/3rdparty/modules/apache/spec/acceptance/nodesets/ubuntu-server-1310-x64.yml b/3rdparty/modules/apache/spec/acceptance/nodesets/ubuntu-server-1310-x64.yml new file mode 100644 index 000000000..f4b2366f3 --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/nodesets/ubuntu-server-1310-x64.yml @@ -0,0 +1,11 @@ +HOSTS: + ubuntu-server-1310-x64: + roles: + - master + platform: ubuntu-13.10-amd64 + box : ubuntu-server-1310-x64-vbox4210-nocm + box_url : http://puppet-vagrant-boxes.puppetlabs.com/ubuntu-1310-x64-virtualbox-nocm.box + hypervisor : vagrant +CONFIG: + log_level : debug + type: git diff --git a/3rdparty/modules/apache/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml b/3rdparty/modules/apache/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml new file mode 100644 index 000000000..cba1cd04c --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml @@ -0,0 +1,11 @@ +HOSTS: + ubuntu-server-1404-x64: + roles: + - master + platform: ubuntu-14.04-amd64 + box : puppetlabs/ubuntu-14.04-64-nocm + box_url : https://vagrantcloud.com/puppetlabs/ubuntu-14.04-64-nocm + hypervisor : vagrant +CONFIG: + log_level : debug + type: git diff --git a/3rdparty/modules/apache/spec/acceptance/prefork_worker_spec.rb b/3rdparty/modules/apache/spec/acceptance/prefork_worker_spec.rb new file mode 100644 index 000000000..0ac27232d --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/prefork_worker_spec.rb @@ -0,0 +1,81 @@ +require 'spec_helper_acceptance' + +case fact('osfamily') +when 'RedHat' + servicename = 'httpd' +when 'Debian' + servicename = 'apache2' +when 'FreeBSD' + servicename = 'apache24' +when 'Gentoo' + servicename = 'apache2' +end + +case fact('osfamily') +when 'FreeBSD' + describe 'apache::mod::event class' do + describe 'running puppet code' do + # Using puppet_apply as a helper + it 'should work with no errors' do + pp = <<-EOS + class { 'apache': + mpm_module => 'event', + } + EOS + + # Run it twice and test for idempotency + apply_manifest(pp, :catch_failures => true) + expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero + end + end + + describe service(servicename) do + it { is_expected.to be_running } + it { is_expected.to be_enabled } + end + end +end + +describe 'apache::mod::worker class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + describe 'running puppet code' do + # Using puppet_apply as a helper + it 'should work with no errors' do + pp = <<-EOS + class { 'apache': + mpm_module => 'worker', + } + EOS + + # Run it twice and test for idempotency + apply_manifest(pp, :catch_failures => true) + expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero + end + end + + describe service(servicename) do + it { is_expected.to be_running } + it { is_expected.to be_enabled } + end +end + +describe 'apache::mod::prefork class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + describe 'running puppet code' do + # Using puppet_apply as a helper + it 'should work with no errors' do + pp = <<-EOS + class { 'apache': + mpm_module => 'prefork', + } + EOS + + # Run it twice and test for idempotency + apply_manifest(pp, :catch_failures => true) + expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero + end + end + + describe service(servicename) do + it { is_expected.to be_running } + it { is_expected.to be_enabled } + end +end diff --git a/3rdparty/modules/apache/spec/acceptance/service_spec.rb b/3rdparty/modules/apache/spec/acceptance/service_spec.rb new file mode 100644 index 000000000..b51ca386f --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/service_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper_acceptance' + +describe 'apache::service class', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + describe 'adding dependencies in between the base class and service class' do + it 'should work with no errors' do + pp = <<-EOS + class { 'apache': } + file { '/tmp/test': + require => Class['apache'], + notify => Class['apache::service'], + } + EOS + + # Run it twice and test for idempotency + apply_manifest(pp, :catch_failures => true) + expect(apply_manifest(pp, :catch_failures => true).exit_code).to be_zero + end + end +end diff --git a/3rdparty/modules/apache/spec/acceptance/unsupported_spec.rb b/3rdparty/modules/apache/spec/acceptance/unsupported_spec.rb new file mode 100644 index 000000000..085845dbf --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/unsupported_spec.rb @@ -0,0 +1,13 @@ +require 'spec_helper_acceptance' + +describe 'unsupported distributions and OSes', :if => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + it 'should fail' do + pp = <<-EOS + class { 'apache': } + apache::vhost { 'test.lan': + docroot => '/var/www', + } + EOS + expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/unsupported/i) + end +end diff --git a/3rdparty/modules/apache/spec/acceptance/version.rb b/3rdparty/modules/apache/spec/acceptance/version.rb new file mode 100644 index 000000000..117e23d9f --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/version.rb @@ -0,0 +1,75 @@ +_osfamily = fact('osfamily') +_operatingsystem = fact('operatingsystem') +_operatingsystemrelease = fact('operatingsystemrelease').to_f + +case _osfamily +when 'RedHat' + $confd_dir = '/etc/httpd/conf.d' + $mod_dir = '/etc/httpd/conf.d' + $conf_file = '/etc/httpd/conf/httpd.conf' + $ports_file = '/etc/httpd/conf/ports.conf' + $vhost_dir = '/etc/httpd/conf.d' + $vhost = '/etc/httpd/conf.d/15-default.conf' + $run_dir = '/var/run/httpd' + $service_name = 'httpd' + $package_name = 'httpd' + $error_log = 'error_log' + $suphp_handler = 'php5-script' + $suphp_configpath = 'undef' + + if (_operatingsystem == 'Fedora' and _operatingsystemrelease >= 18) or (_operatingsystem != 'Fedora' and _operatingsystemrelease >= 7) + $apache_version = '2.4' + else + $apache_version = '2.2' + end +when 'Debian' + $confd_dir = '/etc/apache2/conf.d' + $mod_dir = '/etc/apache2/mods-available' + $conf_file = '/etc/apache2/apache2.conf' + $ports_file = '/etc/apache2/ports.conf' + $vhost = '/etc/apache2/sites-available/15-default.conf' + $vhost_dir = '/etc/apache2/sites-enabled' + $run_dir = '/var/run/apache2' + $service_name = 'apache2' + $package_name = 'apache2' + $error_log = 'error.log' + $suphp_handler = 'x-httpd-php' + $suphp_configpath = '/etc/php5/apache2' + + if _operatingsystem == 'Ubuntu' and _operatingsystemrelease >= 13.10 + $apache_version = '2.4' + elsif _operatingsystem == 'Debian' and _operatingsystemrelease >= 8.0 + $apache_version = '2.4' + else + $apache_version = '2.2' + end +when 'FreeBSD' + $confd_dir = '/usr/local/etc/apache24/Includes' + $mod_dir = '/usr/local/etc/apache24/Modules' + $conf_file = '/usr/local/etc/apache24/httpd.conf' + $ports_file = '/usr/local/etc/apache24/Includes/ports.conf' + $vhost = '/usr/local/etc/apache24/Vhosts/15-default.conf' + $vhost_dir = '/usr/local/etc/apache24/Vhosts' + $run_dir = '/var/run/apache24' + $service_name = 'apache24' + $package_name = 'apache24' + $error_log = 'http-error.log' + + $apache_version = '2.2' +when 'Gentoo' + $confd_dir = '/etc/apache2/conf.d' + $mod_dir = '/etc/apache2/modules.d' + $conf_file = '/etc/apache2/httpd.conf' + $ports_file = '/etc/apache2/ports.conf' + $vhost = '/etc/apache2/vhosts.d/15-default.conf' + $vhost_dir = '/etc/apache2/vhosts.d' + $run_dir = '/var/run/apache2' + $service_name = 'apache2' + $package_name = 'www-servers/apache' + $error_log = 'http-error.log' + + $apache_version = '2.4' +else + $apache_version = '0' +end + diff --git a/3rdparty/modules/apache/spec/acceptance/vhost_spec.rb b/3rdparty/modules/apache/spec/acceptance/vhost_spec.rb new file mode 100644 index 000000000..b5d51e91f --- /dev/null +++ b/3rdparty/modules/apache/spec/acceptance/vhost_spec.rb @@ -0,0 +1,1342 @@ +require 'spec_helper_acceptance' +require_relative './version.rb' + +describe 'apache::vhost define', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + context 'no default vhosts' do + it 'should create no default vhosts' do + pp = <<-EOS + class { 'apache': + default_vhost => false, + default_ssl_vhost => false, + service_ensure => stopped + } + EOS + + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/15-default.conf") do + it { is_expected.not_to be_file } + end + + describe file("#{$vhost_dir}/15-default-ssl.conf") do + it { is_expected.not_to be_file } + end + end + + context "default vhost without ssl" do + it 'should create a default vhost config' do + pp = <<-EOS + class { 'apache': } + EOS + + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/15-default.conf") do + it { is_expected.to contain '' } + end + + describe file("#{$vhost_dir}/15-default-ssl.conf") do + it { is_expected.not_to be_file } + end + end + + context 'default vhost with ssl' do + it 'should create default vhost configs' do + pp = <<-EOS + file { '#{$run_dir}': + ensure => 'directory', + recurse => true, + } + + class { 'apache': + default_ssl_vhost => true, + require => File['#{$run_dir}'], + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/15-default.conf") do + it { is_expected.to contain '' } + end + + describe file("#{$vhost_dir}/15-default-ssl.conf") do + it { is_expected.to contain '' } + it { is_expected.to contain "SSLEngine on" } + end + end + + context 'new vhost on port 80' do + it 'should configure an apache vhost' do + pp = <<-EOS + class { 'apache': } + file { '#{$run_dir}': + ensure => 'directory', + recurse => true, + } + + apache::vhost { 'first.example.com': + port => '80', + docroot => '/var/www/first', + require => File['#{$run_dir}'], + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-first.example.com.conf") do + it { is_expected.to contain '' } + it { is_expected.to contain "ServerName first.example.com" } + end + end + + context 'new proxy vhost on port 80' do + it 'should configure an apache proxy vhost' do + pp = <<-EOS + class { 'apache': } + apache::vhost { 'proxy.example.com': + port => '80', + docroot => '/var/www/proxy', + proxy_pass => [ + { 'path' => '/foo', 'url' => 'http://backend-foo/'}, + ], + proxy_preserve_host => true, + proxy_error_override => true, + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-proxy.example.com.conf") do + it { is_expected.to contain '' } + it { is_expected.to contain "ServerName proxy.example.com" } + it { is_expected.to contain "ProxyPass" } + it { is_expected.to contain "ProxyPreserveHost On" } + it { is_expected.to contain "ProxyErrorOverride On" } + it { is_expected.not_to contain "" } + end + end + + context 'new proxy vhost on port 80' do + it 'should configure an apache proxy vhost' do + pp = <<-EOS + class { 'apache': } + apache::vhost { 'proxy.example.com': + port => '80', + docroot => '/var/www/proxy', + proxy_pass_match => [ + { 'path' => '/foo', 'url' => 'http://backend-foo/'}, + ], + proxy_preserve_host => true, + proxy_error_override => true, + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-proxy.example.com.conf") do + it { is_expected.to contain '' } + it { is_expected.to contain "ServerName proxy.example.com" } + it { is_expected.to contain "ProxyPassMatch /foo http://backend-foo/" } + it { is_expected.to contain "ProxyPreserveHost On" } + it { is_expected.to contain "ProxyErrorOverride On" } + it { is_expected.not_to contain "" } + end + end + + context 'new vhost on port 80' do + it 'should configure two apache vhosts' do + pp = <<-EOS + class { 'apache': } + apache::vhost { 'first.example.com': + port => '80', + docroot => '/var/www/first', + } + host { 'first.example.com': ip => '127.0.0.1', } + file { '/var/www/first/index.html': + ensure => file, + content => "Hello from first\\n", + } + apache::vhost { 'second.example.com': + port => '80', + docroot => '/var/www/second', + } + host { 'second.example.com': ip => '127.0.0.1', } + file { '/var/www/second/index.html': + ensure => file, + content => "Hello from second\\n", + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service($service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + it 'should answer to first.example.com' do + shell("/usr/bin/curl first.example.com:80", {:acceptable_exit_codes => 0}) do |r| + expect(r.stdout).to eq("Hello from first\n") + end + end + + it 'should answer to second.example.com' do + shell("/usr/bin/curl second.example.com:80", {:acceptable_exit_codes => 0}) do |r| + expect(r.stdout).to eq("Hello from second\n") + end + end + end + + context 'apache_directories' do + describe 'readme example, adapted' do + it 'should configure a vhost with Files' do + pp = <<-EOS + class { 'apache': } + + if versioncmp($apache::apache_version, '2.4') >= 0 { + $_files_match_directory = { 'path' => '(\.swp|\.bak|~)$', 'provider' => 'filesmatch', 'require' => 'all denied', } + } else { + $_files_match_directory = { 'path' => '(\.swp|\.bak|~)$', 'provider' => 'filesmatch', 'deny' => 'from all', } + } + + $_directories = [ + { 'path' => '/var/www/files', }, + $_files_match_directory, + ] + + apache::vhost { 'files.example.net': + docroot => '/var/www/files', + directories => $_directories, + } + file { '/var/www/files/index.html': + ensure => file, + content => "Hello World\\n", + } + file { '/var/www/files/index.html.bak': + ensure => file, + content => "Hello World\\n", + } + host { 'files.example.net': ip => '127.0.0.1', } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service($service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + it 'should answer to files.example.net' do + expect(shell("/usr/bin/curl -sSf files.example.net:80/index.html").stdout).to eq("Hello World\n") + expect(shell("/usr/bin/curl -sSf files.example.net:80/index.html.bak", {:acceptable_exit_codes => 22}).stderr).to match(/curl: \(22\) The requested URL returned error: 403/) + end + end + + describe 'other Directory options' do + it 'should configure a vhost with multiple Directory sections' do + pp = <<-EOS + class { 'apache': } + + if versioncmp($apache::apache_version, '2.4') >= 0 { + $_files_match_directory = { 'path' => 'private.html$', 'provider' => 'filesmatch', 'require' => 'all denied' } + } else { + $_files_match_directory = [ + { 'path' => 'private.html$', 'provider' => 'filesmatch', 'deny' => 'from all' }, + { 'path' => '/bar/bar.html', 'provider' => 'location', allow => [ 'from 127.0.0.1', ] }, + ] + } + + $_directories = [ + { 'path' => '/var/www/files', }, + { 'path' => '/foo/', 'provider' => 'location', 'directoryindex' => 'notindex.html', }, + $_files_match_directory, + ] + + apache::vhost { 'files.example.net': + docroot => '/var/www/files', + directories => $_directories, + } + file { '/var/www/files/foo': + ensure => directory, + } + file { '/var/www/files/foo/notindex.html': + ensure => file, + content => "Hello Foo\\n", + } + file { '/var/www/files/private.html': + ensure => file, + content => "Hello World\\n", + } + file { '/var/www/files/bar': + ensure => directory, + } + file { '/var/www/files/bar/bar.html': + ensure => file, + content => "Hello Bar\\n", + } + host { 'files.example.net': ip => '127.0.0.1', } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service($service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + it 'should answer to files.example.net' do + expect(shell("/usr/bin/curl -sSf files.example.net:80/").stdout).to eq("Hello World\n") + expect(shell("/usr/bin/curl -sSf files.example.net:80/foo/").stdout).to eq("Hello Foo\n") + expect(shell("/usr/bin/curl -sSf files.example.net:80/private.html", {:acceptable_exit_codes => 22}).stderr).to match(/curl: \(22\) The requested URL returned error: 403/) + expect(shell("/usr/bin/curl -sSf files.example.net:80/bar/bar.html").stdout).to eq("Hello Bar\n") + end + end + + describe 'SetHandler directive' do + it 'should configure a vhost with a SetHandler directive' do + pp = <<-EOS + class { 'apache': } + apache::mod { 'status': } + host { 'files.example.net': ip => '127.0.0.1', } + apache::vhost { 'files.example.net': + docroot => '/var/www/files', + directories => [ + { path => '/var/www/files', }, + { path => '/server-status', provider => 'location', sethandler => 'server-status', }, + ], + } + file { '/var/www/files/index.html': + ensure => file, + content => "Hello World\\n", + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service($service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + it 'should answer to files.example.net' do + expect(shell("/usr/bin/curl -sSf files.example.net:80/index.html").stdout).to eq("Hello World\n") + expect(shell("/usr/bin/curl -sSf files.example.net:80/server-status?auto").stdout).to match(/Scoreboard: /) + end + end + + describe 'Satisfy and Auth directive', :unless => $apache_version == '2.4' do + it 'should configure a vhost with Satisfy and Auth directive' do + pp = <<-EOS + class { 'apache': } + host { 'files.example.net': ip => '127.0.0.1', } + apache::vhost { 'files.example.net': + docroot => '/var/www/files', + directories => [ + { + path => '/var/www/files/foo', + auth_type => 'Basic', + auth_name => 'Basic Auth', + auth_user_file => '/var/www/htpasswd', + auth_require => "valid-user", + }, + { + path => '/var/www/files/bar', + auth_type => 'Basic', + auth_name => 'Basic Auth', + auth_user_file => '/var/www/htpasswd', + auth_require => 'valid-user', + satisfy => 'Any', + }, + { + path => '/var/www/files/baz', + allow => 'from 10.10.10.10', + auth_type => 'Basic', + auth_name => 'Basic Auth', + auth_user_file => '/var/www/htpasswd', + auth_require => 'valid-user', + satisfy => 'Any', + }, + ], + } + file { '/var/www/files/foo': + ensure => directory, + } + file { '/var/www/files/bar': + ensure => directory, + } + file { '/var/www/files/baz': + ensure => directory, + } + file { '/var/www/files/foo/index.html': + ensure => file, + content => "Hello World\\n", + } + file { '/var/www/files/bar/index.html': + ensure => file, + content => "Hello World\\n", + } + file { '/var/www/files/baz/index.html': + ensure => file, + content => "Hello World\\n", + } + file { '/var/www/htpasswd': + ensure => file, + content => "login:IZ7jMcLSx0oQk", # "password" as password + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service($service_name) do + it { should be_enabled } + it { should be_running } + end + + it 'should answer to files.example.net' do + shell("/usr/bin/curl -sSf files.example.net:80/foo/index.html", {:acceptable_exit_codes => 22}).stderr.should match(/curl: \(22\) The requested URL returned error: 401/) + shell("/usr/bin/curl -sSf -u login:password files.example.net:80/foo/index.html").stdout.should eq("Hello World\n") + shell("/usr/bin/curl -sSf files.example.net:80/bar/index.html").stdout.should eq("Hello World\n") + shell("/usr/bin/curl -sSf -u login:password files.example.net:80/bar/index.html").stdout.should eq("Hello World\n") + shell("/usr/bin/curl -sSf files.example.net:80/baz/index.html", {:acceptable_exit_codes => 22}).stderr.should match(/curl: \(22\) The requested URL returned error: 401/) + shell("/usr/bin/curl -sSf -u login:password files.example.net:80/baz/index.html").stdout.should eq("Hello World\n") + end + end + end + + case fact('lsbdistcodename') + when 'precise', 'wheezy' + context 'vhost fallbackresource example' do + it 'should configure a vhost with Fallbackresource' do + pp = <<-EOS + class { 'apache': } + apache::vhost { 'fallback.example.net': + docroot => '/var/www/fallback', + fallbackresource => '/index.html' + } + file { '/var/www/fallback/index.html': + ensure => file, + content => "Hello World\\n", + } + host { 'fallback.example.net': ip => '127.0.0.1', } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service($service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + it 'should answer to fallback.example.net' do + shell("/usr/bin/curl fallback.example.net:80/Does/Not/Exist") do |r| + expect(r.stdout).to eq("Hello World\n") + end + end + + end + else + # The current stable RHEL release (6.4) comes with Apache httpd 2.2.15 + # That was released March 6, 2010. + # FallbackResource was backported to 2.2.16, and released July 25, 2010. + # Ubuntu Lucid (10.04) comes with apache2 2.2.14, released October 3, 2009. + # https://svn.apache.org/repos/asf/httpd/httpd/branches/2.2.x/STATUS + end + + context 'virtual_docroot hosting separate sites' do + it 'should configure a vhost with VirtualDocumentRoot' do + pp = <<-EOS + class { 'apache': } + apache::vhost { 'virt.example.com': + vhost_name => '*', + serveraliases => '*virt.example.com', + port => '80', + docroot => '/var/www/virt', + virtual_docroot => '/var/www/virt/%1', + } + host { 'virt.example.com': ip => '127.0.0.1', } + host { 'a.virt.example.com': ip => '127.0.0.1', } + host { 'b.virt.example.com': ip => '127.0.0.1', } + file { [ '/var/www/virt/a', '/var/www/virt/b', ]: ensure => directory, } + file { '/var/www/virt/a/index.html': ensure => file, content => "Hello from a.virt\\n", } + file { '/var/www/virt/b/index.html': ensure => file, content => "Hello from b.virt\\n", } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe service($service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + it 'should answer to a.virt.example.com' do + shell("/usr/bin/curl a.virt.example.com:80", {:acceptable_exit_codes => 0}) do |r| + expect(r.stdout).to eq("Hello from a.virt\n") + end + end + + it 'should answer to b.virt.example.com' do + shell("/usr/bin/curl b.virt.example.com:80", {:acceptable_exit_codes => 0}) do |r| + expect(r.stdout).to eq("Hello from b.virt\n") + end + end + end + + context 'proxy_pass for alternative vhost' do + it 'should configure a local vhost and a proxy vhost' do + apply_manifest(%{ + class { 'apache': default_vhost => false, } + apache::vhost { 'localhost': + docroot => '/var/www/local', + ip => '127.0.0.1', + port => '8888', + } + apache::listen { '*:80': } + apache::vhost { 'proxy.example.com': + docroot => '/var/www', + port => '80', + add_listen => false, + proxy_pass => { + 'path' => '/', + 'url' => 'http://localhost:8888/subdir/', + }, + } + host { 'proxy.example.com': ip => '127.0.0.1', } + file { ['/var/www/local', '/var/www/local/subdir']: ensure => directory, } + file { '/var/www/local/subdir/index.html': + ensure => file, + content => "Hello from localhost\\n", + } + }, :catch_failures => true) + end + + describe service($service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + it 'should get a response from the back end' do + shell("/usr/bin/curl --max-redirs 0 proxy.example.com:80") do |r| + expect(r.stdout).to eq("Hello from localhost\n") + expect(r.exit_code).to eq(0) + end + end + end + + context 'proxy_pass_match for alternative vhost' do + it 'should configure a local vhost and a proxy vhost' do + apply_manifest(%{ + class { 'apache': default_vhost => false, } + apache::vhost { 'localhost': + docroot => '/var/www/local', + ip => '127.0.0.1', + port => '8888', + } + apache::listen { '*:80': } + apache::vhost { 'proxy.example.com': + docroot => '/var/www', + port => '80', + add_listen => false, + proxy_pass_match => { + 'path' => '/', + 'url' => 'http://localhost:8888/subdir/', + }, + } + host { 'proxy.example.com': ip => '127.0.0.1', } + file { ['/var/www/local', '/var/www/local/subdir']: ensure => directory, } + file { '/var/www/local/subdir/index.html': + ensure => file, + content => "Hello from localhost\\n", + } + }, :catch_failures => true) + end + + describe service($service_name) do + it { is_expected.to be_enabled } + it { is_expected.to be_running } + end + + it 'should get a response from the back end' do + shell("/usr/bin/curl --max-redirs 0 proxy.example.com:80") do |r| + expect(r.stdout).to eq("Hello from localhost\n") + expect(r.exit_code).to eq(0) + end + end + end + + describe 'ip_based' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + ip_based => true, + servername => 'test.server', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file($ports_file) do + it { is_expected.to be_file } + it { is_expected.not_to contain 'NameVirtualHost test.server' } + end + end + + describe 'add_listen' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': default_vhost => false } + host { 'testlisten.server': ip => '127.0.0.1' } + apache::listen { '81': } + apache::vhost { 'testlisten.server': + docroot => '/tmp', + port => '80', + add_listen => false, + servername => 'testlisten.server', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file($ports_file) do + it { is_expected.to be_file } + it { is_expected.not_to contain 'Listen 80' } + it { is_expected.to contain 'Listen 81' } + end + end + + describe 'docroot' do + it 'applies cleanly' do + pp = <<-EOS + user { 'test_owner': ensure => present, } + group { 'test_group': ensure => present, } + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp/test', + docroot_owner => 'test_owner', + docroot_group => 'test_group', + docroot_mode => '0750', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file('/tmp/test') do + it { is_expected.to be_directory } + it { is_expected.to be_owned_by 'test_owner' } + it { is_expected.to be_grouped_into 'test_group' } + it { is_expected.to be_mode 750 } + end + end + + describe 'default_vhost' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + default_vhost => true, + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file($ports_file) do + it { is_expected.to be_file } + if fact('osfamily') == 'RedHat' and fact('operatingsystemmajrelease') == '7' + it { is_expected.not_to contain 'NameVirtualHost test.server' } + elsif fact('operatingsystem') == 'Ubuntu' and fact('operatingsystemrelease') =~ /(14\.04|13\.10)/ + it { is_expected.not_to contain 'NameVirtualHost test.server' } + else + it { is_expected.to contain 'NameVirtualHost test.server' } + end + end + + describe file("#{$vhost_dir}/10-test.server.conf") do + it { is_expected.to be_file } + end + end + + describe 'options' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + options => ['Indexes','FollowSymLinks', 'ExecCGI'], + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'Options Indexes FollowSymLinks ExecCGI' } + end + end + + describe 'override' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + override => ['All'], + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'AllowOverride All' } + end + end + + describe 'logroot' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + logroot => '/tmp', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain ' CustomLog "/tmp' } + end + end + + ['access', 'error'].each do |logtype| + case logtype + when 'access' + logname = 'CustomLog' + when 'error' + logname = 'ErrorLog' + end + + describe "#{logtype}_log" do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + logroot => '/tmp', + #{logtype}_log => false, + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.not_to contain " #{logname} \"/tmp" } + end + end + + describe "#{logtype}_log_pipe" do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + logroot => '/tmp', + #{logtype}_log_pipe => '|/bin/sh', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain " #{logname} \"|/bin/sh" } + end + end + + describe "#{logtype}_log_syslog" do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + logroot => '/tmp', + #{logtype}_log_syslog => 'syslog', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain " #{logname} \"syslog\"" } + end + end + end + + describe 'access_log_format' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + logroot => '/tmp', + access_log_syslog => 'syslog', + access_log_format => '%h %l', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'CustomLog "syslog" "%h %l"' } + end + end + + describe 'access_log_env_var' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + logroot => '/tmp', + access_log_syslog => 'syslog', + access_log_env_var => 'admin', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'CustomLog "syslog" combined env=admin' } + end + end + + describe 'multiple access_logs' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + logroot => '/tmp', + access_logs => [ + {'file' => 'log1'}, + {'file' => 'log2', 'env' => 'admin' }, + {'file' => '/var/tmp/log3', 'format' => '%h %l'}, + {'syslog' => 'syslog' } + ] + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'CustomLog "/tmp/log1" combined' } + it { is_expected.to contain 'CustomLog "/tmp/log2" combined env=admin' } + it { is_expected.to contain 'CustomLog "/var/tmp/log3" "%h %l"' } + it { is_expected.to contain 'CustomLog "syslog" combined' } + end + end + + describe 'aliases' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + aliases => [ + { alias => '/image' , path => '/ftp/pub/image' } , + { scriptalias => '/myscript' , path => '/usr/share/myscript' } + ], + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'Alias /image "/ftp/pub/image"' } + it { is_expected.to contain 'ScriptAlias /myscript "/usr/share/myscript"' } + end + end + + describe 'scriptaliases' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + scriptaliases => [{ alias => '/myscript', path => '/usr/share/myscript', }], + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'ScriptAlias /myscript "/usr/share/myscript"' } + end + end + + describe 'proxy' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': service_ensure => stopped, } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + proxy_dest => 'test2', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'ProxyPass / test2/' } + end + end + + describe 'actions' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + action => 'php-fastcgi', + } + EOS + pp = pp + "\nclass { 'apache::mod::actions': }" if fact('osfamily') == 'Debian' + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'Action php-fastcgi /cgi-bin virtual' } + end + end + + describe 'suphp' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': service_ensure => stopped, } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + suphp_addhandler => '#{$suphp_handler}', + suphp_engine => 'on', + suphp_configpath => '#{$suphp_configpath}', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain "suPHP_AddHandler #{$suphp_handler}" } + it { is_expected.to contain 'suPHP_Engine on' } + it { is_expected.to contain "suPHP_ConfigPath \"#{$suphp_configpath}\"" } + end + end + + describe 'no_proxy_uris' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': service_ensure => stopped, } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + proxy_dest => 'http://test2', + no_proxy_uris => [ 'http://test2/test' ], + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'ProxyPass / http://test2/' } + it { is_expected.to contain 'ProxyPass http://test2/test !' } + end + end + + describe 'redirect' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + redirect_source => ['/images'], + redirect_dest => ['http://test.server/'], + redirect_status => ['permanent'], + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'Redirect permanent /images http://test.server/' } + end + end + + # Passenger isn't even in EPEL on el-5 + if default['platform'] !~ /^el-5/ + if fact('osfamily') == 'RedHat' and fact('operatingsystemmajrelease') == '7' + pending('Since we don\'t have passenger on RHEL7 rack_base_uris tests will fail') + else + describe 'rack_base_uris' do + if fact('osfamily') == 'RedHat' + it 'adds epel' do + pp = "class { 'epel': }" + apply_manifest(pp, :catch_failures => true) + end + end + + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + rack_base_uris => ['/test'], + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'RackBaseURI /test' } + end + end + end + end + + + describe 'request_headers' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + request_headers => ['append MirrorID "mirror 12"'], + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'append MirrorID "mirror 12"' } + end + end + + describe 'rewrite rules' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + rewrites => [ + { comment => 'test', + rewrite_cond => '%{HTTP_USER_AGENT} ^Lynx/ [OR]', + rewrite_rule => ['^index\.html$ welcome.html'], + rewrite_map => ['lc int:tolower'], + } + ], + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain '#test' } + it { is_expected.to contain 'RewriteCond %{HTTP_USER_AGENT} ^Lynx/ [OR]' } + it { is_expected.to contain 'RewriteRule ^index.html$ welcome.html' } + it { is_expected.to contain 'RewriteMap lc int:tolower' } + end + end + + describe 'directory rewrite rules' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + if ! defined(Class['apache::mod::rewrite']) { + include ::apache::mod::rewrite + } + apache::vhost { 'test.server': + docroot => '/tmp', + directories => [ + { + path => '/tmp', + rewrites => [ + { + comment => 'Permalink Rewrites', + rewrite_base => '/', + }, + { rewrite_rule => [ '^index\\.php$ - [L]' ] }, + { rewrite_cond => [ + '%{REQUEST_FILENAME} !-f', + '%{REQUEST_FILENAME} !-d', ], rewrite_rule => [ '. /index.php [L]' ], } + ], + }, + ], + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { should be_file } + it { should contain '#Permalink Rewrites' } + it { should contain 'RewriteEngine On' } + it { should contain 'RewriteBase /' } + it { should contain 'RewriteRule ^index\.php$ - [L]' } + it { should contain 'RewriteCond %{REQUEST_FILENAME} !-f' } + it { should contain 'RewriteCond %{REQUEST_FILENAME} !-d' } + it { should contain 'RewriteRule . /index.php [L]' } + end + end + + describe 'setenv/setenvif' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + setenv => ['TEST /test'], + setenvif => ['Request_URI "\.gif$" object_is_image=gif'] + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'SetEnv TEST /test' } + it { is_expected.to contain 'SetEnvIf Request_URI "\.gif$" object_is_image=gif' } + end + end + + describe 'block' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + block => 'scm', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain '' } + end + end + + describe 'wsgi' do + it 'import_script applies cleanly' do + pp = <<-EOS + class { 'apache': } + class { 'apache::mod::wsgi': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + wsgi_application_group => '%{GLOBAL}', + wsgi_daemon_process => 'wsgi', + wsgi_daemon_process_options => {processes => '2'}, + wsgi_process_group => 'nobody', + wsgi_script_aliases => { '/test' => '/test1' }, + wsgi_pass_authorization => 'On', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + it 'import_script applies cleanly', :unless => (fact('lsbdistcodename') == 'lucid' or UNSUPPORTED_PLATFORMS.include?(fact('osfamily'))) do + pp = <<-EOS + class { 'apache': } + class { 'apache::mod::wsgi': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + wsgi_application_group => '%{GLOBAL}', + wsgi_daemon_process => 'wsgi', + wsgi_daemon_process_options => {processes => '2'}, + wsgi_import_script => '/test1', + wsgi_import_script_options => { application-group => '%{GLOBAL}', process-group => 'wsgi' }, + wsgi_process_group => 'nobody', + wsgi_script_aliases => { '/test' => '/test1' }, + wsgi_pass_authorization => 'On', + wsgi_chunked_request => 'On', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf"), :unless => (fact('lsbdistcodename') == 'lucid' or UNSUPPORTED_PLATFORMS.include?(fact('osfamily'))) do + it { is_expected.to be_file } + it { is_expected.to contain 'WSGIApplicationGroup %{GLOBAL}' } + it { is_expected.to contain 'WSGIDaemonProcess wsgi processes=2' } + it { is_expected.to contain 'WSGIImportScript /test1 application-group=%{GLOBAL} process-group=wsgi' } + it { is_expected.to contain 'WSGIProcessGroup nobody' } + it { is_expected.to contain 'WSGIScriptAlias /test "/test1"' } + it { is_expected.to contain 'WSGIPassAuthorization On' } + it { is_expected.to contain 'WSGIChunkedRequest On' } + end + end + + describe 'custom_fragment' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + custom_fragment => inline_template('#weird test string'), + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain '#weird test string' } + end + end + + describe 'itk' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + itk => { user => 'nobody', group => 'nobody' } + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'AssignUserId nobody nobody' } + end + end + + # So what does this work on? + if default['platform'] !~ /^(debian-(6|7)|el-(5|6|7))/ + describe 'fastcgi' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + class { 'apache::mod::fastcgi': } + host { 'test.server': ip => '127.0.0.1' } + apache::vhost { 'test.server': + docroot => '/tmp', + fastcgi_server => 'localhost', + fastcgi_socket => '/tmp/fast/1234', + fastcgi_dir => '/tmp/fast', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'FastCgiExternalServer localhost -socket /tmp/fast/1234' } + it { is_expected.to contain '' } + end + end + end + + describe 'additional_includes' do + it 'applies cleanly' do + pp = <<-EOS + if $::osfamily == 'RedHat' and $::selinux { + $semanage_package = $::operatingsystemmajrelease ? { + '5' => 'policycoreutils', + default => 'policycoreutils-python', + } + exec { 'set_apache_defaults': + command => 'semanage fcontext -a -t httpd_sys_content_t "/apache_spec(/.*)?"', + path => '/bin:/usr/bin/:/sbin:/usr/sbin', + require => Package[$semanage_package], + } + package { $semanage_package: ensure => installed } + exec { 'restorecon_apache': + command => 'restorecon -Rv /apache_spec', + path => '/bin:/usr/bin/:/sbin:/usr/sbin', + before => Service['httpd'], + require => Class['apache'], + } + } + class { 'apache': } + host { 'test.server': ip => '127.0.0.1' } + file { '/apache_spec': ensure => directory, } + file { '/apache_spec/include': ensure => present, content => '#additional_includes' } + apache::vhost { 'test.server': + docroot => '/apache_spec', + additional_includes => '/apache_spec/include', + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/25-test.server.conf") do + it { is_expected.to be_file } + it { is_expected.to contain 'Include "/apache_spec/include"' } + end + end + + describe 'virtualhost without priority prefix' do + it 'applies cleanly' do + pp = <<-EOS + class { 'apache': } + apache::vhost { 'test.server': + priority => false, + docroot => '/tmp' + } + EOS + apply_manifest(pp, :catch_failures => true) + end + + describe file("#{$vhost_dir}/test.server.conf") do + it { is_expected.to be_file } + end + end +end diff --git a/3rdparty/modules/apache/spec/classes/apache_spec.rb b/3rdparty/modules/apache/spec/classes/apache_spec.rb new file mode 100644 index 000000000..b82eafa0d --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/apache_spec.rb @@ -0,0 +1,819 @@ +require 'spec_helper' + +describe 'apache', :type => :class do + context "on a Debian OS" do + let :facts do + { + :id => 'root', + :kernel => 'Linux', + :lsbdistcodename => 'squeeze', + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => '6', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :concat_basedir => '/dne', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_package("httpd").with( + 'notify' => 'Class[Apache::Service]', + 'ensure' => 'installed' + ) + } + it { is_expected.to contain_user("www-data") } + it { is_expected.to contain_group("www-data") } + it { is_expected.to contain_class("apache::service") } + it { is_expected.to contain_file("/var/www").with( + 'ensure' => 'directory' + ) + } + it { is_expected.to contain_file("/etc/apache2/sites-enabled").with( + 'ensure' => 'directory', + 'recurse' => 'true', + 'purge' => 'true', + 'notify' => 'Class[Apache::Service]', + 'require' => 'Package[httpd]' + ) + } + it { is_expected.to contain_file("/etc/apache2/mods-enabled").with( + 'ensure' => 'directory', + 'recurse' => 'true', + 'purge' => 'true', + 'notify' => 'Class[Apache::Service]', + 'require' => 'Package[httpd]' + ) + } + it { is_expected.to contain_file("/etc/apache2/mods-available").with( + 'ensure' => 'directory', + 'recurse' => 'true', + 'purge' => 'false', + 'notify' => 'Class[Apache::Service]', + 'require' => 'Package[httpd]' + ) + } + it { is_expected.to contain_concat("/etc/apache2/ports.conf").with( + 'owner' => 'root', + 'group' => 'root', + 'mode' => '0644', + 'notify' => 'Class[Apache::Service]' + ) + } + # Assert that load files are placed and symlinked for these mods, but no conf file. + [ + 'auth_basic', + 'authn_file', + 'authz_default', + 'authz_groupfile', + 'authz_host', + 'authz_user', + 'dav', + 'env' + ].each do |modname| + it { is_expected.to contain_file("#{modname}.load").with( + 'path' => "/etc/apache2/mods-available/#{modname}.load", + 'ensure' => 'file' + ) } + it { is_expected.to contain_file("#{modname}.load symlink").with( + 'path' => "/etc/apache2/mods-enabled/#{modname}.load", + 'ensure' => 'link', + 'target' => "/etc/apache2/mods-available/#{modname}.load" + ) } + it { is_expected.not_to contain_file("#{modname}.conf") } + it { is_expected.not_to contain_file("#{modname}.conf symlink") } + end + + context "with Apache version < 2.4" do + let :params do + { :apache_version => '2.2' } + end + + it { is_expected.to contain_file("/etc/apache2/apache2.conf").with_content %r{^Include "/etc/apache2/conf\.d/\*\.conf"$} } + end + + context "with Apache version >= 2.4" do + let :params do + { + :apache_version => '2.4', + :use_optional_includes => true + } + end + + it { is_expected.to contain_file("/etc/apache2/apache2.conf").with_content %r{^IncludeOptional "/etc/apache2/conf\.d/\*\.conf"$} } + end + + context "when specifying slash encoding behaviour" do + let :params do + { :allow_encoded_slashes => 'nodecode' } + end + + it { is_expected.to contain_file("/etc/apache2/apache2.conf").with_content %r{^AllowEncodedSlashes nodecode$} } + end + + context "when specifying default character set" do + let :params do + { :default_charset => 'none' } + end + + it { is_expected.to contain_file("/etc/apache2/apache2.conf").with_content %r{^AddDefaultCharset none$} } + end + + # Assert that both load files and conf files are placed and symlinked for these mods + [ + 'alias', + 'autoindex', + 'dav_fs', + 'deflate', + 'dir', + 'mime', + 'negotiation', + 'setenvif', + ].each do |modname| + it { is_expected.to contain_file("#{modname}.load").with( + 'path' => "/etc/apache2/mods-available/#{modname}.load", + 'ensure' => 'file' + ) } + it { is_expected.to contain_file("#{modname}.load symlink").with( + 'path' => "/etc/apache2/mods-enabled/#{modname}.load", + 'ensure' => 'link', + 'target' => "/etc/apache2/mods-available/#{modname}.load" + ) } + it { is_expected.to contain_file("#{modname}.conf").with( + 'path' => "/etc/apache2/mods-available/#{modname}.conf", + 'ensure' => 'file' + ) } + it { is_expected.to contain_file("#{modname}.conf symlink").with( + 'path' => "/etc/apache2/mods-enabled/#{modname}.conf", + 'ensure' => 'link', + 'target' => "/etc/apache2/mods-available/#{modname}.conf" + ) } + end + + describe "Check default type" do + context "with Apache version < 2.4" do + let :params do + { + :apache_version => '2.2', + } + end + + context "when default_type => 'none'" do + let :params do + { :default_type => 'none' } + end + + it { is_expected.to contain_file("/etc/apache2/apache2.conf").with_content %r{^DefaultType none$} } + end + context "when default_type => 'text/plain'" do + let :params do + { :default_type => 'text/plain' } + end + + it { is_expected.to contain_file("/etc/apache2/apache2.conf").with_content %r{^DefaultType text/plain$} } + end + end + + context "with Apache version >= 2.4" do + let :params do + { + :apache_version => '2.4', + } + end + it { is_expected.to contain_file("/etc/apache2/apache2.conf").without_content %r{^DefaultType [.]*$} } + end + end + + describe "Don't create user resource" do + context "when parameter manage_user is false" do + let :params do + { :manage_user => false } + end + + it { is_expected.not_to contain_user('www-data') } + it { is_expected.to contain_file("/etc/apache2/apache2.conf").with_content %r{^User www-data\n} } + end + end + describe "Don't create group resource" do + context "when parameter manage_group is false" do + let :params do + { :manage_group => false } + end + + it { is_expected.not_to contain_group('www-data') } + it { is_expected.to contain_file("/etc/apache2/apache2.conf").with_content %r{^Group www-data\n} } + end + end + + describe "Add extra LogFormats" do + context "When parameter log_formats is a hash" do + let :params do + { :log_formats => { + 'vhost_common' => "%v %h %l %u %t \"%r\" %>s %b", + 'vhost_combined' => "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" + } } + end + + it { is_expected.to contain_file("/etc/apache2/apache2.conf").with_content %r{^LogFormat "%v %h %l %u %t \"%r\" %>s %b" vhost_common\n} } + it { is_expected.to contain_file("/etc/apache2/apache2.conf").with_content %r{^LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%\{Referer\}i\" \"%\{User-agent\}i\"" vhost_combined\n} } + end + end + + describe "Override existing LogFormats" do + context "When parameter log_formats is a hash" do + let :params do + { :log_formats => { + 'common' => "%v %h %l %u %t \"%r\" %>s %b", + 'combined' => "%v %h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-agent}i\"" + } } + end + + it { is_expected.to contain_file("/etc/apache2/apache2.conf").with_content %r{^LogFormat "%v %h %l %u %t \"%r\" %>s %b" common\n} } + it { is_expected.to contain_file("/etc/apache2/apache2.conf").without_content %r{^LogFormat "%h %l %u %t \"%r\" %>s %b \"%\{Referer\}i\" \"%\{User-agent\}i\"" combined\n} } + it { is_expected.to contain_file("/etc/apache2/apache2.conf").with_content %r{^LogFormat "%v %h %l %u %t \"%r\" %>s %b" common\n} } + it { is_expected.to contain_file("/etc/apache2/apache2.conf").with_content %r{^LogFormat "%v %h %l %u %t \"%r\" %>s %b \"%\{Referer\}i\" \"%\{User-agent\}i\"" combined\n} } + it { is_expected.to contain_file("/etc/apache2/apache2.conf").without_content %r{^LogFormat "%h %l %u %t \"%r\" %>s %b \"%\{Referer\}i\" \"%\{User-agent\}i\"" combined\n} } + end + end + + context "on Ubuntu" do + let :facts do + super().merge({ + :operatingsystem => 'Ubuntu' + }) + end + + context "13.10" do + let :facts do + super().merge({ + :lsbdistrelease => '13.10', + :operatingsystemrelease => '13.10' + }) + end + it { is_expected.to contain_class('apache').with_apache_version('2.4') } + end + context "12.04" do + let :facts do + super().merge({ + :lsbdistrelease => '12.04', + :operatingsystemrelease => '12.04' + }) + end + it { is_expected.to contain_class('apache').with_apache_version('2.2') } + end + context "13.04" do + let :facts do + super().merge({ + :lsbdistrelease => '13.04', + :operatingsystemrelease => '13.04' + }) + end + it { is_expected.to contain_class('apache').with_apache_version('2.2') } + end + end + end + context "on a RedHat 5 OS" do + let :facts do + { + :id => 'root', + :kernel => 'Linux', + :osfamily => 'RedHat', + :operatingsystem => 'RedHat', + :operatingsystemrelease => '5', + :concat_basedir => '/dne', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_package("httpd").with( + 'notify' => 'Class[Apache::Service]', + 'ensure' => 'installed' + ) + } + it { is_expected.to contain_user("apache") } + it { is_expected.to contain_group("apache") } + it { is_expected.to contain_class("apache::service") } + it { is_expected.to contain_file("/var/www/html").with( + 'ensure' => 'directory' + ) + } + it { is_expected.to contain_file("/etc/httpd/conf.d").with( + 'ensure' => 'directory', + 'recurse' => 'true', + 'purge' => 'true', + 'notify' => 'Class[Apache::Service]', + 'require' => 'Package[httpd]' + ) + } + it { is_expected.to contain_concat("/etc/httpd/conf/ports.conf").with( + 'owner' => 'root', + 'group' => 'root', + 'mode' => '0644', + 'notify' => 'Class[Apache::Service]' + ) + } + describe "Alternate confd/mod/vhosts directory" do + let :params do + { + :vhost_dir => '/etc/httpd/site.d', + :confd_dir => '/etc/httpd/conf.d', + :mod_dir => '/etc/httpd/mod.d', + } + end + + ['mod.d','site.d','conf.d'].each do |dir| + it { is_expected.to contain_file("/etc/httpd/#{dir}").with( + 'ensure' => 'directory', + 'recurse' => 'true', + 'purge' => 'true', + 'notify' => 'Class[Apache::Service]', + 'require' => 'Package[httpd]' + ) } + end + + # Assert that load files are placed for these mods, but no conf file. + [ + 'auth_basic', + 'authn_file', + 'authz_default', + 'authz_groupfile', + 'authz_host', + 'authz_user', + 'dav', + 'env', + ].each do |modname| + it { is_expected.to contain_file("#{modname}.load").with_path( + "/etc/httpd/mod.d/#{modname}.load" + ) } + it { is_expected.not_to contain_file("#{modname}.conf").with_path( + "/etc/httpd/mod.d/#{modname}.conf" + ) } + end + + # Assert that both load files and conf files are placed for these mods + [ + 'alias', + 'autoindex', + 'dav_fs', + 'deflate', + 'dir', + 'mime', + 'negotiation', + 'setenvif', + ].each do |modname| + it { is_expected.to contain_file("#{modname}.load").with_path( + "/etc/httpd/mod.d/#{modname}.load" + ) } + it { is_expected.to contain_file("#{modname}.conf").with_path( + "/etc/httpd/mod.d/#{modname}.conf" + ) } + end + + context "with Apache version < 2.4" do + let :params do + { :apache_version => '2.2' } + end + + it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^Include "/etc/httpd/conf\.d/\*\.conf"$} } + end + + context "with Apache version >= 2.4" do + let :params do + { + :apache_version => '2.4', + :use_optional_includes => true + } + end + + it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^IncludeOptional "/etc/httpd/conf\.d/\*\.conf"$} } + end + + context "when specifying slash encoding behaviour" do + let :params do + { :allow_encoded_slashes => 'nodecode' } + end + + it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^AllowEncodedSlashes nodecode$} } + end + + context "when specifying default character set" do + let :params do + { :default_charset => 'none' } + end + + it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^AddDefaultCharset none$} } + end + + context "with Apache version < 2.4" do + let :params do + { + :apache_version => '2.2', + } + end + + context "when default_type => 'none'" do + let :params do + { :default_type => 'none' } + end + + it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^DefaultType none$} } + end + context "when default_type => 'text/plain'" do + let :params do + { :default_type => 'text/plain' } + end + + it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^DefaultType text/plain$} } + end + end + + context "with Apache version >= 2.4" do + let :params do + { + :apache_version => '2.4', + } + end + it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").without_content %r{^DefaultType [.]*$} } + end + + it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^Include "/etc/httpd/site\.d/\*"$} } + it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^Include "/etc/httpd/mod\.d/\*\.conf"$} } + it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^Include "/etc/httpd/mod\.d/\*\.load"$} } + end + + describe "Alternate conf directory" do + let :params do + { :conf_dir => '/opt/rh/root/etc/httpd/conf' } + end + + it { is_expected.to contain_file("/opt/rh/root/etc/httpd/conf/httpd.conf").with( + 'ensure' => 'file', + 'notify' => 'Class[Apache::Service]', + 'require' => 'Package[httpd]' + ) } + end + + describe "Alternate conf.d directory" do + let :params do + { :confd_dir => '/etc/httpd/special_conf.d' } + end + + it { is_expected.to contain_file("/etc/httpd/special_conf.d").with( + 'ensure' => 'directory', + 'recurse' => 'true', + 'purge' => 'true', + 'notify' => 'Class[Apache::Service]', + 'require' => 'Package[httpd]' + ) } + end + + describe "Alternate mpm_modules" do + context "when declaring mpm_module is false" do + let :params do + { :mpm_module => false } + end + it 'should not declare mpm modules' do + is_expected.not_to contain_class('apache::mod::event') + is_expected.not_to contain_class('apache::mod::itk') + is_expected.not_to contain_class('apache::mod::peruser') + is_expected.not_to contain_class('apache::mod::prefork') + is_expected.not_to contain_class('apache::mod::worker') + end + end + context "when declaring mpm_module => prefork" do + let :params do + { :mpm_module => 'prefork' } + end + it { is_expected.to contain_class('apache::mod::prefork') } + it { is_expected.not_to contain_class('apache::mod::event') } + it { is_expected.not_to contain_class('apache::mod::itk') } + it { is_expected.not_to contain_class('apache::mod::peruser') } + it { is_expected.not_to contain_class('apache::mod::worker') } + end + context "when declaring mpm_module => worker" do + let :params do + { :mpm_module => 'worker' } + end + it { is_expected.to contain_class('apache::mod::worker') } + it { is_expected.not_to contain_class('apache::mod::event') } + it { is_expected.not_to contain_class('apache::mod::itk') } + it { is_expected.not_to contain_class('apache::mod::peruser') } + it { is_expected.not_to contain_class('apache::mod::prefork') } + end + context "when declaring mpm_module => breakme" do + let :params do + { :mpm_module => 'breakme' } + end + it { expect { catalogue }.to raise_error Puppet::Error, /does not match/ } + end + end + + describe "different templates for httpd.conf" do + context "with default" do + let :params do + { :conf_template => 'apache/httpd.conf.erb' } + end + it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^# Security\n} } + end + context "with non-default" do + let :params do + { :conf_template => 'site_apache/fake.conf.erb' } + end + it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^Fake template for rspec.$} } + end + end + + describe "default mods" do + context "without" do + let :params do + { :default_mods => false } + end + + it { is_expected.to contain_apache__mod('authz_host') } + it { is_expected.not_to contain_apache__mod('env') } + end + context "custom" do + let :params do + { :default_mods => [ + 'info', + 'alias', + 'mime', + 'env', + 'setenv', + 'expires', + ]} + end + + it { is_expected.to contain_apache__mod('authz_host') } + it { is_expected.to contain_apache__mod('env') } + it { is_expected.to contain_class('apache::mod::info') } + it { is_expected.to contain_class('apache::mod::mime') } + end + end + describe "Don't create user resource" do + context "when parameter manage_user is false" do + let :params do + { :manage_user => false } + end + + it { is_expected.not_to contain_user('apache') } + it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^User apache\n} } + end + end + describe "Don't create group resource" do + context "when parameter manage_group is false" do + let :params do + { :manage_group => false } + end + + it { is_expected.not_to contain_group('apache') } + it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^Group apache\n} } + + end + end + describe "sendfile" do + context "with invalid value" do + let :params do + { :sendfile => 'foo' } + end + it "should fail" do + expect do + catalogue + end.to raise_error(Puppet::Error, /"foo" does not match/) + end + end + context "On" do + let :params do + { :sendfile => 'On' } + end + it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^EnableSendfile On\n} } + end + context "Off" do + let :params do + { :sendfile => 'Off' } + end + it { is_expected.to contain_file("/etc/httpd/conf/httpd.conf").with_content %r{^EnableSendfile Off\n} } + end + end + context "on Fedora" do + let :facts do + super().merge({ + :operatingsystem => 'Fedora' + }) + end + + context "21" do + let :facts do + super().merge({ + :lsbdistrelease => '21', + :operatingsystemrelease => '21' + }) + end + it { is_expected.to contain_class('apache').with_apache_version('2.4') } + end + context "Rawhide" do + let :facts do + super().merge({ + :lsbdistrelease => 'Rawhide', + :operatingsystemrelease => 'Rawhide' + }) + end + it { is_expected.to contain_class('apache').with_apache_version('2.4') } + end + # kinda obsolete + context "17" do + let :facts do + super().merge({ + :lsbdistrelease => '17', + :operatingsystemrelease => '17' + }) + end + it { is_expected.to contain_class('apache').with_apache_version('2.2') } + end + end + end + context "on a FreeBSD OS" do + let :facts do + { + :id => 'root', + :kernel => 'FreeBSD', + :osfamily => 'FreeBSD', + :operatingsystem => 'FreeBSD', + :operatingsystemrelease => '10', + :concat_basedir => '/dne', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_class("apache::package").with({'ensure' => 'present'}) } + it { is_expected.to contain_user("www") } + it { is_expected.to contain_group("www") } + it { is_expected.to contain_class("apache::service") } + it { is_expected.to contain_file("/usr/local/www/apache24/data").with( + 'ensure' => 'directory' + ) + } + it { is_expected.to contain_file("/usr/local/etc/apache24/Vhosts").with( + 'ensure' => 'directory', + 'recurse' => 'true', + 'purge' => 'true', + 'notify' => 'Class[Apache::Service]', + 'require' => 'Package[httpd]' + ) } + it { is_expected.to contain_file("/usr/local/etc/apache24/Modules").with( + 'ensure' => 'directory', + 'recurse' => 'true', + 'purge' => 'true', + 'notify' => 'Class[Apache::Service]', + 'require' => 'Package[httpd]' + ) } + it { is_expected.to contain_concat("/usr/local/etc/apache24/ports.conf").with( + 'owner' => 'root', + 'group' => 'wheel', + 'mode' => '0644', + 'notify' => 'Class[Apache::Service]' + ) } + # Assert that load files are placed for these mods, but no conf file. + [ + 'auth_basic', + 'authn_core', + 'authn_file', + 'authz_groupfile', + 'authz_host', + 'authz_user', + 'dav', + 'env' + ].each do |modname| + it { is_expected.to contain_file("#{modname}.load").with( + 'path' => "/usr/local/etc/apache24/Modules/#{modname}.load", + 'ensure' => 'file' + ) } + it { is_expected.not_to contain_file("#{modname}.conf") } + end + + # Assert that both load files and conf files are placed for these mods + [ + 'alias', + 'autoindex', + 'dav_fs', + 'deflate', + 'dir', + 'mime', + 'negotiation', + 'setenvif', + ].each do |modname| + it { is_expected.to contain_file("#{modname}.load").with( + 'path' => "/usr/local/etc/apache24/Modules/#{modname}.load", + 'ensure' => 'file' + ) } + it { is_expected.to contain_file("#{modname}.conf").with( + 'path' => "/usr/local/etc/apache24/Modules/#{modname}.conf", + 'ensure' => 'file' + ) } + end + end + context "on a Gentoo OS" do + let :facts do + { + :id => 'root', + :kernel => 'Linux', + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_user("apache") } + it { is_expected.to contain_group("apache") } + it { is_expected.to contain_class("apache::service") } + it { is_expected.to contain_file("/var/www/localhost/htdocs").with( + 'ensure' => 'directory' + ) + } + it { is_expected.to contain_file("/etc/apache2/vhosts.d").with( + 'ensure' => 'directory', + 'recurse' => 'true', + 'purge' => 'true', + 'notify' => 'Class[Apache::Service]', + 'require' => 'Package[httpd]' + ) } + it { is_expected.to contain_file("/etc/apache2/modules.d").with( + 'ensure' => 'directory', + 'recurse' => 'true', + 'purge' => 'true', + 'notify' => 'Class[Apache::Service]', + 'require' => 'Package[httpd]' + ) } + it { is_expected.to contain_concat("/etc/apache2/ports.conf").with( + 'owner' => 'root', + 'group' => 'wheel', + 'mode' => '0644', + 'notify' => 'Class[Apache::Service]' + ) } + end + context 'on all OSes' do + let :facts do + { + :id => 'root', + :kernel => 'Linux', + :osfamily => 'RedHat', + :operatingsystem => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + context 'with a custom apache_name parameter' do + let :params do { + :apache_name => 'httpd24-httpd' + } + end + it { is_expected.to contain_package("httpd").with( + 'notify' => 'Class[Apache::Service]', + 'ensure' => 'installed', + 'name' => 'httpd24-httpd' + ) + } + end + context 'default vhost defaults' do + it { is_expected.to contain_apache__vhost('default').with_ensure('present') } + it { is_expected.to contain_apache__vhost('default-ssl').with_ensure('absent') } + end + context 'without default non-ssl vhost' do + let :params do { + :default_vhost => false + } + end + it { is_expected.to contain_apache__vhost('default').with_ensure('absent') } + it { is_expected.not_to contain_file('/var/www/html') } + end + context 'with default ssl vhost' do + let :params do { + :default_ssl_vhost => true + } + end + it { is_expected.to contain_apache__vhost('default-ssl').with_ensure('present') } + it { is_expected.to contain_file('/var/www/html') } + end + end + context 'with unsupported osfamily' do + let :facts do + { :osfamily => 'Darwin', + :operatingsystemrelease => '13.1.0', + :concat_basedir => '/dne', + :is_pe => false, + } + end + + it do + expect { + catalogue + }.to raise_error(Puppet::Error, /Unsupported osfamily/) + end + end +end diff --git a/3rdparty/modules/apache/spec/classes/dev_spec.rb b/3rdparty/modules/apache/spec/classes/dev_spec.rb new file mode 100644 index 000000000..eb3d76593 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/dev_spec.rb @@ -0,0 +1,90 @@ +require 'spec_helper' + +describe 'apache::dev', :type => :class do + let(:pre_condition) {[ + 'include apache' + ]} + context "on a Debian OS" do + let :facts do + { + :lsbdistcodename => 'squeeze', + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => '6', + :is_pe => false, + :concat_basedir => '/foo', + :id => 'root', + :path => '/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin', + :kernel => 'Linux' + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_package("libaprutil1-dev") } + it { is_expected.to contain_package("libapr1-dev") } + it { is_expected.to contain_package("apache2-prefork-dev") } + end + context "on an Ubuntu 14 OS" do + let :facts do + { + :lsbdistrelease => '14.04', + :lsbdistcodename => 'trusty', + :osfamily => 'Debian', + :operatingsystem => 'Ubuntu', + :operatingsystemrelease => '14.04', + :is_pe => false, + :concat_basedir => '/foo', + :id => 'root', + :path => '/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin', + :kernel => 'Linux' + } + end + it { is_expected.to contain_package("apache2-dev") } + end + context "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystem => 'RedHat', + :operatingsystemrelease => '6', + :is_pe => false, + :concat_basedir => '/foo', + :id => 'root', + :path => '/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin', + :kernel => 'Linux' + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_package("httpd-devel") } + end + context "on a FreeBSD OS" do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystem => 'FreeBSD', + :operatingsystemrelease => '9', + :is_pe => false, + :concat_basedir => '/foo', + :id => 'root', + :path => '/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin', + :kernel => 'FreeBSD' + } + end + it { is_expected.to contain_class("apache::params") } + end + context "on a Gentoo OS" do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :is_pe => false, + :concat_basedir => '/foo', + :id => 'root', + :path => '/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin', + :kernel => 'Linux' + } + end + it { is_expected.to contain_class("apache::params") } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/alias_spec.rb b/3rdparty/modules/apache/spec/classes/mod/alias_spec.rb new file mode 100644 index 000000000..9bb28b3aa --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/alias_spec.rb @@ -0,0 +1,96 @@ +require 'spec_helper' + +describe 'apache::mod::alias', :type => :class do + let :pre_condition do + 'include apache' + end + context "on a Debian OS", :compile do + let :facts do + { + :id => 'root', + :kernel => 'Linux', + :lsbdistcodename => 'squeeze', + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => '6', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :concat_basedir => '/dne', + :is_pe => false, + } + end + it { is_expected.to contain_apache__mod("alias") } + it { is_expected.to contain_file("alias.conf").with(:content => /Alias \/icons\/ "\/usr\/share\/apache2\/icons\/"/) } + end + context "on a RedHat 6-based OS", :compile do + let :facts do + { + :id => 'root', + :kernel => 'Linux', + :osfamily => 'RedHat', + :operatingsystem => 'RedHat', + :operatingsystemrelease => '6', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :concat_basedir => '/dne', + :is_pe => false, + } + end + it { is_expected.to contain_apache__mod("alias") } + it { is_expected.to contain_file("alias.conf").with(:content => /Alias \/icons\/ "\/var\/www\/icons\/"/) } + end + context "on a RedHat 7-based OS", :compile do + let :facts do + { + :id => 'root', + :kernel => 'Linux', + :osfamily => 'RedHat', + :operatingsystem => 'RedHat', + :operatingsystemrelease => '7', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :concat_basedir => '/dne', + :is_pe => false, + } + end + it { is_expected.to contain_apache__mod("alias") } + it { is_expected.to contain_file("alias.conf").with(:content => /Alias \/icons\/ "\/usr\/share\/httpd\/icons\/"/) } + end + context "with icons options", :compile do + let :pre_condition do + 'class { apache: default_mods => false }' + end + let :facts do + { + :id => 'root', + :kernel => 'Linux', + :osfamily => 'RedHat', + :operatingsystem => 'RedHat', + :operatingsystemrelease => '7', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :concat_basedir => '/dne', + :is_pe => false, + } + end + let :params do + { + 'icons_options' => 'foo' + } + end + it { is_expected.to contain_apache__mod("alias") } + it { is_expected.to contain_file("alias.conf").with(:content => /Options foo/) } + end + context "on a FreeBSD OS", :compile do + let :facts do + { + :id => 'root', + :kernel => 'FreeBSD', + :osfamily => 'FreeBSD', + :operatingsystem => 'FreeBSD', + :operatingsystemrelease => '10', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :concat_basedir => '/dne', + :is_pe => false, + } + end + it { is_expected.to contain_apache__mod("alias") } + it { is_expected.to contain_file("alias.conf").with(:content => /Alias \/icons\/ "\/usr\/local\/www\/apache24\/icons\/"/) } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/auth_cas_spec.rb b/3rdparty/modules/apache/spec/classes/mod/auth_cas_spec.rb new file mode 100644 index 000000000..53c13c5a1 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/auth_cas_spec.rb @@ -0,0 +1,54 @@ +require 'spec_helper' + +describe 'apache::mod::auth_cas', :type => :class do + let :params do + { + :cas_login_url => 'https://cas.example.com/login', + :cas_validate_url => 'https://cas.example.com/validate', + } + end + + let :pre_condition do + 'include ::apache' + end + + context "on a Debian OS", :compile do + let :facts do + { + :id => 'root', + :kernel => 'Linux', + :lsbdistcodename => 'squeeze', + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => '6', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :concat_basedir => '/dne', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod("auth_cas") } + it { is_expected.to contain_package("libapache2-mod-auth-cas") } + it { is_expected.to contain_file("auth_cas.conf").with_path('/etc/apache2/mods-available/auth_cas.conf') } + it { is_expected.to contain_file("/var/cache/apache2/mod_auth_cas/").with_owner('www-data') } + end + context "on a RedHat OS", :compile do + let :facts do + { + :id => 'root', + :kernel => 'Linux', + :osfamily => 'RedHat', + :operatingsystem => 'RedHat', + :operatingsystemrelease => '6', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :concat_basedir => '/dne', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod("auth_cas") } + it { is_expected.to contain_package("mod_auth_cas") } + it { is_expected.to contain_file("auth_cas.conf").with_path('/etc/httpd/conf.d/auth_cas.conf') } + it { is_expected.to contain_file("/var/cache/mod_auth_cas/").with_owner('apache') } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/auth_kerb_spec.rb b/3rdparty/modules/apache/spec/classes/mod/auth_kerb_spec.rb new file mode 100644 index 000000000..beba378a9 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/auth_kerb_spec.rb @@ -0,0 +1,76 @@ +require 'spec_helper' + +describe 'apache::mod::auth_kerb', :type => :class do + let :pre_condition do + 'include apache' + end + context "on a Debian OS", :compile do + let :facts do + { + :id => 'root', + :kernel => 'Linux', + :lsbdistcodename => 'squeeze', + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => '6', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :concat_basedir => '/dne', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod("auth_kerb") } + it { is_expected.to contain_package("libapache2-mod-auth-kerb") } + end + context "on a RedHat OS", :compile do + let :facts do + { + :id => 'root', + :kernel => 'Linux', + :osfamily => 'RedHat', + :operatingsystem => 'RedHat', + :operatingsystemrelease => '6', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :concat_basedir => '/dne', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod("auth_kerb") } + it { is_expected.to contain_package("mod_auth_kerb") } + end + context "on a FreeBSD OS", :compile do + let :facts do + { + :id => 'root', + :kernel => 'FreeBSD', + :osfamily => 'FreeBSD', + :operatingsystem => 'FreeBSD', + :operatingsystemrelease => '9', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :concat_basedir => '/dne', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod("auth_kerb") } + it { is_expected.to contain_package("www/mod_auth_kerb2") } + end + context "on a Gentoo OS", :compile do + let :facts do + { + :id => 'root', + :kernel => 'Linux', + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod("auth_kerb") } + it { is_expected.to contain_package("www-apache/mod_auth_kerb") } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/authnz_ldap_spec.rb b/3rdparty/modules/apache/spec/classes/mod/authnz_ldap_spec.rb new file mode 100644 index 000000000..f89783399 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/authnz_ldap_spec.rb @@ -0,0 +1,78 @@ +require 'spec_helper' + +describe 'apache::mod::authnz_ldap', :type => :class do + let :pre_condition do + 'include apache' + end + + context "on a Debian OS" do + let :facts do + { + :lsbdistcodename => 'squeeze', + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :operatingsystem => 'Debian', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_class("apache::mod::ldap") } + it { is_expected.to contain_apache__mod('authnz_ldap') } + + context 'default verifyServerCert' do + it { is_expected.to contain_file('authnz_ldap.conf').with_content(/^LDAPVerifyServerCert On$/) } + end + + context 'verifyServerCert = false' do + let(:params) { { :verifyServerCert => false } } + it { is_expected.to contain_file('authnz_ldap.conf').with_content(/^LDAPVerifyServerCert Off$/) } + end + + context 'verifyServerCert = wrong' do + let(:params) { { :verifyServerCert => 'wrong' } } + it 'should raise an error' do + expect { is_expected.to raise_error Puppet::Error } + end + end + end #Debian + + context "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :operatingsystem => 'RedHat', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_class("apache::mod::ldap") } + it { is_expected.to contain_apache__mod('authnz_ldap') } + + context 'default verifyServerCert' do + it { is_expected.to contain_file('authnz_ldap.conf').with_content(/^LDAPVerifyServerCert On$/) } + end + + context 'verifyServerCert = false' do + let(:params) { { :verifyServerCert => false } } + it { is_expected.to contain_file('authnz_ldap.conf').with_content(/^LDAPVerifyServerCert Off$/) } + end + + context 'verifyServerCert = wrong' do + let(:params) { { :verifyServerCert => 'wrong' } } + it 'should raise an error' do + expect { is_expected.to raise_error Puppet::Error } + end + end + end # Redhat + +end + diff --git a/3rdparty/modules/apache/spec/classes/mod/dav_svn_spec.rb b/3rdparty/modules/apache/spec/classes/mod/dav_svn_spec.rb new file mode 100644 index 000000000..06c6b870f --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/dav_svn_spec.rb @@ -0,0 +1,79 @@ +require 'spec_helper' + +describe 'apache::mod::dav_svn', :type => :class do + let :pre_condition do + 'include apache' + end + context "on a Debian OS" do + let :facts do + { + :lsbdistcodename => 'squeeze', + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :operatingsystemmajrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('dav_svn') } + it { is_expected.to contain_package("libapache2-svn") } + end + context "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :operatingsystemmajrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('dav_svn') } + it { is_expected.to contain_package("mod_dav_svn") } + end + context "on a FreeBSD OS" do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '9', + :operatingsystemmajrelease => '9', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('dav_svn') } + it { is_expected.to contain_package("devel/subversion") } + end + context "on a Gentoo OS", :compile do + let :facts do + { + :id => 'root', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :kernel => 'Linux', + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('dav_svn') } + it { is_expected.to contain_package("dev-vcs/subversion") } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/deflate_spec.rb b/3rdparty/modules/apache/spec/classes/mod/deflate_spec.rb new file mode 100644 index 000000000..d0d8fedc2 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/deflate_spec.rb @@ -0,0 +1,126 @@ +require 'spec_helper' + +# This function is called inside the OS specific contexts +def general_deflate_specs + it { is_expected.to contain_apache__mod("deflate") } + + it do + is_expected.to contain_file("deflate.conf").with_content( + "AddOutputFilterByType DEFLATE text/css\n"\ + "AddOutputFilterByType DEFLATE text/html\n"\ + "\n"\ + "DeflateFilterNote Input instream\n"\ + "DeflateFilterNote Ratio ratio\n" + ) + end +end + +describe 'apache::mod::deflate', :type => :class do + let :pre_condition do + 'class { "apache": + default_mods => false, + } + class { "apache::mod::deflate": + types => [ "text/html", "text/css" ], + notes => { + "Input" => "instream", + "Ratio" => "ratio", + } + } + ' + end + + context "On a Debian OS with default params" do + let :facts do + { + :id => 'root', + :lsbdistcodename => 'squeeze', + :kernel => 'Linux', + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => '6', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :concat_basedir => '/dne', + :is_pe => false, + } + end + + # Load the more generic tests for this context + general_deflate_specs() + + it { is_expected.to contain_file("deflate.conf").with({ + :ensure => 'file', + :path => '/etc/apache2/mods-available/deflate.conf', + } ) } + it { is_expected.to contain_file("deflate.conf symlink").with({ + :ensure => 'link', + :path => '/etc/apache2/mods-enabled/deflate.conf', + } ) } + end + + context "on a RedHat OS with default params" do + let :facts do + { + :id => 'root', + :kernel => 'Linux', + :osfamily => 'RedHat', + :operatingsystem => 'RedHat', + :operatingsystemrelease => '6', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :concat_basedir => '/dne', + :is_pe => false, + } + end + + # Load the more generic tests for this context + general_deflate_specs() + + it { is_expected.to contain_file("deflate.conf").with_path("/etc/httpd/conf.d/deflate.conf") } + end + + context "On a FreeBSD OS with default params" do + let :facts do + { + :id => 'root', + :kernel => 'FreeBSD', + :osfamily => 'FreeBSD', + :operatingsystem => 'FreeBSD', + :operatingsystemrelease => '9', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :concat_basedir => '/dne', + :is_pe => false, + } + end + + # Load the more generic tests for this context + general_deflate_specs() + + it { is_expected.to contain_file("deflate.conf").with({ + :ensure => 'file', + :path => '/usr/local/etc/apache24/Modules/deflate.conf', + } ) } + end + + context "On a Gentoo OS with default params" do + let :facts do + { + :id => 'root', + :kernel => 'Linux', + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :is_pe => false, + } + end + + # Load the more generic tests for this context + general_deflate_specs() + + it { is_expected.to contain_file("deflate.conf").with({ + :ensure => 'file', + :path => '/etc/apache2/modules.d/deflate.conf', + } ) } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/dev_spec.rb b/3rdparty/modules/apache/spec/classes/mod/dev_spec.rb new file mode 100644 index 000000000..1686a0275 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/dev_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' + +describe 'apache::mod::dev', :type => :class do + let(:pre_condition) {[ + 'include apache' + ]} + [ + ['RedHat', '6', 'Santiago', 'Linux'], + ['Debian', '6', 'squeeze', 'Linux'], + ['FreeBSD', '9', 'FreeBSD', 'FreeBSD'], + ].each do |osfamily, operatingsystemrelease, lsbdistcodename, kernel| + context "on a #{osfamily} OS" do + let :facts do + { + :lsbdistcodename => lsbdistcodename, + :osfamily => osfamily, + :operatingsystem => osfamily, + :operatingsystemrelease => operatingsystemrelease, + :is_pe => false, + :concat_basedir => '/foo', + :id => 'root', + :path => '/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin', + :kernel => kernel + } + end + it { is_expected.to contain_class('apache::dev') } + end + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/dir_spec.rb b/3rdparty/modules/apache/spec/classes/mod/dir_spec.rb new file mode 100644 index 000000000..11622a41c --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/dir_spec.rb @@ -0,0 +1,138 @@ +require 'spec_helper' + +describe 'apache::mod::dir', :type => :class do + let :pre_condition do + 'class { "apache": + default_mods => false, + }' + end + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :lsbdistcodename => 'squeeze', + :is_pe => false, + } + end + context "passing no parameters" do + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('dir') } + it { is_expected.to contain_file('dir.conf').with_content(/^DirectoryIndex /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.html /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.html\.var /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.cgi /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.pl /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.php /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.xhtml$/) } + end + context "passing indexes => ['example.txt','fearsome.aspx']" do + let :params do + {:indexes => ['example.txt','fearsome.aspx']} + end + it { is_expected.to contain_file('dir.conf').with_content(/ example\.txt /) } + it { is_expected.to contain_file('dir.conf').with_content(/ fearsome\.aspx$/) } + end + end + context "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'Redhat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + context "passing no parameters" do + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('dir') } + it { is_expected.to contain_file('dir.conf').with_content(/^DirectoryIndex /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.html /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.html\.var /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.cgi /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.pl /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.php /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.xhtml$/) } + end + context "passing indexes => ['example.txt','fearsome.aspx']" do + let :params do + {:indexes => ['example.txt','fearsome.aspx']} + end + it { is_expected.to contain_file('dir.conf').with_content(/ example\.txt /) } + it { is_expected.to contain_file('dir.conf').with_content(/ fearsome\.aspx$/) } + end + end + context "on a FreeBSD OS" do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '9', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + context "passing no parameters" do + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('dir') } + it { is_expected.to contain_file('dir.conf').with_content(/^DirectoryIndex /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.html /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.html\.var /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.cgi /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.pl /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.php /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.xhtml$/) } + end + context "passing indexes => ['example.txt','fearsome.aspx']" do + let :params do + {:indexes => ['example.txt','fearsome.aspx']} + end + it { is_expected.to contain_file('dir.conf').with_content(/ example\.txt /) } + it { is_expected.to contain_file('dir.conf').with_content(/ fearsome\.aspx$/) } + end + end + context "on a Gentoo OS" do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + context "passing no parameters" do + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('dir') } + it { is_expected.to contain_file('dir.conf').with_content(/^DirectoryIndex /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.html /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.html\.var /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.cgi /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.pl /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.php /) } + it { is_expected.to contain_file('dir.conf').with_content(/ index\.xhtml$/) } + end + context "passing indexes => ['example.txt','fearsome.aspx']" do + let :params do + {:indexes => ['example.txt','fearsome.aspx']} + end + it { is_expected.to contain_file('dir.conf').with_content(/ example\.txt /) } + it { is_expected.to contain_file('dir.conf').with_content(/ fearsome\.aspx$/) } + end + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/event_spec.rb b/3rdparty/modules/apache/spec/classes/mod/event_spec.rb new file mode 100644 index 000000000..dd0a427ea --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/event_spec.rb @@ -0,0 +1,154 @@ +require 'spec_helper' + +describe 'apache::mod::event', :type => :class do + let :pre_condition do + 'class { "apache": mpm_module => false, }' + end + context "on a FreeBSD OS" do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '9', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.not_to contain_apache__mod('event') } + it { is_expected.to contain_file("/usr/local/etc/apache24/Modules/event.conf").with_ensure('file') } + end + context "on a Gentoo OS" do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.not_to contain_apache__mod('event') } + it { is_expected.to contain_file("/etc/apache2/modules.d/event.conf").with_ensure('file') } + end + context "on a Debian OS" do + let :facts do + { + :lsbdistcodename => 'squeeze', + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + + it { is_expected.to contain_class("apache::params") } + it { is_expected.not_to contain_apache__mod('event') } + it { is_expected.to contain_file("/etc/apache2/mods-available/event.conf").with_ensure('file') } + it { is_expected.to contain_file("/etc/apache2/mods-enabled/event.conf").with_ensure('link') } + + context "Test mpm_event params" do + let :params do + { + :serverlimit => '0', + :startservers => '1', + :maxclients => '2', + :minsparethreads => '3', + :maxsparethreads => '4', + :threadsperchild => '5', + :maxrequestsperchild => '6', + :threadlimit => '7', + :listenbacklog => '8', + :maxrequestworkers => '9', + :maxconnectionsperchild => '10', + } + end + + it { is_expected.to contain_file("/etc/apache2/mods-available/event.conf").with_ensure('file').with_content(/^\s*ServerLimit\s*0/) } + it { is_expected.to contain_file("/etc/apache2/mods-available/event.conf").with_ensure('file').with_content(/^\s*StartServers\s*1/) } + it { is_expected.to contain_file("/etc/apache2/mods-available/event.conf").with_ensure('file').with_content(/^\s*MaxClients\s*2/) } + it { is_expected.to contain_file("/etc/apache2/mods-available/event.conf").with_ensure('file').with_content(/^\s*MinSpareThreads\s*3/) } + it { is_expected.to contain_file("/etc/apache2/mods-available/event.conf").with_ensure('file').with_content(/^\s*MaxSpareThreads\s*4/) } + it { is_expected.to contain_file("/etc/apache2/mods-available/event.conf").with_ensure('file').with_content(/^\s*ThreadsPerChild\s*5/) } + it { is_expected.to contain_file("/etc/apache2/mods-available/event.conf").with_ensure('file').with_content(/^\s*MaxRequestsPerChild\s*6/) } + it { is_expected.to contain_file("/etc/apache2/mods-available/event.conf").with_ensure('file').with_content(/^\s*ThreadLimit\s*7/) } + it { is_expected.to contain_file("/etc/apache2/mods-available/event.conf").with_ensure('file').with_content(/^\s*ListenBacklog\s*8/) } + it { is_expected.to contain_file("/etc/apache2/mods-available/event.conf").with_ensure('file').with_content(/^\s*MaxRequestWorkers\s*9/) } + it { is_expected.to contain_file("/etc/apache2/mods-available/event.conf").with_ensure('file').with_content(/^\s*MaxConnectionsPerChild\s*10/) } + end + + context "with Apache version < 2.4" do + let :params do + { + :apache_version => '2.2', + } + end + + it { is_expected.not_to contain_file("/etc/apache2/mods-available/event.load") } + it { is_expected.not_to contain_file("/etc/apache2/mods-enabled/event.load") } + + it { is_expected.to contain_package("apache2-mpm-event") } + end + + context "with Apache version >= 2.4" do + let :params do + { + :apache_version => '2.4', + } + end + + it { is_expected.to contain_file("/etc/apache2/mods-available/event.load").with({ + 'ensure' => 'file', + 'content' => "LoadModule mpm_event_module /usr/lib/apache2/modules/mod_mpm_event.so\n" + }) + } + it { is_expected.to contain_file("/etc/apache2/mods-enabled/event.load").with_ensure('link') } + end + end + context "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + context "with Apache version >= 2.4" do + let :params do + { + :apache_version => '2.4', + } + end + + it { is_expected.to contain_class("apache::params") } + it { is_expected.not_to contain_apache__mod('worker') } + it { is_expected.not_to contain_apache__mod('prefork') } + + it { is_expected.to contain_file("/etc/httpd/conf.d/event.conf").with_ensure('file') } + + it { is_expected.to contain_file("/etc/httpd/conf.d/event.load").with({ + 'ensure' => 'file', + 'content' => "LoadModule mpm_event_module modules/mod_mpm_event.so\n", + }) + } + end + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/expires_spec.rb b/3rdparty/modules/apache/spec/classes/mod/expires_spec.rb new file mode 100644 index 000000000..e6eab7c48 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/expires_spec.rb @@ -0,0 +1,84 @@ +require 'spec_helper' + +describe 'apache::mod::expires', :type => :class do + let :pre_condition do + 'include apache' + end + context "with expires active", :compile do + let :facts do + { + :id => 'root', + :kernel => 'Linux', + :lsbdistcodename => 'squeeze', + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => '6', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :concat_basedir => '/dne', + :is_pe => false, + } + end + it { is_expected.to contain_apache__mod("expires") } + it { is_expected.to contain_file("expires.conf").with(:content => /ExpiresActive On\n/) } + end + context "with expires default", :compile do + let :pre_condition do + 'class { apache: default_mods => false }' + end + let :facts do + { + :id => 'root', + :kernel => 'Linux', + :osfamily => 'RedHat', + :operatingsystem => 'RedHat', + :operatingsystemrelease => '7', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :concat_basedir => '/dne', + :is_pe => false, + } + end + let :params do + { + 'expires_default' => 'access plus 1 month' + } + end + it { is_expected.to contain_apache__mod("expires") } + it { is_expected.to contain_file("expires.conf").with_content( + "ExpiresActive On\n" \ + "ExpiresDefault \"access plus 1 month\"\n" + ) + } + end + context "with expires by type", :compile do + let :pre_condition do + 'class { apache: default_mods => false }' + end + let :facts do + { + :id => 'root', + :kernel => 'Linux', + :osfamily => 'RedHat', + :operatingsystem => 'RedHat', + :operatingsystemrelease => '7', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :concat_basedir => '/dne', + :is_pe => false, + } + end + let :params do + { + 'expires_by_type' => [ + { 'text/json' => 'mod plus 1 day' }, + { 'text/html' => 'access plus 1 year' }, + ] + } + end + it { is_expected.to contain_apache__mod("expires") } + it { is_expected.to contain_file("expires.conf").with_content( + "ExpiresActive On\n" \ + "ExpiresByType text/json \"mod plus 1 day\"\n" \ + "ExpiresByType text/html \"access plus 1 year\"\n" + ) + } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/fastcgi_spec.rb b/3rdparty/modules/apache/spec/classes/mod/fastcgi_spec.rb new file mode 100644 index 000000000..e204bb746 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/fastcgi_spec.rb @@ -0,0 +1,45 @@ +require 'spec_helper' + +describe 'apache::mod::fastcgi', :type => :class do + let :pre_condition do + 'include apache' + end + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('fastcgi') } + it { is_expected.to contain_package("libapache2-mod-fastcgi") } + it { is_expected.to contain_file('fastcgi.conf') } + end + + context "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('fastcgi') } + it { is_expected.to contain_package("mod_fastcgi") } + it { is_expected.not_to contain_file('fastcgi.conf') } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/fcgid_spec.rb b/3rdparty/modules/apache/spec/classes/mod/fcgid_spec.rb new file mode 100644 index 000000000..096717d35 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/fcgid_spec.rb @@ -0,0 +1,136 @@ +require 'spec_helper' + +describe 'apache::mod::fcgid', :type => :class do + let :pre_condition do + 'include apache' + end + + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :operatingsystemmajrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('fcgid') } + it { is_expected.to contain_package("libapache2-mod-fcgid") } + end + + context "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :operatingsystemmajrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + describe 'without parameters' do + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('fcgid') } + it { is_expected.to contain_package("mod_fcgid") } + end + + describe 'with parameters' do + let :params do { + :options => { + 'FcgidIPCDir' => '/var/run/fcgidsock', + 'SharememPath' => '/var/run/fcgid_shm', + 'FcgidMinProcessesPerClass' => '0', + 'AddHandler' => 'fcgid-script .fcgi', + } + } end + + it 'should contain the correct config' do + content = catalogue.resource('file', 'fcgid.conf').send(:parameters)[:content] + expect(content.split("\n").reject { |c| c =~ /(^#|^$)/ }).to eq([ + '', + ' AddHandler fcgid-script .fcgi', + ' FcgidIPCDir /var/run/fcgidsock', + ' FcgidMinProcessesPerClass 0', + ' SharememPath /var/run/fcgid_shm', + '', + ]) + end + end + end + + context "on RHEL7" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '7', + :operatingsystemmajrelease => '7', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + describe 'without parameters' do + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('fcgid').with({ + 'loadfile_name' => 'unixd_fcgid.load' + }) + } + it { is_expected.to contain_package("mod_fcgid") } + end + end + + context "on a FreeBSD OS" do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '9', + :operatingsystemmajrelease => '9', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('fcgid') } + it { is_expected.to contain_package("www/mod_fcgid") } + end + + context "on a Gentoo OS" do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('fcgid') } + it { is_expected.to contain_package("www-apache/mod_fcgid") } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/info_spec.rb b/3rdparty/modules/apache/spec/classes/mod/info_spec.rb new file mode 100644 index 000000000..b444bc003 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/info_spec.rb @@ -0,0 +1,222 @@ +# This function is called inside the OS specific contexts +def general_info_specs_22 + it { is_expected.to contain_apache__mod('info') } + + context 'passing no parameters' do + it { + is_expected.to contain_file('info.conf').with_content( + "\n"\ + " SetHandler server-info\n"\ + " Order deny,allow\n"\ + " Deny from all\n"\ + " Allow from 127.0.0.1\n"\ + " Allow from ::1\n"\ + "\n" + ) + } + end + context 'passing restrict_access => false' do + let :params do { + :restrict_access => false + } + end + it { + is_expected.to contain_file('info.conf').with_content( + "\n"\ + " SetHandler server-info\n"\ + "\n" + ) + } + end + context "passing allow_from => ['10.10.1.2', '192.168.1.2', '127.0.0.1']" do + let :params do + {:allow_from => ['10.10.1.2', '192.168.1.2', '127.0.0.1']} + end + it { + is_expected.to contain_file('info.conf').with_content( + "\n"\ + " SetHandler server-info\n"\ + " Order deny,allow\n"\ + " Deny from all\n"\ + " Allow from 10.10.1.2\n"\ + " Allow from 192.168.1.2\n"\ + " Allow from 127.0.0.1\n"\ + "\n" + ) + } + end + context 'passing both restrict_access and allow_from' do + let :params do + { + :restrict_access => false, + :allow_from => ['10.10.1.2', '192.168.1.2', '127.0.0.1'] + } + end + it { + is_expected.to contain_file('info.conf').with_content( + "\n"\ + " SetHandler server-info\n"\ + "\n" + ) + } + end +end + +def general_info_specs_24 + it { is_expected.to contain_apache__mod('info') } + + context 'passing no parameters' do + it { + is_expected.to contain_file('info.conf').with_content( + "\n"\ + " SetHandler server-info\n"\ + " Require ip 127.0.0.1 ::1\n"\ + "\n" + ) + } + end + context 'passing restrict_access => false' do + let :params do { + :restrict_access => false + } + end + it { + is_expected.to contain_file('info.conf').with_content( + "\n"\ + " SetHandler server-info\n"\ + "\n" + ) + } + end + context "passing allow_from => ['10.10.1.2', '192.168.1.2', '127.0.0.1']" do + let :params do + {:allow_from => ['10.10.1.2', '192.168.1.2', '127.0.0.1']} + end + it { + is_expected.to contain_file('info.conf').with_content( + "\n"\ + " SetHandler server-info\n"\ + " Require ip 10.10.1.2 192.168.1.2 127.0.0.1\n"\ + "\n" + ) + } + end + context 'passing both restrict_access and allow_from' do + let :params do + { + :restrict_access => false, + :allow_from => ['10.10.1.2', '192.168.1.2', '127.0.0.1'] + } + end + it { + is_expected.to contain_file('info.conf').with_content( + "\n"\ + " SetHandler server-info\n"\ + "\n" + ) + } + end +end + +describe 'apache::mod::info', :type => :class do + let :pre_condition do + "class { 'apache': default_mods => false, }" + end + + context 'On a Debian OS' do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + # Load the more generic tests for this context + general_info_specs_22() + + it { is_expected.to contain_file('info.conf').with({ + :ensure => 'file', + :path => '/etc/apache2/mods-available/info.conf', + } ) } + it { is_expected.to contain_file('info.conf symlink').with({ + :ensure => 'link', + :path => '/etc/apache2/mods-enabled/info.conf', + } ) } + end + + context 'on a RedHat OS' do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + # Load the more generic tests for this context + general_info_specs_22() + + it { is_expected.to contain_file('info.conf').with({ + :ensure => 'file', + :path => '/etc/httpd/conf.d/info.conf', + } ) } + end + + context 'on a FreeBSD OS' do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '10', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + # Load the more generic tests for this context + general_info_specs_24() + + it { is_expected.to contain_file('info.conf').with({ + :ensure => 'file', + :path => '/usr/local/etc/apache24/Modules/info.conf', + } ) } + end + + context 'on a Gentoo OS' do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + + # Load the more generic tests for this context + general_info_specs_24() + + it { is_expected.to contain_file('info.conf').with({ + :ensure => 'file', + :path => '/etc/apache2/modules.d/info.conf', + } ) } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/itk_spec.rb b/3rdparty/modules/apache/spec/classes/mod/itk_spec.rb new file mode 100644 index 000000000..164440876 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/itk_spec.rb @@ -0,0 +1,73 @@ +require 'spec_helper' + +describe 'apache::mod::itk', :type => :class do + let :pre_condition do + 'class { "apache": mpm_module => false, }' + end + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.not_to contain_apache__mod('itk') } + it { is_expected.to contain_file("/etc/apache2/mods-available/itk.conf").with_ensure('file') } + it { is_expected.to contain_file("/etc/apache2/mods-enabled/itk.conf").with_ensure('link') } + + context "with Apache version < 2.4" do + let :params do + { + :apache_version => '2.2', + } + end + + it { is_expected.not_to contain_file("/etc/apache2/mods-available/itk.load") } + it { is_expected.not_to contain_file("/etc/apache2/mods-enabled/itk.load") } + + it { is_expected.to contain_package("apache2-mpm-itk") } + end + + context "with Apache version >= 2.4" do + let :params do + { + :apache_version => '2.4', + } + end + + it { is_expected.to contain_file("/etc/apache2/mods-available/itk.load").with({ + 'ensure' => 'file', + 'content' => "LoadModule mpm_itk_module /usr/lib/apache2/modules/mod_mpm_itk.so\n" + }) + } + it { is_expected.to contain_file("/etc/apache2/mods-enabled/itk.load").with_ensure('link') } + end + end + context "on a FreeBSD OS" do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '10', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + :mpm_module => 'itk', + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.not_to contain_apache__mod('itk') } + it { is_expected.to contain_file("/usr/local/etc/apache24/Modules/itk.conf").with_ensure('file') } + it { is_expected.to contain_package("www/mod_mpm_itk") } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/mime_magic_spec.rb b/3rdparty/modules/apache/spec/classes/mod/mime_magic_spec.rb new file mode 100644 index 000000000..f846ce386 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/mime_magic_spec.rb @@ -0,0 +1,112 @@ +require 'spec_helper' + +# This function is called inside the OS specific contexts +def general_mime_magic_specs + it { is_expected.to contain_apache__mod("mime_magic") } +end + +describe 'apache::mod::mime_magic', :type => :class do + let :pre_condition do + 'include apache' + end + + context "On a Debian OS with default params" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + general_mime_magic_specs() + + it do + is_expected.to contain_file("mime_magic.conf").with_content( + "MIMEMagicFile \"/etc/apache2/magic\"\n" + ) + end + + it { is_expected.to contain_file("mime_magic.conf").with({ + :ensure => 'file', + :path => '/etc/apache2/mods-available/mime_magic.conf', + } ) } + it { is_expected.to contain_file("mime_magic.conf symlink").with({ + :ensure => 'link', + :path => '/etc/apache2/mods-enabled/mime_magic.conf', + } ) } + + context "with magic_file => /tmp/Debian_magic" do + let :params do + { :magic_file => "/tmp/Debian_magic" } + end + + it do + is_expected.to contain_file("mime_magic.conf").with_content( + "MIMEMagicFile \"/tmp/Debian_magic\"\n" + ) + end + end + + end + + context "on a RedHat OS with default params" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + general_mime_magic_specs() + + it do + is_expected.to contain_file("mime_magic.conf").with_content( + "MIMEMagicFile \"/etc/httpd/conf/magic\"\n" + ) + end + + it { is_expected.to contain_file("mime_magic.conf").with_path("/etc/httpd/conf.d/mime_magic.conf") } + + end + + context "with magic_file => /tmp/magic" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + let :params do + { :magic_file => "/tmp/magic" } + end + + it do + is_expected.to contain_file("mime_magic.conf").with_content( + "MIMEMagicFile \"/tmp/magic\"\n" + ) + end + end + + +end diff --git a/3rdparty/modules/apache/spec/classes/mod/mime_spec.rb b/3rdparty/modules/apache/spec/classes/mod/mime_spec.rb new file mode 100644 index 000000000..3c7ad88d1 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/mime_spec.rb @@ -0,0 +1,54 @@ +require 'spec_helper' + +# This function is called inside the OS specific conte, :compilexts +def general_mime_specs + it { is_expected.to contain_apache__mod("mime") } +end + +describe 'apache::mod::mime', :type => :class do + let :pre_condition do + 'include apache' + end + + context "On a Debian OS with default params", :compile do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + general_mime_specs() + + it { is_expected.to contain_file("mime.conf").with_path('/etc/apache2/mods-available/mime.conf') } + + end + + context "on a RedHat OS with default params", :compile do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + general_mime_specs() + + it { is_expected.to contain_file("mime.conf").with_path("/etc/httpd/conf.d/mime.conf") } + + end + +end diff --git a/3rdparty/modules/apache/spec/classes/mod/negotiation_spec.rb b/3rdparty/modules/apache/spec/classes/mod/negotiation_spec.rb new file mode 100644 index 000000000..813e76def --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/negotiation_spec.rb @@ -0,0 +1,65 @@ +require 'spec_helper' + +describe 'apache::mod::negotiation', :type => :class do + describe "OS independent tests" do + + let :facts do + { + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :kernel => 'Linux', + :lsbdistcodename => 'squeeze', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :id => 'root', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + context "default params" do + let :pre_condition do + 'class {"::apache": }' + end + it { should contain_class("apache") } + it do + should contain_file('negotiation.conf').with( { + :ensure => 'file', + :content => 'LanguagePriority en ca cs da de el eo es et fr he hr it ja ko ltz nl nn no pl pt pt-BR ru sv zh-CN zh-TW +ForceLanguagePriority Prefer Fallback +', + } ) + end + end + + context 'with force_language_priority parameter' do + let :pre_condition do + 'class {"::apache": default_mods => ["negotiation"]}' + end + let :params do + { :force_language_priority => 'Prefer' } + end + it do + should contain_file('negotiation.conf').with( { + :ensure => 'file', + :content => /^ForceLanguagePriority Prefer$/, + } ) + end + end + + context 'with language_priority parameter' do + let :pre_condition do + 'class {"::apache": default_mods => ["negotiation"]}' + end + let :params do + { :language_priority => [ 'en', 'es' ] } + end + it do + should contain_file('negotiation.conf').with( { + :ensure => 'file', + :content => /^LanguagePriority en es$/, + } ) + end + end + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/pagespeed_spec.rb b/3rdparty/modules/apache/spec/classes/mod/pagespeed_spec.rb new file mode 100644 index 000000000..c3f5a4144 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/pagespeed_spec.rb @@ -0,0 +1,45 @@ +require 'spec_helper' + +describe 'apache::mod::pagespeed', :type => :class do + let :pre_condition do + 'include apache' + end + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('pagespeed') } + it { is_expected.to contain_package("mod-pagespeed-stable") } + it { is_expected.to contain_file('pagespeed.conf') } + end + + context "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('pagespeed') } + it { is_expected.to contain_package("mod-pagespeed-stable") } + it { is_expected.to contain_file('pagespeed.conf') } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/passenger_spec.rb b/3rdparty/modules/apache/spec/classes/mod/passenger_spec.rb new file mode 100644 index 000000000..07ce358fe --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/passenger_spec.rb @@ -0,0 +1,288 @@ +require 'spec_helper' + +describe 'apache::mod::passenger', :type => :class do + let :pre_condition do + 'include apache' + end + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :kernel => 'Linux', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('passenger') } + it { is_expected.to contain_package("libapache2-mod-passenger") } + it { is_expected.to contain_file('zpassenger.load').with({ + 'path' => '/etc/apache2/mods-available/zpassenger.load', + }) } + it { is_expected.to contain_file('passenger.conf').with({ + 'path' => '/etc/apache2/mods-available/passenger.conf', + }) } + describe "with passenger_root => '/usr/lib/example'" do + let :params do + { :passenger_root => '/usr/lib/example' } + end + it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerRoot "/usr/lib/example"}) } + end + describe "with passenger_ruby => /usr/lib/example/ruby" do + let :params do + { :passenger_ruby => '/usr/lib/example/ruby' } + end + it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerRuby "/usr/lib/example/ruby"}) } + end + describe "with passenger_default_ruby => /usr/lib/example/ruby1.9.3" do + let :params do + { :passenger_ruby => '/usr/lib/example/ruby1.9.3' } + end + it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerRuby "/usr/lib/example/ruby1.9.3"}) } + end + describe "with passenger_high_performance => on" do + let :params do + { :passenger_high_performance => 'on' } + end + it { is_expected.to contain_file('passenger.conf').with_content(/^ PassengerHighPerformance on$/) } + end + describe "with passenger_pool_idle_time => 1200" do + let :params do + { :passenger_pool_idle_time => 1200 } + end + it { is_expected.to contain_file('passenger.conf').with_content(/^ PassengerPoolIdleTime 1200$/) } + end + describe "with passenger_max_requests => 20" do + let :params do + { :passenger_max_requests => 20 } + end + it { is_expected.to contain_file('passenger.conf').with_content(/^ PassengerMaxRequests 20$/) } + end + describe "with passenger_stat_throttle_rate => 10" do + let :params do + { :passenger_stat_throttle_rate => 10 } + end + it { is_expected.to contain_file('passenger.conf').with_content(/^ PassengerStatThrottleRate 10$/) } + end + describe "with passenger_max_pool_size => 16" do + let :params do + { :passenger_max_pool_size => 16 } + end + it { is_expected.to contain_file('passenger.conf').with_content(/^ PassengerMaxPoolSize 16$/) } + end + describe "with passenger_min_instances => 5" do + let :params do + { :passenger_min_instances => 5 } + end + it { is_expected.to contain_file('passenger.conf').with_content(/^ PassengerMinInstances 5$/) } + end + describe "with rack_autodetect => on" do + let :params do + { :rack_autodetect => 'on' } + end + it { is_expected.to contain_file('passenger.conf').with_content(/^ RackAutoDetect on$/) } + end + describe "with rails_autodetect => on" do + let :params do + { :rails_autodetect => 'on' } + end + it { is_expected.to contain_file('passenger.conf').with_content(/^ RailsAutoDetect on$/) } + end + describe "with passenger_use_global_queue => on" do + let :params do + { :passenger_use_global_queue => 'on' } + end + it { is_expected.to contain_file('passenger.conf').with_content(/^ PassengerUseGlobalQueue on$/) } + end + describe "with passenger_app_env => 'foo'" do + let :params do + { :passenger_app_env => 'foo' } + end + it { is_expected.to contain_file('passenger.conf').with_content(/^ PassengerAppEnv foo$/) } + end + describe "with mod_path => '/usr/lib/foo/mod_foo.so'" do + let :params do + { :mod_path => '/usr/lib/foo/mod_foo.so' } + end + it { is_expected.to contain_file('zpassenger.load').with_content(/^LoadModule passenger_module \/usr\/lib\/foo\/mod_foo\.so$/) } + end + describe "with mod_lib_path => '/usr/lib/foo'" do + let :params do + { :mod_lib_path => '/usr/lib/foo' } + end + it { is_expected.to contain_file('zpassenger.load').with_content(/^LoadModule passenger_module \/usr\/lib\/foo\/mod_passenger\.so$/) } + end + describe "with mod_lib => 'mod_foo.so'" do + let :params do + { :mod_lib => 'mod_foo.so' } + end + it { is_expected.to contain_file('zpassenger.load').with_content(/^LoadModule passenger_module \/usr\/lib\/apache2\/modules\/mod_foo\.so$/) } + end + describe "with mod_id => 'mod_foo'" do + let :params do + { :mod_id => 'mod_foo' } + end + it { is_expected.to contain_file('zpassenger.load').with_content(/^LoadModule mod_foo \/usr\/lib\/apache2\/modules\/mod_passenger\.so$/) } + end + + context "with Ubuntu 12.04 defaults" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '12.04', + :kernel => 'Linux', + :operatingsystem => 'Ubuntu', + :lsbdistrelease => '12.04', + :concat_basedir => '/dne', + :id => 'root', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerRoot "/usr"}) } + it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerRuby "/usr/bin/ruby"}) } + it { is_expected.to contain_file('passenger.conf').without_content(/PassengerDefaultRuby/) } + end + + context "with Ubuntu 14.04 defaults" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '14.04', + :operatingsystem => 'Ubuntu', + :kernel => 'Linux', + :lsbdistrelease => '14.04', + :concat_basedir => '/dne', + :id => 'root', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerRoot "/usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini"}) } + it { is_expected.to contain_file('passenger.conf').without_content(/PassengerRuby/) } + it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerDefaultRuby "/usr/bin/ruby"}) } + end + + context "with Debian 7 defaults" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '7.3', + :operatingsystem => 'Debian', + :kernel => 'Linux', + :lsbdistcodename => 'wheezy', + :concat_basedir => '/dne', + :id => 'root', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerRoot "/usr"}) } + it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerRuby "/usr/bin/ruby"}) } + it { is_expected.to contain_file('passenger.conf').without_content(/PassengerDefaultRuby/) } + end + + context "with Debian 8 defaults" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '8.0', + :operatingsystem => 'Debian', + :kernel => 'Linux', + :lsbdistcodename => 'jessie', + :concat_basedir => '/dne', + :id => 'root', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerRoot "/usr/lib/ruby/vendor_ruby/phusion_passenger/locations.ini"}) } + it { is_expected.to contain_file('passenger.conf').without_content(/PassengerRuby/) } + it { is_expected.to contain_file('passenger.conf').with_content(%r{PassengerDefaultRuby "/usr/bin/ruby"}) } + end + end + + context "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('passenger') } + it { is_expected.to contain_package("mod_passenger") } + it { is_expected.to contain_file('passenger_package.conf').with({ + 'path' => '/etc/httpd/conf.d/passenger.conf', + }) } + it { is_expected.to contain_file('passenger_package.conf').without_content } + it { is_expected.to contain_file('passenger_package.conf').without_source } + it { is_expected.to contain_file('zpassenger.load').with({ + 'path' => '/etc/httpd/conf.d/zpassenger.load', + }) } + it { is_expected.to contain_file('passenger.conf').without_content(/PassengerRoot/) } + it { is_expected.to contain_file('passenger.conf').without_content(/PassengerRuby/) } + describe "with passenger_root => '/usr/lib/example'" do + let :params do + { :passenger_root => '/usr/lib/example' } + end + it { is_expected.to contain_file('passenger.conf').with_content(/^ PassengerRoot "\/usr\/lib\/example"$/) } + end + describe "with passenger_ruby => /usr/lib/example/ruby" do + let :params do + { :passenger_ruby => '/usr/lib/example/ruby' } + end + it { is_expected.to contain_file('passenger.conf').with_content(/^ PassengerRuby "\/usr\/lib\/example\/ruby"$/) } + end + end + context "on a FreeBSD OS" do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '9', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('passenger') } + it { is_expected.to contain_package("www/rubygem-passenger") } + end + context "on a Gentoo OS" do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('passenger') } + it { is_expected.to contain_package("www-apache/passenger") } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/perl_spec.rb b/3rdparty/modules/apache/spec/classes/mod/perl_spec.rb new file mode 100644 index 000000000..17ee1b366 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/perl_spec.rb @@ -0,0 +1,76 @@ +require 'spec_helper' + +describe 'apache::mod::perl', :type => :class do + let :pre_condition do + 'include apache' + end + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('perl') } + it { is_expected.to contain_package("libapache2-mod-perl2") } + end + context "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('perl') } + it { is_expected.to contain_package("mod_perl") } + end + context "on a FreeBSD OS" do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '9', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('perl') } + it { is_expected.to contain_package("www/mod_perl2") } + end + context "on a Gentoo OS" do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :operatingsystem => 'Gentoo', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('perl') } + it { is_expected.to contain_package("www-apache/mod_perl") } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/peruser_spec.rb b/3rdparty/modules/apache/spec/classes/mod/peruser_spec.rb new file mode 100644 index 000000000..097a36fff --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/peruser_spec.rb @@ -0,0 +1,43 @@ +require 'spec_helper' + +describe 'apache::mod::peruser', :type => :class do + let :pre_condition do + 'class { "apache": mpm_module => false, }' + end + context "on a FreeBSD OS" do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '10', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it do + expect { + catalogue + }.to raise_error(Puppet::Error, /Unsupported osfamily FreeBSD/) + end + end + context "on a Gentoo OS" do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.not_to contain_apache__mod('peruser') } + it { is_expected.to contain_file("/etc/apache2/modules.d/peruser.conf").with_ensure('file') } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/php_spec.rb b/3rdparty/modules/apache/spec/classes/mod/php_spec.rb new file mode 100644 index 000000000..246b3bbd4 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/php_spec.rb @@ -0,0 +1,289 @@ +require 'spec_helper' + +describe 'apache::mod::php', :type => :class do + describe "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + context "with mpm_module => prefork" do + let :pre_condition do + 'class { "apache": mpm_module => prefork, }' + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_class("apache::mod::prefork") } + it { is_expected.to contain_apache__mod('php5') } + it { is_expected.to contain_package("libapache2-mod-php5") } + it { is_expected.to contain_file("php5.load").with( + :content => "LoadModule php5_module /usr/lib/apache2/modules/libphp5.so\n" + ) } + end + context "with mpm_module => itk" do + let :pre_condition do + 'class { "apache": mpm_module => itk, }' + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_class("apache::mod::itk") } + it { is_expected.to contain_apache__mod('php5') } + it { is_expected.to contain_package("libapache2-mod-php5") } + it { is_expected.to contain_file("php5.load").with( + :content => "LoadModule php5_module /usr/lib/apache2/modules/libphp5.so\n" + ) } + end + end + describe "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + context "with default params" do + let :pre_condition do + 'class { "apache": }' + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('php5') } + it { is_expected.to contain_package("php") } + it { is_expected.to contain_file("php5.load").with( + :content => "LoadModule php5_module modules/libphp5.so\n" + ) } + end + context "with alternative package name" do let :pre_condition do + 'class { "apache": }' + end + let :params do + { :package_name => 'php54'} + end + it { is_expected.to contain_package("php54") } + end + context "with alternative path" do let :pre_condition do + 'class { "apache": }' + end + let :params do + { :path => 'alternative-path'} + end + it { is_expected.to contain_file("php5.load").with( + :content => "LoadModule php5_module alternative-path\n" + ) } + end + context "with alternative extensions" do let :pre_condition do + 'class { "apache": }' + end + let :params do + { :extensions => ['.php','.php5']} + end + it { is_expected.to contain_file("php5.conf").with_content(/AddHandler php5-script .php .php5\n/) } + end + context "with specific version" do + let :pre_condition do + 'class { "apache": }' + end + let :params do + { :package_ensure => '5.3.13'} + end + it { is_expected.to contain_package("php").with( + :ensure => '5.3.13' + ) } + end + context "with mpm_module => prefork" do + let :pre_condition do + 'class { "apache": mpm_module => prefork, }' + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_class("apache::mod::prefork") } + it { is_expected.to contain_apache__mod('php5') } + it { is_expected.to contain_package("php") } + it { is_expected.to contain_file("php5.load").with( + :content => "LoadModule php5_module modules/libphp5.so\n" + ) } + end + context "with mpm_module => itk" do + let :pre_condition do + 'class { "apache": mpm_module => itk, }' + end + it 'should raise an error' do + expect { expect(subject).to contain_class("apache::mod::itk") }.to raise_error Puppet::Error, /Unsupported osfamily RedHat/ + end + end + end + describe "on a FreeBSD OS" do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '10', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + context "with mpm_module => prefork" do + let :pre_condition do + 'class { "apache": mpm_module => prefork, }' + end + it { is_expected.to contain_class('apache::params') } + it { is_expected.to contain_apache__mod('php5') } + it { is_expected.to contain_package("www/mod_php5") } + it { is_expected.to contain_file('php5.load') } + end + context "with mpm_module => itk" do + let :pre_condition do + 'class { "apache": mpm_module => itk, }' + end + it { is_expected.to contain_class('apache::params') } + it { is_expected.to contain_class('apache::mod::itk') } + it { is_expected.to contain_apache__mod('php5') } + it { is_expected.to contain_package("www/mod_php5") } + it { is_expected.to contain_file('php5.load') } + end + end + describe "on a Gentoo OS" do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + context "with mpm_module => prefork" do + let :pre_condition do + 'class { "apache": mpm_module => prefork, }' + end + it { is_expected.to contain_class('apache::params') } + it { is_expected.to contain_apache__mod('php5') } + it { is_expected.to contain_package("dev-lang/php") } + it { is_expected.to contain_file('php5.load') } + end + context "with mpm_module => itk" do + let :pre_condition do + 'class { "apache": mpm_module => itk, }' + end + it { is_expected.to contain_class('apache::params') } + it { is_expected.to contain_class('apache::mod::itk') } + it { is_expected.to contain_apache__mod('php5') } + it { is_expected.to contain_package("dev-lang/php") } + it { is_expected.to contain_file('php5.load') } + end + end + describe "OS independent tests" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => '6', + :kernel => 'Linux', + :lsbdistcodename => 'squeeze', + :concat_basedir => '/dne', + :id => 'root', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + context 'with content param' do + let :pre_condition do + 'class { "apache": mpm_module => prefork, }' + end + let :params do + { :content => 'somecontent' } + end + it { should contain_file('php5.conf').with( + :content => 'somecontent' + ) } + end + context 'with template param' do + let :pre_condition do + 'class { "apache": mpm_module => prefork, }' + end + let :params do + { :template => 'apache/mod/php5.conf.erb' } + end + it { should contain_file('php5.conf').with( + :content => /^# PHP is an HTML-embedded scripting language which attempts to make it/ + ) } + end + context 'with source param' do + let :pre_condition do + 'class { "apache": mpm_module => prefork, }' + end + let :params do + { :source => 'some-path' } + end + it { should contain_file('php5.conf').with( + :source => 'some-path' + ) } + end + context 'content has priority over template' do + let :pre_condition do + 'class { "apache": mpm_module => prefork, }' + end + let :params do + { + :template => 'apache/mod/php5.conf.erb', + :content => 'somecontent' + } + end + it { should contain_file('php5.conf').with( + :content => 'somecontent' + ) } + end + context 'source has priority over template' do + let :pre_condition do + 'class { "apache": mpm_module => prefork, }' + end + let :params do + { + :template => 'apache/mod/php5.conf.erb', + :source => 'some-path' + } + end + it { should contain_file('php5.conf').with( + :source => 'some-path' + ) } + end + context 'source has priority over content' do + let :pre_condition do + 'class { "apache": mpm_module => prefork, }' + end + let :params do + { + :content => 'somecontent', + :source => 'some-path' + } + end + it { should contain_file('php5.conf').with( + :source => 'some-path' + ) } + end + context 'with mpm_module => worker' do + let :pre_condition do + 'class { "apache": mpm_module => worker, }' + end + it 'should raise an error' do + expect { expect(subject).to contain_apache__mod('php5') }.to raise_error Puppet::Error, /mpm_module => 'prefork' or mpm_module => 'itk'/ + end + end + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/prefork_spec.rb b/3rdparty/modules/apache/spec/classes/mod/prefork_spec.rb new file mode 100644 index 000000000..3e2954fc7 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/prefork_spec.rb @@ -0,0 +1,134 @@ +require 'spec_helper' + +describe 'apache::mod::prefork', :type => :class do + let :pre_condition do + 'class { "apache": mpm_module => false, }' + end + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.not_to contain_apache__mod('prefork') } + it { is_expected.to contain_file("/etc/apache2/mods-available/prefork.conf").with_ensure('file') } + it { is_expected.to contain_file("/etc/apache2/mods-enabled/prefork.conf").with_ensure('link') } + + context "with Apache version < 2.4" do + let :params do + { + :apache_version => '2.2', + } + end + + it { is_expected.not_to contain_file("/etc/apache2/mods-available/prefork.load") } + it { is_expected.not_to contain_file("/etc/apache2/mods-enabled/prefork.load") } + + it { is_expected.to contain_package("apache2-mpm-prefork") } + end + + context "with Apache version >= 2.4" do + let :params do + { + :apache_version => '2.4', + } + end + + it { is_expected.to contain_file("/etc/apache2/mods-available/prefork.load").with({ + 'ensure' => 'file', + 'content' => "LoadModule mpm_prefork_module /usr/lib/apache2/modules/mod_mpm_prefork.so\n" + }) + } + it { is_expected.to contain_file("/etc/apache2/mods-enabled/prefork.load").with_ensure('link') } + end + end + context "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.not_to contain_apache__mod('prefork') } + it { is_expected.to contain_file("/etc/httpd/conf.d/prefork.conf").with_ensure('file') } + + context "with Apache version < 2.4" do + let :params do + { + :apache_version => '2.2', + } + end + + it { is_expected.to contain_file_line("/etc/sysconfig/httpd prefork enable").with({ + 'require' => 'Package[httpd]', + }) + } + end + + context "with Apache version >= 2.4" do + let :params do + { + :apache_version => '2.4', + } + end + + it { is_expected.not_to contain_apache__mod('event') } + + it { is_expected.to contain_file("/etc/httpd/conf.d/prefork.load").with({ + 'ensure' => 'file', + 'content' => "LoadModule mpm_prefork_module modules/mod_mpm_prefork.so\n", + }) + } + end + end + context "on a FreeBSD OS" do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '9', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.not_to contain_apache__mod('prefork') } + it { is_expected.to contain_file("/usr/local/etc/apache24/Modules/prefork.conf").with_ensure('file') } + end + context "on a Gentoo OS" do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.not_to contain_apache__mod('prefork') } + it { is_expected.to contain_file("/etc/apache2/modules.d/prefork.conf").with_ensure('file') } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/proxy_connect_spec.rb b/3rdparty/modules/apache/spec/classes/mod/proxy_connect_spec.rb new file mode 100644 index 000000000..dbb314c2b --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/proxy_connect_spec.rb @@ -0,0 +1,65 @@ +require 'spec_helper' + +describe 'apache::mod::proxy_connect', :type => :class do + let :pre_condition do + [ + 'include apache', + 'include apache::mod::proxy', + ] + end + context 'on a Debian OS' do + let :facts do + { + :osfamily => 'Debian', + :concat_basedir => '/dne', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + context 'with Apache version < 2.2' do + let :facts do + super().merge({ + :operatingsystemrelease => '7.0', + :lsbdistcodename => 'wheezy', + }) + end + let :params do + { + :apache_version => '2.1', + } + end + it { is_expected.not_to contain_apache__mod('proxy_connect') } + end + context 'with Apache version = 2.2' do + let :facts do + super().merge({ + :operatingsystemrelease => '7.0', + :lsbdistcodename => 'wheezy', + }) + end + let :params do + { + :apache_version => '2.2', + } + end + it { is_expected.to contain_apache__mod('proxy_connect') } + end + context 'with Apache version >= 2.4' do + let :facts do + super().merge({ + :operatingsystemrelease => '8.0', + :lsbdistcodename => 'jessie', + }) + end + let :params do + { + :apache_version => '2.4', + } + end + it { is_expected.to contain_apache__mod('proxy_connect') } + end + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/proxy_html_spec.rb b/3rdparty/modules/apache/spec/classes/mod/proxy_html_spec.rb new file mode 100644 index 000000000..80106931e --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/proxy_html_spec.rb @@ -0,0 +1,105 @@ +require 'spec_helper' + +describe 'apache::mod::proxy_html', :type => :class do + let :pre_condition do + [ + 'include apache', + 'include apache::mod::proxy', + 'include apache::mod::proxy_http', + ] + end + context "on a Debian OS" do + shared_examples "debian" do |loadfiles| + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('proxy_html').with(:loadfiles => loadfiles) } + it { is_expected.to contain_package("libapache2-mod-proxy-html") } + end + let :facts do + { + :osfamily => 'Debian', + :concat_basedir => '/dne', + :architecture => 'i386', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :hardwaremodel => 'i386', + :is_pe => false, + } + end + + context "on squeeze" do + let(:facts) { super().merge({ :operatingsystemrelease => '6' }) } + it_behaves_like "debian", ['/usr/lib/libxml2.so.2'] + end + context "on wheezy" do + let(:facts) { super().merge({ :operatingsystemrelease => '7' }) } + context "i386" do + let(:facts) { super().merge({ + :hardwaremodel => 'i686', + :architecture => 'i386' + })} + it_behaves_like "debian", ["/usr/lib/i386-linux-gnu/libxml2.so.2"] + end + context "x64" do + let(:facts) { super().merge({ + :hardwaremodel => 'x86_64', + :architecture => 'amd64' + })} + it_behaves_like "debian", ["/usr/lib/x86_64-linux-gnu/libxml2.so.2"] + end + end + end + context "on a RedHat OS", :compile do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('proxy_html').with(:loadfiles => nil) } + it { is_expected.to contain_package("mod_proxy_html") } + end + context "on a FreeBSD OS", :compile do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '9', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('proxy_html').with(:loadfiles => nil) } + it { is_expected.to contain_package("www/mod_proxy_html") } + end + context "on a Gentoo OS", :compile do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('proxy_html').with(:loadfiles => nil) } + it { is_expected.to contain_package("www-apache/mod_proxy_html") } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/python_spec.rb b/3rdparty/modules/apache/spec/classes/mod/python_spec.rb new file mode 100644 index 000000000..46c4cde3a --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/python_spec.rb @@ -0,0 +1,76 @@ +require 'spec_helper' + +describe 'apache::mod::python', :type => :class do + let :pre_condition do + 'include apache' + end + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod("python") } + it { is_expected.to contain_package("libapache2-mod-python") } + end + context "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod("python") } + it { is_expected.to contain_package("mod_python") } + end + context "on a FreeBSD OS" do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '9', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod("python") } + it { is_expected.to contain_package("www/mod_python3") } + end + context "on a Gentoo OS" do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod("python") } + it { is_expected.to contain_package("www-apache/mod_python") } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/remoteip_spec.rb b/3rdparty/modules/apache/spec/classes/mod/remoteip_spec.rb new file mode 100644 index 000000000..c9f5b4e83 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/remoteip_spec.rb @@ -0,0 +1,53 @@ +require 'spec_helper' + +describe 'apache::mod::remoteip', :type => :class do + let :pre_condition do + [ + 'include apache', + ] + end + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '8', + :concat_basedir => '/dne', + :lsbdistcodename => 'jessie', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + } + end + let :params do + { :apache_version => '2.4' } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('remoteip') } + it { is_expected.to contain_file('remoteip.conf').with({ + 'path' => '/etc/apache2/mods-available/remoteip.conf', + }) } + + describe "with header X-Forwarded-For" do + let :params do + { :header => 'X-Forwarded-For' } + end + it { is_expected.to contain_file('remoteip.conf').with_content(/^RemoteIPHeader X-Forwarded-For$/) } + end + describe "with proxy_ips => [ 10.42.17.8, 10.42.18.99 ]" do + let :params do + { :proxy_ips => [ '10.42.17.8', '10.42.18.99' ] } + end + it { is_expected.to contain_file('remoteip.conf').with_content(/^RemoteIPInternalProxy 10.42.17.8$/) } + it { is_expected.to contain_file('remoteip.conf').with_content(/^RemoteIPInternalProxy 10.42.18.99$/) } + end + describe "with Apache version < 2.4" do + let :params do + { :apache_version => '2.2' } + end + it 'should fail' do + expect { catalogue }.to raise_error(Puppet::Error, /mod_remoteip is only available in Apache 2.4/) + end + end + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/reqtimeout_spec.rb b/3rdparty/modules/apache/spec/classes/mod/reqtimeout_spec.rb new file mode 100644 index 000000000..1869eb68d --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/reqtimeout_spec.rb @@ -0,0 +1,150 @@ +require 'spec_helper' + +describe 'apache::mod::reqtimeout', :type => :class do + let :pre_condition do + 'class { "apache": + default_mods => false, + }' + end + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :lsbdistcodename => 'squeeze', + :is_pe => false, + } + end + context "passing no parameters" do + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('reqtimeout') } + it { is_expected.to contain_file('reqtimeout.conf').with_content(/^RequestReadTimeout header=20-40,minrate=500\nRequestReadTimeout body=10,minrate=500$/) } + end + context "passing timeouts => ['header=20-60,minrate=600', 'body=60,minrate=600']" do + let :params do + {:timeouts => ['header=20-60,minrate=600', 'body=60,minrate=600']} + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('reqtimeout') } + it { is_expected.to contain_file('reqtimeout.conf').with_content(/^RequestReadTimeout header=20-60,minrate=600\nRequestReadTimeout body=60,minrate=600$/) } + end + context "passing timeouts => 'header=20-60,minrate=600'" do + let :params do + {:timeouts => 'header=20-60,minrate=600'} + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('reqtimeout') } + it { is_expected.to contain_file('reqtimeout.conf').with_content(/^RequestReadTimeout header=20-60,minrate=600$/) } + end + end + context "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'Redhat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + context "passing no parameters" do + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('reqtimeout') } + it { is_expected.to contain_file('reqtimeout.conf').with_content(/^RequestReadTimeout header=20-40,minrate=500\nRequestReadTimeout body=10,minrate=500$/) } + end + context "passing timeouts => ['header=20-60,minrate=600', 'body=60,minrate=600']" do + let :params do + {:timeouts => ['header=20-60,minrate=600', 'body=60,minrate=600']} + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('reqtimeout') } + it { is_expected.to contain_file('reqtimeout.conf').with_content(/^RequestReadTimeout header=20-60,minrate=600\nRequestReadTimeout body=60,minrate=600$/) } + end + context "passing timeouts => 'header=20-60,minrate=600'" do + let :params do + {:timeouts => 'header=20-60,minrate=600'} + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('reqtimeout') } + it { is_expected.to contain_file('reqtimeout.conf').with_content(/^RequestReadTimeout header=20-60,minrate=600$/) } + end + end + context "on a FreeBSD OS" do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '9', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + context "passing no parameters" do + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('reqtimeout') } + it { is_expected.to contain_file('reqtimeout.conf').with_content(/^RequestReadTimeout header=20-40,minrate=500\nRequestReadTimeout body=10,minrate=500$/) } + end + context "passing timeouts => ['header=20-60,minrate=600', 'body=60,minrate=600']" do + let :params do + {:timeouts => ['header=20-60,minrate=600', 'body=60,minrate=600']} + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('reqtimeout') } + it { is_expected.to contain_file('reqtimeout.conf').with_content(/^RequestReadTimeout header=20-60,minrate=600\nRequestReadTimeout body=60,minrate=600$/) } + end + context "passing timeouts => 'header=20-60,minrate=600'" do + let :params do + {:timeouts => 'header=20-60,minrate=600'} + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('reqtimeout') } + it { is_expected.to contain_file('reqtimeout.conf').with_content(/^RequestReadTimeout header=20-60,minrate=600$/) } + end + end + context "on a Gentoo OS" do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + context "passing no parameters" do + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('reqtimeout') } + it { is_expected.to contain_file('reqtimeout.conf').with_content(/^RequestReadTimeout header=20-40,minrate=500\nRequestReadTimeout body=10,minrate=500$/) } + end + context "passing timeouts => ['header=20-60,minrate=600', 'body=60,minrate=600']" do + let :params do + {:timeouts => ['header=20-60,minrate=600', 'body=60,minrate=600']} + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('reqtimeout') } + it { is_expected.to contain_file('reqtimeout.conf').with_content(/^RequestReadTimeout header=20-60,minrate=600\nRequestReadTimeout body=60,minrate=600$/) } + end + context "passing timeouts => 'header=20-60,minrate=600'" do + let :params do + {:timeouts => 'header=20-60,minrate=600'} + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('reqtimeout') } + it { is_expected.to contain_file('reqtimeout.conf').with_content(/^RequestReadTimeout header=20-60,minrate=600$/) } + end + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/rpaf_spec.rb b/3rdparty/modules/apache/spec/classes/mod/rpaf_spec.rb new file mode 100644 index 000000000..83591bc28 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/rpaf_spec.rb @@ -0,0 +1,130 @@ +require 'spec_helper' + +describe 'apache::mod::rpaf', :type => :class do + let :pre_condition do + [ + 'include apache', + ] + end + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('rpaf') } + it { is_expected.to contain_package("libapache2-mod-rpaf") } + it { is_expected.to contain_file('rpaf.conf').with({ + 'path' => '/etc/apache2/mods-available/rpaf.conf', + }) } + it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFenable On$/) } + + describe "with sethostname => true" do + let :params do + { :sethostname => 'true' } + end + it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFsethostname On$/) } + end + describe "with proxy_ips => [ 10.42.17.8, 10.42.18.99 ]" do + let :params do + { :proxy_ips => [ '10.42.17.8', '10.42.18.99' ] } + end + it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFproxy_ips 10.42.17.8 10.42.18.99$/) } + end + describe "with header => X-Real-IP" do + let :params do + { :header => 'X-Real-IP' } + end + it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFheader X-Real-IP$/) } + end + end + context "on a FreeBSD OS" do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '9', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('rpaf') } + it { is_expected.to contain_package("www/mod_rpaf2") } + it { is_expected.to contain_file('rpaf.conf').with({ + 'path' => '/usr/local/etc/apache24/Modules/rpaf.conf', + }) } + it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFenable On$/) } + + describe "with sethostname => true" do + let :params do + { :sethostname => 'true' } + end + it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFsethostname On$/) } + end + describe "with proxy_ips => [ 10.42.17.8, 10.42.18.99 ]" do + let :params do + { :proxy_ips => [ '10.42.17.8', '10.42.18.99' ] } + end + it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFproxy_ips 10.42.17.8 10.42.18.99$/) } + end + describe "with header => X-Real-IP" do + let :params do + { :header => 'X-Real-IP' } + end + it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFheader X-Real-IP$/) } + end + end + context "on a Gentoo OS" do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__mod('rpaf') } + it { is_expected.to contain_package("www-apache/mod_rpaf") } + it { is_expected.to contain_file('rpaf.conf').with({ + 'path' => '/etc/apache2/modules.d/rpaf.conf', + }) } + it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFenable On$/) } + + describe "with sethostname => true" do + let :params do + { :sethostname => 'true' } + end + it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFsethostname On$/) } + end + describe "with proxy_ips => [ 10.42.17.8, 10.42.18.99 ]" do + let :params do + { :proxy_ips => [ '10.42.17.8', '10.42.18.99' ] } + end + it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFproxy_ips 10.42.17.8 10.42.18.99$/) } + end + describe "with header => X-Real-IP" do + let :params do + { :header => 'X-Real-IP' } + end + it { is_expected.to contain_file('rpaf.conf').with_content(/^RPAFheader X-Real-IP$/) } + end + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/security_spec.rb b/3rdparty/modules/apache/spec/classes/mod/security_spec.rb new file mode 100644 index 000000000..93f751ee4 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/security_spec.rb @@ -0,0 +1,95 @@ +require 'spec_helper' + +describe 'apache::mod::security', :type => :class do + let :pre_condition do + 'include apache' + end + + context "on RedHat based systems" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystem => 'CentOS', + :operatingsystemrelease => '7', + :kernel => 'Linux', + :id => 'root', + :concat_basedir => '/', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { should contain_apache__mod('security').with( + :id => 'security2_module', + :lib => 'mod_security2.so' + ) } + it { should contain_apache__mod('unique_id_module').with( + :id => 'unique_id_module', + :lib => 'mod_unique_id.so' + ) } + it { should contain_package('mod_security_crs') } + it { should contain_file('security.conf').with( + :path => '/etc/httpd/conf.d/security.conf' + ) } + it { should contain_file('/etc/httpd/modsecurity.d').with( + :ensure => 'directory', + :path => '/etc/httpd/modsecurity.d', + :owner => 'apache', + :group => 'apache' + ) } + it { should contain_file('/etc/httpd/modsecurity.d/activated_rules').with( + :ensure => 'directory', + :path => '/etc/httpd/modsecurity.d/activated_rules', + :owner => 'apache', + :group => 'apache' + ) } + it { should contain_file('/etc/httpd/modsecurity.d/security_crs.conf').with( + :path => '/etc/httpd/modsecurity.d/security_crs.conf' + ) } + it { should contain_apache__security__rule_link('base_rules/modsecurity_35_bad_robots.data') } + end + + context "on Debian based systems" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/', + :lsbdistcodename => 'squeeze', + :id => 'root', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :kernel => 'Linux', + :is_pe => false, + } + end + it { should contain_apache__mod('security').with( + :id => 'security2_module', + :lib => 'mod_security2.so' + ) } + it { should contain_apache__mod('unique_id_module').with( + :id => 'unique_id_module', + :lib => 'mod_unique_id.so' + ) } + it { should contain_package('modsecurity-crs') } + it { should contain_file('security.conf').with( + :path => '/etc/apache2/mods-available/security.conf' + ) } + it { should contain_file('/etc/modsecurity').with( + :ensure => 'directory', + :path => '/etc/modsecurity', + :owner => 'www-data', + :group => 'www-data' + ) } + it { should contain_file('/etc/modsecurity/activated_rules').with( + :ensure => 'directory', + :path => '/etc/modsecurity/activated_rules', + :owner => 'www-data', + :group => 'www-data' + ) } + it { should contain_file('/etc/modsecurity/security_crs.conf').with( + :path => '/etc/modsecurity/security_crs.conf' + ) } + it { should contain_apache__security__rule_link('base_rules/modsecurity_35_bad_robots.data') } + end + +end diff --git a/3rdparty/modules/apache/spec/classes/mod/shib_spec.rb b/3rdparty/modules/apache/spec/classes/mod/shib_spec.rb new file mode 100644 index 000000000..0254d4c3c --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/shib_spec.rb @@ -0,0 +1,42 @@ +describe 'apache::mod::shib', :type => :class do + let :pre_condition do + 'include apache' + end + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :fqdn => 'test.example.com', + :is_pe => false, + } + end + describe 'with no parameters' do + it { should contain_apache__mod('shib2').with_id('mod_shib') } + end + end + context "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :fqdn => 'test.example.com', + :is_pe => false, + } + end + describe 'with no parameters' do + it { should contain_apache__mod('shib2').with_id('mod_shib') } + end + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/speling_spec.rb b/3rdparty/modules/apache/spec/classes/mod/speling_spec.rb new file mode 100644 index 000000000..b07af2589 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/speling_spec.rb @@ -0,0 +1,39 @@ +require 'spec_helper' + +describe 'apache::mod::speling', :type => :class do + let :pre_condition do + 'include apache' + end + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_apache__mod('speling') } + end + + context "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_apache__mod('speling') } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/ssl_spec.rb b/3rdparty/modules/apache/spec/classes/mod/ssl_spec.rb new file mode 100644 index 000000000..50aa8292f --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/ssl_spec.rb @@ -0,0 +1,140 @@ +require 'spec_helper' + +describe 'apache::mod::ssl', :type => :class do + let :pre_condition do + 'include apache' + end + context 'on an unsupported OS' do + let :facts do + { + :osfamily => 'Magic', + :operatingsystemrelease => '0', + :concat_basedir => '/dne', + :operatingsystem => 'Magic', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { expect { catalogue }.to raise_error(Puppet::Error, /Unsupported osfamily:/) } + end + + context 'on a RedHat OS' do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class('apache::params') } + it { is_expected.to contain_apache__mod('ssl') } + it { is_expected.to contain_package('mod_ssl') } + context 'with a custom package_name parameter' do + let :params do + { :package_name => 'httpd24-mod_ssl' } + end + it { is_expected.to contain_class('apache::params') } + it { is_expected.to contain_apache__mod('ssl') } + it { is_expected.to contain_package('httpd24-mod_ssl') } + it { is_expected.not_to contain_package('mod_ssl') } + end + end + + context 'on a Debian OS' do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class('apache::params') } + it { is_expected.to contain_apache__mod('ssl') } + it { is_expected.not_to contain_package('libapache2-mod-ssl') } + end + + context 'on a FreeBSD OS' do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '9', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class('apache::params') } + it { is_expected.to contain_apache__mod('ssl') } + end + + context 'on a Gentoo OS' do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class('apache::params') } + it { is_expected.to contain_apache__mod('ssl') } + end + + # Template config doesn't vary by distro + context "on all distros" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystem => 'CentOS', + :operatingsystemrelease => '6', + :kernel => 'Linux', + :id => 'root', + :concat_basedir => '/dne', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + context 'not setting ssl_pass_phrase_dialog' do + it { is_expected.to contain_file('ssl.conf').with_content(/^ SSLPassPhraseDialog builtin$/)} + end + + context 'setting ssl_pass_phrase_dialog' do + let :params do + { + :ssl_pass_phrase_dialog => 'exec:/path/to/program', + } + end + it { is_expected.to contain_file('ssl.conf').with_content(/^ SSLPassPhraseDialog exec:\/path\/to\/program$/)} + end + + context 'setting ssl_random_seed_bytes' do + let :params do + { + :ssl_random_seed_bytes => '1024', + } + end + it { is_expected.to contain_file('ssl.conf').with_content(%r{^ SSLRandomSeed startup file:/dev/urandom 1024$})} + end + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/status_spec.rb b/3rdparty/modules/apache/spec/classes/mod/status_spec.rb new file mode 100644 index 000000000..e3b3d2442 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/status_spec.rb @@ -0,0 +1,206 @@ +require 'spec_helper' + +# Helper function for testing the contents of `status.conf` +def status_conf_spec(allow_from, extended_status, status_path) + it do + is_expected.to contain_file("status.conf").with_content( + "\n"\ + " SetHandler server-status\n"\ + " Order deny,allow\n"\ + " Deny from all\n"\ + " Allow from #{Array(allow_from).join(' ')}\n"\ + "\n"\ + "ExtendedStatus #{extended_status}\n"\ + "\n"\ + "\n"\ + " # Show Proxy LoadBalancer status in mod_status\n"\ + " ProxyStatus On\n"\ + "\n" + ) + end +end + +describe 'apache::mod::status', :type => :class do + let :pre_condition do + 'include apache' + end + + context "on a Debian OS with default params" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + it { is_expected.to contain_apache__mod("status") } + + status_conf_spec(["127.0.0.1", "::1"], "On", "/server-status") + + it { is_expected.to contain_file("status.conf").with({ + :ensure => 'file', + :path => '/etc/apache2/mods-available/status.conf', + } ) } + + it { is_expected.to contain_file("status.conf symlink").with({ + :ensure => 'link', + :path => '/etc/apache2/mods-enabled/status.conf', + } ) } + + end + + context "on a RedHat OS with default params" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + it { is_expected.to contain_apache__mod("status") } + + status_conf_spec(["127.0.0.1", "::1"], "On", "/server-status") + + it { is_expected.to contain_file("status.conf").with_path("/etc/httpd/conf.d/status.conf") } + + end + + context "with custom parameters $allow_from => ['10.10.10.10','11.11.11.11'], $extended_status => 'Off', $status_path => '/custom-status'" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + let :params do + { + :allow_from => ['10.10.10.10','11.11.11.11'], + :extended_status => 'Off', + :status_path => '/custom-status', + } + end + + status_conf_spec(["10.10.10.10", "11.11.11.11"], "Off", "/custom-status") + + end + + context "with valid parameter type $allow_from => ['10.10.10.10']" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + let :params do + { :allow_from => ['10.10.10.10'] } + end + it 'should expect to succeed array validation' do + expect { + is_expected.to contain_file("status.conf") + }.not_to raise_error() + end + end + + context "with invalid parameter type $allow_from => '10.10.10.10'" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + let :params do + { :allow_from => '10.10.10.10' } + end + it 'should expect to fail array validation' do + expect { + is_expected.to contain_file("status.conf") + }.to raise_error(Puppet::Error) + end + end + + # Only On or Off are valid options + ['On', 'Off'].each do |valid_param| + context "with valid value $extended_status => '#{valid_param}'" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + let :params do + { :extended_status => valid_param } + end + it 'should expect to succeed regular expression validation' do + expect { + is_expected.to contain_file("status.conf") + }.not_to raise_error() + end + end + end + + ['Yes', 'No'].each do |invalid_param| + context "with invalid value $extended_status => '#{invalid_param}'" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + let :params do + { :extended_status => invalid_param } + end + it 'should expect to fail regular expression validation' do + expect { + is_expected.to contain_file("status.conf") + }.to raise_error(Puppet::Error) + end + end + end + +end diff --git a/3rdparty/modules/apache/spec/classes/mod/suphp_spec.rb b/3rdparty/modules/apache/spec/classes/mod/suphp_spec.rb new file mode 100644 index 000000000..9b20000f3 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/suphp_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe 'apache::mod::suphp', :type => :class do + let :pre_condition do + 'include apache' + end + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_package("libapache2-mod-suphp") } + end + context "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_package("mod_suphp") } + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/worker_spec.rb b/3rdparty/modules/apache/spec/classes/mod/worker_spec.rb new file mode 100644 index 000000000..38a79aeb2 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/worker_spec.rb @@ -0,0 +1,186 @@ +require 'spec_helper' + +describe 'apache::mod::worker', :type => :class do + let :pre_condition do + 'class { "apache": mpm_module => false, }' + end + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.not_to contain_apache__mod('worker') } + it { is_expected.to contain_file("/etc/apache2/mods-available/worker.conf").with_ensure('file') } + it { is_expected.to contain_file("/etc/apache2/mods-enabled/worker.conf").with_ensure('link') } + + context "with Apache version < 2.4" do + let :params do + { + :apache_version => '2.2', + } + end + + it { is_expected.not_to contain_file("/etc/apache2/mods-available/worker.load") } + it { is_expected.not_to contain_file("/etc/apache2/mods-enabled/worker.load") } + + it { is_expected.to contain_package("apache2-mpm-worker") } + end + + context "with Apache version >= 2.4" do + let :params do + { + :apache_version => '2.4', + } + end + + it { is_expected.to contain_file("/etc/apache2/mods-available/worker.load").with({ + 'ensure' => 'file', + 'content' => "LoadModule mpm_worker_module /usr/lib/apache2/modules/mod_mpm_worker.so\n" + }) + } + it { is_expected.to contain_file("/etc/apache2/mods-enabled/worker.load").with_ensure('link') } + end + end + context "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.not_to contain_apache__mod('worker') } + it { is_expected.to contain_file("/etc/httpd/conf.d/worker.conf").with_ensure('file') } + + context "with Apache version < 2.4" do + let :params do + { + :apache_version => '2.2', + } + end + + it { is_expected.to contain_file_line("/etc/sysconfig/httpd worker enable").with({ + 'require' => 'Package[httpd]', + }) + } + end + + context "with Apache version >= 2.4" do + let :params do + { + :apache_version => '2.4', + } + end + + it { is_expected.not_to contain_apache__mod('event') } + + it { is_expected.to contain_file("/etc/httpd/conf.d/worker.load").with({ + 'ensure' => 'file', + 'content' => "LoadModule mpm_worker_module modules/mod_mpm_worker.so\n", + }) + } + end + end + context "on a FreeBSD OS" do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '9', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.not_to contain_apache__mod('worker') } + it { is_expected.to contain_file("/usr/local/etc/apache24/Modules/worker.conf").with_ensure('file') } + end + context "on a Gentoo OS" do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.not_to contain_apache__mod('worker') } + it { is_expected.to contain_file("/etc/apache2/modules.d/worker.conf").with_ensure('file') } + end + + # Template config doesn't vary by distro + context "on all distros" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystem => 'CentOS', + :operatingsystemrelease => '6', + :kernel => 'Linux', + :id => 'root', + :concat_basedir => '/dne', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + context 'defaults' do + it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^$/) } + it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+ServerLimit\s+25$/) } + it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+StartServers\s+2$/) } + it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+MaxClients\s+150$/) } + it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+MinSpareThreads\s+25$/) } + it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+MaxSpareThreads\s+75$/) } + it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+ThreadsPerChild\s+25$/) } + it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+MaxRequestsPerChild\s+0$/) } + it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+ThreadLimit\s+64$/) } + end + + context 'setting params' do + let :params do + { + :serverlimit => 10, + :startservers => 11, + :maxclients => 12, + :minsparethreads => 13, + :maxsparethreads => 14, + :threadsperchild => 15, + :maxrequestsperchild => 16, + :threadlimit => 17 + } + end + it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^$/) } + it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+ServerLimit\s+10$/) } + it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+StartServers\s+11$/) } + it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+MaxClients\s+12$/) } + it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+MinSpareThreads\s+13$/) } + it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+MaxSpareThreads\s+14$/) } + it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+ThreadsPerChild\s+15$/) } + it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+MaxRequestsPerChild\s+16$/) } + it { should contain_file('/etc/httpd/conf.d/worker.conf').with(:content => /^\s+ThreadLimit\s+17$/) } + end + end +end diff --git a/3rdparty/modules/apache/spec/classes/mod/wsgi_spec.rb b/3rdparty/modules/apache/spec/classes/mod/wsgi_spec.rb new file mode 100644 index 000000000..5fe313acf --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/mod/wsgi_spec.rb @@ -0,0 +1,147 @@ +require 'spec_helper' + +describe 'apache::mod::wsgi', :type => :class do + let :pre_condition do + 'include apache' + end + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_class('apache::mod::wsgi').with( + 'wsgi_socket_prefix' => nil + ) + } + it { is_expected.to contain_package("libapache2-mod-wsgi") } + end + context "on a RedHat OS" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_class('apache::mod::wsgi').with( + 'wsgi_socket_prefix' => '/var/run/wsgi' + ) + } + it { is_expected.to contain_package("mod_wsgi") } + + describe "with custom WSGISocketPrefix" do + let :params do + { :wsgi_socket_prefix => 'run/wsgi' } + end + it {is_expected.to contain_file('wsgi.conf').with_content(/^ WSGISocketPrefix run\/wsgi$/)} + end + describe "with custom WSGIPythonHome" do + let :params do + { :wsgi_python_home => '/path/to/virtenv' } + end + it {is_expected.to contain_file('wsgi.conf').with_content(/^ WSGIPythonHome "\/path\/to\/virtenv"$/)} + end + describe "with custom package_name and mod_path" do + let :params do + { + :package_name => 'mod_wsgi_package', + :mod_path => '/foo/bar/baz', + } + end + it { is_expected.to contain_apache__mod('wsgi').with({ + 'package' => 'mod_wsgi_package', + 'path' => '/foo/bar/baz', + }) + } + it { is_expected.to contain_package("mod_wsgi_package") } + it { is_expected.to contain_file('wsgi.load').with_content(%r"LoadModule wsgi_module /foo/bar/baz") } + end + describe "with custom mod_path not containing /" do + let :params do + { + :package_name => 'mod_wsgi_package', + :mod_path => 'wsgi_mod_name.so', + } + end + it { is_expected.to contain_apache__mod('wsgi').with({ + 'path' => 'modules/wsgi_mod_name.so', + 'package' => 'mod_wsgi_package', + }) + } + it { is_expected.to contain_file('wsgi.load').with_content(%r"LoadModule wsgi_module modules/wsgi_mod_name.so") } + + end + describe "with package_name but no mod_path" do + let :params do + { + :mod_path => '/foo/bar/baz', + } + end + it { expect { catalogue }.to raise_error Puppet::Error, /apache::mod::wsgi - both package_name and mod_path must be specified!/ } + end + describe "with mod_path but no package_name" do + let :params do + { + :package_name => '/foo/bar/baz', + } + end + it { expect { catalogue }.to raise_error Puppet::Error, /apache::mod::wsgi - both package_name and mod_path must be specified!/ } + end + end + context "on a FreeBSD OS" do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '9', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_class('apache::mod::wsgi').with( + 'wsgi_socket_prefix' => nil + ) + } + it { is_expected.to contain_package("www/mod_wsgi") } + end + context "on a Gentoo OS" do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_class('apache::mod::wsgi').with( + 'wsgi_socket_prefix' => nil + ) + } + it { is_expected.to contain_package("www-apache/mod_wsgi") } + end +end diff --git a/3rdparty/modules/apache/spec/classes/params_spec.rb b/3rdparty/modules/apache/spec/classes/params_spec.rb new file mode 100644 index 000000000..d02209497 --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/params_spec.rb @@ -0,0 +1,24 @@ +require 'spec_helper' + +describe 'apache::params', :type => :class do + context "On a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_apache__params } + + it "Should not contain any resources" do + should have_resource_count(0) + end + end +end diff --git a/3rdparty/modules/apache/spec/classes/service_spec.rb b/3rdparty/modules/apache/spec/classes/service_spec.rb new file mode 100644 index 000000000..4c851385c --- /dev/null +++ b/3rdparty/modules/apache/spec/classes/service_spec.rb @@ -0,0 +1,175 @@ +require 'spec_helper' + +describe 'apache::service', :type => :class do + let :pre_condition do + 'include apache::params' + end + context "on a Debian OS" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_service("httpd").with( + 'name' => 'apache2', + 'ensure' => 'running', + 'enable' => 'true' + ) + } + + context "with $service_name => 'foo'" do + let (:params) {{ :service_name => 'foo' }} + it { is_expected.to contain_service("httpd").with( + 'name' => 'foo' + ) + } + end + + context "with $service_enable => true" do + let (:params) {{ :service_enable => true }} + it { is_expected.to contain_service("httpd").with( + 'name' => 'apache2', + 'ensure' => 'running', + 'enable' => 'true' + ) + } + end + + context "with $service_enable => false" do + let (:params) {{ :service_enable => false }} + it { is_expected.to contain_service("httpd").with( + 'name' => 'apache2', + 'ensure' => 'running', + 'enable' => 'false' + ) + } + end + + context "$service_enable must be a bool" do + let (:params) {{ :service_enable => 'not-a-boolean' }} + + it 'should fail' do + expect { catalogue }.to raise_error(Puppet::Error, /is not a boolean/) + end + end + + context "$service_manage must be a bool" do + let (:params) {{ :service_manage => 'not-a-boolean' }} + + it 'should fail' do + expect { catalogue }.to raise_error(Puppet::Error, /is not a boolean/) + end + end + + context "with $service_ensure => 'running'" do + let (:params) {{ :service_ensure => 'running', }} + it { is_expected.to contain_service("httpd").with( + 'ensure' => 'running', + 'enable' => 'true' + ) + } + end + + context "with $service_ensure => 'stopped'" do + let (:params) {{ :service_ensure => 'stopped', }} + it { is_expected.to contain_service("httpd").with( + 'ensure' => 'stopped', + 'enable' => 'true' + ) + } + end + + context "with $service_ensure => 'UNDEF'" do + let (:params) {{ :service_ensure => 'UNDEF' }} + it { is_expected.to contain_service("httpd").without_ensure } + end + + context "with $service_restart unset" do + it { is_expected.to contain_service("httpd").without_restart } + end + + context "with $service_restart => '/usr/sbin/apachectl graceful'" do + let (:params) {{ :service_restart => '/usr/sbin/apachectl graceful' }} + it { is_expected.to contain_service("httpd").with( + 'restart' => '/usr/sbin/apachectl graceful' + ) + } + end + end + + + context "on a RedHat 5 OS, do not manage service" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '5', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + let(:params) do + { + 'service_ensure' => 'running', + 'service_name' => 'httpd', + 'service_manage' => false + } + end + it 'should not manage the httpd service' do + subject.should_not contain_service('httpd') + end + end + + context "on a FreeBSD 5 OS" do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '9', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { is_expected.to contain_service("httpd").with( + 'name' => 'apache24', + 'ensure' => 'running', + 'enable' => 'true' + ) + } + end + + context "on a Gentoo OS" do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + it { is_expected.to contain_service("httpd").with( + 'name' => 'apache2', + 'ensure' => 'running', + 'enable' => 'true' + ) + } + end +end diff --git a/3rdparty/modules/apache/spec/defines/balancermember_spec.rb b/3rdparty/modules/apache/spec/defines/balancermember_spec.rb new file mode 100644 index 000000000..0322d308e --- /dev/null +++ b/3rdparty/modules/apache/spec/defines/balancermember_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe 'apache::balancermember', :type => :define do + let :pre_condition do + 'include apache + apache::balancer {"balancer":} + apache::balancer {"balancer-external":} + apache::balancermember {"http://127.0.0.1:8080-external": url => "http://127.0.0.1:8080/", balancer_cluster => "balancer-external"} + ' + end + let :title do + 'http://127.0.0.1:8080/' + end + let :params do + { + :options => [], + :url => 'http://127.0.0.1:8080/', + :balancer_cluster => 'balancer-internal' + } + end + let :facts do + { + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => '6', + :lsbdistcodename => 'squeeze', + :id => 'root', + :concat_basedir => '/dne', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :kernel => 'Linux', + :is_pe => false, + } + end + describe "allows multiple balancermembers with the same url" do + it { should contain_concat__fragment('BalancerMember http://127.0.0.1:8080/') } + end +end diff --git a/3rdparty/modules/apache/spec/defines/custom_config_spec.rb b/3rdparty/modules/apache/spec/defines/custom_config_spec.rb new file mode 100644 index 000000000..a5efd15a2 --- /dev/null +++ b/3rdparty/modules/apache/spec/defines/custom_config_spec.rb @@ -0,0 +1,138 @@ +require 'spec_helper' + +describe 'apache::custom_config', :type => :define do + let :pre_condition do + 'class { "apache": }' + end + let :title do + 'rspec' + end + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + context 'defaults with content' do + let :params do + { + 'content' => '# Test', + } + end + it { is_expected.to contain_exec("service notify for rspec").with({ + 'refreshonly' => 'true', + 'subscribe' => 'File[apache_rspec]', + 'command' => '/usr/sbin/apachectl -t', + 'notify' => 'Class[Apache::Service]', + 'before' => 'Exec[remove rspec if invalid]', + }) + } + it { is_expected.to contain_exec("remove rspec if invalid").with({ + 'unless' => '/usr/sbin/apachectl -t', + 'subscribe' => 'File[apache_rspec]', + 'refreshonly' => 'true', + }) + } + it { is_expected.to contain_file("apache_rspec").with({ + 'ensure' => 'present', + 'content' => '# Test', + 'require' => 'Package[httpd]', + }) + } + end + context 'set everything with source' do + let :params do + { + 'confdir' => '/dne', + 'priority' => '30', + 'source' => 'puppet:///modules/apache/test', + 'verify_command' => '/bin/true', + } + end + it { is_expected.to contain_exec("service notify for rspec").with({ + 'command' => '/bin/true', + }) + } + it { is_expected.to contain_exec("remove rspec if invalid").with({ + 'command' => '/bin/rm /dne/30-rspec.conf', + 'unless' => '/bin/true', + }) + } + it { is_expected.to contain_file("apache_rspec").with({ + 'path' => '/dne/30-rspec.conf', + 'ensure' => 'present', + 'source' => 'puppet:///modules/apache/test', + 'require' => 'Package[httpd]', + }) + } + end + context 'verify_config => false' do + let :params do + { + 'content' => '# test', + 'verify_config' => false, + } + end + it { is_expected.to_not contain_exec('service notify for rspec') } + it { is_expected.to_not contain_exec('remove rspec if invalid') } + it { is_expected.to contain_file('apache_rspec').with({ + 'notify' => 'Class[Apache::Service]' + }) + } + end + context 'ensure => absent' do + let :params do + { + 'ensure' => 'absent' + } + end + it { is_expected.to_not contain_exec('service notify for rspec') } + it { is_expected.to_not contain_exec('remove rspec if invalid') } + it { is_expected.to contain_file('apache_rspec').with({ + 'ensure' => 'absent', + }) + } + end + describe 'validation' do + context 'both content and source' do + let :params do + { + 'content' => 'foo', + 'source' => 'bar', + } + end + it do + expect { + catalogue + }.to raise_error(Puppet::Error, /Only one of \$content and \$source can be specified\./) + end + end + context 'neither content nor source' do + it do + expect { + catalogue + }.to raise_error(Puppet::Error, /One of \$content and \$source must be specified\./) + end + end + context 'bad ensure' do + let :params do + { + 'content' => 'foo', + 'ensure' => 'foo', + } + end + it do + expect { + catalogue + }.to raise_error(Puppet::Error, /is not supported for ensure/) + end + end + end +end diff --git a/3rdparty/modules/apache/spec/defines/fastcgi_server_spec.rb b/3rdparty/modules/apache/spec/defines/fastcgi_server_spec.rb new file mode 100644 index 000000000..1a6d3199c --- /dev/null +++ b/3rdparty/modules/apache/spec/defines/fastcgi_server_spec.rb @@ -0,0 +1,133 @@ +require 'spec_helper' + +describe 'apache::fastcgi::server', :type => :define do + let :pre_condition do + 'include apache' + end + let :title do + 'www' + end + describe 'os-dependent items' do + context "on RedHat based systems" do + let :default_facts do + { + :osfamily => 'RedHat', + :operatingsystem => 'CentOS', + :operatingsystemrelease => '6', + :kernel => 'Linux', + :id => 'root', + :concat_basedir => '/dne', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + let :facts do default_facts end + it { should contain_class("apache") } + it { should contain_class("apache::mod::fastcgi") } + it { should contain_file("fastcgi-pool-#{title}.conf").with( + :ensure => 'present', + :path => "/etc/httpd/conf.d/fastcgi-pool-#{title}.conf" + ) } + end + context "on Debian based systems" do + let :default_facts do + { + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => '6', + :lsbdistcodename => 'squeeze', + :kernel => 'Linux', + :id => 'root', + :concat_basedir => '/dne', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + let :facts do default_facts end + it { should contain_class("apache") } + it { should contain_class("apache::mod::fastcgi") } + it { should contain_file("fastcgi-pool-#{title}.conf").with( + :ensure => 'present', + :path => "/etc/apache2/conf.d/fastcgi-pool-#{title}.conf" + ) } + end + context "on FreeBSD systems" do + let :default_facts do + { + :osfamily => 'FreeBSD', + :operatingsystem => 'FreeBSD', + :operatingsystemrelease => '9', + :kernel => 'FreeBSD', + :id => 'root', + :concat_basedir => '/dne', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + let :facts do default_facts end + it { should contain_class("apache") } + it { should contain_class("apache::mod::fastcgi") } + it { should contain_file("fastcgi-pool-#{title}.conf").with( + :ensure => 'present', + :path => "/usr/local/etc/apache24/Includes/fastcgi-pool-#{title}.conf" + ) } + end + context "on Gentoo systems" do + let :default_facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :kernel => 'Linux', + :id => 'root', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + let :facts do default_facts end + it { should contain_class("apache") } + it { should contain_class("apache::mod::fastcgi") } + it { should contain_file("fastcgi-pool-#{title}.conf").with( + :ensure => 'present', + :path => "/etc/apache2/conf.d/fastcgi-pool-#{title}.conf" + ) } + end + end + describe 'os-independent items' do + let :facts do + { + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => '6', + :lsbdistcodename => 'squeeze', + :kernel => 'Linux', + :id => 'root', + :concat_basedir => '/dne', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + describe ".conf content" do + let :params do + { + :host => '127.0.0.1:9001', + :timeout => 30, + :flush => true, + :faux_path => '/var/www/php-www.fcgi', + :fcgi_alias => '/php-www.fcgi', + :file_type => 'application/x-httpd-php' + } + end + let :expected do +'FastCGIExternalServer /var/www/php-www.fcgi -idle-timeout 30 -flush -host 127.0.0.1:9001 +Alias /php-www.fcgi /var/www/php-www.fcgi +Action application/x-httpd-php /php-www.fcgi +' + end + it do + should contain_file("fastcgi-pool-www.conf").with_content(expected) + end + end + end +end diff --git a/3rdparty/modules/apache/spec/defines/mod_spec.rb b/3rdparty/modules/apache/spec/defines/mod_spec.rb new file mode 100644 index 000000000..e4e984529 --- /dev/null +++ b/3rdparty/modules/apache/spec/defines/mod_spec.rb @@ -0,0 +1,152 @@ +require 'spec_helper' + +describe 'apache::mod', :type => :define do + let :pre_condition do + 'include apache' + end + context "on a RedHat osfamily" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + describe "for non-special modules" do + let :title do + 'spec_m' + end + it { is_expected.to contain_class("apache::params") } + it "should manage the module load file" do + is_expected.to contain_file('spec_m.load').with({ + :path => '/etc/httpd/conf.d/spec_m.load', + :content => "LoadModule spec_m_module modules/mod_spec_m.so\n", + :owner => 'root', + :group => 'root', + :mode => '0644', + } ) + end + end + + describe "with shibboleth module and package param passed" do + # name/title for the apache::mod define + let :title do + 'xsendfile' + end + # parameters + let(:params) { {:package => 'mod_xsendfile'} } + + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_package('mod_xsendfile') } + end + end + + context "on a Debian osfamily" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + describe "for non-special modules" do + let :title do + 'spec_m' + end + it { is_expected.to contain_class("apache::params") } + it "should manage the module load file" do + is_expected.to contain_file('spec_m.load').with({ + :path => '/etc/apache2/mods-available/spec_m.load', + :content => "LoadModule spec_m_module /usr/lib/apache2/modules/mod_spec_m.so\n", + :owner => 'root', + :group => 'root', + :mode => '0644', + } ) + end + it "should link the module load file" do + is_expected.to contain_file('spec_m.load symlink').with({ + :path => '/etc/apache2/mods-enabled/spec_m.load', + :target => '/etc/apache2/mods-available/spec_m.load', + :owner => 'root', + :group => 'root', + :mode => '0644', + } ) + end + end + end + + context "on a FreeBSD osfamily" do + let :facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '9', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + + describe "for non-special modules" do + let :title do + 'spec_m' + end + it { is_expected.to contain_class("apache::params") } + it "should manage the module load file" do + is_expected.to contain_file('spec_m.load').with({ + :path => '/usr/local/etc/apache24/Modules/spec_m.load', + :content => "LoadModule spec_m_module /usr/local/libexec/apache24/mod_spec_m.so\n", + :owner => 'root', + :group => 'wheel', + :mode => '0644', + } ) + end + end + end + + context "on a Gentoo osfamily" do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + + describe "for non-special modules" do + let :title do + 'spec_m' + end + it { is_expected.to contain_class("apache::params") } + it "should manage the module load file" do + is_expected.to contain_file('spec_m.load').with({ + :path => '/etc/apache2/modules.d/spec_m.load', + :content => "LoadModule spec_m_module /usr/lib/apache2/modules/mod_spec_m.so\n", + :owner => 'root', + :group => 'wheel', + :mode => '0644', + } ) + end + end + end +end diff --git a/3rdparty/modules/apache/spec/defines/modsec_link_spec.rb b/3rdparty/modules/apache/spec/defines/modsec_link_spec.rb new file mode 100644 index 000000000..a5b4c5390 --- /dev/null +++ b/3rdparty/modules/apache/spec/defines/modsec_link_spec.rb @@ -0,0 +1,53 @@ +require 'spec_helper' + +describe 'apache::security::rule_link', :type => :define do + let :pre_condition do + 'class { "apache": } + class { "apache::mod::security": activated_rules => [] } + ' + end + + let :title do + 'base_rules/modsecurity_35_bad_robots.data' + end + + context "on RedHat based systems" do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystem => 'CentOS', + :operatingsystemrelease => '7', + :kernel => 'Linux', + :id => 'root', + :concat_basedir => '/', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + it { should contain_file('modsecurity_35_bad_robots.data').with( + :path => '/etc/httpd/modsecurity.d/activated_rules/modsecurity_35_bad_robots.data', + :target => '/usr/lib/modsecurity.d/base_rules/modsecurity_35_bad_robots.data' + ) } + end + + context "on Debian based systems" do + let :facts do + { + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/', + :lsbdistcodename => 'squeeze', + :id => 'root', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :kernel => 'Linux', + :is_pe => false, + } + end + it { should contain_file('modsecurity_35_bad_robots.data').with( + :path => '/etc/modsecurity/activated_rules/modsecurity_35_bad_robots.data', + :target => '/usr/share/modsecurity-crs/base_rules/modsecurity_35_bad_robots.data' + ) } + end + +end diff --git a/3rdparty/modules/apache/spec/defines/vhost_spec.rb b/3rdparty/modules/apache/spec/defines/vhost_spec.rb new file mode 100644 index 000000000..47c1b1f45 --- /dev/null +++ b/3rdparty/modules/apache/spec/defines/vhost_spec.rb @@ -0,0 +1,810 @@ +require 'spec_helper' + +describe 'apache::vhost', :type => :define do + let :pre_condition do + 'class { "apache": default_vhost => false, default_mods => false, vhost_enable_dir => "/etc/apache2/sites-enabled"}' + end + let :title do + 'rspec.example.com' + end + let :default_params do + { + :docroot => '/rspec/docroot', + :port => '84', + } + end + describe 'os-dependent items' do + context "on RedHat based systems" do + let :default_facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + let :params do default_params end + let :facts do default_facts end + it { is_expected.to contain_class("apache") } + it { is_expected.to contain_class("apache::params") } + end + context "on Debian based systems" do + let :default_facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + let :params do default_params end + let :facts do default_facts end + it { is_expected.to contain_class("apache") } + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_file("25-rspec.example.com.conf").with( + :ensure => 'present', + :path => '/etc/apache2/sites-available/25-rspec.example.com.conf' + ) } + it { is_expected.to contain_file("25-rspec.example.com.conf symlink").with( + :ensure => 'link', + :path => '/etc/apache2/sites-enabled/25-rspec.example.com.conf', + :target => '/etc/apache2/sites-available/25-rspec.example.com.conf' + ) } + end + context "on FreeBSD systems" do + let :default_facts do + { + :osfamily => 'FreeBSD', + :operatingsystemrelease => '9', + :concat_basedir => '/dne', + :operatingsystem => 'FreeBSD', + :id => 'root', + :kernel => 'FreeBSD', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + let :params do default_params end + let :facts do default_facts end + it { is_expected.to contain_class("apache") } + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_file("25-rspec.example.com.conf").with( + :ensure => 'present', + :path => '/usr/local/etc/apache24/Vhosts/25-rspec.example.com.conf' + ) } + end + context "on Gentoo systems" do + let :default_facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => '3.16.1-gentoo', + :concat_basedir => '/dne', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/opt/bin', + :is_pe => false, + } + end + let :params do default_params end + let :facts do default_facts end + it { is_expected.to contain_class("apache") } + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_file("25-rspec.example.com.conf").with( + :ensure => 'present', + :path => '/etc/apache2/vhosts.d/25-rspec.example.com.conf' + ) } + end + end + describe 'os-independent items' do + let :facts do + { + :osfamily => 'Debian', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :lsbdistcodename => 'squeeze', + :operatingsystem => 'Debian', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + describe 'basic assumptions' do + let :params do default_params end + it { is_expected.to contain_class("apache") } + it { is_expected.to contain_class("apache::params") } + it { is_expected.to contain_apache__listen(params[:port]) } + it { is_expected.to contain_apache__namevirtualhost("*:#{params[:port]}") } + end + context 'set everything!' do + let :params do + { + 'docroot' => '/var/www/foo', + 'manage_docroot' => false, + 'virtual_docroot' => true, + 'port' => '8080', + 'ip' => '127.0.0.1', + 'ip_based' => true, + 'add_listen' => false, + 'docroot_owner' => 'user', + 'docroot_group' => 'wheel', + 'docroot_mode' => '0664', + 'serveradmin' => 'foo@localhost', + 'ssl' => true, + 'ssl_cert' => '/ssl/cert', + 'ssl_key' => '/ssl/key', + 'ssl_chain' => '/ssl/chain', + 'ssl_crl_path' => '/ssl/crl', + 'ssl_crl' => 'foo.crl', + 'ssl_certs_dir' => '/ssl/certs', + 'ssl_protocol' => 'SSLv2', + 'ssl_cipher' => 'HIGH', + 'ssl_honorcipherorder' => 'Off', + 'ssl_verify_client' => 'optional', + 'ssl_verify_depth' => '3', + 'ssl_options' => '+ExportCertData', + 'ssl_proxyengine' => true, + 'priority' => '30', + 'default_vhost' => true, + 'servername' => 'example.com', + 'serveraliases' => ['test-example.com'], + 'options' => ['MultiView'], + 'override' => ['All'], + 'directoryindex' => 'index.html', + 'vhost_name' => 'test', + 'logroot' => '/var/www/logs', + 'logroot_ensure' => 'directory', + 'logroot_mode' => '0600', + 'log_level' => 'crit', + 'access_log' => false, + 'access_log_file' => 'httpd_access_log', + 'access_log_syslog' => true, + 'access_log_format' => '%h %l %u %t \"%r\" %>s %b', + 'access_log_env_var' => '', + 'aliases' => '/image', + 'directories' => [ + { + 'path' => '/var/www/files', + 'provider' => 'files', + 'require' => [ 'valid-user', 'all denied', ], + }, + { + 'path' => '/var/www/files', + 'provider' => 'files', + 'require' => 'all granted', + }, + { 'path' => '/var/www/files/indexed_directory', + 'directoryindex' => 'disabled', + 'options' => ['Indexes','FollowSymLinks','MultiViews'], + 'index_options' => ['FancyIndexing'], + 'index_style_sheet' => '/styles/style.css', + }, + ], + 'error_log' => false, + 'error_log_file' => 'httpd_error_log', + 'error_log_syslog' => true, + 'error_documents' => 'true', + 'fallbackresource' => '/index.php', + 'scriptalias' => '/usr/lib/cgi-bin', + 'scriptaliases' => [ + { + 'alias' => '/myscript', + 'path' => '/usr/share/myscript', + }, + { + 'aliasmatch' => '^/foo(.*)', + 'path' => '/usr/share/fooscripts$1', + }, + ], + 'proxy_dest' => '/', + 'proxy_pass' => [ + { + 'path' => '/a', + 'url' => 'http://backend-a/', + 'keywords' => ['noquery', 'interpolate'], + 'params' => { + 'retry' => '0', + 'timeout' => '5' + }, + 'setenv' => ['proxy-nokeepalive 1','force-proxy-request-1.0 1'], + } + ], + 'proxy_pass_match' => [ + { + 'path' => '/a', + 'url' => 'http://backend-a/', + 'keywords' => ['noquery', 'interpolate'], + 'params' => { + 'retry' => '0', + 'timeout' => '5' + }, + 'setenv' => ['proxy-nokeepalive 1','force-proxy-request-1.0 1'], + } + ], + 'suphp_addhandler' => 'foo', + 'suphp_engine' => 'on', + 'suphp_configpath' => '/var/www/html', + 'php_admin_flags' => ['foo', 'bar'], + 'php_admin_values' => ['true', 'false'], + 'no_proxy_uris' => '/foo', + 'no_proxy_uris_match' => '/foomatch', + 'proxy_preserve_host' => true, + 'proxy_error_override' => true, + 'redirect_source' => '/bar', + 'redirect_dest' => '/', + 'redirect_status' => 'temp', + 'redirectmatch_status' => ['404'], + 'redirectmatch_regexp' => ['\.git$'], + 'redirectmatch_dest' => ['http://www.example.com'], + 'rack_base_uris' => ['/rackapp1'], + 'headers' => 'Set X-Robots-Tag "noindex, noarchive, nosnippet"', + 'request_headers' => ['append MirrorID "mirror 12"'], + 'rewrites' => [ + { + 'rewrite_rule' => ['^index\.html$ welcome.html'] + } + ], + 'rewrite_base' => '/', + 'rewrite_rule' => '^index\.html$ welcome.html', + 'rewrite_cond' => '%{HTTP_USER_AGENT} ^MSIE', + 'setenv' => ['FOO=/bin/true'], + 'setenvif' => 'Request_URI "\.gif$" object_is_image=gif', + 'block' => 'scm', + 'wsgi_application_group' => '%{GLOBAL}', + 'wsgi_daemon_process' => 'wsgi', + 'wsgi_daemon_process_options' => { + 'processes' => '2', + 'threads' => '15', + 'display-name' => '%{GROUP}', + }, + 'wsgi_import_script' => '/var/www/demo.wsgi', + 'wsgi_import_script_options' => { + 'process-group' => 'wsgi', + 'application-group' => '%{GLOBAL}' + }, + 'wsgi_process_group' => 'wsgi', + 'wsgi_script_aliases' => { + '/' => '/var/www/demo.wsgi' + }, + 'wsgi_pass_authorization' => 'On', + 'custom_fragment' => '#custom string', + 'itk' => { + 'user' => 'someuser', + 'group' => 'somegroup' + }, + 'wsgi_chunked_request' => 'On', + 'action' => 'foo', + 'fastcgi_server' => 'localhost', + 'fastcgi_socket' => '/tmp/fastcgi.socket', + 'fastcgi_dir' => '/tmp', + 'additional_includes' => '/custom/path/includes', + 'apache_version' => '2.4', + 'suexec_user_group' => 'root root', + 'allow_encoded_slashes' => 'nodecode', + 'passenger_app_root' => '/usr/share/myapp', + 'passenger_app_env' => 'test', + 'passenger_ruby' => '/usr/bin/ruby1.9.1', + 'passenger_min_instances' => '1', + 'passenger_start_timeout' => '600', + 'passenger_pre_start' => 'http://localhost/myapp', + 'add_default_charset' => 'UTF-8', + } + end + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '7', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :kernelversion => '3.6.2', + :is_pe => false, + } + end + + it { is_expected.to compile } + it { is_expected.to_not contain_file('/var/www/foo') } + it { is_expected.to contain_class('apache::mod::ssl') } + it { is_expected.to contain_file('ssl.conf').with( + :content => /^\s+SSLHonorCipherOrder On$/ ) } + it { is_expected.to contain_file('ssl.conf').with( + :content => /^\s+SSLPassPhraseDialog builtin$/ ) } + it { is_expected.to contain_file('ssl.conf').with( + :content => /^\s+SSLSessionCacheTimeout 300$/ ) } + it { is_expected.to contain_class('apache::mod::mime') } + it { is_expected.to contain_class('apache::mod::vhost_alias') } + it { is_expected.to contain_class('apache::mod::wsgi') } + it { is_expected.to contain_class('apache::mod::suexec') } + it { is_expected.to contain_class('apache::mod::passenger') } + it { is_expected.to contain_file('/var/www/logs').with({ + 'ensure' => 'directory', + 'mode' => '0600', + }) + } + it { is_expected.to contain_class('apache::mod::rewrite') } + it { is_expected.to contain_class('apache::mod::alias') } + it { is_expected.to contain_class('apache::mod::proxy') } + it { is_expected.to contain_class('apache::mod::proxy_http') } + it { is_expected.to contain_class('apache::mod::passenger') } + it { is_expected.to contain_class('apache::mod::passenger') } + it { is_expected.to contain_class('apache::mod::fastcgi') } + it { is_expected.to contain_class('apache::mod::headers') } + it { is_expected.to contain_class('apache::mod::setenvif') } + it { is_expected.to contain_concat('30-rspec.example.com.conf').with({ + 'owner' => 'root', + 'mode' => '0644', + 'require' => 'Package[httpd]', + 'notify' => 'Class[Apache::Service]', + }) + } + it { is_expected.to contain_file('30-rspec.example.com.conf symlink').with({ + 'ensure' => 'link', + 'path' => '/etc/apache2/sites-enabled/30-rspec.example.com.conf', + }) + } + it { is_expected.to contain_concat__fragment('rspec.example.com-apache-header') } + it { is_expected.to contain_concat__fragment('rspec.example.com-docroot') } + it { is_expected.to contain_concat__fragment('rspec.example.com-aliases') } + it { is_expected.to contain_concat__fragment('rspec.example.com-itk') } + it { is_expected.to contain_concat__fragment('rspec.example.com-fallbackresource') } + it { is_expected.to contain_concat__fragment('rspec.example.com-directories') } + it { is_expected.to contain_concat__fragment('rspec.example.com-directories').with( + :content => /^\s+Require valid-user$/ ) } + it { is_expected.to contain_concat__fragment('rspec.example.com-directories').with( + :content => /^\s+Require all denied$/ ) } + it { is_expected.to contain_concat__fragment('rspec.example.com-directories').with( + :content => /^\s+Require all granted$/ ) } + it { is_expected.to contain_concat__fragment('rspec.example.com-directories').with( + :content => /^\s+Options\sIndexes\sFollowSymLinks\sMultiViews$/ ) } + it { is_expected.to contain_concat__fragment('rspec.example.com-directories').with( + :content => /^\s+IndexOptions\sFancyIndexing$/ ) } + it { is_expected.to contain_concat__fragment('rspec.example.com-directories').with( + :content => /^\s+IndexStyleSheet\s'\/styles\/style\.css'$/ ) } + it { is_expected.to contain_concat__fragment('rspec.example.com-directories').with( + :content => /^\s+DirectoryIndex\sdisabled$/ ) } + it { is_expected.to contain_concat__fragment('rspec.example.com-additional_includes') } + it { is_expected.to contain_concat__fragment('rspec.example.com-logging') } + it { is_expected.to contain_concat__fragment('rspec.example.com-serversignature') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-access_log') } + it { is_expected.to contain_concat__fragment('rspec.example.com-action') } + it { is_expected.to contain_concat__fragment('rspec.example.com-block') } + it { is_expected.to contain_concat__fragment('rspec.example.com-error_document') } + it { is_expected.to contain_concat__fragment('rspec.example.com-proxy').with_content( + /retry=0/) } + it { is_expected.to contain_concat__fragment('rspec.example.com-proxy').with_content( + /timeout=5/) } + it { is_expected.to contain_concat__fragment('rspec.example.com-proxy').with_content( + /SetEnv force-proxy-request-1.0 1/) } + it { is_expected.to contain_concat__fragment('rspec.example.com-proxy').with_content( + /SetEnv proxy-nokeepalive 1/) } + it { is_expected.to contain_concat__fragment('rspec.example.com-proxy').with_content( + /noquery interpolate/) } + it { is_expected.to contain_concat__fragment('rspec.example.com-rack') } + it { is_expected.to contain_concat__fragment('rspec.example.com-redirect') } + it { is_expected.to contain_concat__fragment('rspec.example.com-rewrite') } + it { is_expected.to contain_concat__fragment('rspec.example.com-scriptalias') } + it { is_expected.to contain_concat__fragment('rspec.example.com-serveralias') } + it { is_expected.to contain_concat__fragment('rspec.example.com-setenv') } + it { is_expected.to contain_concat__fragment('rspec.example.com-ssl') } + it { is_expected.to contain_concat__fragment('rspec.example.com-suphp') } + it { is_expected.to contain_concat__fragment('rspec.example.com-php_admin') } + it { is_expected.to contain_concat__fragment('rspec.example.com-header') } + it { is_expected.to contain_concat__fragment('rspec.example.com-requestheader') } + it { is_expected.to contain_concat__fragment('rspec.example.com-wsgi') } + it { is_expected.to contain_concat__fragment('rspec.example.com-custom_fragment') } + it { is_expected.to contain_concat__fragment('rspec.example.com-fastcgi') } + it { is_expected.to contain_concat__fragment('rspec.example.com-suexec') } + it { is_expected.to contain_concat__fragment('rspec.example.com-allow_encoded_slashes') } + it { is_expected.to contain_concat__fragment('rspec.example.com-passenger') } + it { is_expected.to contain_concat__fragment('rspec.example.com-charsets') } + it { is_expected.to contain_concat__fragment('rspec.example.com-file_footer') } + end + context 'not everything can be set together...' do + let :params do + { + 'access_log_pipe' => '/dev/null', + 'error_log_pipe' => '/dev/null', + 'docroot' => '/var/www/foo', + 'ensure' => 'absent', + 'manage_docroot' => true, + 'logroot' => '/tmp/logroot', + 'logroot_ensure' => 'absent', + 'directories' => [ + { + 'path' => '/var/www/files', + 'provider' => 'files', + 'allow' => [ 'from 127.0.0.1', 'from 127.0.0.2', ], + 'deny' => [ 'from 127.0.0.3', 'from 127.0.0.4', ], + 'satisfy' => 'any', + }, + { + 'path' => '/var/www/foo', + 'provider' => 'files', + 'allow' => 'from 127.0.0.5', + 'deny' => 'from all', + 'order' => 'deny,allow', + }, + ], + + } + end + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :kernelversion => '3.6.2', + :is_pe => false, + } + end + + it { is_expected.to compile } + it { is_expected.to_not contain_class('apache::mod::ssl') } + it { is_expected.to_not contain_class('apache::mod::mime') } + it { is_expected.to_not contain_class('apache::mod::vhost_alias') } + it { is_expected.to_not contain_class('apache::mod::wsgi') } + it { is_expected.to_not contain_class('apache::mod::passenger') } + it { is_expected.to_not contain_class('apache::mod::suexec') } + it { is_expected.to_not contain_class('apache::mod::rewrite') } + it { is_expected.to_not contain_class('apache::mod::alias') } + it { is_expected.to_not contain_class('apache::mod::proxy') } + it { is_expected.to_not contain_class('apache::mod::proxy_http') } + it { is_expected.to_not contain_class('apache::mod::passenger') } + it { is_expected.to_not contain_class('apache::mod::headers') } + it { is_expected.to contain_file('/var/www/foo') } + it { is_expected.to contain_file('/tmp/logroot').with({ + 'ensure' => 'absent', + }) + } + it { is_expected.to contain_concat('25-rspec.example.com.conf').with({ + 'ensure' => 'absent', + }) + } + it { is_expected.to contain_concat__fragment('rspec.example.com-apache-header') } + it { is_expected.to contain_concat__fragment('rspec.example.com-docroot') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-aliases') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-itk') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-fallbackresource') } + it { is_expected.to contain_concat__fragment('rspec.example.com-directories') } + it { is_expected.to contain_concat__fragment('rspec.example.com-directories').with( + :content => /^\s+Allow from 127\.0\.0\.1$/ ) } + it { is_expected.to contain_concat__fragment('rspec.example.com-directories').with( + :content => /^\s+Allow from 127\.0\.0\.2$/ ) } + it { is_expected.to contain_concat__fragment('rspec.example.com-directories').with( + :content => /^\s+Allow from 127\.0\.0\.5$/ ) } + it { is_expected.to contain_concat__fragment('rspec.example.com-directories').with( + :content => /^\s+Deny from 127\.0\.0\.3$/ ) } + it { is_expected.to contain_concat__fragment('rspec.example.com-directories').with( + :content => /^\s+Deny from 127\.0\.0\.4$/ ) } + it { is_expected.to contain_concat__fragment('rspec.example.com-directories').with( + :content => /^\s+Deny from all$/ ) } + it { is_expected.to contain_concat__fragment('rspec.example.com-directories').with( + :content => /^\s+Satisfy any$/ ) } + it { is_expected.to contain_concat__fragment('rspec.example.com-directories').with( + :content => /^\s+Order deny,allow$/ ) } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-additional_includes') } + it { is_expected.to contain_concat__fragment('rspec.example.com-logging') } + it { is_expected.to contain_concat__fragment('rspec.example.com-serversignature') } + it { is_expected.to contain_concat__fragment('rspec.example.com-access_log') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-action') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-block') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-error_document') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-proxy') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-rack') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-redirect') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-rewrite') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-scriptalias') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-serveralias') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-setenv') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-ssl') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-suphp') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-php_admin') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-header') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-requestheader') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-wsgi') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-custom_fragment') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-fastcgi') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-suexec') } + it { is_expected.to_not contain_concat__fragment('rspec.example.com-charsets') } + it { is_expected.to contain_concat__fragment('rspec.example.com-file_footer') } + end + end + describe 'access logs' do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystemrelease => '6', + :concat_basedir => '/dne', + :operatingsystem => 'RedHat', + :id => 'root', + :kernel => 'Linux', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :is_pe => false, + } + end + context 'single log file' do + let(:params) do + { + 'docroot' => '/rspec/docroot', + 'access_log_file' => 'my_log_file', + } + end + it { is_expected.to contain_concat__fragment('rspec.example.com-access_log').with( + :content => /^\s+CustomLog.*my_log_file" combined\s*$/ + )} + end + context 'single log file with environment' do + let(:params) do + { + 'docroot' => '/rspec/docroot', + 'access_log_file' => 'my_log_file', + 'access_log_env_var' => 'prod' + } + end + it { is_expected.to contain_concat__fragment('rspec.example.com-access_log').with( + :content => /^\s+CustomLog.*my_log_file" combined\s+env=prod$/ + )} + end + context 'multiple log files' do + let(:params) do + { + 'docroot' => '/rspec/docroot', + 'access_logs' => [ + { 'file' => '/tmp/log1', 'env' => 'dev' }, + { 'file' => 'log2' }, + { 'syslog' => 'syslog', 'format' => '%h %l' } + ], + } + end + it { is_expected.to contain_concat__fragment('rspec.example.com-access_log').with( + :content => /^\s+CustomLog "\/tmp\/log1"\s+combined\s+env=dev$/ + )} + it { is_expected.to contain_concat__fragment('rspec.example.com-access_log').with( + :content => /^\s+CustomLog "\/var\/log\/httpd\/log2"\s+combined\s*$/ + )} + it { is_expected.to contain_concat__fragment('rspec.example.com-access_log').with( + :content => /^\s+CustomLog "syslog" "%h %l"\s*$/ + )} + end + end # access logs + describe 'validation' do + context 'bad ensure' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'ensure' => 'bogus', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'bad suphp_engine' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'suphp_engine' => 'bogus', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'bad ip_based' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'ip_based' => 'bogus', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'bad access_log' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'access_log' => 'bogus', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'bad error_log' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'error_log' => 'bogus', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'bad_ssl' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'ssl' => 'bogus', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'bad default_vhost' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'default_vhost' => 'bogus', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'bad ssl_proxyengine' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'ssl_proxyengine' => 'bogus', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'bad rewrites' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'rewrites' => 'bogus', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'bad rewrites 2' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'rewrites' => ['bogus'], + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'bad suexec_user_group' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'suexec_user_group' => 'bogus', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'bad wsgi_script_alias' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'wsgi_script_alias' => 'bogus', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'bad wsgi_daemon_process_options' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'wsgi_daemon_process_options' => 'bogus', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'bad wsgi_import_script_alias' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'wsgi_import_script_alias' => 'bogus', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'bad itk' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'itk' => 'bogus', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'bad logroot_ensure' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'log_level' => 'bogus', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'bad log_level' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'log_level' => 'bogus', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'access_log_file and access_log_pipe' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'access_log_file' => 'bogus', + 'access_log_pipe' => 'bogus', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'error_log_file and error_log_pipe' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'error_log_file' => 'bogus', + 'error_log_pipe' => 'bogus', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'bad fallbackresource' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'fallbackresource' => 'bogus', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'bad custom_fragment' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'custom_fragment' => true, + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + context 'bad access_logs' do + let :params do + { + 'docroot' => '/rspec/docroot', + 'access_logs' => '/var/log/somewhere', + } + end + let :facts do default_facts end + it { expect { is_expected.to compile }.to raise_error } + end + end +end diff --git a/3rdparty/modules/apache/spec/spec.opts b/3rdparty/modules/apache/spec/spec.opts new file mode 100644 index 000000000..91cd6427e --- /dev/null +++ b/3rdparty/modules/apache/spec/spec.opts @@ -0,0 +1,6 @@ +--format +s +--colour +--loadby +mtime +--backtrace diff --git a/3rdparty/modules/apache/spec/spec_helper.rb b/3rdparty/modules/apache/spec/spec_helper.rb new file mode 100644 index 000000000..65379ee38 --- /dev/null +++ b/3rdparty/modules/apache/spec/spec_helper.rb @@ -0,0 +1,25 @@ +require 'puppetlabs_spec_helper/module_spec_helper' + +RSpec.configure do |c| + c.treat_symbols_as_metadata_keys_with_true_values = true + + c.before :each do + # Ensure that we don't accidentally cache facts and environment + # between test cases. + Facter::Util::Loader.any_instance.stubs(:load_all) + Facter.clear + Facter.clear_messages + + # Store any environment variables away to be restored later + @old_env = {} + ENV.each_key {|k| @old_env[k] = ENV[k]} + + if ENV['STRICT_VARIABLES'] == 'yes' + Puppet.settings[:strict_variables]=true + end + end +end + +shared_examples :compile, :compile => true do + it { should compile.with_all_deps } +end diff --git a/3rdparty/modules/apache/spec/spec_helper_acceptance.rb b/3rdparty/modules/apache/spec/spec_helper_acceptance.rb new file mode 100644 index 000000000..599cc5663 --- /dev/null +++ b/3rdparty/modules/apache/spec/spec_helper_acceptance.rb @@ -0,0 +1,54 @@ +require 'beaker-rspec/spec_helper' +require 'beaker-rspec/helpers/serverspec' + + +unless ENV['RS_PROVISION'] == 'no' + # This will install the latest available package on el and deb based + # systems fail on windows and osx, and install via gem on other *nixes + foss_opts = { :default_action => 'gem_install' } + + if default.is_pe?; then install_pe; else install_puppet( foss_opts ); end + + hosts.each do |host| + if host['platform'] =~ /debian/ + on host, 'echo \'export PATH=/var/lib/gems/1.8/bin/:${PATH}\' >> ~/.bashrc' + end + + on host, "mkdir -p #{host['distmoduledir']}" + end +end + +UNSUPPORTED_PLATFORMS = ['Suse','windows','AIX','Solaris'] + +RSpec.configure do |c| + # Project root + proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) + + # Readable test descriptions + c.formatter = :documentation + + # Configure all nodes in nodeset + c.before :suite do + # Install module and dependencies + hosts.each do |host| + copy_module_to(host, :source => proj_root, :module_name => 'apache') + # Required for mod_passenger tests. + if fact('osfamily') == 'RedHat' + on host, puppet('module','install','stahnma/epel'), { :acceptable_exit_codes => [0,1] } + end + # Required for manifest to make mod_pagespeed repository available + if fact('osfamily') == 'Debian' + on host, puppet('module','install','puppetlabs-apt', '--version 1.8.0', '--force'), { :acceptable_exit_codes => [0,1] } + end + on host, puppet('module','install','puppetlabs-stdlib'), { :acceptable_exit_codes => [0,1] } + on host, puppet('module','install','puppetlabs-concat', '--version 1.1.1', '--force'), { :acceptable_exit_codes => [0,1] } + + # Make sure selinux is disabled before each test or apache won't work. + if ! UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) + on host, puppet('apply', '-e', + %{"exec { 'setenforce 0': path => '/bin:/sbin:/usr/bin:/usr/sbin', onlyif => 'which setenforce && getenforce | grep Enforcing', }"}), + { :acceptable_exit_codes => [0] } + end + end + end +end diff --git a/3rdparty/modules/apache/spec/unit/provider/a2mod/gentoo_spec.rb b/3rdparty/modules/apache/spec/unit/provider/a2mod/gentoo_spec.rb new file mode 100644 index 000000000..78f902bf7 --- /dev/null +++ b/3rdparty/modules/apache/spec/unit/provider/a2mod/gentoo_spec.rb @@ -0,0 +1,184 @@ +#!/usr/bin/env rspec + +require 'spec_helper' + +provider_class = Puppet::Type.type(:a2mod).provider(:gentoo) + +describe provider_class do + before :each do + provider_class.clear + end + + [:conf_file, :instances, :modules, :initvars, :conf_file, :clear].each do |method| + it "should respond to the class method #{method}" do + expect(provider_class).to respond_to(method) + end + end + + describe "when fetching modules" do + before do + @filetype = mock() + end + + it "should return a sorted array of the defined parameters" do + @filetype.expects(:read).returns(%Q{APACHE2_OPTS="-D FOO -D BAR -D BAZ"\n}) + provider_class.expects(:filetype).returns(@filetype) + + expect(provider_class.modules).to eq(%w{bar baz foo}) + end + + it "should cache the module list" do + @filetype.expects(:read).once.returns(%Q{APACHE2_OPTS="-D FOO -D BAR -D BAZ"\n}) + provider_class.expects(:filetype).once.returns(@filetype) + + 2.times { expect(provider_class.modules).to eq(%w{bar baz foo}) } + end + + it "should normalize parameters" do + @filetype.expects(:read).returns(%Q{APACHE2_OPTS="-D FOO -D BAR -D BAR"\n}) + provider_class.expects(:filetype).returns(@filetype) + + expect(provider_class.modules).to eq(%w{bar foo}) + end + end + + describe "when prefetching" do + it "should match providers to resources" do + provider = mock("ssl_provider", :name => "ssl") + resource = mock("ssl_resource") + resource.expects(:provider=).with(provider) + + provider_class.expects(:instances).returns([provider]) + provider_class.prefetch("ssl" => resource) + end + end + + describe "when flushing" do + before :each do + @filetype = mock() + @filetype.stubs(:backup) + provider_class.expects(:filetype).at_least_once.returns(@filetype) + + @info = mock() + @info.stubs(:[]).with(:name).returns("info") + @info.stubs(:provider=) + + @mpm = mock() + @mpm.stubs(:[]).with(:name).returns("mpm") + @mpm.stubs(:provider=) + + @ssl = mock() + @ssl.stubs(:[]).with(:name).returns("ssl") + @ssl.stubs(:provider=) + end + + it "should add modules whose ensure is present" do + @filetype.expects(:read).at_least_once.returns(%Q{APACHE2_OPTS=""}) + @filetype.expects(:write).with(%Q{APACHE2_OPTS="-D INFO"}) + + @info.stubs(:should).with(:ensure).returns(:present) + provider_class.prefetch("info" => @info) + + provider_class.flush + end + + it "should remove modules whose ensure is present" do + @filetype.expects(:read).at_least_once.returns(%Q{APACHE2_OPTS="-D INFO"}) + @filetype.expects(:write).with(%Q{APACHE2_OPTS=""}) + + @info.stubs(:should).with(:ensure).returns(:absent) + @info.stubs(:provider=) + provider_class.prefetch("info" => @info) + + provider_class.flush + end + + it "should not modify providers without resources" do + @filetype.expects(:read).at_least_once.returns(%Q{APACHE2_OPTS="-D INFO -D MPM"}) + @filetype.expects(:write).with(%Q{APACHE2_OPTS="-D MPM -D SSL"}) + + @info.stubs(:should).with(:ensure).returns(:absent) + provider_class.prefetch("info" => @info) + + @ssl.stubs(:should).with(:ensure).returns(:present) + provider_class.prefetch("ssl" => @ssl) + + provider_class.flush + end + + it "should write the modules in sorted order" do + @filetype.expects(:read).at_least_once.returns(%Q{APACHE2_OPTS=""}) + @filetype.expects(:write).with(%Q{APACHE2_OPTS="-D INFO -D MPM -D SSL"}) + + @mpm.stubs(:should).with(:ensure).returns(:present) + provider_class.prefetch("mpm" => @mpm) + @info.stubs(:should).with(:ensure).returns(:present) + provider_class.prefetch("info" => @info) + @ssl.stubs(:should).with(:ensure).returns(:present) + provider_class.prefetch("ssl" => @ssl) + + provider_class.flush + end + + it "should write the records back once" do + @filetype.expects(:read).at_least_once.returns(%Q{APACHE2_OPTS=""}) + @filetype.expects(:write).once.with(%Q{APACHE2_OPTS="-D INFO -D SSL"}) + + @info.stubs(:should).with(:ensure).returns(:present) + provider_class.prefetch("info" => @info) + + @ssl.stubs(:should).with(:ensure).returns(:present) + provider_class.prefetch("ssl" => @ssl) + + provider_class.flush + end + + it "should only modify the line containing APACHE2_OPTS" do + @filetype.expects(:read).at_least_once.returns(%Q{# Comment\nAPACHE2_OPTS=""\n# Another comment}) + @filetype.expects(:write).once.with(%Q{# Comment\nAPACHE2_OPTS="-D INFO"\n# Another comment}) + + @info.stubs(:should).with(:ensure).returns(:present) + provider_class.prefetch("info" => @info) + provider_class.flush + end + + it "should restore any arbitrary arguments" do + @filetype.expects(:read).at_least_once.returns(%Q{APACHE2_OPTS="-Y -D MPM -X"}) + @filetype.expects(:write).once.with(%Q{APACHE2_OPTS="-Y -X -D INFO -D MPM"}) + + @info.stubs(:should).with(:ensure).returns(:present) + provider_class.prefetch("info" => @info) + provider_class.flush + end + + it "should backup the file once if changes were made" do + @filetype.expects(:read).at_least_once.returns(%Q{APACHE2_OPTS=""}) + @filetype.expects(:write).once.with(%Q{APACHE2_OPTS="-D INFO -D SSL"}) + + @info.stubs(:should).with(:ensure).returns(:present) + provider_class.prefetch("info" => @info) + + @ssl.stubs(:should).with(:ensure).returns(:present) + provider_class.prefetch("ssl" => @ssl) + + @filetype.unstub(:backup) + @filetype.expects(:backup) + provider_class.flush + end + + it "should not write the file or run backups if no changes were made" do + @filetype.expects(:read).at_least_once.returns(%Q{APACHE2_OPTS="-X -D INFO -D SSL -Y"}) + @filetype.expects(:write).never + + @info.stubs(:should).with(:ensure).returns(:present) + provider_class.prefetch("info" => @info) + + @ssl.stubs(:should).with(:ensure).returns(:present) + provider_class.prefetch("ssl" => @ssl) + + @filetype.unstub(:backup) + @filetype.expects(:backup).never + provider_class.flush + end + end +end diff --git a/3rdparty/modules/apache/spec/unit/puppet/parser/functions/bool2httpd_spec.rb b/3rdparty/modules/apache/spec/unit/puppet/parser/functions/bool2httpd_spec.rb new file mode 100644 index 000000000..b0bcbb622 --- /dev/null +++ b/3rdparty/modules/apache/spec/unit/puppet/parser/functions/bool2httpd_spec.rb @@ -0,0 +1,54 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the bool2httpd function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + expect(Puppet::Parser::Functions.function("bool2httpd")).to eq("function_bool2httpd") + end + + it "should raise a ParseError if there is less than 1 arguments" do + expect { scope.function_bool2httpd([]) }.to( raise_error(Puppet::ParseError)) + end + + it "should convert true to 'On'" do + result = scope.function_bool2httpd([true]) + expect(result).to(eq('On')) + end + + it "should convert true to a string" do + result = scope.function_bool2httpd([true]) + expect(result.class).to(eq(String)) + end + + it "should convert false to 'Off'" do + result = scope.function_bool2httpd([false]) + expect(result).to(eq('Off')) + end + + it "should convert false to a string" do + result = scope.function_bool2httpd([false]) + expect(result.class).to(eq(String)) + end + + it "should accept (and return) any string" do + result = scope.function_bool2httpd(["mail"]) + expect(result).to(eq('mail')) + end + + it "should accept a nil value (and return Off)" do + result = scope.function_bool2httpd([nil]) + expect(result).to(eq('Off')) + end + + it "should accept an undef value (and return 'Off')" do + result = scope.function_bool2httpd([:undef]) + expect(result).to(eq('Off')) + end + + it "should return a default value on non-matches" do + result = scope.function_bool2httpd(['foo']) + expect(result).to(eq('foo')) + end +end diff --git a/3rdparty/modules/apache/spec/unit/puppet/parser/functions/validate_apache_log_level.rb b/3rdparty/modules/apache/spec/unit/puppet/parser/functions/validate_apache_log_level.rb new file mode 100644 index 000000000..dfef66eea --- /dev/null +++ b/3rdparty/modules/apache/spec/unit/puppet/parser/functions/validate_apache_log_level.rb @@ -0,0 +1,39 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the validate_apache_log_level function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + expect(Puppet::Parser::Functions.function("validate_apache_log_level")).to eq("function_validate_apache_log_level") + end + + it "should raise a ParseError if there is less than 1 arguments" do + expect { scope.function_validate_apache_log_level([]) }.to( raise_error(Puppet::ParseError) ) + end + + it "should raise a ParseError when given garbage" do + expect { scope.function_validate_apache_log_level(['garbage']) }.to( raise_error(Puppet::ParseError) ) + end + + it "should not raise a ParseError when given a plain log level" do + expect { scope.function_validate_apache_log_level(['info']) }.to_not raise_error + end + + it "should not raise a ParseError when given a log level and module log level" do + expect { scope.function_validate_apache_log_level(['warn ssl:info']) }.to_not raise_error + end + + it "should not raise a ParseError when given a log level and module log level" do + expect { scope.function_validate_apache_log_level(['warn mod_ssl.c:info']) }.to_not raise_error + end + + it "should not raise a ParseError when given a log level and module log level" do + expect { scope.function_validate_apache_log_level(['warn ssl_module:info']) }.to_not raise_error + end + + it "should not raise a ParseError when given a trace level" do + expect { scope.function_validate_apache_log_level(['trace4']) }.to_not raise_error + end + +end diff --git a/3rdparty/modules/apache/templates/confd/no-accf.conf.erb b/3rdparty/modules/apache/templates/confd/no-accf.conf.erb new file mode 100644 index 000000000..10e51644c --- /dev/null +++ b/3rdparty/modules/apache/templates/confd/no-accf.conf.erb @@ -0,0 +1,4 @@ + + AcceptFilter http none + AcceptFilter https none + diff --git a/3rdparty/modules/apache/templates/fastcgi/server.erb b/3rdparty/modules/apache/templates/fastcgi/server.erb new file mode 100644 index 000000000..9cb25b76e --- /dev/null +++ b/3rdparty/modules/apache/templates/fastcgi/server.erb @@ -0,0 +1,3 @@ +FastCGIExternalServer <%= @faux_path %> -idle-timeout <%= @timeout %> <%= if @flush then '-flush' end %> -host <%= @host %> +Alias <%= @fcgi_alias %> <%= @faux_path %> +Action <%= @file_type %> <%= @fcgi_alias %> diff --git a/3rdparty/modules/apache/templates/httpd.conf.erb b/3rdparty/modules/apache/templates/httpd.conf.erb new file mode 100644 index 000000000..8664a43e4 --- /dev/null +++ b/3rdparty/modules/apache/templates/httpd.conf.erb @@ -0,0 +1,130 @@ +# Security +ServerTokens <%= @server_tokens %> +ServerSignature <%= scope.function_bool2httpd([@server_signature]) %> +TraceEnable <%= scope.function_bool2httpd([@trace_enable]) %> + +ServerName "<%= @servername %>" +ServerRoot "<%= @server_root %>" +PidFile <%= @pidfile %> +Timeout <%= @timeout %> +KeepAlive <%= @keepalive %> +MaxKeepAliveRequests <%= @max_keepalive_requests %> +KeepAliveTimeout <%= @keepalive_timeout %> + +User <%= @user %> +Group <%= @group %> + +AccessFileName .htaccess + +<%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> + Require all denied +<%- else -%> + Order allow,deny + Deny from all + Satisfy all +<%- end -%> + + + + Options FollowSymLinks + AllowOverride None + + +<% if @default_charset -%> +AddDefaultCharset <%= @default_charset %> +<% end -%> + +<%- if scope.function_versioncmp([@apache_version, '2.4']) < 0 -%> +DefaultType <%= @default_type %> +<%- end -%> +HostnameLookups Off +ErrorLog "<%= @logroot %>/<%= @error_log %>" +LogLevel <%= @log_level %> +EnableSendfile <%= @sendfile %> +<%- if @allow_encoded_slashes -%> +AllowEncodedSlashes <%= @allow_encoded_slashes %> +<%- end -%> + +#Listen 80 + +<% if @apxs_workaround -%> +# Workaround: without this hack apxs would be confused about where to put +# LoadModule directives and fail entire procedure of apache package +# installation/reinstallation. This problem was observed on FreeBSD (apache22). +#LoadModule fake_module libexec/apache22/mod_fake.so +<% end -%> + +Include "<%= @mod_load_dir %>/*.load" +<% if @mod_load_dir != @confd_dir and @mod_load_dir != @vhost_load_dir -%> +Include "<%= @mod_load_dir %>/*.conf" +<% end -%> +Include "<%= @ports_file %>" + +<% unless @log_formats.has_key?('combined') -%> +LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined +<% end -%> +<% unless @log_formats.has_key?('common') -%> +LogFormat "%h %l %u %t \"%r\" %>s %b" common +<% end -%> +<% unless @log_formats.has_key?('referer') -%> +LogFormat "%{Referer}i -> %U" referer +<% end -%> +<% unless @log_formats.has_key?('agent') -%> +LogFormat "%{User-agent}i" agent +<% end -%> +<% if @log_formats and !@log_formats.empty? -%> + <%- @log_formats.sort.each do |nickname,format| -%> +LogFormat "<%= format -%>" <%= nickname %> + <%- end -%> +<% end -%> + +<%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> +IncludeOptional "<%= @confd_dir %>/*.conf" +<%- else -%> +Include "<%= @confd_dir %>/*.conf" +<%- end -%> +<% if @vhost_load_dir != @confd_dir -%> +<%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> +IncludeOptional "<%= @vhost_load_dir %>/*" +<%- else -%> +Include "<%= @vhost_load_dir %>/*" +<%- end -%> +<% end -%> + +<% if @error_documents -%> +# /usr/share/apache2/error on debian +Alias /error/ "<%= @error_documents_path %>/" + +"> + AllowOverride None + Options IncludesNoExec + AddOutputFilter Includes html + AddHandler type-map var +<%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> + Require all granted +<%- else -%> + Order allow,deny + Allow from all +<%- end -%> + LanguagePriority en cs de es fr it nl sv pt-br ro + ForceLanguagePriority Prefer Fallback + + +ErrorDocument 400 /error/HTTP_BAD_REQUEST.html.var +ErrorDocument 401 /error/HTTP_UNAUTHORIZED.html.var +ErrorDocument 403 /error/HTTP_FORBIDDEN.html.var +ErrorDocument 404 /error/HTTP_NOT_FOUND.html.var +ErrorDocument 405 /error/HTTP_METHOD_NOT_ALLOWED.html.var +ErrorDocument 408 /error/HTTP_REQUEST_TIME_OUT.html.var +ErrorDocument 410 /error/HTTP_GONE.html.var +ErrorDocument 411 /error/HTTP_LENGTH_REQUIRED.html.var +ErrorDocument 412 /error/HTTP_PRECONDITION_FAILED.html.var +ErrorDocument 413 /error/HTTP_REQUEST_ENTITY_TOO_LARGE.html.var +ErrorDocument 414 /error/HTTP_REQUEST_URI_TOO_LARGE.html.var +ErrorDocument 415 /error/HTTP_UNSUPPORTED_MEDIA_TYPE.html.var +ErrorDocument 500 /error/HTTP_INTERNAL_SERVER_ERROR.html.var +ErrorDocument 501 /error/HTTP_NOT_IMPLEMENTED.html.var +ErrorDocument 502 /error/HTTP_BAD_GATEWAY.html.var +ErrorDocument 503 /error/HTTP_SERVICE_UNAVAILABLE.html.var +ErrorDocument 506 /error/HTTP_VARIANT_ALSO_VARIES.html.var +<% end -%> diff --git a/3rdparty/modules/apache/templates/listen.erb b/3rdparty/modules/apache/templates/listen.erb new file mode 100644 index 000000000..8fc871b0a --- /dev/null +++ b/3rdparty/modules/apache/templates/listen.erb @@ -0,0 +1,6 @@ +<%# Listen should always be one of: + - + - : + - [ +-%> +Listen <%= @listen_addr_port %> diff --git a/3rdparty/modules/apache/templates/mod/alias.conf.erb b/3rdparty/modules/apache/templates/mod/alias.conf.erb new file mode 100644 index 000000000..2056476e8 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/alias.conf.erb @@ -0,0 +1,13 @@ + +Alias /icons/ "<%= @icons_path %>/" +"> + Options <%= @icons_options %> + AllowOverride None +<%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> + Require all granted +<%- else -%> + Order allow,deny + Allow from all +<%- end -%> + + diff --git a/3rdparty/modules/apache/templates/mod/auth_cas.conf.erb b/3rdparty/modules/apache/templates/mod/auth_cas.conf.erb new file mode 100644 index 000000000..926bd65f5 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/auth_cas.conf.erb @@ -0,0 +1,40 @@ +CASCookiePath <%= @cas_cookie_path %> +CASLoginURL <%= @cas_login_url %> +CASValidateURL <%= @cas_validate_url %> + +CASVersion <%= @cas_version %> +CASDebug <%= @cas_debug %> + +<% if @cas_certificate_path -%> +CASCertificatePath <%= @cas_certificate_path %> +<% end -%> +<% if @cas_proxy_validate_url -%> +CASProxyValidateURL <%= @cas_proxy_validate_url %> +<% end -%> +<% if @cas_validate_depth -%> +CASValidateDepth <%= @cas_validate_depth %> +<% end -%> +<% if @cas_root_proxied_as -%> +CASRootProxiedAs <%= @cas_root_proxied_as %> +<% end -%> +<% if @cas_cookie_entropy -%> +CASCookieEntropy <%= @cas_cookie_entropy %> +<% end -%> +<% if @cas_timeout -%> +CASTimeout <%= @cas_timeout %> +<% end -%> +<% if @cas_idle_timeout -%> +CASIdleTimeout <%= @cas_idle_timeout %> +<% end -%> +<% if @cas_cache_clean_interval -%> +CASCacheCleanInterval <%= @cas_cache_clean_interval %> +<% end -%> +<% if @cas_cookie_domain -%> +CASCookieDomain <%= @cas_cookie_domain %> +<% end -%> +<% if @cas_cookie_http_only -%> +CASCookieHttpOnly <%= @cas_cookie_http_only %> +<% end -%> +<% if @cas_authoritative -%> +CASAuthoritative <%= @cas_authoritative %> +<% end -%> diff --git a/3rdparty/modules/apache/templates/mod/authnz_ldap.conf.erb b/3rdparty/modules/apache/templates/mod/authnz_ldap.conf.erb new file mode 100644 index 000000000..565fcf0df --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/authnz_ldap.conf.erb @@ -0,0 +1,5 @@ +<% if @verifyServerCert == true -%> +LDAPVerifyServerCert On +<% else -%> +LDAPVerifyServerCert Off +<% end -%> diff --git a/3rdparty/modules/apache/templates/mod/autoindex.conf.erb b/3rdparty/modules/apache/templates/mod/autoindex.conf.erb new file mode 100644 index 000000000..ef6bbebea --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/autoindex.conf.erb @@ -0,0 +1,56 @@ +IndexOptions FancyIndexing VersionSort HTMLTable NameWidth=* DescriptionWidth=* Charset=UTF-8 +AddIconByEncoding (CMP,/icons/compressed.gif) x-compress x-gzip x-bzip2 + +AddIconByType (TXT,/icons/text.gif) text/* +AddIconByType (IMG,/icons/image2.gif) image/* +AddIconByType (SND,/icons/sound2.gif) audio/* +AddIconByType (VID,/icons/movie.gif) video/* + +AddIcon /icons/binary.gif .bin .exe +AddIcon /icons/binhex.gif .hqx +AddIcon /icons/tar.gif .tar +AddIcon /icons/world2.gif .wrl .wrl.gz .vrml .vrm .iv +AddIcon /icons/compressed.gif .Z .z .tgz .gz .zip +AddIcon /icons/a.gif .ps .ai .eps +AddIcon /icons/layout.gif .html .shtml .htm .pdf +AddIcon /icons/text.gif .txt +AddIcon /icons/c.gif .c +AddIcon /icons/p.gif .pl .py +AddIcon /icons/f.gif .for +AddIcon /icons/dvi.gif .dvi +AddIcon /icons/uuencoded.gif .uu +AddIcon /icons/script.gif .conf .sh .shar .csh .ksh .tcl +AddIcon /icons/tex.gif .tex +AddIcon /icons/bomb.gif /core +AddIcon (SND,/icons/sound2.gif) .ogg +AddIcon (VID,/icons/movie.gif) .ogm + +AddIcon /icons/back.gif .. +AddIcon /icons/hand.right.gif README +AddIcon /icons/folder.gif ^^DIRECTORY^^ +AddIcon /icons/blank.gif ^^BLANKICON^^ + +AddIcon /icons/odf6odt-20x22.png .odt +AddIcon /icons/odf6ods-20x22.png .ods +AddIcon /icons/odf6odp-20x22.png .odp +AddIcon /icons/odf6odg-20x22.png .odg +AddIcon /icons/odf6odc-20x22.png .odc +AddIcon /icons/odf6odf-20x22.png .odf +AddIcon /icons/odf6odb-20x22.png .odb +AddIcon /icons/odf6odi-20x22.png .odi +AddIcon /icons/odf6odm-20x22.png .odm + +AddIcon /icons/odf6ott-20x22.png .ott +AddIcon /icons/odf6ots-20x22.png .ots +AddIcon /icons/odf6otp-20x22.png .otp +AddIcon /icons/odf6otg-20x22.png .otg +AddIcon /icons/odf6otc-20x22.png .otc +AddIcon /icons/odf6otf-20x22.png .otf +AddIcon /icons/odf6oti-20x22.png .oti +AddIcon /icons/odf6oth-20x22.png .oth + +DefaultIcon /icons/unknown.gif +ReadmeName README.html +HeaderName HEADER.html + +IndexIgnore .??* *~ *# HEADER* README* RCS CVS *,v *,t diff --git a/3rdparty/modules/apache/templates/mod/cgid.conf.erb b/3rdparty/modules/apache/templates/mod/cgid.conf.erb new file mode 100644 index 000000000..5f82d7424 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/cgid.conf.erb @@ -0,0 +1 @@ +ScriptSock "<%= @cgisock_path %>" diff --git a/3rdparty/modules/apache/templates/mod/dav_fs.conf.erb b/3rdparty/modules/apache/templates/mod/dav_fs.conf.erb new file mode 100644 index 000000000..3c53e9e14 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/dav_fs.conf.erb @@ -0,0 +1 @@ +DAVLockDB "<%= @dav_lock %>" diff --git a/3rdparty/modules/apache/templates/mod/deflate.conf.erb b/3rdparty/modules/apache/templates/mod/deflate.conf.erb new file mode 100644 index 000000000..ede8b2e76 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/deflate.conf.erb @@ -0,0 +1,7 @@ +<%- @types.sort.each do |type| -%> +AddOutputFilterByType DEFLATE <%= type %> +<%- end -%> + +<%- @notes.sort.each do |type,note| -%> +DeflateFilterNote <%= type %> <%=note %> +<%- end -%> diff --git a/3rdparty/modules/apache/templates/mod/dir.conf.erb b/3rdparty/modules/apache/templates/mod/dir.conf.erb new file mode 100644 index 000000000..741f6ae03 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/dir.conf.erb @@ -0,0 +1 @@ +DirectoryIndex <%= @indexes.join(' ') %> diff --git a/3rdparty/modules/apache/templates/mod/disk_cache.conf.erb b/3rdparty/modules/apache/templates/mod/disk_cache.conf.erb new file mode 100644 index 000000000..0c7e2c4b7 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/disk_cache.conf.erb @@ -0,0 +1,8 @@ + + + CacheEnable disk / + CacheRoot "<%= @cache_root %>" + CacheDirLevels 2 + CacheDirLength 1 + + diff --git a/3rdparty/modules/apache/templates/mod/event.conf.erb b/3rdparty/modules/apache/templates/mod/event.conf.erb new file mode 100644 index 000000000..970ce088c --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/event.conf.erb @@ -0,0 +1,13 @@ + + ServerLimit <%= @serverlimit %> + StartServers <%= @startservers %> + MaxClients <%= @maxclients %> + MinSpareThreads <%= @minsparethreads %> + MaxSpareThreads <%= @maxsparethreads %> + ThreadsPerChild <%= @threadsperchild %> + MaxRequestsPerChild <%= @maxrequestsperchild %> + ThreadLimit <%= @threadlimit %> + ListenBacklog <%= @listenbacklog %> + MaxRequestWorkers <%= @maxrequestworkers %> + MaxConnectionsPerChild <%= @maxconnectionsperchild %> + diff --git a/3rdparty/modules/apache/templates/mod/expires.conf.erb b/3rdparty/modules/apache/templates/mod/expires.conf.erb new file mode 100644 index 000000000..7660cfcd0 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/expires.conf.erb @@ -0,0 +1,11 @@ +ExpiresActive <%= scope.function_bool2httpd([@expires_active]) %> +<%- if ! @expires_default.nil? and ! @expires_default.empty? -%> +ExpiresDefault "<%= @expires_default %>" +<%- end -%> +<%- if ! @expires_by_type.nil? and ! @expires_by_type.empty? -%> +<%- [@expires_by_type].flatten.each do |line| -%> +<%- line.map do |type, seconds| -%> +ExpiresByType <%= type %> "<%= seconds -%>" +<%- end -%> +<%- end -%> +<%- end -%> diff --git a/3rdparty/modules/apache/templates/mod/fastcgi.conf.erb b/3rdparty/modules/apache/templates/mod/fastcgi.conf.erb new file mode 100644 index 000000000..8d94a2361 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/fastcgi.conf.erb @@ -0,0 +1,6 @@ +# The Fastcgi Apache module configuration file is being +# managed by Puppet and changes will be overwritten. + + AddHandler fastcgi-script .fcgi + FastCgiIpcDir "<%= @fastcgi_lib_path %>" + diff --git a/3rdparty/modules/apache/templates/mod/fcgid.conf.erb b/3rdparty/modules/apache/templates/mod/fcgid.conf.erb new file mode 100644 index 000000000..a82bc30df --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/fcgid.conf.erb @@ -0,0 +1,5 @@ + +<% @options.sort_by {|key, value| key}.each do |key, value| -%> + <%= key %> <%= value %> +<% end -%> + diff --git a/3rdparty/modules/apache/templates/mod/geoip.conf.erb b/3rdparty/modules/apache/templates/mod/geoip.conf.erb new file mode 100644 index 000000000..84b5dfe92 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/geoip.conf.erb @@ -0,0 +1,22 @@ +GeoIPEnable <%= scope.function_bool2httpd([@enable]) %> + +<%- if @db_file and ! [ false, 'false', '' ].include?(@db_file) -%> + <%- if @db_file.kind_of?(Array) -%> + <%- Array(@db_file).each do |file| -%> +GeoIPDBFile <%= file %> <%= @flag %> + <%- end -%> + <%- else -%> +GeoIPDBFile <%= @db_file %> <%= @flag %> + <%- end -%> +<%- end -%> +GeoIPOutput <%= @output %> +<% if ! @enable_utf8.nil? -%> +GeoIPEnableUTF8 <%= scope.function_bool2httpd([@enable_utf8]) %> +<% end -%> +<% if ! @scan_proxy_headers.nil? -%> +GeoIPScanProxyHeaders <%= scope.function_bool2httpd([@scan_proxy_headers]) %> +<% end -%> +<% if ! @use_last_xforwarededfor_ip.nil? -%> +GeoIPUseLastXForwardedForIP <%= scope.function_bool2httpd([@use_last_xforwarededfor_ip]) %> +<% end -%> + diff --git a/3rdparty/modules/apache/templates/mod/info.conf.erb b/3rdparty/modules/apache/templates/mod/info.conf.erb new file mode 100644 index 000000000..1a025b7a6 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/info.conf.erb @@ -0,0 +1,19 @@ + + SetHandler server-info +<%- if @restrict_access -%> + <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> + Require ip <%= Array(@allow_from).join(" ") %> + <%- else -%> + Order deny,allow + Deny from all + <%- if @allow_from and ! @allow_from.empty? -%> + <%- @allow_from.each do |allowed| -%> + Allow from <%= allowed %> + <%- end -%> + <%- else -%> + Allow from 127.0.0.1 + Allow from ::1 + <%- end -%> + <%- end -%> +<%- end -%> + diff --git a/3rdparty/modules/apache/templates/mod/itk.conf.erb b/3rdparty/modules/apache/templates/mod/itk.conf.erb new file mode 100644 index 000000000..f45f2b35d --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/itk.conf.erb @@ -0,0 +1,8 @@ + + StartServers <%= @startservers %> + MinSpareServers <%= @minspareservers %> + MaxSpareServers <%= @maxspareservers %> + ServerLimit <%= @serverlimit %> + MaxClients <%= @maxclients %> + MaxRequestsPerChild <%= @maxrequestsperchild %> + diff --git a/3rdparty/modules/apache/templates/mod/ldap.conf.erb b/3rdparty/modules/apache/templates/mod/ldap.conf.erb new file mode 100644 index 000000000..001977617 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/ldap.conf.erb @@ -0,0 +1,11 @@ + + SetHandler ldap-status + <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> + Require ip 127.0.0.1 ::1 + <%- else -%> + Order deny,allow + Deny from all + Allow from 127.0.0.1 ::1 + Satisfy all + <%- end -%> + diff --git a/3rdparty/modules/apache/templates/mod/load.erb b/3rdparty/modules/apache/templates/mod/load.erb new file mode 100644 index 000000000..51f45edb2 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/load.erb @@ -0,0 +1,7 @@ +<% if @loadfiles -%> +<% Array(@loadfiles).each do |loadfile| -%> +LoadFile <%= loadfile %> +<% end -%> + +<% end -%> +LoadModule <%= @_id %> <%= @_path %> diff --git a/3rdparty/modules/apache/templates/mod/mime.conf.erb b/3rdparty/modules/apache/templates/mod/mime.conf.erb new file mode 100644 index 000000000..a69a424a6 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/mime.conf.erb @@ -0,0 +1,36 @@ +TypesConfig <%= @mime_types_config %> + +AddType application/x-compress .Z +AddType application/x-gzip .gz .tgz +AddType application/x-bzip2 .bz2 + +AddLanguage ca .ca +AddLanguage cs .cz .cs +AddLanguage da .dk +AddLanguage de .de +AddLanguage el .el +AddLanguage en .en +AddLanguage eo .eo +AddLanguage es .es +AddLanguage et .et +AddLanguage fr .fr +AddLanguage he .he +AddLanguage hr .hr +AddLanguage it .it +AddLanguage ja .ja +AddLanguage ko .ko +AddLanguage ltz .ltz +AddLanguage nl .nl +AddLanguage nn .nn +AddLanguage no .no +AddLanguage pl .po +AddLanguage pt .pt +AddLanguage pt-BR .pt-br +AddLanguage ru .ru +AddLanguage sv .sv +AddLanguage zh-CN .zh-cn +AddLanguage zh-TW .zh-tw + +AddHandler type-map var +AddType text/html .shtml +AddOutputFilter INCLUDES .shtml diff --git a/3rdparty/modules/apache/templates/mod/mime_magic.conf.erb b/3rdparty/modules/apache/templates/mod/mime_magic.conf.erb new file mode 100644 index 000000000..1ce1bc3c1 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/mime_magic.conf.erb @@ -0,0 +1 @@ +MIMEMagicFile "<%= @magic_file %>" diff --git a/3rdparty/modules/apache/templates/mod/mpm_event.conf.erb b/3rdparty/modules/apache/templates/mod/mpm_event.conf.erb new file mode 100644 index 000000000..eb6f1ff5f --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/mpm_event.conf.erb @@ -0,0 +1,9 @@ + + StartServers 2 + MinSpareThreads 25 + MaxSpareThreads 75 + ThreadLimit 64 + ThreadsPerChild 25 + MaxClients 150 + MaxRequestsPerChild 0 + diff --git a/3rdparty/modules/apache/templates/mod/negotiation.conf.erb b/3rdparty/modules/apache/templates/mod/negotiation.conf.erb new file mode 100644 index 000000000..2fb4700d6 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/negotiation.conf.erb @@ -0,0 +1,2 @@ +LanguagePriority <%= Array(@language_priority).join(' ') %> +ForceLanguagePriority <%= Array(@force_language_priority).join(' ') %> diff --git a/3rdparty/modules/apache/templates/mod/nss.conf.erb b/3rdparty/modules/apache/templates/mod/nss.conf.erb new file mode 100644 index 000000000..a5c81752f --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/nss.conf.erb @@ -0,0 +1,228 @@ +# +# This is the Apache server configuration file providing SSL support using. +# the mod_nss plugin. It contains the configuration directives to instruct +# the server how to serve pages over an https connection. +# +# Do NOT simply read the instructions in here without understanding +# what they do. They're here only as hints or reminders. If you are unsure +# consult the online docs. You have been warned. +# + +#LoadModule nss_module modules/libmodnss.so + +# +# When we also provide SSL we have to listen to the +# standard HTTP port (see above) and to the HTTPS port +# +# Note: Configurations that use IPv6 but not IPv4-mapped addresses need two +# Listen directives: "Listen [::]:8443" and "Listen 0.0.0.0:443" +# +Listen 8443 + +## +## SSL Global Context +## +## All SSL configuration in this context applies both to +## the main server and all SSL-enabled virtual hosts. +## + +# +# Some MIME-types for downloading Certificates and CRLs +# +AddType application/x-x509-ca-cert .crt +AddType application/x-pkcs7-crl .crl + +# Pass Phrase Dialog: +# Configure the pass phrase gathering process. +# The filtering dialog program (`builtin' is a internal +# terminal dialog) has to provide the pass phrase on stdout. +<% if @passwd_file -%> +NSSPassPhraseDialog "file:<%= @passwd_file %>" +<% else -%> +NSSPassPhraseDialog builtin +<% end -%> + +# Pass Phrase Helper: +# This helper program stores the token password pins between +# restarts of Apache. +NSSPassPhraseHelper /usr/sbin/nss_pcache + +# Configure the SSL Session Cache. +# NSSSessionCacheSize is the number of entries in the cache. +# NSSSessionCacheTimeout is the SSL2 session timeout (in seconds). +# NSSSession3CacheTimeout is the SSL3/TLS session timeout (in seconds). +NSSSessionCacheSize 10000 +NSSSessionCacheTimeout 100 +NSSSession3CacheTimeout 86400 + +# +# Pseudo Random Number Generator (PRNG): +# Configure one or more sources to seed the PRNG of the SSL library. +# The seed data should be of good random quality. +# WARNING! On some platforms /dev/random blocks if not enough entropy +# is available. Those platforms usually also provide a non-blocking +# device, /dev/urandom, which may be used instead. +# +# This does not support seeding the RNG with each connection. + +NSSRandomSeed startup builtin +#NSSRandomSeed startup file:/dev/random 512 +#NSSRandomSeed startup file:/dev/urandom 512 + +# +# TLS Negotiation configuration under RFC 5746 +# +# Only renegotiate if the peer's hello bears the TLS renegotiation_info +# extension. Default off. +NSSRenegotiation off + +# Peer must send Signaling Cipher Suite Value (SCSV) or +# Renegotiation Info (RI) extension in ALL handshakes. Default: off +NSSRequireSafeNegotiation off + +## +## SSL Virtual Host Context +## + + + +# General setup for the virtual host +#DocumentRoot "/etc/httpd/htdocs" +#ServerName www.example.com:8443 +#ServerAdmin you@example.com + +# mod_nss can log to separate log files, you can choose to do that if you'd like +# LogLevel is not inherited from httpd.conf. +ErrorLog "<%= @error_log %>" +TransferLog "<%= @transfer_log %>" +LogLevel warn + +# SSL Engine Switch: +# Enable/Disable SSL for this virtual host. +NSSEngine on + +# SSL Cipher Suite: +# List the ciphers that the client is permitted to negotiate. +# See the mod_nss documentation for a complete list. + +# SSL 3 ciphers. SSL 2 is disabled by default. +NSSCipherSuite +rsa_rc4_128_md5,+rsa_rc4_128_sha,+rsa_3des_sha,-rsa_des_sha,-rsa_rc4_40_md5,-rsa_rc2_40_md5,-rsa_null_md5,-rsa_null_sha,+fips_3des_sha,-fips_des_sha,-fortezza,-fortezza_rc4_128_sha,-fortezza_null,-rsa_des_56_sha,-rsa_rc4_56_sha,+rsa_aes_128_sha,+rsa_aes_256_sha + +# SSL 3 ciphers + ECC ciphers. SSL 2 is disabled by default. +# +# Comment out the NSSCipherSuite line above and use the one below if you have +# ECC enabled NSS and mod_nss and want to use Elliptical Curve Cryptography +#NSSCipherSuite +rsa_rc4_128_md5,+rsa_rc4_128_sha,+rsa_3des_sha,-rsa_des_sha,-rsa_rc4_40_md5,-rsa_rc2_40_md5,-rsa_null_md5,-rsa_null_sha,+fips_3des_sha,-fips_des_sha,-fortezza,-fortezza_rc4_128_sha,-fortezza_null,-rsa_des_56_sha,-rsa_rc4_56_sha,+rsa_aes_128_sha,+rsa_aes_256_sha,-ecdh_ecdsa_null_sha,+ecdh_ecdsa_rc4_128_sha,+ecdh_ecdsa_3des_sha,+ecdh_ecdsa_aes_128_sha,+ecdh_ecdsa_aes_256_sha,-ecdhe_ecdsa_null_sha,+ecdhe_ecdsa_rc4_128_sha,+ecdhe_ecdsa_3des_sha,+ecdhe_ecdsa_aes_128_sha,+ecdhe_ecdsa_aes_256_sha,-ecdh_rsa_null_sha,+ecdh_rsa_128_sha,+ecdh_rsa_3des_sha,+ecdh_rsa_aes_128_sha,+ecdh_rsa_aes_256_sha,-echde_rsa_null,+ecdhe_rsa_rc4_128_sha,+ecdhe_rsa_3des_sha,+ecdhe_rsa_aes_128_sha,+ecdhe_rsa_aes_256_sha + +# SSL Protocol: +# Cryptographic protocols that provide communication security. +# NSS handles the specified protocols as "ranges", and automatically +# negotiates the use of the strongest protocol for a connection starting +# with the maximum specified protocol and downgrading as necessary to the +# minimum specified protocol that can be used between two processes. +# Since all protocol ranges are completely inclusive, and no protocol in the +# middle of a range may be excluded, the entry "NSSProtocol SSLv3,TLSv1.1" +# is identical to the entry "NSSProtocol SSLv3,TLSv1.0,TLSv1.1". +NSSProtocol SSLv3,TLSv1.0,TLSv1.1 + +# SSL Certificate Nickname: +# The nickname of the RSA server certificate you are going to use. +NSSNickname Server-Cert + +# SSL Certificate Nickname: +# The nickname of the ECC server certificate you are going to use, if you +# have an ECC-enabled version of NSS and mod_nss +#NSSECCNickname Server-Cert-ecc + +# Server Certificate Database: +# The NSS security database directory that holds the certificates and +# keys. The database consists of 3 files: cert8.db, key3.db and secmod.db. +# Provide the directory that these files exist. +NSSCertificateDatabase "<%= @httpd_dir -%>/alias" + +# Database Prefix: +# In order to be able to store multiple NSS databases in one directory +# they need unique names. This option sets the database prefix used for +# cert8.db and key3.db. +#NSSDBPrefix my-prefix- + +# Client Authentication (Type): +# Client certificate verification type. Types are none, optional and +# require. +#NSSVerifyClient none + +# +# Online Certificate Status Protocol (OCSP). +# Verify that certificates have not been revoked before accepting them. +#NSSOCSP off + +# +# Use a default OCSP responder. If enabled this will be used regardless +# of whether one is included in a client certificate. Note that the +# server certificate is verified during startup. +# +# NSSOCSPDefaultURL defines the service URL of the OCSP responder +# NSSOCSPDefaultName is the nickname of the certificate to trust to +# sign the OCSP responses. +#NSSOCSPDefaultResponder on +#NSSOCSPDefaultURL http://example.com/ocsp/status +#NSSOCSPDefaultName ocsp-nickname + +# Access Control: +# With SSLRequire you can do per-directory access control based +# on arbitrary complex boolean expressions containing server +# variable checks and other lookup directives. The syntax is a +# mixture between C and Perl. See the mod_nss documentation +# for more details. +# +#NSSRequire ( %{SSL_CIPHER} !~ m/^(EXP|NULL)/ \ +# and %{SSL_CLIENT_S_DN_O} eq "Snake Oil, Ltd." \ +# and %{SSL_CLIENT_S_DN_OU} in {"Staff", "CA", "Dev"} \ +# and %{TIME_WDAY} >= 1 and %{TIME_WDAY} <= 5 \ +# and %{TIME_HOUR} >= 8 and %{TIME_HOUR} <= 20 ) \ +# or %{REMOTE_ADDR} =~ m/^192\.76\.162\.[0-9]+$/ +# + +# SSL Engine Options: +# Set various options for the SSL engine. +# o FakeBasicAuth: +# Translate the client X.509 into a Basic Authorisation. This means that +# the standard Auth/DBMAuth methods can be used for access control. The +# user name is the `one line' version of the client's X.509 certificate. +# Note that no password is obtained from the user. Every entry in the user +# file needs this password: `xxj31ZMTZzkVA'. +# o ExportCertData: +# This exports two additional environment variables: SSL_CLIENT_CERT and +# SSL_SERVER_CERT. These contain the PEM-encoded certificates of the +# server (always existing) and the client (only existing when client +# authentication is used). This can be used to import the certificates +# into CGI scripts. +# o StdEnvVars: +# This exports the standard SSL/TLS related `SSL_*' environment variables. +# Per default this exportation is switched off for performance reasons, +# because the extraction step is an expensive operation and is usually +# useless for serving static content. So one usually enables the +# exportation for CGI and SSI requests only. +# o StrictRequire: +# This denies access when "NSSRequireSSL" or "NSSRequire" applied even +# under a "Satisfy any" situation, i.e. when it applies access is denied +# and no other module can change it. +# o OptRenegotiate: +# This enables optimized SSL connection renegotiation handling when SSL +# directives are used in per-directory context. +#NSSOptions +FakeBasicAuth +ExportCertData +CompatEnvVars +StrictRequire + + NSSOptions +StdEnvVars + + + NSSOptions +StdEnvVars + + +# Per-Server Logging: +# The home of a custom SSL log file. Use this when you want a +# compact non-error SSL logfile on a virtual host basis. +#CustomLog /home/rcrit/redhat/apache/logs/ssl_request_log \ +# "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b" + + + diff --git a/3rdparty/modules/apache/templates/mod/pagespeed.conf.erb b/3rdparty/modules/apache/templates/mod/pagespeed.conf.erb new file mode 100644 index 000000000..a1b6f117a --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/pagespeed.conf.erb @@ -0,0 +1,98 @@ +ModPagespeed on + +ModPagespeedInheritVHostConfig <%= @inherit_vhost_config %> +AddOutputFilterByType MOD_PAGESPEED_OUTPUT_FILTER text/html +<% if @filter_xhtml -%> +AddOutputFilterByType MOD_PAGESPEED_OUTPUT_FILTER application/xhtml+xml +<% end -%> +ModPagespeedFileCachePath "<%= @cache_path %>" +ModPagespeedLogDir "<%= @log_dir %>" + +<% @memcache_servers.each do |server| -%> +ModPagespeedMemcachedServers <%= server %> +<% end -%> + +ModPagespeedRewriteLevel <%= @rewrite_level -%> + +<% @disable_filters.each do |filter| -%> +ModPagespeedDisableFilters <%= filter %> +<% end -%> + +<% @enable_filters.each do |filter| -%> +ModPagespeedEnableFilters <%= filter %> +<% end -%> + +<% @forbid_filters.each do |filter| -%> +ModPagespeedForbidFilters <%= filter %> +<% end -%> + +ModPagespeedRewriteDeadlinePerFlushMs <%= @rewrite_deadline_per_flush_ms %> + +<% if @additional_domains -%> +ModPagespeedDomain <%= @additional_domains -%> +<% end -%> + +ModPagespeedFileCacheSizeKb <%= @file_cache_size_kb %> +ModPagespeedFileCacheCleanIntervalMs <%= @file_cache_clean_interval_ms %> +ModPagespeedLRUCacheKbPerProcess <%= @lru_cache_per_process %> +ModPagespeedLRUCacheByteLimit <%= @lru_cache_byte_limit %> +ModPagespeedCssFlattenMaxBytes <%= @css_flatten_max_bytes %> +ModPagespeedCssInlineMaxBytes <%= @css_inline_max_bytes %> +ModPagespeedCssImageInlineMaxBytes <%= @css_image_inline_max_bytes %> +ModPagespeedImageInlineMaxBytes <%= @image_inline_max_bytes %> +ModPagespeedJsInlineMaxBytes <%= @js_inline_max_bytes %> +ModPagespeedCssOutlineMinBytes <%= @css_outline_min_bytes %> +ModPagespeedJsOutlineMinBytes <%= @js_outline_min_bytes %> + + +ModPagespeedFileCacheInodeLimit <%= @inode_limit %> +ModPagespeedImageMaxRewritesAtOnce <%= @image_max_rewrites_at_once %> + +ModPagespeedNumRewriteThreads <%= @num_rewrite_threads %> +ModPagespeedNumExpensiveRewriteThreads <%= @num_expensive_rewrite_threads %> + +ModPagespeedStatistics <%= @collect_statistics %> + + + # You may insert other "Allow from" lines to add hosts you want to + # allow to look at generated statistics. Another possibility is + # to comment out the "Order" and "Allow" options from the config + # file, to allow any client that can reach your server to examine + # statistics. This might be appropriate in an experimental setup or + # if the Apache server is protected by a reverse proxy that will + # filter URLs in some fashion. + <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> + Require ip 127.0.0.1 ::1 <%= Array(@allow_view_stats).join(" ") %> + <%- else -%> + Order allow,deny + Allow from 127.0.0.1 ::1 <%= Array(@allow_view_stats).join(" ") %> + <%- end -%> + SetHandler mod_pagespeed_statistics + + +ModPagespeedStatisticsLogging <%= @statistics_logging %> + + <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> + Require ip 127.0.0.1 ::1 <%= Array(@allow_pagespeed_console).join(" ") %> + <%- else -%> + Order allow,deny + Allow from 127.0.0.1 ::1 <%= Array(@allow_pagespeed_console).join(" ") %> + <%- end -%> + SetHandler pagespeed_console + + +ModPagespeedMessageBufferSize <%= @message_buffer_size %> + + + <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> + Require ip 127.0.0.1 ::1 <%= Array(@allow_pagespeed_message).join(" ") %> + <%- else -%> + Order allow,deny + Allow from 127.0.0.1 ::1 <%= Array(@allow_pagespeed_message).join(" ") %> + <%- end -%> + SetHandler mod_pagespeed_message + + +<% @additional_configuration.each_pair do |key, value| -%> +<%= key %> <%= value %> +<% end -%> diff --git a/3rdparty/modules/apache/templates/mod/passenger.conf.erb b/3rdparty/modules/apache/templates/mod/passenger.conf.erb new file mode 100644 index 000000000..e50a2d636 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/passenger.conf.erb @@ -0,0 +1,43 @@ +# The Passenger Apache module configuration file is being +# managed by Puppet and changes will be overwritten. + + <%- if @passenger_root -%> + PassengerRoot "<%= @passenger_root %>" + <%- end -%> + <%- if @passenger_ruby -%> + PassengerRuby "<%= @passenger_ruby %>" + <%- end -%> + <%- if @passenger_default_ruby -%> + PassengerDefaultRuby "<%= @passenger_default_ruby %>" + <%- end -%> + <%- if @passenger_high_performance -%> + PassengerHighPerformance <%= @passenger_high_performance %> + <%- end -%> + <%- if @passenger_max_pool_size -%> + PassengerMaxPoolSize <%= @passenger_max_pool_size %> + <%- end -%> + <%- if @passenger_min_instances -%> + PassengerMinInstances <%= @passenger_min_instances %> + <%- end -%> + <%- if @passenger_pool_idle_time -%> + PassengerPoolIdleTime <%= @passenger_pool_idle_time %> + <%- end -%> + <%- if @passenger_max_requests -%> + PassengerMaxRequests <%= @passenger_max_requests %> + <%- end -%> + <%- if @passenger_stat_throttle_rate -%> + PassengerStatThrottleRate <%= @passenger_stat_throttle_rate %> + <%- end -%> + <%- if @rack_autodetect -%> + RackAutoDetect <%= @rack_autodetect %> + <%- end -%> + <%- if @rails_autodetect -%> + RailsAutoDetect <%= @rails_autodetect %> + <%- end -%> + <%- if @passenger_use_global_queue -%> + PassengerUseGlobalQueue <%= @passenger_use_global_queue %> + <%- end -%> + <%- if @passenger_app_env -%> + PassengerAppEnv <%= @passenger_app_env %> + <%- end -%> + diff --git a/3rdparty/modules/apache/templates/mod/peruser.conf.erb b/3rdparty/modules/apache/templates/mod/peruser.conf.erb new file mode 100644 index 000000000..13c8d708d --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/peruser.conf.erb @@ -0,0 +1,12 @@ + + MinSpareProcessors <%= @minspareprocessors %> + MinProcessors <%= @minprocessors %> + MaxProcessors <%= @maxprocessors %> + MaxClients <%= @maxclients %> + MaxRequestsPerChild <%= @maxrequestsperchild %> + IdleTimeout <%= @idletimeout %> + ExpireTimeout <%= @expiretimeout %> + KeepAlive <%= @keepalive %> + Include "<%= @mod_dir %>/peruser/multiplexers/*.conf" + Include "<%= @mod_dir %>/peruser/processors/*.conf" + diff --git a/3rdparty/modules/apache/templates/mod/php5.conf.erb b/3rdparty/modules/apache/templates/mod/php5.conf.erb new file mode 100644 index 000000000..44df2ae06 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/php5.conf.erb @@ -0,0 +1,30 @@ +# +# PHP is an HTML-embedded scripting language which attempts to make it +# easy for developers to write dynamically generated webpages. +# +# +# LoadModule php5_module modules/libphp5.so +# +# +# # Use of the "ZTS" build with worker is experimental, and no shared +# # modules are supported. +# LoadModule php5_module modules/libphp5-zts.so +# + +# +# Cause the PHP interpreter to handle files with a .php extension. +# +AddHandler php5-script <%= @extensions.flatten.compact.join(' ') %> +AddType text/html .php + +# +# Add index.php to the list of files that will be served as directory +# indexes. +# +DirectoryIndex index.php + +# +# Uncomment the following line to allow PHP to pretty-print .phps +# files as PHP source code: +# +#AddType application/x-httpd-php-source .phps diff --git a/3rdparty/modules/apache/templates/mod/prefork.conf.erb b/3rdparty/modules/apache/templates/mod/prefork.conf.erb new file mode 100644 index 000000000..aabfdf7b2 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/prefork.conf.erb @@ -0,0 +1,8 @@ + + StartServers <%= @startservers %> + MinSpareServers <%= @minspareservers %> + MaxSpareServers <%= @maxspareservers %> + ServerLimit <%= @serverlimit %> + MaxClients <%= @maxclients %> + MaxRequestsPerChild <%= @maxrequestsperchild %> + diff --git a/3rdparty/modules/apache/templates/mod/proxy.conf.erb b/3rdparty/modules/apache/templates/mod/proxy.conf.erb new file mode 100644 index 000000000..5ea829eeb --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/proxy.conf.erb @@ -0,0 +1,27 @@ +# +# Proxy Server directives. Uncomment the following lines to +# enable the proxy server: +# + + # Do not enable proxying with ProxyRequests until you have secured your + # server. Open proxy servers are dangerous both to your network and to the + # Internet at large. + ProxyRequests <%= @proxy_requests %> + + <% if @proxy_requests != 'Off' or ( @allow_from and ! @allow_from.empty? ) -%> + + <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> + Require ip <%= Array(@allow_from).join(" ") %> + <%- else -%> + Order deny,allow + Deny from all + Allow from <%= Array(@allow_from).join(" ") %> + <%- end -%> + + <% end -%> + + # Enable/disable the handling of HTTP/1.1 "Via:" headers. + # ("Full" adds the server version; "Block" removes all outgoing Via: headers) + # Set to one of: Off | On | Full | Block + ProxyVia On + diff --git a/3rdparty/modules/apache/templates/mod/proxy_html.conf.erb b/3rdparty/modules/apache/templates/mod/proxy_html.conf.erb new file mode 100644 index 000000000..fea15f393 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/proxy_html.conf.erb @@ -0,0 +1,18 @@ +ProxyHTMLLinks a href +ProxyHTMLLinks area href +ProxyHTMLLinks link href +ProxyHTMLLinks img src longdesc usemap +ProxyHTMLLinks object classid codebase data usemap +ProxyHTMLLinks q cite +ProxyHTMLLinks blockquote cite +ProxyHTMLLinks ins cite +ProxyHTMLLinks del cite +ProxyHTMLLinks form action +ProxyHTMLLinks input src usemap +ProxyHTMLLinks head profileProxyHTMLLinks base href +ProxyHTMLLinks script src for + +ProxyHTMLEvents onclick ondblclick onmousedown onmouseup \ + onmouseover onmousemove onmouseout onkeypress \ + onkeydown onkeyup onfocus onblur onload \ + onunload onsubmit onreset onselect onchange diff --git a/3rdparty/modules/apache/templates/mod/remoteip.conf.erb b/3rdparty/modules/apache/templates/mod/remoteip.conf.erb new file mode 100644 index 000000000..b4518f9b0 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/remoteip.conf.erb @@ -0,0 +1,23 @@ +# Declare the header field which should be parsed for useragent IP addresses +RemoteIPHeader <%= @header %> + +<%- if @proxy_ips -%> +# Declare client intranet IP addresses trusted to present +# the RemoteIPHeader value +<%- [@proxy_ips].flatten.each do |proxy| -%> +RemoteIPInternalProxy <%= proxy %> +<%- end -%> +<%- end -%> + +<%- if @proxies_header -%> +# Declare the header field which will record all intermediate IP addresses +RemoteIPProxiesHeader <%= @proxies_header %> +<%- end -%> + +<%- if @trusted_proxy_ips -%> +# Declare client intranet IP addresses trusted to present +# the RemoteIPHeader value + <%- [@trusted_proxy_ips].flatten.each do |proxy| -%> +RemoteIPTrustedProxy <%= proxy %> + <%- end -%> +<%- end -%> diff --git a/3rdparty/modules/apache/templates/mod/reqtimeout.conf.erb b/3rdparty/modules/apache/templates/mod/reqtimeout.conf.erb new file mode 100644 index 000000000..6ffc5ffe2 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/reqtimeout.conf.erb @@ -0,0 +1,3 @@ +<% Array(@timeouts).each do |timeout| -%> +RequestReadTimeout <%= timeout %> +<%- end -%> diff --git a/3rdparty/modules/apache/templates/mod/rpaf.conf.erb b/3rdparty/modules/apache/templates/mod/rpaf.conf.erb new file mode 100644 index 000000000..56e2398b5 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/rpaf.conf.erb @@ -0,0 +1,15 @@ +# Enable reverse proxy add forward +RPAFenable On +# RPAFsethostname will, when enabled, take the incoming X-Host header and +# update the virtual host settings accordingly. This allows to have the same +# hostnames as in the "real" configuration for the forwarding proxy. +<% if @sethostname -%> +RPAFsethostname On +<% else -%> +RPAFsethostname Off +<% end -%> +# Which IPs are forwarding requests to us +RPAFproxy_ips <%= Array(@proxy_ips).join(" ") %> +# Setting RPAFheader allows you to change the header name to parse from the +# default X-Forwarded-For to something of your choice. +RPAFheader <%= @header %> diff --git a/3rdparty/modules/apache/templates/mod/security.conf.erb b/3rdparty/modules/apache/templates/mod/security.conf.erb new file mode 100644 index 000000000..7597c461f --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/security.conf.erb @@ -0,0 +1,68 @@ + + # ModSecurity Core Rules Set configuration +<%- if scope.function_versioncmp([scope.lookupvar('::apache::apache_version'), '2.4']) >= 0 -%> + IncludeOptional <%= @modsec_dir %>/*.conf + IncludeOptional <%= @modsec_dir %>/activated_rules/*.conf +<%- else -%> + Include <%= @modsec_dir %>/*.conf + Include <%= @modsec_dir %>/activated_rules/*.conf +<%- end -%> + + # Default recommended configuration + SecRuleEngine On + SecRequestBodyAccess On + SecRule REQUEST_HEADERS:Content-Type "text/xml" \ + "id:'200000',phase:1,t:none,t:lowercase,pass,nolog,ctl:requestBodyProcessor=XML" + SecRequestBodyLimit 13107200 + SecRequestBodyNoFilesLimit 131072 + SecRequestBodyInMemoryLimit 131072 + SecRequestBodyLimitAction Reject + SecRule REQBODY_ERROR "!@eq 0" \ + "id:'200001', phase:2,t:none,log,deny,status:400,msg:'Failed to parse request body.',logdata:'%{reqbody_error_msg}',severity:2" + SecRule MULTIPART_STRICT_ERROR "!@eq 0" \ + "id:'200002',phase:2,t:none,log,deny,status:44,msg:'Multipart request body failed strict validation: \ + PE %{REQBODY_PROCESSOR_ERROR}, \ + BQ %{MULTIPART_BOUNDARY_QUOTED}, \ + BW %{MULTIPART_BOUNDARY_WHITESPACE}, \ + DB %{MULTIPART_DATA_BEFORE}, \ + DA %{MULTIPART_DATA_AFTER}, \ + HF %{MULTIPART_HEADER_FOLDING}, \ + LF %{MULTIPART_LF_LINE}, \ + SM %{MULTIPART_MISSING_SEMICOLON}, \ + IQ %{MULTIPART_INVALID_QUOTING}, \ + IP %{MULTIPART_INVALID_PART}, \ + IH %{MULTIPART_INVALID_HEADER_FOLDING}, \ + FL %{MULTIPART_FILE_LIMIT_EXCEEDED}'" + + SecRule MULTIPART_UNMATCHED_BOUNDARY "!@eq 0" \ + "id:'200003',phase:2,t:none,log,deny,status:44,msg:'Multipart parser detected a possible unmatched boundary.'" + + SecPcreMatchLimit 1000 + SecPcreMatchLimitRecursion 1000 + + SecRule TX:/^MSC_/ "!@streq 0" \ + "id:'200004',phase:2,t:none,deny,msg:'ModSecurity internal error flagged: %{MATCHED_VAR_NAME}'" + + SecResponseBodyAccess Off + SecResponseBodyMimeType text/plain text/html text/xml + SecResponseBodyLimit 524288 + SecResponseBodyLimitAction ProcessPartial + SecDebugLogLevel 0 + SecAuditEngine RelevantOnly + SecAuditLogRelevantStatus "^(?:5|4(?!04))" + SecAuditLogParts ABIJDEFHZ + SecAuditLogType Serial + SecArgumentSeparator & + SecCookieFormat 0 +<%- if scope.lookupvar('::osfamily') == 'Debian' -%> + SecDebugLog /var/log/apache2/modsec_debug.log + SecAuditLog /var/log/apache2/modsec_audit.log + SecTmpDir /var/cache/modsecurity + SecDataDir /var/cache/modsecurity +<% else -%> + SecDebugLog /var/log/httpd/modsec_debug.log + SecAuditLog /var/log/httpd/modsec_audit.log + SecTmpDir /var/lib/mod_security + SecDataDir /var/lib/mod_security +<% end -%> + diff --git a/3rdparty/modules/apache/templates/mod/security_crs.conf.erb b/3rdparty/modules/apache/templates/mod/security_crs.conf.erb new file mode 100644 index 000000000..016efc797 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/security_crs.conf.erb @@ -0,0 +1,428 @@ +# --------------------------------------------------------------- +# Core ModSecurity Rule Set ver.2.2.6 +# Copyright (C) 2006-2012 Trustwave All rights reserved. +# +# The OWASP ModSecurity Core Rule Set is distributed under +# Apache Software License (ASL) version 2 +# Please see the enclosed LICENCE file for full details. +# --------------------------------------------------------------- + + +# +# -- [[ Recommended Base Configuration ]] ------------------------------------------------- +# +# The configuration directives/settings in this file are used to control +# the OWASP ModSecurity CRS. These settings do **NOT** configure the main +# ModSecurity settings such as: +# +# - SecRuleEngine +# - SecRequestBodyAccess +# - SecAuditEngine +# - SecDebugLog +# +# You should use the modsecurity.conf-recommended file that comes with the +# ModSecurity source code archive. +# +# Ref: http://mod-security.svn.sourceforge.net/viewvc/mod-security/m2/trunk/modsecurity.conf-recommended +# + + +# +# -- [[ Rule Version ]] ------------------------------------------------------------------- +# +# Rule version data is added to the "Producer" line of Section H of the Audit log: +# +# - Producer: ModSecurity for Apache/2.7.0-rc1 (http://www.modsecurity.org/); OWASP_CRS/2.2.4. +# +# Ref: https://sourceforge.net/apps/mediawiki/mod-security/index.php?title=Reference_Manual#SecComponentSignature +# +SecComponentSignature "OWASP_CRS/2.2.6" + + +# +# -- [[ Modes of Operation: Self-Contained vs. Collaborative Detection ]] ----------------- +# +# Each detection rule uses the "block" action which will inherit the SecDefaultAction +# specified below. Your settings here will determine which mode of operation you use. +# +# -- [[ Self-Contained Mode ]] -- +# Rules inherit the "deny" disruptive action. The first rule that matches will block. +# +# -- [[ Collaborative Detection Mode ]] -- +# This is a "delayed blocking" mode of operation where each matching rule will inherit +# the "pass" action and will only contribute to anomaly scores. Transactional blocking +# can be applied +# +# -- [[ Alert Logging Control ]] -- +# You have three options - +# +# - To log to both the Apache error_log and ModSecurity audit_log file use: "log" +# - To log *only* to the ModSecurity audit_log file use: "nolog,auditlog" +# - To log *only* to the Apache error_log file use: "log,noauditlog" +# +# Ref: http://blog.spiderlabs.com/2010/11/advanced-topic-of-the-week-traditional-vs-anomaly-scoring-detection-modes.html +# Ref: https://sourceforge.net/apps/mediawiki/mod-security/index.php?title=Reference_Manual#SecDefaultAction +# +SecDefaultAction "phase:1,deny,log" + + +# +# -- [[ Collaborative Detection Severity Levels ]] ---------------------------------------- +# +# These are the default scoring points for each severity level. You may +# adjust these to you liking. These settings will be used in macro expansion +# in the rules to increment the anomaly scores when rules match. +# +# These are the default Severity ratings (with anomaly scores) of the individual rules - +# +# - 2: Critical - Anomaly Score of 5. +# Is the highest severity level possible without correlation. It is +# normally generated by the web attack rules (40 level files). +# - 3: Error - Anomaly Score of 4. +# Is generated mostly from outbound leakage rules (50 level files). +# - 4: Warning - Anomaly Score of 3. +# Is generated by malicious client rules (35 level files). +# - 5: Notice - Anomaly Score of 2. +# Is generated by the Protocol policy and anomaly files. +# +SecAction \ + "id:'900001', \ + phase:1, \ + t:none, \ + setvar:tx.critical_anomaly_score=5, \ + setvar:tx.error_anomaly_score=4, \ + setvar:tx.warning_anomaly_score=3, \ + setvar:tx.notice_anomaly_score=2, \ + nolog, \ + pass" + + +# +# -- [[ Collaborative Detection Scoring Threshold Levels ]] ------------------------------ +# +# These variables are used in macro expansion in the 49 inbound blocking and 59 +# outbound blocking files. +# +# **MUST HAVE** ModSecurity v2.5.12 or higher to use macro expansion in numeric +# operators. If you have an earlier version, edit the 49/59 files directly to +# set the appropriate anomaly score levels. +# +# You should set the score to the proper threshold you would prefer. If set to "5" +# it will work similarly to previous Mod CRS rules and will create an event in the error_log +# file if there are any rules that match. If you would like to lessen the number of events +# generated in the error_log file, you should increase the anomaly score threshold to +# something like "20". This would only generate an event in the error_log file if +# there are multiple lower severity rule matches or if any 1 higher severity item matches. +# +SecAction \ + "id:'900002', \ + phase:1, \ + t:none, \ + setvar:tx.inbound_anomaly_score_level=5, \ + nolog, \ + pass" + + +SecAction \ + "id:'900003', \ + phase:1, \ + t:none, \ + setvar:tx.outbound_anomaly_score_level=4, \ + nolog, \ + pass" + + +# +# -- [[ Collaborative Detection Blocking ]] ----------------------------------------------- +# +# This is a collaborative detection mode where each rule will increment an overall +# anomaly score for the transaction. The scores are then evaluated in the following files: +# +# Inbound anomaly score - checked in the modsecurity_crs_49_inbound_blocking.conf file +# Outbound anomaly score - checked in the modsecurity_crs_59_outbound_blocking.conf file +# +# If you want to use anomaly scoring mode, then uncomment this line. +# +#SecAction \ + "id:'900004', \ + phase:1, \ + t:none, \ + setvar:tx.anomaly_score_blocking=on, \ + nolog, \ + pass" + + +# +# -- [[ GeoIP Database ]] ----------------------------------------------------------------- +# +# There are some rulesets that need to inspect the GEO data of the REMOTE_ADDR data. +# +# You must first download the MaxMind GeoIP Lite City DB - +# +# http://geolite.maxmind.com/download/geoip/database/GeoLiteCity.dat.gz +# +# You then need to define the proper path for the SecGeoLookupDb directive +# +# Ref: http://blog.spiderlabs.com/2010/10/detecting-malice-with-modsecurity-geolocation-data.html +# Ref: http://blog.spiderlabs.com/2010/11/detecting-malice-with-modsecurity-ip-forensics.html +# +#SecGeoLookupDb /opt/modsecurity/lib/GeoLiteCity.dat + +# +# -- [[ Regression Testing Mode ]] -------------------------------------------------------- +# +# If you are going to run the regression testing mode, you should uncomment the +# following rule. It will enable DetectionOnly mode for the SecRuleEngine and +# will enable Response Header tagging so that the client testing script can see +# which rule IDs have matched. +# +# You must specify the your source IP address where you will be running the tests +# from. +# +#SecRule REMOTE_ADDR "@ipMatch 192.168.1.100" \ + "id:'900005', \ + phase:1, \ + t:none, \ + ctl:ruleEngine=DetectionOnly, \ + setvar:tx.regression_testing=1, \ + nolog, \ + pass" + + +# +# -- [[ HTTP Policy Settings ]] ---------------------------------------------------------- +# +# Set the following policy settings here and they will be propagated to the 23 rules +# file (modsecurity_common_23_request_limits.conf) by using macro expansion. +# If you run into false positives, you can adjust the settings here. +# +# Only the max number of args is uncommented by default as there are a high rate +# of false positives. Uncomment the items you wish to set. +# +# +# -- Maximum number of arguments in request limited +SecAction \ + "id:'900006', \ + phase:1, \ + t:none, \ + setvar:tx.max_num_args=255, \ + nolog, \ + pass" + +# +# -- Limit argument name length +#SecAction \ + "id:'900007', \ + phase:1, \ + t:none, \ + setvar:tx.arg_name_length=100, \ + nolog, \ + pass" + +# +# -- Limit value name length +#SecAction \ + "id:'900008', \ + phase:1, \ + t:none, \ + setvar:tx.arg_length=400, \ + nolog, \ + pass" + +# +# -- Limit arguments total length +#SecAction \ + "id:'900009', \ + phase:1, \ + t:none, \ + setvar:tx.total_arg_length=64000, \ + nolog, \ + pass" + +# +# -- Individual file size is limited +#SecAction \ + "id:'900010', \ + phase:1, \ + t:none, \ + setvar:tx.max_file_size=1048576, \ + nolog, \ + pass" + +# +# -- Combined file size is limited +#SecAction \ + "id:'900011', \ + phase:1, \ + t:none, \ + setvar:tx.combined_file_sizes=1048576, \ + nolog, \ + pass" + + +# +# Set the following policy settings here and they will be propagated to the 30 rules +# file (modsecurity_crs_30_http_policy.conf) by using macro expansion. +# If you run into false positves, you can adjust the settings here. +# +SecAction \ + "id:'900012', \ + phase:1, \ + t:none, \ + setvar:'tx.allowed_methods=<%= @allowed_methods -%>', \ + setvar:'tx.allowed_request_content_type=<%= @content_types -%>', \ + setvar:'tx.allowed_http_versions=HTTP/0.9 HTTP/1.0 HTTP/1.1', \ + setvar:'tx.restricted_extensions=<%= @restricted_extensions -%>', \ + setvar:'tx.restricted_headers=<%= @restricted_headers -%>', \ + nolog, \ + pass" + + +# +# -- [[ Content Security Policy (CSP) Settings ]] ----------------------------------------- +# +# The purpose of these settings is to send CSP response headers to +# Mozilla FireFox users so that you can enforce how dynamic content +# is used. CSP usage helps to prevent XSS attacks against your users. +# +# Reference Link: +# +# https://developer.mozilla.org/en/Security/CSP +# +# Uncomment this SecAction line if you want use CSP enforcement. +# You need to set the appropriate directives and settings for your site/domain and +# and activate the CSP file in the experimental_rules directory. +# +# Ref: http://blog.spiderlabs.com/2011/04/modsecurity-advanced-topic-of-the-week-integrating-content-security-policy-csp.html +# +#SecAction \ + "id:'900013', \ + phase:1, \ + t:none, \ + setvar:tx.csp_report_only=1, \ + setvar:tx.csp_report_uri=/csp_violation_report, \ + setenv:'csp_policy=allow \'self\'; img-src *.yoursite.com; media-src *.yoursite.com; style-src *.yoursite.com; frame-ancestors *.yoursite.com; script-src *.yoursite.com; report-uri %{tx.csp_report_uri}', \ + nolog, \ + pass" + + +# +# -- [[ Brute Force Protection ]] --------------------------------------------------------- +# +# If you are using the Brute Force Protection rule set, then uncomment the following +# lines and set the following variables: +# - Protected URLs: resources to protect (e.g. login pages) - set to your login page +# - Burst Time Slice Interval: time interval window to monitor for bursts +# - Request Threshold: request # threshold to trigger a burst +# - Block Period: temporary block timeout +# +#SecAction \ + "id:'900014', \ + phase:1, \ + t:none, \ + setvar:'tx.brute_force_protected_urls=/login.jsp /partner_login.php', \ + setvar:'tx.brute_force_burst_time_slice=60', \ + setvar:'tx.brute_force_counter_threshold=10', \ + setvar:'tx.brute_force_block_timeout=300', \ + nolog, \ + pass" + + +# +# -- [[ DoS Protection ]] ---------------------------------------------------------------- +# +# If you are using the DoS Protection rule set, then uncomment the following +# lines and set the following variables: +# - Burst Time Slice Interval: time interval window to monitor for bursts +# - Request Threshold: request # threshold to trigger a burst +# - Block Period: temporary block timeout +# +#SecAction \ + "id:'900015', \ + phase:1, \ + t:none, \ + setvar:'tx.dos_burst_time_slice=60', \ + setvar:'tx.dos_counter_threshold=100', \ + setvar:'tx.dos_block_timeout=600', \ + nolog, \ + pass" + + +# +# -- [[ Check UTF enconding ]] ----------------------------------------------------------- +# +# We only want to apply this check if UTF-8 encoding is actually used by the site, otherwise +# it will result in false positives. +# +# Uncomment this line if your site uses UTF8 encoding +#SecAction \ + "id:'900016', \ + phase:1, \ + t:none, \ + setvar:tx.crs_validate_utf8_encoding=1, \ + nolog, \ + pass" + + +# +# -- [[ Enable XML Body Parsing ]] ------------------------------------------------------- +# +# The rules in this file will trigger the XML parser upon an XML request +# +# Initiate XML Processor in case of xml content-type +# +SecRule REQUEST_HEADERS:Content-Type "text/xml" \ + "id:'900017', \ + phase:1, \ + t:none,t:lowercase, \ + nolog, \ + pass, \ + chain" + SecRule REQBODY_PROCESSOR "!@streq XML" \ + "ctl:requestBodyProcessor=XML" + + +# +# -- [[ Global and IP Collections ]] ----------------------------------------------------- +# +# Create both Global and IP collections for rules to use +# There are some CRS rules that assume that these two collections +# have already been initiated. +# +SecRule REQUEST_HEADERS:User-Agent "^(.*)$" \ + "id:'900018', \ + phase:1, \ + t:none,t:sha1,t:hexEncode, \ + setvar:tx.ua_hash=%{matched_var}, \ + nolog, \ + pass" + + +SecRule REQUEST_HEADERS:x-forwarded-for "^\b(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\b" \ + "id:'900019', \ + phase:1, \ + t:none, \ + capture, \ + setvar:tx.real_ip=%{tx.1}, \ + nolog, \ + pass" + + +SecRule &TX:REAL_IP "!@eq 0" \ + "id:'900020', \ + phase:1, \ + t:none, \ + initcol:global=global, \ + initcol:ip=%{tx.real_ip}_%{tx.ua_hash}, \ + nolog, \ + pass" + + +SecRule &TX:REAL_IP "@eq 0" \ + "id:'900021', \ + phase:1, \ + t:none, \ + initcol:global=global, \ + initcol:ip=%{remote_addr}_%{tx.ua_hash}, \ + nolog, \ + pass" diff --git a/3rdparty/modules/apache/templates/mod/setenvif.conf.erb b/3rdparty/modules/apache/templates/mod/setenvif.conf.erb new file mode 100644 index 000000000..d31c79fe5 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/setenvif.conf.erb @@ -0,0 +1,34 @@ +# +# The following directives modify normal HTTP response behavior to +# handle known problems with browser implementations. +# +BrowserMatch "Mozilla/2" nokeepalive +BrowserMatch "MSIE 4\.0b2;" nokeepalive downgrade-1.0 force-response-1.0 +BrowserMatch "RealPlayer 4\.0" force-response-1.0 +BrowserMatch "Java/1\.0" force-response-1.0 +BrowserMatch "JDK/1\.0" force-response-1.0 + +# +# The following directive disables redirects on non-GET requests for +# a directory that does not include the trailing slash. This fixes a +# problem with Microsoft WebFolders which does not appropriately handle +# redirects for folders with DAV methods. +# Same deal with Apple's DAV filesystem and Gnome VFS support for DAV. +# +BrowserMatch "Microsoft Data Access Internet Publishing Provider" redirect-carefully +BrowserMatch "MS FrontPage" redirect-carefully +BrowserMatch "^WebDrive" redirect-carefully +BrowserMatch "^WebDAVFS/1.[0123]" redirect-carefully +BrowserMatch "^gnome-vfs/1.0" redirect-carefully +BrowserMatch "^gvfs/1" redirect-carefully +BrowserMatch "^XML Spy" redirect-carefully +BrowserMatch "^Dreamweaver-WebDAV-SCM1" redirect-carefully +BrowserMatch " Konqueror/4" redirect-carefully + + + BrowserMatch "MSIE [2-6]" \ + nokeepalive ssl-unclean-shutdown \ + downgrade-1.0 force-response-1.0 + # MSIE 7 and newer should be able to use keepalive + BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown + diff --git a/3rdparty/modules/apache/templates/mod/ssl.conf.erb b/3rdparty/modules/apache/templates/mod/ssl.conf.erb new file mode 100644 index 000000000..933aa1fcc --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/ssl.conf.erb @@ -0,0 +1,28 @@ + + SSLRandomSeed startup builtin + SSLRandomSeed startup file:/dev/urandom <%= @ssl_random_seed_bytes %> + SSLRandomSeed connect builtin + SSLRandomSeed connect file:/dev/urandom <%= @ssl_random_seed_bytes %> + + AddType application/x-x509-ca-cert .crt + AddType application/x-pkcs7-crl .crl + + SSLPassPhraseDialog <%= @ssl_pass_phrase_dialog %> + SSLSessionCache "shmcb:<%= @session_cache %>" + SSLSessionCacheTimeout <%= @ssl_sessioncachetimeout %> +<% if @ssl_compression -%> + SSLCompression On +<% end -%> + <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> + Mutex <%= @ssl_mutex %> + <%- else -%> + SSLMutex <%= @ssl_mutex %> + <%- end -%> + SSLCryptoDevice <%= @ssl_cryptodevice %> + SSLHonorCipherOrder <%= @ssl_honorcipherorder %> + SSLCipherSuite <%= @ssl_cipher %> + SSLProtocol <%= @ssl_protocol.compact.join(' ') %> +<% if @ssl_options -%> + SSLOptions <%= @ssl_options.compact.join(' ') %> +<% end -%> + diff --git a/3rdparty/modules/apache/templates/mod/status.conf.erb b/3rdparty/modules/apache/templates/mod/status.conf.erb new file mode 100644 index 000000000..f02ed156f --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/status.conf.erb @@ -0,0 +1,16 @@ +> + SetHandler server-status + <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> + Require ip <%= Array(@allow_from).join(" ") %> + <%- else -%> + Order deny,allow + Deny from all + Allow from <%= Array(@allow_from).join(" ") %> + <%- end -%> + +ExtendedStatus <%= @extended_status %> + + + # Show Proxy LoadBalancer status in mod_status + ProxyStatus On + diff --git a/3rdparty/modules/apache/templates/mod/suphp.conf.erb b/3rdparty/modules/apache/templates/mod/suphp.conf.erb new file mode 100644 index 000000000..95fbf97c7 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/suphp.conf.erb @@ -0,0 +1,19 @@ + + AddType application/x-httpd-suphp .php .php3 .php4 .php5 .phtml + suPHP_AddHandler application/x-httpd-suphp + + + suPHP_Engine on + + + # By default, disable suPHP for debian packaged web applications as files + # are owned by root and cannot be executed by suPHP because of min_uid. + + suPHP_Engine off + + +# # Use a specific php config file (a dir which contains a php.ini file) +# suPHP_ConfigPath /etc/php4/cgi/suphp/ +# # Tells mod_suphp NOT to handle requests with the type . +# suPHP_RemoveHandler + diff --git a/3rdparty/modules/apache/templates/mod/userdir.conf.erb b/3rdparty/modules/apache/templates/mod/userdir.conf.erb new file mode 100644 index 000000000..9032a3acc --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/userdir.conf.erb @@ -0,0 +1,27 @@ + +<% if @disable_root -%> + UserDir disabled root +<% end -%> + UserDir <%= @dir %> + + /*/<%= @dir %>"> + AllowOverride FileInfo AuthConfig Limit Indexes + Options <%= @options.join(' ') %> + + <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> + Require all granted + <%- else -%> + Order allow,deny + Allow from all + <%- end -%> + + + <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> + Require all granted + <%- else -%> + Order allow,deny + Allow from all + <%- end -%> + + + diff --git a/3rdparty/modules/apache/templates/mod/worker.conf.erb b/3rdparty/modules/apache/templates/mod/worker.conf.erb new file mode 100644 index 000000000..597e05f8d --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/worker.conf.erb @@ -0,0 +1,10 @@ + + ServerLimit <%= @serverlimit %> + StartServers <%= @startservers %> + MaxClients <%= @maxclients %> + MinSpareThreads <%= @minsparethreads %> + MaxSpareThreads <%= @maxsparethreads %> + ThreadsPerChild <%= @threadsperchild %> + MaxRequestsPerChild <%= @maxrequestsperchild %> + ThreadLimit <%= @threadlimit %> + diff --git a/3rdparty/modules/apache/templates/mod/wsgi.conf.erb b/3rdparty/modules/apache/templates/mod/wsgi.conf.erb new file mode 100644 index 000000000..18752d2c4 --- /dev/null +++ b/3rdparty/modules/apache/templates/mod/wsgi.conf.erb @@ -0,0 +1,13 @@ +# The WSGI Apache module configuration file is being +# managed by Puppet an changes will be overwritten. + + <%- if @wsgi_socket_prefix -%> + WSGISocketPrefix <%= @wsgi_socket_prefix %> + <%- end -%> + <%- if @wsgi_python_home -%> + WSGIPythonHome "<%= @wsgi_python_home %>" + <%- end -%> + <%- if @wsgi_python_path -%> + WSGIPythonPath "<%= @wsgi_python_path %>" + <%- end -%> + diff --git a/3rdparty/modules/apache/templates/namevirtualhost.erb b/3rdparty/modules/apache/templates/namevirtualhost.erb new file mode 100644 index 000000000..cf767680f --- /dev/null +++ b/3rdparty/modules/apache/templates/namevirtualhost.erb @@ -0,0 +1,8 @@ +<%# NameVirtualHost should always be one of: + - * + - *: + - _default_: + - + - : +-%> +NameVirtualHost <%= @addr_port %> diff --git a/3rdparty/modules/apache/templates/ports_header.erb b/3rdparty/modules/apache/templates/ports_header.erb new file mode 100644 index 000000000..4908db4ad --- /dev/null +++ b/3rdparty/modules/apache/templates/ports_header.erb @@ -0,0 +1,5 @@ +# ************************************ +# Listen & NameVirtualHost resources in module puppetlabs-apache +# Managed by Puppet +# ************************************ + diff --git a/3rdparty/modules/apache/templates/vhost/_access_log.erb b/3rdparty/modules/apache/templates/vhost/_access_log.erb new file mode 100644 index 000000000..d1ec426a4 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_access_log.erb @@ -0,0 +1,21 @@ +<% @_access_logs.each do |log| -%> +<% env ||= "env=#{log['env']}" if log['env'] -%> +<% env ||= '' -%> +<% format ||= "\"#{log['format']}\"" if log['format'] -%> +<% format ||= 'combined' -%> +<% if log['file'] -%> +<% if log['file'].chars.first == '/' -%> +<% destination = "#{log['file']}" -%> +<% else -%> +<% destination = "#{@logroot}/#{log['file']}" -%> +<% end -%> +<% elsif log['syslog'] -%> +<% destination = "syslog" -%> +<% elsif log['pipe'] -%> +<% destination = log['pipe'] -%> +<% else -%> +<% destination ||= "#{@logroot}/#{@name}_access_ssl.log" if @ssl -%> +<% destination ||= "#{@logroot}/#{@name}_access.log" -%> +<% end -%> + CustomLog "<%= destination %>" <%= format %> <%= env %> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_action.erb b/3rdparty/modules/apache/templates/vhost/_action.erb new file mode 100644 index 000000000..8a0229059 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_action.erb @@ -0,0 +1,4 @@ +<% if @action -%> + + Action <%= @action %> /cgi-bin virtual +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_additional_includes.erb b/3rdparty/modules/apache/templates/vhost/_additional_includes.erb new file mode 100644 index 000000000..aa9f0fe35 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_additional_includes.erb @@ -0,0 +1,10 @@ +<% Array(@additional_includes).each do |include| -%> + + ## Load additional static includes +<%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 && @use_optional_includes -%> +IncludeOptional "<%= include %>" +<%- else -%> +Include "<%= include %>" +<%- end -%> + +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_aliases.erb b/3rdparty/modules/apache/templates/vhost/_aliases.erb new file mode 100644 index 000000000..f9771bc72 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_aliases.erb @@ -0,0 +1,16 @@ +<% if @aliases and ! @aliases.empty? -%> + ## Alias declarations for resources outside the DocumentRoot + <%- [@aliases].flatten.compact.each do |alias_statement| -%> + <%- if alias_statement["path"] != '' -%> + <%- if alias_statement["alias"] and alias_statement["alias"] != '' -%> + Alias <%= alias_statement["alias"] %> "<%= alias_statement["path"] %>" + <%- elsif alias_statement["aliasmatch"] and alias_statement["aliasmatch"] != '' -%> + AliasMatch <%= alias_statement["aliasmatch"] %> "<%= alias_statement["path"] %>" + <%- elsif alias_statement["scriptalias"] and alias_statement["scriptalias"] != '' -%> + ScriptAlias <%= alias_statement["scriptalias"] %> "<%= alias_statement["path"] %>" + <%- elsif alias_statement["scriptaliasmatch"] and alias_statement["scriptaliasmatch"] != '' -%> + ScriptAliasMatch <%= alias_statement["scriptaliasmatch"] %> "<%= alias_statement["path"] %>" + <%- end -%> + <%- end -%> + <%- end -%> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_allow_encoded_slashes.erb b/3rdparty/modules/apache/templates/vhost/_allow_encoded_slashes.erb new file mode 100644 index 000000000..40c73433b --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_allow_encoded_slashes.erb @@ -0,0 +1,4 @@ +<%- if @allow_encoded_slashes -%> + + AllowEncodedSlashes <%= @allow_encoded_slashes %> +<%- end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_block.erb b/3rdparty/modules/apache/templates/vhost/_block.erb new file mode 100644 index 000000000..d0776829d --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_block.erb @@ -0,0 +1,14 @@ +<% if @block and ! @block.empty? -%> + + ## Block access statements +<% if @block.include? 'scm' -%> + # Block access to SCM directories. + + <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> + Require all denied + <%- else -%> + Deny From All + <%- end -%> + +<% end -%> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_charsets.erb b/3rdparty/modules/apache/templates/vhost/_charsets.erb new file mode 100644 index 000000000..ef83def4b --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_charsets.erb @@ -0,0 +1,4 @@ +<% if @add_default_charset -%> + + AddDefaultCharset <%= @add_default_charset %> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_custom_fragment.erb b/3rdparty/modules/apache/templates/vhost/_custom_fragment.erb new file mode 100644 index 000000000..973964655 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_custom_fragment.erb @@ -0,0 +1,5 @@ +<% if @custom_fragment -%> + + ## Custom fragment +<%= @custom_fragment %> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_directories.erb b/3rdparty/modules/apache/templates/vhost/_directories.erb new file mode 100644 index 000000000..529d9bdff --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_directories.erb @@ -0,0 +1,261 @@ +<% if @_directories and ! @_directories.empty? -%> + + ## Directories, there should at least be a declaration for <%= @docroot %> + <%- [@_directories].flatten.compact.each do |directory| -%> + <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> + <%- if directory['allow'] and ! [ false, 'false', '' ].include?(directory['allow']) -%> + <%- scope.function_warning(["Apache::Vhost: Using allow is deprecated in your Apache version"]) -%> + <%- end -%> + <%- if directory['deny'] and ! [ false, 'false', '' ].include?(directory['deny']) -%> + <%- scope.function_warning(["Apache::Vhost: Using deny is deprecated in your Apache version"]) -%> + <%- end -%> + <%- if directory['order'] and ! [ false, 'false', '' ].include?(directory['order']) -%> + <%- scope.function_warning(["Apache::Vhost: Using order is deprecated in your Apache version"]) -%> + <%- end -%> + <%- if directory['satisfy'] and ! [ false, 'false', '' ].include?(directory['satisfy']) -%> + <%- scope.function_warning(["Apache::Vhost: Using satisfy is deprecated in your Apache version"]) -%> + <%- end -%> + <%- end -%> + <%- if directory['path'] and directory['path'] != '' -%> + <%- if directory['provider'] and directory['provider'].match('(directory|location|files)') -%> + <%- if /^(.*)match$/ =~ directory['provider'] -%> + <%- provider = $1.capitalize + 'Match' -%> + <%- else -%> + <%- provider = directory['provider'].capitalize -%> + <%- end -%> + <%- else -%> + <%- provider = 'Directory' -%> + <%- end -%> + <%- path = directory['path'] -%> + + <<%= provider %> "<%= path %>"> + <%- if directory['headers'] -%> + <%- Array(directory['headers']).each do |header| -%> + Header <%= header %> + <%- end -%> + <%- end -%> + <%- if ! directory['geoip_enable'].nil? -%> + GeoIPEnable <%= scope.function_bool2httpd([directory['geoip_enable']]) %> + <%- end -%> + <%- if directory['options'] -%> + Options <%= Array(directory['options']).join(' ') %> + <%- end -%> + <%- if provider == 'Directory' -%> + <%- if directory['index_options'] -%> + IndexOptions <%= Array(directory['index_options']).join(' ') %> + <%- end -%> + <%- if directory['index_order_default'] -%> + IndexOrderDefault <%= Array(directory['index_order_default']).join(' ') %> + <%- end -%> + <%- if directory['index_style_sheet'] -%> + IndexStyleSheet '<%= directory['index_style_sheet'] %>' + <%- end -%> + <%- if directory['allow_override'] -%> + AllowOverride <%= Array(directory['allow_override']).join(' ') %> + <%- elsif provider == 'Directory' -%> + AllowOverride None + <%- end -%> + <%- end -%> + <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> + <%- if directory['require'] and directory['require'] != '' -%> + <%- Array(directory['require']).each do |req| -%> + Require <%= req %> + <%- end -%> + <%- end -%> + <%- if directory['auth_require'] -%> + Require <%= directory['auth_require'] %> + <%- end -%> + <%- if !(directory['require'] and directory['require'] != '') && !(directory['auth_require']) -%> + Require all granted + <%- end -%> + <%- else -%> + <%- if directory['auth_require'] -%> + Require <%= directory['auth_require'] %> + <%- end -%> + <%- if directory['order'] and directory['order'] != '' -%> + Order <%= Array(directory['order']).join(',') %> + <%- else -%> + Order allow,deny + <%- end -%> + <%- if directory['deny'] and ! [ false, 'false', '' ].include?(directory['deny']) -%> + <%- if directory['deny'].kind_of?(Array) -%> + <%- Array(directory['deny']).each do |restrict| -%> + Deny <%= restrict %> + <%- end -%> + <%- else -%> + Deny <%= directory['deny'] %> + <%- end -%> + <%- end -%> + <%- if directory['allow'] and ! [ false, 'false', '' ].include?(directory['allow']) -%> + <%- if directory['allow'].kind_of?(Array) -%> + <%- Array(directory['allow']).each do |access| -%> + Allow <%= access %> + <%- end -%> + <%- else -%> + Allow <%= directory['allow'] %> + <%- end -%> + <%- elsif [ 'from all', 'from All' ].include?(directory['deny']) -%> + <%- elsif ! directory['deny'] and [ false, 'false', '' ].include?(directory['allow']) -%> + Deny from all + <%- else -%> + Allow from all + <%- end -%> + <%- if directory['satisfy'] and directory['satisfy'] != '' -%> + Satisfy <%= directory['satisfy'] %> + <%- end -%> + <%- end -%> + <%- if directory['addhandlers'] and ! directory['addhandlers'].empty? -%> + <%- [directory['addhandlers']].flatten.compact.each do |addhandler| -%> + AddHandler <%= addhandler['handler'] %> <%= Array(addhandler['extensions']).join(' ') %> + <%- end -%> + <%- end -%> + <%- if directory['sethandler'] and directory['sethandler'] != '' -%> + SetHandler <%= directory['sethandler'] %> + <%- end -%> + <%- if directory['passenger_enabled'] and directory['passenger_enabled'] != '' -%> + PassengerEnabled <%= directory['passenger_enabled'] %> + <%- end -%> + <%- if directory['php_flags'] and ! directory['php_flags'].empty? -%> + <%- directory['php_flags'].sort.each do |flag,value| -%> + <%- value = if value =~ /true|yes|on|1/i then 'on' else 'off' end -%> + php_flag <%= "#{flag} #{value}" %> + <%- end -%> + <%- end -%> + <%- if directory['php_values'] and ! directory['php_values'].empty? -%> + <%- directory['php_values'].sort.each do |key,value| -%> + php_value <%= "#{key} #{value}" %> + <%- end -%> + <%- end -%> + <%- if directory['php_admin_flags'] and ! directory['php_admin_flags'].empty? -%> + <%- directory['php_admin_flags'].sort.each do |flag,value| -%> + <%- value = if value =~ /true|yes|on|1/i then 'on' else 'off' end -%> + php_admin_flag <%= "#{flag} #{value}" %> + <%- end -%> + <%- end -%> + <%- if directory['php_admin_values'] and ! directory['php_admin_values'].empty? -%> + <%- directory['php_admin_values'].sort.each do |key,value| -%> + php_admin_value <%= "#{key} #{value}" %> + <%- end -%> + <%- end -%> + <%- if directory['directoryindex'] and directory['directoryindex'] != '' -%> + DirectoryIndex <%= directory['directoryindex'] %> + <%- end -%> + <%- if directory['error_documents'] and ! directory['error_documents'].empty? -%> + <%- [directory['error_documents']].flatten.compact.each do |error_document| -%> + ErrorDocument <%= error_document['error_code'] %> <%= error_document['document'] %> + <%- end -%> + <%- end -%> + <%- if directory['auth_type'] -%> + AuthType <%= directory['auth_type'] %> + <%- end -%> + <%- if directory['auth_name'] -%> + AuthName "<%= directory['auth_name'] %>" + <%- end -%> + <%- if directory['auth_digest_algorithm'] -%> + AuthDigestAlgorithm <%= directory['auth_digest_algorithm'] %> + <%- end -%> + <%- if directory['auth_digest_domain'] -%> + AuthDigestDomain <%= Array(directory['auth_digest_domain']).join(' ') %> + <%- end -%> + <%- if directory['auth_digest_nonce_lifetime'] -%> + AuthDigestNonceLifetime <%= directory['auth_digest_nonce_lifetime'] %> + <%- end -%> + <%- if directory['auth_digest_provider'] -%> + AuthDigestProvider <%= directory['auth_digest_provider'] %> + <%- end -%> + <%- if directory['auth_digest_qop'] -%> + AuthDigestQop <%= directory['auth_digest_qop'] %> + <%- end -%> + <%- if directory['auth_digest_shmem_size'] -%> + AuthDigestShmemSize <%= directory['auth_digest_shmem_size'] %> + <%- end -%> + <%- if directory['auth_basic_authoritative'] -%> + AuthBasicAuthoritative <%= directory['auth_basic_authoritative'] %> + <%- end -%> + <%- if directory['auth_basic_fake'] -%> + AuthBasicFake <%= directory['auth_basic_fake'] %> + <%- end -%> + <%- if directory['auth_basic_provider'] -%> + AuthBasicProvider <%= directory['auth_basic_provider'] %> + <%- end -%> + <%- if directory['auth_user_file'] -%> + AuthUserFile <%= directory['auth_user_file'] %> + <%- end -%> + <%- if directory['auth_group_file'] -%> + AuthGroupFile <%= directory['auth_group_file'] %> + <%- end -%> + <%- if directory['fallbackresource'] -%> + FallbackResource <%= directory['fallbackresource'] %> + <%- end -%> + <%- if directory['expires_active'] -%> + ExpiresActive <%= directory['expires_active'] %> + <%- end -%> + <%- if directory['expires_default'] -%> + ExpiresDefault <%= directory['expires_default'] %> + <%- end -%> + <%- if directory['expires_by_type'] -%> + <%- Array(directory['expires_by_type']).each do |rule| -%> + ExpiresByType <%= rule %> + <%- end -%> + <%- end -%> + <%- if directory['force_type'] -%> + ForceType <%= directory['force_type'] %> + <%- end -%> + <%- if directory['ssl_options'] -%> + SSLOptions <%= Array(directory['ssl_options']).join(' ') %> + <%- end -%> + <%- if directory['suphp'] and @suphp_engine == 'on' -%> + suPHP_UserGroup <%= directory['suphp']['user'] %> <%= directory['suphp']['group'] %> + <%- end -%> + <%- if directory['fcgiwrapper'] -%> + FcgidWrapper <%= directory['fcgiwrapper']['command'] %> <%= directory['fcgiwrapper']['suffix'] %> <%= directory['fcgiwrapper']['virtual'] %> + <%- end -%> + <%- if directory['rewrites'] -%> + # Rewrite rules + RewriteEngine On + <%- directory['rewrites'].flatten.compact.each do |rewrite_details| -%> + <%- if rewrite_details['comment'] -%> + #<%= rewrite_details['comment'] %> + <%- end -%> + <%- if rewrite_details['rewrite_base'] -%> + RewriteBase <%= rewrite_details['rewrite_base'] %> + <%- end -%> + <%- if rewrite_details['rewrite_cond'] -%> + <%- Array(rewrite_details['rewrite_cond']).each do |commands| -%> + <%- Array(commands).each do |command| -%> + RewriteCond <%= command %> + <%- end -%> + <%- end -%> + <%- end -%> + <%- Array(rewrite_details['rewrite_rule']).each do |commands| -%> + <%- Array(commands).each do |command| -%> + RewriteRule <%= command %> + <%- end -%> + <%- end -%> + <%- end -%> + <%- end -%> + <%- if directory['setenv'] -%> + <%- Array(directory['setenv']).each do |setenv| -%> + SetEnv <%= setenv %> + <%- end -%> + <%- end -%> + <%- if @shibboleth_enabled -%> + <%- if directory['shib_require_session'] and ! directory['shib_require_session'].empty? -%> + ShibRequireSession <%= directory['shib_require_session'] %> + <%- end -%> + <%- if directory['shib_request_settings'] and ! directory['shib_request_settings'].empty? -%> + <%- directory['shib_request_settings'].each do |key,value| -%> + ShibRequestSetting <%= key %> <%= value %> + <%- end -%> + <%- end -%> + <%- if directory['shib_use_headers'] and ! directory['shib_use_headers'].empty? -%> + ShibUseHeaders <%= directory['shib_use_headers'] %> + <%- end -%> + <%- end -%> + <%- if directory['custom_fragment'] -%> + <%= directory['custom_fragment'] %> + <%- end -%> + > + <%- end -%> + <%- end -%> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_docroot.erb b/3rdparty/modules/apache/templates/vhost/_docroot.erb new file mode 100644 index 000000000..6039fa63c --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_docroot.erb @@ -0,0 +1,7 @@ + + ## Vhost docroot +<% if @virtual_docroot -%> + VirtualDocumentRoot "<%= @virtual_docroot %>" +<% else -%> + DocumentRoot "<%= @docroot %>" +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_error_document.erb b/3rdparty/modules/apache/templates/vhost/_error_document.erb new file mode 100644 index 000000000..654e72c67 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_error_document.erb @@ -0,0 +1,7 @@ +<% if @error_documents and ! @error_documents.empty? -%> + <%- [@error_documents].flatten.compact.each do |error_document| -%> + <%- if error_document["error_code"] != '' and error_document["document"] != '' -%> + ErrorDocument <%= error_document["error_code"] %> <%= error_document["document"] %> + <%- end -%> + <%- end -%> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_fallbackresource.erb b/3rdparty/modules/apache/templates/vhost/_fallbackresource.erb new file mode 100644 index 000000000..f1e4c35dc --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_fallbackresource.erb @@ -0,0 +1,4 @@ +<% if @fallbackresource -%> + + FallbackResource <%= @fallbackresource %> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_fastcgi.erb b/3rdparty/modules/apache/templates/vhost/_fastcgi.erb new file mode 100644 index 000000000..3a2baa559 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_fastcgi.erb @@ -0,0 +1,22 @@ +<% if @fastcgi_server -%> + + FastCgiExternalServer <%= @fastcgi_server %> -socket <%= @fastcgi_socket %> +<% end -%> +<% if @fastcgi_dir -%> + + "> + Options +ExecCGI + AllowOverride All + SetHandler fastcgi-script + <%- if scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> + Require all granted + <%- else -%> + Order allow,deny + Allow From All + <%- end -%> + AuthBasicAuthoritative Off + + + AllowEncodedSlashes On + ServerSignature Off +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_file_footer.erb b/3rdparty/modules/apache/templates/vhost/_file_footer.erb new file mode 100644 index 000000000..84035efa4 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_file_footer.erb @@ -0,0 +1 @@ + diff --git a/3rdparty/modules/apache/templates/vhost/_file_header.erb b/3rdparty/modules/apache/templates/vhost/_file_header.erb new file mode 100644 index 000000000..e6f2f95e7 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_file_header.erb @@ -0,0 +1,10 @@ +# ************************************ +# Vhost template in module puppetlabs-apache +# Managed by Puppet +# ************************************ + +> + ServerName <%= @servername %> +<% if @serveradmin -%> + ServerAdmin <%= @serveradmin %> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_header.erb b/3rdparty/modules/apache/templates/vhost/_header.erb new file mode 100644 index 000000000..c0f68c825 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_header.erb @@ -0,0 +1,10 @@ +<% if @headers and ! @headers.empty? -%> + + ## Header rules + ## as per http://httpd.apache.org/docs/2.2/mod/mod_headers.html#header + <%- Array(@headers).each do |header_statement| -%> + <%- if header_statement != '' -%> + Header <%= header_statement %> + <%- end -%> + <%- end -%> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_itk.erb b/3rdparty/modules/apache/templates/vhost/_itk.erb new file mode 100644 index 000000000..803a73db7 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_itk.erb @@ -0,0 +1,29 @@ +<% if @itk and ! @itk.empty? -%> + + ## ITK statement + + <%- if @itk["user"] and @itk["group"] -%> + AssignUserId <%= @itk["user"] %> <%= @itk["group"] %> + <%- end -%> + <%- if @itk["assignuseridexpr"] -%> + AssignUserIdExpr <%= @itk["assignuseridexpr"] %> + <%- end -%> + <%- if @itk["assigngroupidexpr"] -%> + AssignGroupIdExpr <%= @itk["assigngroupidexpr"] %> + <%- end -%> + <%- if @itk["maxclientvhost"] -%> + MaxClientsVHost <%= @itk["maxclientvhost"] %> + <%- end -%> + <%- if @itk["nice"] -%> + NiceValue <%= @itk["nice"] %> + <%- end -%> + <%- if @kernelversion >= '3.5.0' -%> + <%- if @itk["limituidrange"] -%> + LimitUIDRange <%= @itk["limituidrange"] %> + <%- end -%> + <%- if @itk["limitgidrange"] -%> + LimitGIDRange <%= @itk["limitgidrange"] %> + <%- end -%> + <%- end -%> + +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_logging.erb b/3rdparty/modules/apache/templates/vhost/_logging.erb new file mode 100644 index 000000000..35a924d29 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_logging.erb @@ -0,0 +1,10 @@ +<% if @error_log or @log_level -%> + + ## Logging +<% end -%> +<% if @error_log -%> + ErrorLog "<%= @error_log_destination %>" +<% end -%> +<% if @log_level -%> + LogLevel <%= @log_level %> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_passenger.erb b/3rdparty/modules/apache/templates/vhost/_passenger.erb new file mode 100644 index 000000000..130e76935 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_passenger.erb @@ -0,0 +1,18 @@ +<% if @passenger_app_root -%> + PassengerAppRoot <%= @passenger_app_root %> +<% end -%> +<% if @passenger_app_env -%> + PassengerAppEnv <%= @passenger_app_env %> +<% end -%> +<% if @passenger_ruby -%> + PassengerRuby <%= @passenger_ruby %> +<% end -%> +<% if @passenger_min_instances -%> + PassengerMinInstances <%= @passenger_min_instances %> +<% end -%> +<% if @passenger_start_timeout -%> + PassengerStartTimeout <%= @passenger_start_timeout %> +<% end -%> +<% if @passenger_pre_start -%> + PassengerPreStart <%= @passenger_pre_start %> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_php.erb b/3rdparty/modules/apache/templates/vhost/_php.erb new file mode 100644 index 000000000..369fdb7f9 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_php.erb @@ -0,0 +1,12 @@ +<% if @php_values and not @php_values.empty? -%> + <%- @php_values.sort.each do |key,value| -%> + php_value <%= key %> <%= value %> + <%- end -%> +<% end -%> +<% if @php_flags and not @php_flags.empty? -%> + <%- @php_flags.sort.each do |key,flag| -%> + <%-# normalize flag -%> + <%- if flag =~ /true|yes|on|1/i then flag = 'on' else flag = 'off' end -%> + php_flag <%= key %> <%= flag %> + <%- end -%> +<% end -%> \ No newline at end of file diff --git a/3rdparty/modules/apache/templates/vhost/_php_admin.erb b/3rdparty/modules/apache/templates/vhost/_php_admin.erb new file mode 100644 index 000000000..c0c8dd60a --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_php_admin.erb @@ -0,0 +1,12 @@ +<% if @php_admin_values and not @php_admin_values.empty? -%> + <%- @php_admin_values.sort.each do |key,value| -%> + php_admin_value <%= key %> <%= value %> + <%- end -%> +<% end -%> +<% if @php_admin_flags and not @php_admin_flags.empty? -%> + <%- @php_admin_flags.sort.each do |key,flag| -%> + <%-# normalize flag -%> + <%- if flag =~ /true|yes|on|1/i then flag = 'on' else flag = 'off' end -%> + php_admin_flag <%= key %> <%= flag %> + <%- end -%> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_proxy.erb b/3rdparty/modules/apache/templates/vhost/_proxy.erb new file mode 100644 index 000000000..f290fcb76 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_proxy.erb @@ -0,0 +1,75 @@ +<% if @proxy_dest or @proxy_pass -%> + + ## Proxy rules + ProxyRequests Off +<%- end -%> +<% if @proxy_preserve_host -%> + ProxyPreserveHost On +<%- end -%> +<% if @proxy_error_override -%> + ProxyErrorOverride On +<%- end -%> +<%- [@proxy_pass].flatten.compact.each do |proxy| -%> + ProxyPass <%= proxy['path'] %> <%= proxy['url'] -%> + <%- if proxy['params'] -%> + <%- proxy['params'].each_pair do |key, value| -%> <%= key %>=<%= value -%> + <%- end -%> + <%- end -%> + <%- if proxy['keywords'] %> <%= proxy['keywords'].join(' ') -%> + <%- end %> + > + <%- if proxy['reverse_urls'].nil? -%> + ProxyPassReverse <%= proxy['url'] %> + <%- else -%> + <%- Array(proxy['reverse_urls']).each do |reverse_url| -%> + ProxyPassReverse <%= reverse_url %> + <%- end -%> + <%- end -%> + <%- if proxy['setenv'] -%> + <%- Array(proxy['setenv']).each do |setenv_var| -%> + SetEnv <%= setenv_var %> + <%- end -%> + <%- end -%> + +<% end -%> +<% [@proxy_pass_match].flatten.compact.each do |proxy| %> + ProxyPassMatch <%= proxy['path'] %> <%= proxy['url'] %> + <%- if proxy['params'] -%> + <%- proxy['params'].each_pair do |key, value| -%> <%= key %>=<%= value -%> + <%- end -%> + <%- end -%> + <%- if proxy['keywords'] %> <%= proxy['keywords'].join(' ') -%> + <%- end %> + > + <%- if proxy['reverse_urls'].nil? -%> + ProxyPassReverse <%= proxy['url'] %> + <%- else -%> + <%- Array(proxy['reverse_urls']).each do |reverse_url| -%> + ProxyPassReverse <%= reverse_url %> + <%- end -%> + <%- end -%> + <%- if proxy['setenv'] -%> + <%- Array(proxy['setenv']).each do |setenv_var| -%> + SetEnv <%= setenv_var -%> + <%- end -%> + <%- end -%> + +<% end -%> +<% if @proxy_dest -%> +<%- Array(@no_proxy_uris).each do |uri| -%> + ProxyPass <%= uri %> ! +<% end -%> + ProxyPass / <%= @proxy_dest %>/ + + ProxyPassReverse <%= @proxy_dest %>/ + +<% end -%> +<% if @proxy_dest_match -%> +<%- Array(@no_proxy_uris_match).each do |uri| -%> + ProxyPassMatch <%= uri %> ! +<% end -%> + ProxyPassMatch / <%= @proxy_dest_match %>/ + + ProxyPassReverse <%= @proxy_dest_reverse_match %>/ + +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_rack.erb b/3rdparty/modules/apache/templates/vhost/_rack.erb new file mode 100644 index 000000000..4a5b5f1cd --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_rack.erb @@ -0,0 +1,7 @@ +<% if @rack_base_uris -%> + + ## Enable rack +<% Array(@rack_base_uris).each do |uri| -%> + RackBaseURI <%= uri %> +<% end -%> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_redirect.erb b/3rdparty/modules/apache/templates/vhost/_redirect.erb new file mode 100644 index 000000000..69bbfd09d --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_redirect.erb @@ -0,0 +1,25 @@ +<% if @redirect_source and @redirect_dest -%> +<% @redirect_dest_a = Array(@redirect_dest) -%> +<% @redirect_source_a = Array(@redirect_source) -%> +<% @redirect_status_a = Array(@redirect_status) -%> + + ## Redirect rules + <%- @redirect_source_a.each_with_index do |source, i| -%> +<% @redirect_dest_a[i] ||= @redirect_dest_a[0] -%> +<% @redirect_status_a[i] ||= @redirect_status_a[0] -%> + Redirect <%= "#{@redirect_status_a[i]} " %><%= source %> <%= @redirect_dest_a[i] %> + <%- end -%> +<% end -%> +<%- if @redirectmatch_status and @redirectmatch_regexp and @redirectmatch_dest -%> +<% @redirectmatch_status_a = Array(@redirectmatch_status) -%> +<% @redirectmatch_regexp_a = Array(@redirectmatch_regexp) -%> +<% @redirectmatch_dest_a = Array(@redirectmatch_dest) -%> + + ## RedirectMatch rules + <%- @redirectmatch_status_a.each_with_index do |status, i| -%> +<% @redirectmatch_status_a[i] ||= @redirectmatch_status_a[0] -%> +<% @redirectmatch_regexp_a[i] ||= @redirectmatch_regexp_a[0] -%> +<% @redirectmatch_dest_a[i] ||= @redirectmatch_dest_a[0] -%> + RedirectMatch <%= "#{@redirectmatch_status_a[i]} " %> <%= @redirectmatch_regexp_a[i] %> <%= @redirectmatch_dest_a[i] %> + <%- end -%> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_requestheader.erb b/3rdparty/modules/apache/templates/vhost/_requestheader.erb new file mode 100644 index 000000000..9f175052b --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_requestheader.erb @@ -0,0 +1,10 @@ +<% if @request_headers and ! @request_headers.empty? -%> + + ## Request header rules + ## as per http://httpd.apache.org/docs/2.2/mod/mod_headers.html#requestheader + <%- Array(@request_headers).each do |request_statement| -%> + <%- if request_statement != '' -%> + RequestHeader <%= request_statement %> + <%- end -%> + <%- end -%> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_rewrite.erb b/3rdparty/modules/apache/templates/vhost/_rewrite.erb new file mode 100644 index 000000000..81e3bc467 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_rewrite.erb @@ -0,0 +1,50 @@ +<%- if @rewrites -%> + ## Rewrite rules + RewriteEngine On + <%- if @rewrite_base -%> + RewriteBase <%= @rewrite_base %> + <%- end -%> + + <%- [@rewrites].flatten.compact.each do |rewrite_details| -%> + <%- if rewrite_details['comment'] -%> + #<%= rewrite_details['comment'] %> + <%- end -%> + <%- if rewrite_details['rewrite_base'] -%> + RewriteBase <%= rewrite_details['rewrite_base'] %> + <%- end -%> + <%- if rewrite_details['rewrite_cond'] -%> + <%- Array(rewrite_details['rewrite_cond']).each do |commands| -%> + <%- Array(commands).each do |command| -%> + RewriteCond <%= command %> + <%- end -%> + <%- end -%> + <%- end -%> + <%- if rewrite_details['rewrite_map'] -%> + <%- Array(rewrite_details['rewrite_map']).each do |commands| -%> + <%- Array(commands).each do |command| -%> + RewriteMap <%= command %> + <%- end -%> + <%- end -%> + <%- end -%> + <%- Array(rewrite_details['rewrite_rule']).each do |commands| -%> + <%- Array(commands).each do |command| -%> + RewriteRule <%= command %> + <%- end -%> + + <%- end -%> + <%- end -%> +<%- end -%> +<%# reverse compatibility -%> +<% if @rewrite_rule and !@rewrites -%> + ## Rewrite rules + RewriteEngine On + <%- if @rewrite_base -%> + RewriteBase <%= @rewrite_base %> + <%- end -%> + <%- if @rewrite_cond -%> + <%- Array(@rewrite_cond).each do |cond| -%> + RewriteCond <%= cond %> + <%- end -%> + <%- end -%> + RewriteRule <%= @rewrite_rule %> +<%- end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_scriptalias.erb b/3rdparty/modules/apache/templates/vhost/_scriptalias.erb new file mode 100644 index 000000000..bb4f6b316 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_scriptalias.erb @@ -0,0 +1,24 @@ +<%- if @scriptaliases.is_a?(Array) -%> +<%- aliases = @scriptaliases -%> +<%- elsif @scriptaliases.is_a?(Hash) -%> +<%- aliases = [@scriptaliases] -%> +<%- else -%> +<%- # Nothing to do with any other data type -%> +<%- aliases = [] -%> +<%- end -%> +<%- if @scriptalias or !aliases.empty? -%> + ## Script alias directives +<%# Combine scriptalais and scriptaliases into a single data structure -%> +<%# for backward compatibility and ease of implementation -%> +<%- aliases << { 'alias' => '/cgi-bin', 'path' => @scriptalias } if @scriptalias -%> +<%- aliases.flatten.compact! -%> +<%- aliases.each do |salias| -%> + <%- if salias["path"] != '' -%> + <%- if salias["alias"] and salias["alias"] != '' -%> + ScriptAlias <%= salias['alias'] %> "<%= salias['path'] %>" + <%- elsif salias["aliasmatch"] and salias["aliasmatch"] != '' -%> + ScriptAliasMatch <%= salias['aliasmatch'] %> "<%= salias['path'] %>" + <%- end -%> + <%- end -%> +<%- end -%> +<%- end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_security.erb b/3rdparty/modules/apache/templates/vhost/_security.erb new file mode 100644 index 000000000..5ab0a5b5d --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_security.erb @@ -0,0 +1,20 @@ +<% if @modsec_disable_vhost -%> + SecRuleEngine Off +<% end -%> +<% if @_modsec_disable_ids.is_a?(Hash) -%> +<% @_modsec_disable_ids.each do |location,rules| -%> + > +<% Array(rules).each do |rule| -%> + SecRuleRemoveById <%= rule %> +<% end -%> + +<% end -%> +<% end -%> +<% ips = Array(@modsec_disable_ips).join(',') %> +<% if ips != '' %> + SecRule REMOTE_ADDR "<%= ips %>" "nolog,allow,id:1234123455" + SecAction "phase:2,pass,nolog,id:1234123456" +<% end -%> +<% if @modsec_body_limit -%> + SecRequestBodyLimit <%= @modsec_body_limit %> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_serveralias.erb b/3rdparty/modules/apache/templates/vhost/_serveralias.erb new file mode 100644 index 000000000..e08a55e32 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_serveralias.erb @@ -0,0 +1,7 @@ +<% if @serveraliases and ! @serveraliases.empty? -%> + + ## Server aliases + <%- Array(@serveraliases).each do |serveralias| -%> + ServerAlias <%= serveralias %> + <%- end -%> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_serversignature.erb b/3rdparty/modules/apache/templates/vhost/_serversignature.erb new file mode 100644 index 000000000..ff13aaf45 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_serversignature.erb @@ -0,0 +1 @@ + ServerSignature Off diff --git a/3rdparty/modules/apache/templates/vhost/_setenv.erb b/3rdparty/modules/apache/templates/vhost/_setenv.erb new file mode 100644 index 000000000..ce1fa955e --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_setenv.erb @@ -0,0 +1,12 @@ +<% if @setenv and ! @setenv.empty? -%> + + ## SetEnv/SetEnvIf for environment variables + <%- Array(@setenv).each do |envvar| -%> + SetEnv <%= envvar %> + <%- end -%> +<% end -%> +<% if @setenvif and ! @setenvif.empty? -%> + <%- Array(@setenvif).each do |envifvar| -%> + SetEnvIf <%= envifvar %> + <%- end -%> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_ssl.erb b/3rdparty/modules/apache/templates/vhost/_ssl.erb new file mode 100644 index 000000000..516992558 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_ssl.erb @@ -0,0 +1,46 @@ +<% if @ssl -%> + + ## SSL directives + SSLEngine on + SSLCertificateFile "<%= @ssl_cert %>" + SSLCertificateKeyFile "<%= @ssl_key %>" + <%- if @ssl_chain -%> + SSLCertificateChainFile "<%= @ssl_chain %>" + <%- end -%> + <%- if @ssl_certs_dir && @ssl_certs_dir != '' -%> + SSLCACertificatePath "<%= @ssl_certs_dir %>" + <%- end -%> + <%- if @ssl_ca -%> + SSLCACertificateFile "<%= @ssl_ca %>" + <%- end -%> + <%- if @ssl_crl_path -%> + SSLCARevocationPath "<%= @ssl_crl_path %>" + <%- end -%> + <%- if @ssl_crl -%> + SSLCARevocationFile "<%= @ssl_crl %>" + <%- end -%> + <%- if @ssl_crl_check && scope.function_versioncmp([@apache_version, '2.4']) >= 0 -%> + SSLCARevocationCheck "<%= @ssl_crl_check %>" + <%- end -%> + <%- if @ssl_proxyengine -%> + SSLProxyEngine On + <%- end -%> + <%- if @ssl_protocol -%> + SSLProtocol <%= @ssl_protocol %> + <%- end -%> + <%- if @ssl_cipher -%> + SSLCipherSuite <%= @ssl_cipher %> + <%- end -%> + <%- if @ssl_honorcipherorder -%> + SSLHonorCipherOrder <%= @ssl_honorcipherorder %> + <%- end -%> + <%- if @ssl_verify_client -%> + SSLVerifyClient <%= @ssl_verify_client %> + <%- end -%> + <%- if @ssl_verify_depth -%> + SSLVerifyDepth <%= @ssl_verify_depth %> + <%- end -%> + <%- if @ssl_options -%> + SSLOptions <%= Array(@ssl_options).join(' ') %> + <%- end -%> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_suexec.erb b/3rdparty/modules/apache/templates/vhost/_suexec.erb new file mode 100644 index 000000000..8a7ae0f17 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_suexec.erb @@ -0,0 +1,4 @@ +<% if @suexec_user_group -%> + + SuexecUserGroup <%= @suexec_user_group %> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_suphp.erb b/3rdparty/modules/apache/templates/vhost/_suphp.erb new file mode 100644 index 000000000..e394b6f94 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_suphp.erb @@ -0,0 +1,11 @@ +<% if @suphp_engine == 'on' -%> + <%- if @suphp_addhandler -%> + suPHP_AddHandler <%= @suphp_addhandler %> + <%- end -%> + <%- if @suphp_engine -%> + suPHP_Engine <%= @suphp_engine %> + <%- end -%> + <%- if @suphp_configpath -%> + suPHP_ConfigPath "<%= @suphp_configpath %>" + <%- end -%> +<% end -%> diff --git a/3rdparty/modules/apache/templates/vhost/_wsgi.erb b/3rdparty/modules/apache/templates/vhost/_wsgi.erb new file mode 100644 index 000000000..9f01d4091 --- /dev/null +++ b/3rdparty/modules/apache/templates/vhost/_wsgi.erb @@ -0,0 +1,27 @@ +<% if @wsgi_application_group -%> + WSGIApplicationGroup <%= @wsgi_application_group %> +<% end -%> +<% if @wsgi_daemon_process and @wsgi_daemon_process_options -%> + WSGIDaemonProcess <%= @wsgi_daemon_process %> <%= @wsgi_daemon_process_options.collect { |k,v| "#{k}=#{v}"}.sort.join(' ') %> +<% elsif @wsgi_daemon_process and !@wsgi_daemon_process_options -%> + WSGIDaemonProcess <%= @wsgi_daemon_process %> +<% end -%> +<% if @wsgi_import_script and @wsgi_import_script_options -%> + WSGIImportScript <%= @wsgi_import_script %> <%= @wsgi_import_script_options.collect { |k,v| "#{k}=#{v}"}.sort.join(' ') %> +<% end -%> +<% if @wsgi_process_group -%> + WSGIProcessGroup <%= @wsgi_process_group %> +<% end -%> +<% if @wsgi_script_aliases and ! @wsgi_script_aliases.empty? -%> + <%- @wsgi_script_aliases.keys.sort.each do |key| -%> + <%- if key != '' and @wsgi_script_aliases[key] != ''-%> + WSGIScriptAlias <%= key %> "<%= @wsgi_script_aliases[key] %>" + <%- end -%> + <%- end -%> +<% end -%> +<% if @wsgi_pass_authorization -%> + WSGIPassAuthorization <%= @wsgi_pass_authorization %> +<% end -%> +<% if @wsgi_chunked_request -%> + WSGIChunkedRequest <%= @wsgi_chunked_request %> +<% end -%> diff --git a/3rdparty/modules/apache/tests/apache.pp b/3rdparty/modules/apache/tests/apache.pp new file mode 100644 index 000000000..0d4543564 --- /dev/null +++ b/3rdparty/modules/apache/tests/apache.pp @@ -0,0 +1,6 @@ +include apache +include apache::mod::php +include apache::mod::cgi +include apache::mod::userdir +include apache::mod::disk_cache +include apache::mod::proxy_http diff --git a/3rdparty/modules/apache/tests/dev.pp b/3rdparty/modules/apache/tests/dev.pp new file mode 100644 index 000000000..6c4f95571 --- /dev/null +++ b/3rdparty/modules/apache/tests/dev.pp @@ -0,0 +1 @@ +include apache::mod::dev diff --git a/3rdparty/modules/apache/tests/init.pp b/3rdparty/modules/apache/tests/init.pp new file mode 100644 index 000000000..b3f9f13aa --- /dev/null +++ b/3rdparty/modules/apache/tests/init.pp @@ -0,0 +1 @@ +include apache diff --git a/3rdparty/modules/apache/tests/mod_load_params.pp b/3rdparty/modules/apache/tests/mod_load_params.pp new file mode 100644 index 000000000..0e84c5efb --- /dev/null +++ b/3rdparty/modules/apache/tests/mod_load_params.pp @@ -0,0 +1,11 @@ +# Tests the path and identifier parameters for the apache::mod class + +# Base class for clarity: +class { 'apache': } + + +# Exaple parameter usage: +apache::mod { 'testmod': + path => '/usr/some/path/mod_testmod.so', + id => 'testmod_custom_name', +} diff --git a/3rdparty/modules/apache/tests/mods.pp b/3rdparty/modules/apache/tests/mods.pp new file mode 100644 index 000000000..59362bd9a --- /dev/null +++ b/3rdparty/modules/apache/tests/mods.pp @@ -0,0 +1,9 @@ +## Default mods + +# Base class. Declares default vhost on port 80 and default ssl +# vhost on port 443 listening on all interfaces and serving +# $apache::docroot, and declaring our default set of modules. +class { 'apache': + default_mods => true, +} + diff --git a/3rdparty/modules/apache/tests/mods_custom.pp b/3rdparty/modules/apache/tests/mods_custom.pp new file mode 100644 index 000000000..0ae699c73 --- /dev/null +++ b/3rdparty/modules/apache/tests/mods_custom.pp @@ -0,0 +1,16 @@ +## custom mods + +# Base class. Declares default vhost on port 80 and default ssl +# vhost on port 443 listening on all interfaces and serving +# $apache::docroot, and declaring a custom set of modules. +class { 'apache': + default_mods => [ + 'info', + 'alias', + 'mime', + 'env', + 'setenv', + 'expires', + ], +} + diff --git a/3rdparty/modules/apache/tests/php.pp b/3rdparty/modules/apache/tests/php.pp new file mode 100644 index 000000000..1d926bfb4 --- /dev/null +++ b/3rdparty/modules/apache/tests/php.pp @@ -0,0 +1,4 @@ +class { 'apache': + mpm_module => 'prefork', +} +include apache::mod::php diff --git a/3rdparty/modules/apache/tests/vhost.pp b/3rdparty/modules/apache/tests/vhost.pp new file mode 100644 index 000000000..a46b67784 --- /dev/null +++ b/3rdparty/modules/apache/tests/vhost.pp @@ -0,0 +1,253 @@ +## Default vhosts, and custom vhosts +# NB: Please see the other vhost_*.pp example files for further +# examples. + +# Base class. Declares default vhost on port 80 and default ssl +# vhost on port 443 listening on all interfaces and serving +# $apache::docroot +class { 'apache': } + +# Most basic vhost +apache::vhost { 'first.example.com': + port => '80', + docroot => '/var/www/first', +} + +# Vhost with different docroot owner/group/mode +apache::vhost { 'second.example.com': + port => '80', + docroot => '/var/www/second', + docroot_owner => 'third', + docroot_group => 'third', + docroot_mode => '0770', +} + +# Vhost with serveradmin +apache::vhost { 'third.example.com': + port => '80', + docroot => '/var/www/third', + serveradmin => 'admin@example.com', +} + +# Vhost with ssl (uses default ssl certs) +apache::vhost { 'ssl.example.com': + port => '443', + docroot => '/var/www/ssl', + ssl => true, +} + +# Vhost with ssl and specific ssl certs +apache::vhost { 'fourth.example.com': + port => '443', + docroot => '/var/www/fourth', + ssl => true, + ssl_cert => '/etc/ssl/fourth.example.com.cert', + ssl_key => '/etc/ssl/fourth.example.com.key', +} + +# Vhost with english title and servername parameter +apache::vhost { 'The fifth vhost': + servername => 'fifth.example.com', + port => '80', + docroot => '/var/www/fifth', +} + +# Vhost with server aliases +apache::vhost { 'sixth.example.com': + serveraliases => [ + 'sixth.example.org', + 'sixth.example.net', + ], + port => '80', + docroot => '/var/www/fifth', +} + +# Vhost with alternate options +apache::vhost { 'seventh.example.com': + port => '80', + docroot => '/var/www/seventh', + options => [ + 'Indexes', + 'MultiViews', + ], +} + +# Vhost with AllowOverride for .htaccess +apache::vhost { 'eighth.example.com': + port => '80', + docroot => '/var/www/eighth', + override => 'All', +} + +# Vhost with access and error logs disabled +apache::vhost { 'ninth.example.com': + port => '80', + docroot => '/var/www/ninth', + access_log => false, + error_log => false, +} + +# Vhost with custom access and error logs and logroot +apache::vhost { 'tenth.example.com': + port => '80', + docroot => '/var/www/tenth', + access_log_file => 'tenth_vhost.log', + error_log_file => 'tenth_vhost_error.log', + logroot => '/var/log', +} + +# Vhost with a cgi-bin +apache::vhost { 'eleventh.example.com': + port => '80', + docroot => '/var/www/eleventh', + scriptalias => '/usr/lib/cgi-bin', +} + +# Vhost with a proxypass configuration +apache::vhost { 'twelfth.example.com': + port => '80', + docroot => '/var/www/twelfth', + proxy_dest => 'http://internal.example.com:8080/twelfth', + no_proxy_uris => ['/login','/logout'], +} + +# Vhost to redirect /login and /logout +apache::vhost { 'thirteenth.example.com': + port => '80', + docroot => '/var/www/thirteenth', + redirect_source => [ + '/login', + '/logout', + ], + redirect_dest => [ + 'http://10.0.0.10/login', + 'http://10.0.0.10/logout', + ], +} + +# Vhost to permamently redirect +apache::vhost { 'fourteenth.example.com': + port => '80', + docroot => '/var/www/fourteenth', + redirect_source => '/blog', + redirect_dest => 'http://blog.example.com', + redirect_status => 'permanent', +} + +# Vhost with a rack configuration +apache::vhost { 'fifteenth.example.com': + port => '80', + docroot => '/var/www/fifteenth', + rack_base_uris => ['/rackapp1', '/rackapp2'], +} + +# Vhost to redirect non-ssl to ssl +apache::vhost { 'sixteenth.example.com non-ssl': + servername => 'sixteenth.example.com', + port => '80', + docroot => '/var/www/sixteenth', + rewrites => [ + { + comment => 'redirect non-SSL traffic to SSL site', + rewrite_cond => ['%{HTTPS} off'], + rewrite_rule => ['(.*) https://%{HTTPS_HOST}%{REQUEST_URI}'], + } + ] +} + +# Rewrite a URL to lower case +apache::vhost { 'sixteenth.example.com non-ssl': + servername => 'sixteenth.example.com', + port => '80', + docroot => '/var/www/sixteenth', + rewrites => [ + { comment => 'Rewrite to lower case', + rewrite_cond => ['%{REQUEST_URI} [A-Z]'], + rewrite_map => ['lc int:tolower'], + rewrite_rule => ['(.*) ${lc:$1} [R=301,L]'], + } + ] +} + +apache::vhost { 'sixteenth.example.com ssl': + servername => 'sixteenth.example.com', + port => '443', + docroot => '/var/www/sixteenth', + ssl => true, +} + +# Vhost to redirect non-ssl to ssl using old rewrite method +apache::vhost { 'sixteenth.example.com non-ssl old rewrite': + servername => 'sixteenth.example.com', + port => '80', + docroot => '/var/www/sixteenth', + rewrite_cond => '%{HTTPS} off', + rewrite_rule => '(.*) https://%{HTTPS_HOST}%{REQUEST_URI}', +} +apache::vhost { 'sixteenth.example.com ssl old rewrite': + servername => 'sixteenth.example.com', + port => '443', + docroot => '/var/www/sixteenth', + ssl => true, +} + +# Vhost to block repository files +apache::vhost { 'seventeenth.example.com': + port => '80', + docroot => '/var/www/seventeenth', + block => 'scm', +} + +# Vhost with special environment variables +apache::vhost { 'eighteenth.example.com': + port => '80', + docroot => '/var/www/eighteenth', + setenv => ['SPECIAL_PATH /foo/bin','KILROY was_here'], +} + +apache::vhost { 'nineteenth.example.com': + port => '80', + docroot => '/var/www/nineteenth', + setenvif => 'Host "^([^\.]*)\.website\.com$" CLIENT_NAME=$1', +} + +# Vhost with additional include files +apache::vhost { 'twentyieth.example.com': + port => '80', + docroot => '/var/www/twelfth', + additional_includes => ['/tmp/proxy_group_a','/tmp/proxy_group_b'], +} + +# Vhost with alias for subdomain mapped to same named directory +# http://example.com.loc => /var/www/example.com +apache::vhost { 'subdomain.loc': + vhost_name => '*', + port => '80', + virtual_docroot => '/var/www/%-2+', + docroot => '/var/www', + serveraliases => ['*.loc',], +} + +# Vhost with SSLProtocol,SSLCipherSuite, SSLHonorCipherOrder +apache::vhost { 'securedomain.com': + priority => '10', + vhost_name => 'www.securedomain.com', + port => '443', + docroot => '/var/www/secure', + ssl => true, + ssl_cert => '/etc/ssl/securedomain.cert', + ssl_key => '/etc/ssl/securedomain.key', + ssl_chain => '/etc/ssl/securedomain.crt', + ssl_protocol => '-ALL +SSLv3 +TLSv1', + ssl_cipher => 'ALL:!aNULL:!ADH:!eNULL:!LOW:!EXP:RC4+RSA:+HIGH:+MEDIUM', + ssl_honorcipherorder => 'On', + add_listen => false, +} + +# Vhost with access log environment variables writing control +apache::vhost { 'twentyfirst.example.com': + port => '80', + docroot => '/var/www/twentyfirst', + access_log_env_var => 'admin', +} + diff --git a/3rdparty/modules/apache/tests/vhost_directories.pp b/3rdparty/modules/apache/tests/vhost_directories.pp new file mode 100644 index 000000000..b8953ee32 --- /dev/null +++ b/3rdparty/modules/apache/tests/vhost_directories.pp @@ -0,0 +1,44 @@ +# Base class. Declares default vhost on port 80 and default ssl +# vhost on port 443 listening on all interfaces and serving +# $apache::docroot +class { 'apache': } + +# Example from README adapted. +apache::vhost { 'readme.example.net': + docroot => '/var/www/readme', + directories => [ + { + 'path' => '/var/www/readme', + 'ServerTokens' => 'prod' , + }, + { + 'path' => '/usr/share/empty', + 'allow' => 'from all', + }, + ], +} + +# location test +apache::vhost { 'location.example.net': + docroot => '/var/www/location', + directories => [ + { + 'path' => '/location', + 'provider' => 'location', + 'ServerTokens' => 'prod' + }, + ], +} + +# files test, curedly disable access to accidental backup files. +apache::vhost { 'files.example.net': + docroot => '/var/www/files', + directories => [ + { + 'path' => '(\.swp|\.bak|~)$', + 'provider' => 'filesmatch', + 'deny' => 'from all' + }, + ], +} + diff --git a/3rdparty/modules/apache/tests/vhost_ip_based.pp b/3rdparty/modules/apache/tests/vhost_ip_based.pp new file mode 100644 index 000000000..dc0fa4f33 --- /dev/null +++ b/3rdparty/modules/apache/tests/vhost_ip_based.pp @@ -0,0 +1,25 @@ +## IP-based vhosts on any listen port +# IP-based vhosts respond to requests on specific IP addresses. + +# Base class. Turn off the default vhosts; we will be declaring +# all vhosts below. +class { 'apache': + default_vhost => false, +} + +# Listen on port 80 and 81; required because the following vhosts +# are not declared with a port parameter. +apache::listen { '80': } +apache::listen { '81': } + +# IP-based vhosts +apache::vhost { 'first.example.com': + ip => '10.0.0.10', + docroot => '/var/www/first', + ip_based => true, +} +apache::vhost { 'second.example.com': + ip => '10.0.0.11', + docroot => '/var/www/second', + ip_based => true, +} diff --git a/3rdparty/modules/apache/tests/vhost_proxypass.pp b/3rdparty/modules/apache/tests/vhost_proxypass.pp new file mode 100644 index 000000000..e911f85f9 --- /dev/null +++ b/3rdparty/modules/apache/tests/vhost_proxypass.pp @@ -0,0 +1,66 @@ +## vhost with proxyPass directive +# NB: Please see the other vhost_*.pp example files for further +# examples. + +# Base class. Declares default vhost on port 80 and default ssl +# vhost on port 443 listening on all interfaces and serving +# $apache::docroot +class { 'apache': } + +# Most basic vhost with proxy_pass +apache::vhost { 'first.example.com': + port => 80, + docroot => '/var/www/first', + proxy_pass => [ + { + 'path' => '/first', + 'url' => 'http://localhost:8080/first' + }, + ], +} + +# vhost with proxy_pass and parameters +apache::vhost { 'second.example.com': + port => 80, + docroot => '/var/www/second', + proxy_pass => [ + { + 'path' => '/second', + 'url' => 'http://localhost:8080/second', + 'params' => { + 'retry' => '0', + 'timeout' => '5' + } + }, + ], +} + +# vhost with proxy_pass and keywords +apache::vhost { 'third.example.com': + port => 80, + docroot => '/var/www/third', + proxy_pass => [ + { + 'path' => '/third', + 'url' => 'http://localhost:8080/third', + 'keywords' => ['noquery', 'interpolate'] + }, + ], +} + +# vhost with proxy_pass, parameters and keywords +apache::vhost { 'fourth.example.com': + port => 80, + docroot => '/var/www/fourth', + proxy_pass => [ + { + 'path' => '/fourth', + 'url' => 'http://localhost:8080/fourth', + 'params' => { + 'retry' => '0', + 'timeout' => '5' + }, + 'keywords' => ['noquery', 'interpolate'] + }, + ], +} diff --git a/3rdparty/modules/apache/tests/vhost_ssl.pp b/3rdparty/modules/apache/tests/vhost_ssl.pp new file mode 100644 index 000000000..8e7a2b279 --- /dev/null +++ b/3rdparty/modules/apache/tests/vhost_ssl.pp @@ -0,0 +1,23 @@ +## SSL-enabled vhosts +# SSL-enabled vhosts respond only to HTTPS queries. + +# Base class. Turn off the default vhosts; we will be declaring +# all vhosts below. +class { 'apache': + default_vhost => false, +} + +# Non-ssl vhost +apache::vhost { 'first.example.com non-ssl': + servername => 'first.example.com', + port => '80', + docroot => '/var/www/first', +} + +# SSL vhost at the same domain +apache::vhost { 'first.example.com ssl': + servername => 'first.example.com', + port => '443', + docroot => '/var/www/first', + ssl => true, +} diff --git a/3rdparty/modules/apache/tests/vhosts_without_listen.pp b/3rdparty/modules/apache/tests/vhosts_without_listen.pp new file mode 100644 index 000000000..e7d6cc036 --- /dev/null +++ b/3rdparty/modules/apache/tests/vhosts_without_listen.pp @@ -0,0 +1,53 @@ +## Declare ip-based and name-based vhosts +# Mixing Name-based vhost with IP-specific vhosts requires `add_listen => +# 'false'` on the non-IP vhosts + +# Base class. Turn off the default vhosts; we will be declaring +# all vhosts below. +class { 'apache': + default_vhost => false, +} + + +# Add two an IP-based vhost on 10.0.0.10, ssl and non-ssl +apache::vhost { 'The first IP-based vhost, non-ssl': + servername => 'first.example.com', + ip => '10.0.0.10', + port => '80', + ip_based => true, + docroot => '/var/www/first', +} +apache::vhost { 'The first IP-based vhost, ssl': + servername => 'first.example.com', + ip => '10.0.0.10', + port => '443', + ip_based => true, + docroot => '/var/www/first-ssl', + ssl => true, +} + +# Two name-based vhost listening on 10.0.0.20 +apache::vhost { 'second.example.com': + ip => '10.0.0.20', + port => '80', + docroot => '/var/www/second', +} +apache::vhost { 'third.example.com': + ip => '10.0.0.20', + port => '80', + docroot => '/var/www/third', +} + +# Two name-based vhosts without IPs specified, so that they will answer on either 10.0.0.10 or 10.0.0.20 . It is requried to declare +# `add_listen => 'false'` to disable declaring "Listen 80" which will conflict +# with the IP-based preceeding vhosts. +apache::vhost { 'fourth.example.com': + port => '80', + docroot => '/var/www/fourth', + add_listen => false, +} +apache::vhost { 'fifth.example.com': + port => '80', + docroot => '/var/www/fifth', + add_listen => false, +} diff --git a/3rdparty/modules/aviator/Aviator_README.md b/3rdparty/modules/aviator/Aviator_README.md new file mode 100644 index 000000000..d85f93a0a --- /dev/null +++ b/3rdparty/modules/aviator/Aviator_README.md @@ -0,0 +1,11 @@ +![Aviator](https://raw.github.com/aviator/www/gh-pages/images/logo-small.png) +
A lightweight library for communicating with the OpenStack API. + +[![Build Status](https://travis-ci.org/aviator/aviator.png?branch=master)](https://travis-ci.org/aviator/aviator) +[![Coverage Status](https://coveralls.io/repos/aviator/aviator/badge.png?branch=master)](https://coveralls.io/r/aviator/aviator?branch=master) +[![Code Climate](https://codeclimate.com/github/aviator/aviator.png)](https://codeclimate.com/github/aviator/aviator) +[![Gem Version](https://badge.fury.io/rb/aviator.png)](http://badge.fury.io/rb/aviator) +[![Dependency Status](https://gemnasium.com/aviator/aviator.png)](https://gemnasium.com/aviator/aviator) + + +Usage and Installation diff --git a/3rdparty/modules/aviator/Gemfile b/3rdparty/modules/aviator/Gemfile new file mode 100644 index 000000000..483cfd0aa --- /dev/null +++ b/3rdparty/modules/aviator/Gemfile @@ -0,0 +1,17 @@ +# A sample Gemfile +source "https://rubygems.org" + +gem 'ci_reporter' +gem 'simplecov' +gem 'simplecov-rcov' +gem "rspec", '~> 2.0' +gem "mocha" +gem 'puppet', '= 3.5.1' +gem 'puppet-lint' +gem 'facter', '>= 1.6.10' +gem 'rspec-puppet', :git => 'https://github.com/rodjek/rspec-puppet.git', :branch => 'master' +gem 'rake', '>= 0.9.2' +gem 'puppetlabs_spec_helper', '0.3.0' +gem 'test-unit' +gem 'rspec_junit_formatter' +gem 'rspec-puppet-utils' diff --git a/3rdparty/modules/aviator/Gemfile.lock b/3rdparty/modules/aviator/Gemfile.lock new file mode 100644 index 000000000..b45c0880d --- /dev/null +++ b/3rdparty/modules/aviator/Gemfile.lock @@ -0,0 +1,81 @@ +GIT + remote: https://github.com/rodjek/rspec-puppet.git + revision: 389f99ef666521fec1b4530fe69dc1ab84a060a8 + branch: master + specs: + rspec-puppet (1.0.1) + rspec + +GEM + remote: https://rubygems.org/ + specs: + CFPropertyList (2.2.8) + builder (3.2.2) + ci_reporter (2.0.0) + builder (>= 2.1.2) + diff-lcs (1.2.5) + docile (1.1.5) + facter (2.2.0) + CFPropertyList (~> 2.2.6) + hiera (1.3.4) + json_pure + json_pure (1.8.1) + metaclass (0.0.4) + mocha (1.1.0) + metaclass (~> 0.0.1) + multi_json (1.10.1) + power_assert (0.1.3) + puppet (3.5.1) + facter (> 1.6, < 3) + hiera (~> 1.0) + json_pure + rgen (~> 0.6.5) + puppet-lint (1.0.1) + puppetlabs_spec_helper (0.3.0) + mocha (>= 0.10.5) + rake + rspec (>= 2.9.0) + rspec-puppet (>= 0.1.1) + rake (10.3.2) + rgen (0.6.6) + rspec (2.99.0) + rspec-core (~> 2.99.0) + rspec-expectations (~> 2.99.0) + rspec-mocks (~> 2.99.0) + rspec-core (2.99.2) + rspec-expectations (2.99.2) + diff-lcs (>= 1.1.3, < 2.0) + rspec-mocks (2.99.2) + rspec-puppet-utils (2.0.4) + rspec_junit_formatter (0.2.0) + builder (< 4) + rspec (>= 2, < 4) + rspec-core (!= 2.12.0) + simplecov (0.9.0) + docile (~> 1.1.0) + multi_json + simplecov-html (~> 0.8.0) + simplecov-html (0.8.0) + simplecov-rcov (0.2.3) + simplecov (>= 0.4.1) + test-unit (3.0.1) + power_assert + +PLATFORMS + ruby + +DEPENDENCIES + ci_reporter + facter (>= 1.6.10) + mocha + puppet (= 3.5.1) + puppet-lint + puppetlabs_spec_helper (= 0.3.0) + rake (>= 0.9.2) + rspec (~> 2.0) + rspec-puppet! + rspec-puppet-utils + rspec_junit_formatter + simplecov + simplecov-rcov + test-unit diff --git a/3rdparty/modules/aviator/LICENSE.txt b/3rdparty/modules/aviator/LICENSE.txt new file mode 100644 index 000000000..5c8a6e3a1 --- /dev/null +++ b/3rdparty/modules/aviator/LICENSE.txt @@ -0,0 +1,22 @@ +Copyright (c) 2014 Mark Maglana + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/3rdparty/modules/aviator/Modulefile b/3rdparty/modules/aviator/Modulefile new file mode 100644 index 000000000..133a66cb9 --- /dev/null +++ b/3rdparty/modules/aviator/Modulefile @@ -0,0 +1,11 @@ +name 'aimonb-aviator' +version '0.5.1' +source 'https://github.com/aimonb/puppet_aviator' +author 'aimonb' +license 'MIT License' +summary 'Puppet feature wrapper for the Aviator OpenStack API library for Ruby' +description 'UNKNOWN' +project_page 'https://github.com/aimonb/puppet_aviator' + +## Add dependencies, if any: +# dependency 'username/name', '>= 1.2.0' diff --git a/3rdparty/modules/aviator/README b/3rdparty/modules/aviator/README new file mode 100644 index 000000000..db81dbee9 --- /dev/null +++ b/3rdparty/modules/aviator/README @@ -0,0 +1,45 @@ +Puppet Aviator + +A feature module for the Aviator project. + +Aviator is a lightweight library for communicating with the OpenStack +API + +See Aviator_README.md for more information on Aviator. + +License +------- +MIT License + +Contact +------- +Aimon Bustardo + +Example Usage: +------- + + $LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', +'..')) + require 'puppet/feature/aviator' + + configuration = { + :provider => 'openstack', + :auth_service => { + :name => 'identity', + :host_uri => 'http://devstack:5000/v2.0', + :request => 'create_token', + :validator => 'list_tenants' + }, + :auth_credentials => { + :username => 'myusername', + :password => 'mypassword', + :tenant_name => 'myproject' + } + } + + openstack = Aviator::Session.new(:config => configuration) + + openstack.authenticate + response = openstack.request :identity_service, :list_tenants, :endpoint_type => 'admin' + + puts response[:body] diff --git a/3rdparty/modules/aviator/checksums.json b/3rdparty/modules/aviator/checksums.json new file mode 100644 index 000000000..751222b9a --- /dev/null +++ b/3rdparty/modules/aviator/checksums.json @@ -0,0 +1,261 @@ +{ + "Aviator_README.md": "06fac4cf003223c93ed23ea30e134e0a", + "Gemfile": "6d7f95a9e9993f49da52c1aa034ca599", + "Gemfile.lock": "5f2229c686025c1c5fcf0386bf08ebc1", + "LICENSE.txt": "25c9cebc4248703a08cfe5c333398bc6", + "Modulefile": "887af1b027892ea3a1e45350d9734643", + "README": "29e71fa36fbf6b393b3922ee892a9cc3", + "feature/aviator/compatibility.rb": "d103a261221e127c48ae8db01623cbb7", + "feature/aviator/core/cli/describer.rb": "a94adec4d61b706461597d23df66f76f", + "feature/aviator/core/cli.rb": "4fe815c3d85859dd6a9893a5aa38c7f8", + "feature/aviator/core/logger.rb": "99aa5ef113f491a563fdf8ecf6a44db2", + "feature/aviator/core/request.rb": "2477263dfc7b32751906c39448600838", + "feature/aviator/core/request_builder.rb": "2e3996fcfe619898c2b4638c96cc1616", + "feature/aviator/core/response.rb": "71629a33c4778a79b9f27fb4b8d469c0", + "feature/aviator/core/service.rb": "8f3c0b07e8a0c2d4ef6af7c7e0113d85", + "feature/aviator/core/session.rb": "3dabc2f13471632e809eb6ace4b6fbbe", + "feature/aviator/core.rb": "3d116a1ade58c869219ad2c2e3a01e59", + "feature/aviator/hashish.rb": "b9cf59c89b22cb6b39ec6916db1c5fb6", + "feature/aviator/openstack/common/v2/admin/base.rb": "8e88c76b3aa87bf3f69772bc5a7b4cfa", + "feature/aviator/openstack/common/v2/public/base.rb": "e1688afd9f65822599cfc8996256f979", + "feature/aviator/openstack/compute/v2/admin/confirm_server_resize.rb": "d7c43043c66a862d5232e999254c8f1a", + "feature/aviator/openstack/compute/v2/admin/create_network.rb": "b11ff615a495b3189ff18d2fdd580340", + "feature/aviator/openstack/compute/v2/admin/get_host_details.rb": "4e0200122c40d2acd95ca29ffb1a648f", + "feature/aviator/openstack/compute/v2/admin/list_hosts.rb": "25448fc1b14189d0d6aa6562c25d2172", + "feature/aviator/openstack/compute/v2/admin/lock_server.rb": "ff124f629375a069d0a39674a835669d", + "feature/aviator/openstack/compute/v2/admin/migrate_server.rb": "9b27fe512de6592e28e8ae534ef4e227", + "feature/aviator/openstack/compute/v2/admin/reset_server.rb": "83ceb5bde8297f40637901107c0779ce", + "feature/aviator/openstack/compute/v2/admin/resize_server.rb": "38d073f289de8cbcd54326dfcceb1203", + "feature/aviator/openstack/compute/v2/admin/revert_server_resize.rb": "c86f20c4c92417da7470a93adf2ac886", + "feature/aviator/openstack/compute/v2/admin/unlock_server.rb": "844f5380140805475c7a44d964960558", + "feature/aviator/openstack/compute/v2/public/change_admin_password.rb": "e5ed804402e4c969de89f669bbdbed52", + "feature/aviator/openstack/compute/v2/public/create_image.rb": "605c7f1dccc0e25f75a22b8133e0ac1c", + "feature/aviator/openstack/compute/v2/public/create_server.rb": "3d1408639e56cf9e32d26967dbbfc3f3", + "feature/aviator/openstack/compute/v2/public/delete_image.rb": "fb0f14aa4d3cd80e0b32ebcd0d32b62b", + "feature/aviator/openstack/compute/v2/public/delete_image_metadata_item.rb": "8f24549420f5b2ec73d245d84364f6a1", + "feature/aviator/openstack/compute/v2/public/delete_server.rb": "89fca14a34d08483992b03e0b3256e24", + "feature/aviator/openstack/compute/v2/public/delete_server_metadata_item.rb": "1caa8f632ee0e7964d0774f8fcdde5f8", + "feature/aviator/openstack/compute/v2/public/get_flavor_details.rb": "335012feb1abc4a0c0bfd57e09dd906f", + "feature/aviator/openstack/compute/v2/public/get_image_details.rb": "779845403f9314ddbda05121b54cd428", + "feature/aviator/openstack/compute/v2/public/get_image_metadata_item.rb": "cdc2caa68f52f33f5944770cb0594623", + "feature/aviator/openstack/compute/v2/public/get_network_details.rb": "43f08bb5513fd78f5685f065111a89e7", + "feature/aviator/openstack/compute/v2/public/get_server.rb": "9b764bb9b93cf368b7bec8ed70654490", + "feature/aviator/openstack/compute/v2/public/get_server_metadata_item.rb": "7e6a0feca6e6e2afc89e8b8cf00e6493", + "feature/aviator/openstack/compute/v2/public/list_addresses.rb": "ff343fead191c3d13677448daee3822c", + "feature/aviator/openstack/compute/v2/public/list_flavors.rb": "7050181d84ada85de9a3cfe476040432", + "feature/aviator/openstack/compute/v2/public/list_image_metadata.rb": "36cc324f2f8ec4e12a7f47846099aaa1", + "feature/aviator/openstack/compute/v2/public/list_images.rb": "9dcace5a72ef644072ede3bdcdf031ed", + "feature/aviator/openstack/compute/v2/public/list_networks.rb": "5639d0a86c7b37a0ba957f9cdb5a83ab", + "feature/aviator/openstack/compute/v2/public/list_server_metadata.rb": "5815bd0f48e81dea65c13bb0bb4c944e", + "feature/aviator/openstack/compute/v2/public/list_servers.rb": "deaf400faab4a9c0dd632be988fa002b", + "feature/aviator/openstack/compute/v2/public/pause_server.rb": "e2ac1913b925f61707516103d5c204cf", + "feature/aviator/openstack/compute/v2/public/reboot_server.rb": "73a34c9cf36b087e167e4d5a0a0b9762", + "feature/aviator/openstack/compute/v2/public/rebuild_server.rb": "907eee7ab63f3c8c3c93c9cc522aa208", + "feature/aviator/openstack/compute/v2/public/resume_server.rb": "f24ef2b6d7e4be1664d89a5d1bd76c2f", + "feature/aviator/openstack/compute/v2/public/root.rb": "cee3dd2aff0710d0f5fccc23508a7f58", + "feature/aviator/openstack/compute/v2/public/set_image_metadata.rb": "e49c35f9b95a268803578549ffce5cc0", + "feature/aviator/openstack/compute/v2/public/set_server_metadata.rb": "ece9d9a873ef6a3e468ae7285cd335f1", + "feature/aviator/openstack/compute/v2/public/suspend_server.rb": "a9fe5dc5c43dbb9da293de1eecd440a4", + "feature/aviator/openstack/compute/v2/public/unpause_server.rb": "9075ce7b123abce8917371fc545bbf92", + "feature/aviator/openstack/compute/v2/public/update_image_metadata.rb": "453dc71ce53a784322460afe8f8a0ffd", + "feature/aviator/openstack/compute/v2/public/update_server.rb": "19bab4a3b3b5fc8af215c53f3582f0cc", + "feature/aviator/openstack/compute/v2/public/update_server_metadata.rb": "72107bf121c284fb859e1d0d544c9f8c", + "feature/aviator/openstack/identity/v2/admin/add_role_to_user_on_tenant.rb": "d5962f765a8e2091aa0d7feab0f860b6", + "feature/aviator/openstack/identity/v2/admin/create_tenant.rb": "eb5b538285459bbc70da43ecb10a2ae1", + "feature/aviator/openstack/identity/v2/admin/create_user.rb": "a6f1152f0d2f2db837e9c87bf6dc8c76", + "feature/aviator/openstack/identity/v2/admin/delete_role_from_user_on_tenant.rb": "82e5b5520e9e10e8dba716b2e852cad9", + "feature/aviator/openstack/identity/v2/admin/delete_tenant.rb": "ad0bd04e86d4025a462ef6094313db63", + "feature/aviator/openstack/identity/v2/admin/delete_user.rb": "152712c94b6cec9da57cbff82a983ae1", + "feature/aviator/openstack/identity/v2/admin/get_tenant_by_id.rb": "0c93905f14e07e67f709739dd763d6e1", + "feature/aviator/openstack/identity/v2/admin/list_tenants.rb": "e75b66b966e49f045b7c61789ffd5b5e", + "feature/aviator/openstack/identity/v2/admin/list_users.rb": "afe6aea93af4ce623eb423e42a56473f", + "feature/aviator/openstack/identity/v2/admin/update_tenant.rb": "5e0250596b90187e09f5da7b2bb6c283", + "feature/aviator/openstack/identity/v2/admin/update_user.rb": "dd0ade2d22271f2e236caa42c65fb2bf", + "feature/aviator/openstack/identity/v2/public/create_token.rb": "2e44dafa7758d4610a5c06d54fc53ffa", + "feature/aviator/openstack/identity/v2/public/list_tenants.rb": "826d93b39fba2b8e85c4c9979f363afd", + "feature/aviator/openstack/identity/v2/public/root.rb": "49c81b24643287440458224c9eabc350", + "feature/aviator/openstack/image/v1/public/list_public_images.rb": "746ac90e4d5099a64ad08f4cc3829d97", + "feature/aviator/openstack/image/v1/public/root.rb": "b3b0897ea44361584961832fedf8f2ce", + "feature/aviator/openstack/metering/v1/admin/list_projects.rb": "22fc778d98d8424efcd14fa64e023c91", + "feature/aviator/openstack/volume/v1/public/create_volume.rb": "b0118b8f421376da64eb4a93afc483ec", + "feature/aviator/openstack/volume/v1/public/delete_volume.rb": "ebbcd8a8e470259cabed51fe41a03249", + "feature/aviator/openstack/volume/v1/public/get_volume.rb": "9a977461b76e1846e256d41bc5636c92", + "feature/aviator/openstack/volume/v1/public/list_volume_types.rb": "4338eb77f2e6df58a57fcd6cf22491cd", + "feature/aviator/openstack/volume/v1/public/list_volumes.rb": "2930615edc76b89b9e5888ca58d4ddd7", + "feature/aviator/openstack/volume/v1/public/root.rb": "fd7f423b9080b158b341530ff37b868e", + "feature/aviator/openstack/volume/v1/public/update_volume.rb": "67b9d740d4477d2d1cb22fa931f91458", + "feature/aviator/string.rb": "3c412951f02b4268890b599125174360", + "feature/aviator/version.rb": "10852d0b210481f820997ca1948953ab", + "feature/aviator.rb": "3ce701ef95c1be09eb46bcc12eeaac32", + "feature/composite_io.rb": "7578e6fc78d81b363658d0c047ef7355", + "feature/faraday/adapter/em_http.rb": "2b62006966ab41b68ba4b22f7499c6e7", + "feature/faraday/adapter/em_http_ssl_patch.rb": "353bac212b9c67a415cad9c2d0a33a1f", + "feature/faraday/adapter/em_synchrony/parallel_manager.rb": "ed23bb89721bfcc7be531d8a7fa1d75a", + "feature/faraday/adapter/em_synchrony.rb": "4d9eb3f1ca759f7008c4cd51ad055ddc", + "feature/faraday/adapter/excon.rb": "4d1bcdeeeb3623c5f5847350420102cb", + "feature/faraday/adapter/httpclient.rb": "cffdad2f5f9f109fb62ace392fabbcf1", + "feature/faraday/adapter/net_http.rb": "98ca2bafc840b0049e12448c12f7d9f6", + "feature/faraday/adapter/net_http_persistent.rb": "1d8cbd07de4b3464ed42774728d866d8", + "feature/faraday/adapter/patron.rb": "771a78d359202538a062b6e1de186b62", + "feature/faraday/adapter/rack.rb": "70078f81411a4294bd20302f9a857120", + "feature/faraday/adapter/test.rb": "e3177c396bb40d922e8aee81c745b173", + "feature/faraday/adapter/typhoeus.rb": "2bb446cc26a8fce211a92670838e977c", + "feature/faraday/adapter.rb": "c8e0aacec14e78a9d1b73bc674c147d7", + "feature/faraday/autoload.rb": "c3825f673dcd897eccbbf0204b290342", + "feature/faraday/connection.rb": "0ffff1f6f1996dbb7643c87e5acc482d", + "feature/faraday/error.rb": "a5900e607b1573bb6b6549e6573e2e90", + "feature/faraday/middleware.rb": "da7f0af70a005cabe297f64f613e04f5", + "feature/faraday/options.rb": "d92eea6cceda8cd61a984893ba5cc25c", + "feature/faraday/parameters.rb": "162fbb7a45756695909c49e099d6b412", + "feature/faraday/rack_builder.rb": "e1a93cd64e1d555530b6aa31b5b7812c", + "feature/faraday/request/authorization.rb": "a2aa3b3b22fa39e4f1fc6c87008a5e50", + "feature/faraday/request/basic_authentication.rb": "3da9b3b931d19e9669c3b32841ececfd", + "feature/faraday/request/instrumentation.rb": "c48435dbd1ba855f71c4f538baa7b665", + "feature/faraday/request/multipart.rb": "dcc172d9443f53d28d06cba93de2cd7b", + "feature/faraday/request/retry.rb": "57892cf880e6db7486daf8e015e9418a", + "feature/faraday/request/token_authentication.rb": "aedd602972c21fccb6b672d8caaa77ac", + "feature/faraday/request/url_encoded.rb": "7d8715e5cea35a1d3416a174e1fb492e", + "feature/faraday/request.rb": "0d5064fe1ae944b7aa21a111ccfbaf4d", + "feature/faraday/response/logger.rb": "0d4a6a3809bb3612715faf2b862ed147", + "feature/faraday/response/raise_error.rb": "8544053fd9007b42885793222f917b26", + "feature/faraday/response.rb": "6423348722701307e11f261b4ca09af8", + "feature/faraday/upload_io.rb": "7b0b80bc2cbbfca411a867d621f7b497", + "feature/faraday/utils.rb": "4df493a45499dbca0770f613da3d7bf6", + "feature/faraday.rb": "61f81f20888a0a1c992c0b108c96019d", + "feature/multipart_post.rb": "3433edf755f20e56edf3c167492a8a0f", + "feature/multipartable.rb": "5465ba7b40057b35eccf93bd1e50180d", + "feature/net/http/post/multipart.rb": "469d05036cd0b981b201d0fe50360f5b", + "feature/parts.rb": "c6a86930e784e4ab7d8d022b6f64e636", + "lib/puppet/feature/aviator/core/cli/describer.rb": "6cadcef2c8c51b5665243f090151afc6", + "lib/puppet/feature/aviator/core/cli.rb": "4fe815c3d85859dd6a9893a5aa38c7f8", + "lib/puppet/feature/aviator/core/logger.rb": "99aa5ef113f491a563fdf8ecf6a44db2", + "lib/puppet/feature/aviator/core/request.rb": "2477263dfc7b32751906c39448600838", + "lib/puppet/feature/aviator/core/request_builder.rb": "1705d21fb6db847d6521f643047f8675", + "lib/puppet/feature/aviator/core/response.rb": "2c6d777c3bf886a36e09855ec96d3911", + "lib/puppet/feature/aviator/core/service.rb": "3186cbe84f209286f03b8c8a347c38cb", + "lib/puppet/feature/aviator/core/session.rb": "a82ca88a3f76379184481e9d9d88bb5c", + "lib/puppet/feature/aviator/core/utils/compatibility.rb": "d103a261221e127c48ae8db01623cbb7", + "lib/puppet/feature/aviator/core/utils/hashish.rb": "3e54d1cdb0b25379c4adb73057072fbb", + "lib/puppet/feature/aviator/core/utils/string.rb": "3b1939aab12529f545b8a10ab27c0e05", + "lib/puppet/feature/aviator/core.rb": "8fd9c5413074f0de2aa5c5860abbbef8", + "lib/puppet/feature/aviator/openstack/common/requests/v0/public/base.rb": "c9690b0fa25efdcdbf6184a740a84fa3", + "lib/puppet/feature/aviator/openstack/common/requests/v2/admin/base.rb": "8e88c76b3aa87bf3f69772bc5a7b4cfa", + "lib/puppet/feature/aviator/openstack/common/requests/v2/public/base.rb": "4766de221d8e84c07e5bc997f4b4bda5", + "lib/puppet/feature/aviator/openstack/common/requests/v3/public/base.rb": "ac958d139dc2eff20ec08e591109bb42", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/confirm_server_resize.rb": "d7c43043c66a862d5232e999254c8f1a", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/create_network.rb": "b11ff615a495b3189ff18d2fdd580340", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/get_host_details.rb": "4e0200122c40d2acd95ca29ffb1a648f", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/list_hosts.rb": "25448fc1b14189d0d6aa6562c25d2172", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/list_hypervisors.rb": "d531290063e073bc72a0f508e5946989", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/lock_server.rb": "ff124f629375a069d0a39674a835669d", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/migrate_server.rb": "9b27fe512de6592e28e8ae534ef4e227", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/reset_server.rb": "83ceb5bde8297f40637901107c0779ce", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/resize_server.rb": "38d073f289de8cbcd54326dfcceb1203", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/revert_server_resize.rb": "ec60b35f97bb6de54d06ae53ab0a48f3", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/unlock_server.rb": "844f5380140805475c7a44d964960558", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/add_floating_ip.rb": "5ce446270f6216b19922f62a63e983bc", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/allocate_floating_ip.rb": "be0c5b2e87a7bf8d29b5997240aca6e5", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/change_admin_password.rb": "e5ed804402e4c969de89f669bbdbed52", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/create_image.rb": "605c7f1dccc0e25f75a22b8133e0ac1c", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/create_keypair.rb": "626715aa5a067328afa056229ee6bc96", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/create_server.rb": "b58dc498308a031f23c8ba2d6cf49293", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/delete_image.rb": "fb0f14aa4d3cd80e0b32ebcd0d32b62b", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/delete_image_metadata_item.rb": "8f24549420f5b2ec73d245d84364f6a1", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/delete_server.rb": "89fca14a34d08483992b03e0b3256e24", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/delete_server_metadata_item.rb": "1caa8f632ee0e7964d0774f8fcdde5f8", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_flavor_details.rb": "335012feb1abc4a0c0bfd57e09dd906f", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_image_details.rb": "779845403f9314ddbda05121b54cd428", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_image_metadata_item.rb": "cdc2caa68f52f33f5944770cb0594623", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_network_details.rb": "43f08bb5513fd78f5685f065111a89e7", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_server.rb": "9b764bb9b93cf368b7bec8ed70654490", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_server_metadata_item.rb": "7e6a0feca6e6e2afc89e8b8cf00e6493", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_addresses.rb": "ff343fead191c3d13677448daee3822c", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_flavors.rb": "7050181d84ada85de9a3cfe476040432", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_floating_ips.rb": "c967d5705e55c1840f1ff18d8b198936", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_image_metadata.rb": "36cc324f2f8ec4e12a7f47846099aaa1", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_images.rb": "9dcace5a72ef644072ede3bdcdf031ed", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_keypairs.rb": "7f2fc592742874b8a9cd05bd67eb8fad", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_networks.rb": "5639d0a86c7b37a0ba957f9cdb5a83ab", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_server_metadata.rb": "5815bd0f48e81dea65c13bb0bb4c944e", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_servers.rb": "deaf400faab4a9c0dd632be988fa002b", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/pause_server.rb": "e2ac1913b925f61707516103d5c204cf", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/reboot_server.rb": "73a34c9cf36b087e167e4d5a0a0b9762", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/rebuild_server.rb": "907eee7ab63f3c8c3c93c9cc522aa208", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/resume_server.rb": "f24ef2b6d7e4be1664d89a5d1bd76c2f", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/root.rb": "cee3dd2aff0710d0f5fccc23508a7f58", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/set_image_metadata.rb": "e49c35f9b95a268803578549ffce5cc0", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/set_server_metadata.rb": "ece9d9a873ef6a3e468ae7285cd335f1", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/suspend_server.rb": "a9fe5dc5c43dbb9da293de1eecd440a4", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/unpause_server.rb": "9075ce7b123abce8917371fc545bbf92", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/update_image_metadata.rb": "453dc71ce53a784322460afe8f8a0ffd", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/update_server.rb": "19bab4a3b3b5fc8af215c53f3582f0cc", + "lib/puppet/feature/aviator/openstack/compute/requests/v2/public/update_server_metadata.rb": "72107bf121c284fb859e1d0d544c9f8c", + "lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/add_role_to_user_on_tenant.rb": "d5962f765a8e2091aa0d7feab0f860b6", + "lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/create_tenant.rb": "eb5b538285459bbc70da43ecb10a2ae1", + "lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/create_user.rb": "817e3936db1e0a000014b0464a64a8ea", + "lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/delete_role_from_user_on_tenant.rb": "82e5b5520e9e10e8dba716b2e852cad9", + "lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/delete_tenant.rb": "ad0bd04e86d4025a462ef6094313db63", + "lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/delete_user.rb": "1a727d8adc5d4a1753acd7224f77e505", + "lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/get_tenant_by_id.rb": "0c93905f14e07e67f709739dd763d6e1", + "lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/get_user.rb": "3fb7869597c8f68adb91fefe5d0c0791", + "lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/list_tenants.rb": "e75b66b966e49f045b7c61789ffd5b5e", + "lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/list_users.rb": "058de058e0a98e2a7549a52e384b5807", + "lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/update_tenant.rb": "ff218d457b3ddce85168a85e98014c51", + "lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/update_user.rb": "47e295d5f138acda2bcb8b6a5ee1f87d", + "lib/puppet/feature/aviator/openstack/identity/requests/v2/public/create_token.rb": "2e44dafa7758d4610a5c06d54fc53ffa", + "lib/puppet/feature/aviator/openstack/identity/requests/v2/public/list_tenants.rb": "826d93b39fba2b8e85c4c9979f363afd", + "lib/puppet/feature/aviator/openstack/identity/requests/v2/public/root.rb": "49c81b24643287440458224c9eabc350", + "lib/puppet/feature/aviator/openstack/identity/requests/v3/public/create_token.rb": "c092532638e57c55c38eaae925e41b71", + "lib/puppet/feature/aviator/openstack/image/requests/v1/public/list_public_images.rb": "746ac90e4d5099a64ad08f4cc3829d97", + "lib/puppet/feature/aviator/openstack/image/requests/v1/public/root.rb": "b3b0897ea44361584961832fedf8f2ce", + "lib/puppet/feature/aviator/openstack/metering/requests/v1/admin/list_projects.rb": "22fc778d98d8424efcd14fa64e023c91", + "lib/puppet/feature/aviator/openstack/provider.rb": "e9ba93565ad683778c5901f30ab9fead", + "lib/puppet/feature/aviator/openstack/volume/requests/v1/public/create_volume.rb": "b0118b8f421376da64eb4a93afc483ec", + "lib/puppet/feature/aviator/openstack/volume/requests/v1/public/delete_volume.rb": "ebbcd8a8e470259cabed51fe41a03249", + "lib/puppet/feature/aviator/openstack/volume/requests/v1/public/get_volume.rb": "9a977461b76e1846e256d41bc5636c92", + "lib/puppet/feature/aviator/openstack/volume/requests/v1/public/list_volume_types.rb": "4338eb77f2e6df58a57fcd6cf22491cd", + "lib/puppet/feature/aviator/openstack/volume/requests/v1/public/list_volumes.rb": "2930615edc76b89b9e5888ca58d4ddd7", + "lib/puppet/feature/aviator/openstack/volume/requests/v1/public/root.rb": "fd7f423b9080b158b341530ff37b868e", + "lib/puppet/feature/aviator/openstack/volume/requests/v1/public/update_volume.rb": "67b9d740d4477d2d1cb22fa931f91458", + "lib/puppet/feature/aviator/version.rb": "7dacc5a489888d3bbb3e29d0d3fd0857", + "lib/puppet/feature/aviator.rb": "2bfe991671863c6b9f66fefb45edd586", + "lib/puppet/feature/composite_io.rb": "7578e6fc78d81b363658d0c047ef7355", + "lib/puppet/feature/faraday/adapter/em_http.rb": "2b62006966ab41b68ba4b22f7499c6e7", + "lib/puppet/feature/faraday/adapter/em_http_ssl_patch.rb": "353bac212b9c67a415cad9c2d0a33a1f", + "lib/puppet/feature/faraday/adapter/em_synchrony/parallel_manager.rb": "ed23bb89721bfcc7be531d8a7fa1d75a", + "lib/puppet/feature/faraday/adapter/em_synchrony.rb": "4d9eb3f1ca759f7008c4cd51ad055ddc", + "lib/puppet/feature/faraday/adapter/excon.rb": "4d1bcdeeeb3623c5f5847350420102cb", + "lib/puppet/feature/faraday/adapter/httpclient.rb": "cffdad2f5f9f109fb62ace392fabbcf1", + "lib/puppet/feature/faraday/adapter/net_http.rb": "98ca2bafc840b0049e12448c12f7d9f6", + "lib/puppet/feature/faraday/adapter/net_http_persistent.rb": "1d8cbd07de4b3464ed42774728d866d8", + "lib/puppet/feature/faraday/adapter/patron.rb": "771a78d359202538a062b6e1de186b62", + "lib/puppet/feature/faraday/adapter/rack.rb": "70078f81411a4294bd20302f9a857120", + "lib/puppet/feature/faraday/adapter/test.rb": "e3177c396bb40d922e8aee81c745b173", + "lib/puppet/feature/faraday/adapter/typhoeus.rb": "2bb446cc26a8fce211a92670838e977c", + "lib/puppet/feature/faraday/adapter.rb": "c8e0aacec14e78a9d1b73bc674c147d7", + "lib/puppet/feature/faraday/autoload.rb": "c3825f673dcd897eccbbf0204b290342", + "lib/puppet/feature/faraday/connection.rb": "0ffff1f6f1996dbb7643c87e5acc482d", + "lib/puppet/feature/faraday/error.rb": "a5900e607b1573bb6b6549e6573e2e90", + "lib/puppet/feature/faraday/middleware.rb": "da7f0af70a005cabe297f64f613e04f5", + "lib/puppet/feature/faraday/options.rb": "d92eea6cceda8cd61a984893ba5cc25c", + "lib/puppet/feature/faraday/parameters.rb": "162fbb7a45756695909c49e099d6b412", + "lib/puppet/feature/faraday/rack_builder.rb": "e1a93cd64e1d555530b6aa31b5b7812c", + "lib/puppet/feature/faraday/request/authorization.rb": "a2aa3b3b22fa39e4f1fc6c87008a5e50", + "lib/puppet/feature/faraday/request/basic_authentication.rb": "3da9b3b931d19e9669c3b32841ececfd", + "lib/puppet/feature/faraday/request/instrumentation.rb": "c48435dbd1ba855f71c4f538baa7b665", + "lib/puppet/feature/faraday/request/multipart.rb": "dcc172d9443f53d28d06cba93de2cd7b", + "lib/puppet/feature/faraday/request/retry.rb": "57892cf880e6db7486daf8e015e9418a", + "lib/puppet/feature/faraday/request/token_authentication.rb": "aedd602972c21fccb6b672d8caaa77ac", + "lib/puppet/feature/faraday/request/url_encoded.rb": "7d8715e5cea35a1d3416a174e1fb492e", + "lib/puppet/feature/faraday/request.rb": "0d5064fe1ae944b7aa21a111ccfbaf4d", + "lib/puppet/feature/faraday/response/logger.rb": "0d4a6a3809bb3612715faf2b862ed147", + "lib/puppet/feature/faraday/response/raise_error.rb": "8544053fd9007b42885793222f917b26", + "lib/puppet/feature/faraday/response.rb": "6423348722701307e11f261b4ca09af8", + "lib/puppet/feature/faraday/upload_io.rb": "7b0b80bc2cbbfca411a867d621f7b497", + "lib/puppet/feature/faraday/utils.rb": "4df493a45499dbca0770f613da3d7bf6", + "lib/puppet/feature/faraday.rb": "61f81f20888a0a1c992c0b108c96019d", + "lib/puppet/feature/multipart_post.rb": "3433edf755f20e56edf3c167492a8a0f", + "lib/puppet/feature/multipartable.rb": "5465ba7b40057b35eccf93bd1e50180d", + "lib/puppet/feature/net/http/post/multipart.rb": "469d05036cd0b981b201d0fe50360f5b", + "lib/puppet/feature/parts.rb": "c6a86930e784e4ab7d8d022b6f64e636" +} \ No newline at end of file diff --git a/3rdparty/modules/aviator/feature/aviator.rb b/3rdparty/modules/aviator/feature/aviator.rb new file mode 100644 index 000000000..3543aac60 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator.rb @@ -0,0 +1,6 @@ +# Add the parent dir to the load path. This is for when +# Aviator is not installed as a gem +lib_path = File.dirname(__FILE__) +$LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include? lib_path + +require 'aviator/core' diff --git a/3rdparty/modules/aviator/feature/aviator/compatibility.rb b/3rdparty/modules/aviator/feature/aviator/compatibility.rb new file mode 100644 index 000000000..560fc2b70 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/compatibility.rb @@ -0,0 +1,34 @@ +module Aviator + + module Compatibility + RUBY_1_8_MODE = (not (RUBY_VERSION =~ /1\.8\.\d*/).nil?) + end + +end + +if Aviator::Compatibility::RUBY_1_8_MODE + + class Module + + alias_method :old_const_defined?, :const_defined? + + def const_defined?(sym, ignore=nil) + old_const_defined?(sym) + end + + + alias_method :old_const_get, :const_get + + def const_get(sym, ignore=nil) + old_const_get(sym) + end + + alias_method :old_instance_methods, :instance_methods + + def instance_methods(include_super=true) + old_instance_methods(include_super).map(&:to_sym) + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/core.rb b/3rdparty/modules/aviator/feature/aviator/core.rb new file mode 100644 index 000000000..eb94adeeb --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/core.rb @@ -0,0 +1,14 @@ +require 'yaml' +require 'json' +require 'faraday' + +require "aviator/string" +require "aviator/version" +require "aviator/compatibility" +require "aviator/hashish" +require "aviator/core/request" +require "aviator/core/request_builder" +require "aviator/core/response" +require "aviator/core/service" +require "aviator/core/session" +require "aviator/core/logger" diff --git a/3rdparty/modules/aviator/feature/aviator/core/cli.rb b/3rdparty/modules/aviator/feature/aviator/core/cli.rb new file mode 100644 index 000000000..cd937d0e7 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/core/cli.rb @@ -0,0 +1,2 @@ +require "terminal-table" +require "aviator/core/cli/describer" diff --git a/3rdparty/modules/aviator/feature/aviator/core/cli/describer.rb b/3rdparty/modules/aviator/feature/aviator/core/cli/describer.rb new file mode 100644 index 000000000..b7426c310 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/core/cli/describer.rb @@ -0,0 +1,146 @@ +module Aviator + + class Describer + + def self.describe_aviator + str = "Available providers:\n" + + provider_names.each do |provider_name| + str << " #{ provider_name }\n" + end + + str + end + + + def self.describe_provider(provider_name) + str = "Available services for #{ provider_name }:\n" + + service_names(provider_name).each do |service_name| + str << " #{ service_name }\n" + end + + str + end + + + def self.describe_request(provider_name, service_name, api_version, endpoint_type, request_name) + service = Aviator::Service.new :provider => provider_name, :service => service_name + request_class = "Aviator::#{ provider_name.camelize }::#{ service_name.camelize }::"\ + "#{ api_version.camelize }::#{ endpoint_type.camelize }::#{ request_name.camelize }".constantize + + display = ":Request => #{ request_name }\n" + + + # Build the parameters + params = request_class.optional_params.map{|p| [p, false]} + + request_class.required_params.map{|p| [p, true]} + + aliases = request_class.param_aliases + + if params.length > 0 + display << "\n" + + headings = ['NAME', 'REQUIRED?'] + + headings << 'ALIAS' if aliases.length > 0 + + rows = [] + params.sort{|a,b| a[0].to_s <=> b[0].to_s }.each do |param| + row = [ param[0], param[1] ? 'Y' : 'N' ] + + if aliases.length > 0 + row << (aliases.find{|a,p| p == param[0] } || [''])[0] + end + + rows << row + end + + widths = [ + rows.map{|row| row[0].to_s.length }.max, + rows.map{|row| row[1].to_s.length }.max + ] + + widths << rows.map{|row| row[2].to_s.length }.max if aliases.length > 0 + + table = Terminal::Table.new(:headings => headings, :rows => rows) + + table.align_column(1, :center) + + display << "Parameters:\n" + display << " " + table.to_s.split("\n").join("\n ") + display << "\n" + end + + + # Build the sample code + display << "\nSample Code:\n" + + display << " session.#{ service_name }_service.request(:#{ request_name })" + + if params && params.length > 0 + display << " do |params|\n" + params.each do |pair| + display << " params.#{ (aliases.find{|a,p| p == pair[0] } || pair)[0] } = value\n" + end + display << " end" + end + + display << "\n" + + + # Build the links + if request_class.links && request_class.links.length > 0 + display << "\nLinks:\n" + + request_class.links.each do |link| + display << " #{ link[:rel] }:\n" + display << " #{ link[:href] }\n" + end + end + + display + end + + + def self.describe_service(provider_name, service_name) + str = "Available requests for #{ provider_name } #{ service_name }_service:\n" + + request_classes(provider_name, service_name).each do |klass| + str << " #{ klass.api_version } #{ klass.endpoint_type } #{ klass.name.split('::').last.underscore }\n" + end + + str + end + + + class < provider_name, :service => service_name) + service.request_classes + end + + + def service_names(provider_name) + Pathname.new(__FILE__) \ + .join('..', '..', '..', provider_name) \ + .children \ + .select{|c| c.directory? } \ + .map{|c| c.basename.to_s } + end + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/core/logger.rb b/3rdparty/modules/aviator/feature/aviator/core/logger.rb new file mode 100644 index 000000000..bbb537d7f --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/core/logger.rb @@ -0,0 +1,55 @@ +module Aviator + + class Logger < Faraday::Response::Middleware + extend Forwardable + + def initialize(app, logger=nil) + super(app) + @logger = logger || begin + require 'logger' + ::Logger.new(self.class::LOG_FILE_PATH) + end + end + + + def_delegators :@logger, :debug, :info, :warn, :error, :fatal + + + def call(env) + info(env[:method].to_s.upcase) { env[:url].to_s } + debug('REQ_HEAD') { dump_headers env[:request_headers] } + debug('REQ_BODY') { dump_body env[:body] } + super + end + + + def on_complete(env) + info('STATUS') { env[:status].to_s } + debug('RES_HEAD') { dump_headers env[:response_headers] } + debug('RES_BODY') { dump_body env[:body] } + end + + + def self.configure(log_file_path) + # Return a subclass with its logfile path set. This + # must be done so that different sessions can log to + # different paths. + Class.new(self) { const_set('LOG_FILE_PATH', log_file_path) } + end + + + private + + def dump_body(body) + return if body.nil? + + # :TODO => Make this configurable + body.gsub(/["']password["']:["']\w*["']/, '"password":[FILTERED_VALUE]') + end + + def dump_headers(headers) + headers.map { |k, v| "#{k}: #{v.inspect}" }.join("; ") + end + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/core/request.rb b/3rdparty/modules/aviator/feature/aviator/core/request.rb new file mode 100644 index 000000000..ed9c6cef1 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/core/request.rb @@ -0,0 +1,229 @@ +module Aviator + + class Request + + class ApiVersionNotDefinedError < StandardError + def initialize + super "api_version is not defined." + end + end + + class EndpointTypeNotDefinedError < StandardError + def initialize + super "endpoint_type is not defined." + end + end + + class PathNotDefinedError < StandardError + def initialize + super "path is not defined." + end + end + + + def initialize(session_data=nil) + @session_data = session_data + + params = self.class.params_class.new if self.class.params_class + + if params + yield(params) if block_given? + validate_params(params) + end + + @params = params + end + + + def anonymous? + self.class.anonymous? + end + + + def body? + self.class.body? + end + + + def headers? + self.class.headers? + end + + + def links + self.class.links + end + + + def optional_params + self.class.optional_params + end + + + def params + @params.dup + end + + + def required_params + self.class.required_params + end + + + def session_data + @session_data + end + + + def session_data? + !session_data.nil? + end + + + def querystring? + self.class.querystring? + end + + + def url? + self.class.url? + end + + + private + + + def validate_params(params) + required_params = self.class.required_params + + required_params.each do |name| + raise ArgumentError.new("Missing parameter #{ name }.") if params.send(name).nil? + end + end + + + # NOTE that, because we are defining the following as class methods, when they + # are called, all 'instance' variables are actually defined in the descendant class, + # not in the instance/object. This is by design since we want to keep these attributes + # within the class and because they don't change between instances anyway. + class << self + + def anonymous? + respond_to?(:anonymous) && anonymous == true + end + + + def body? + instance_methods.include? :body + end + + + def headers? + instance_methods.include? :headers + end + + + def links + @links ||= [] + end + + + def param_aliases + @param_aliases ||= {} + end + + + def params_class + all_params = required_params + optional_params + + if all_params.length > 0 && @params_class.nil? + @params_class = build_params_class(all_params, self.param_aliases) + end + + @params_class + end + + + def optional_params + @optional_params ||= [] + end + + + def querystring? + instance_methods.include? :querystring + end + + + def required_params + @required_params ||= [] + end + + + def url? + instance_methods.include? :url + end + + + private + + + def build_params_class(all_params, param_aliases) + Struct.new(*all_params) do + alias :param_getter :[] + alias :param_setter :[]= + + define_method :[] do |key| + key = param_aliases[key.to_sym] if param_aliases.keys.include? key.to_sym + param_getter(key) + end + + define_method :[]= do |key, value| + key = param_aliases[key.to_sym] if param_aliases.keys.include? key.to_sym + param_setter(key, value) + end + + param_aliases.each do |param_alias, param_name| + define_method param_alias do + param_getter(param_name) + end + + define_method "#{ param_alias }=" do |value| + param_setter(param_name, value) + end + end + end + end + + + def link(rel, href) + links << { :rel => rel, :href => href } + end + + + def meta(attr_name, attr_value) + eigenclass = class << self; self; end + eigenclass.send(:define_method, attr_name) do + attr_value + end + + define_method(attr_name) do + self.class.send(attr_name) + end + end + + + def param(param_name, opts={}) + opts = Hashish.new(opts) + list = (opts[:required] == false ? optional_params : required_params) + list << param_name unless optional_params.include?(param_name) + + if opts[:alias] + self.param_aliases[opts[:alias]] = param_name + end + end + + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/core/request_builder.rb b/3rdparty/modules/aviator/feature/aviator/core/request_builder.rb new file mode 100644 index 000000000..249cf1699 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/core/request_builder.rb @@ -0,0 +1,89 @@ +module Aviator + + class BaseRequestNotFoundError < StandardError + attr_reader :base_request_hierarchy + + def initialize(base_hierarchy) + @base_request_hierarchy = base_hierarchy + super("#{ base_request_hierarchy } could not be found!") + end + end + + + class RequestAlreadyDefinedError < StandardError + attr_reader :namespace, + :request_name + + def initialize(namespace, request_name) + @namespace = namespace + @request_name = request_name + super("#{ namespace }::#{ request_name } is already defined") + end + end + + + class RequestBuilder + + class << self + + def define_request(root_namespace, request_name, options, &block) + base_klass = get_request_class(root_namespace, options[:inherit]) + + klass = Class.new(base_klass, &block) + + namespace_arr = [ + klass.provider, + klass.service, + klass.api_version, + klass.endpoint_type + ] + + namespace = namespace_arr.inject(root_namespace) do |namespace, sym| + const_name = sym.to_s.camelize + namespace.const_set(const_name, Module.new) unless namespace.const_defined?(const_name, false) + namespace.const_get(const_name, false) + end + + klassname = request_name.to_s.camelize + + if namespace.const_defined?(klassname, false) + raise RequestAlreadyDefinedError.new(namespace, klassname) + end + + namespace.const_set(klassname, klass) + end + + + def get_request_class(root_namespace, request_class_arr) + request_class_arr.inject(root_namespace) do |namespace, sym| + namespace.const_get(sym.to_s.camelize, false) + end + rescue NameError => e + arr = ['..', '..'] + request_class_arr + arr[-1,1] = arr.last.to_s + '.rb' + path = Pathname.new(__FILE__).join(*arr.map{|i| i.to_s }).expand_path + + if path.exist? + require path + request_class_arr.inject(root_namespace) do |namespace, sym| + namespace.const_get(sym.to_s.camelize, false) + end + else + raise BaseRequestNotFoundError.new(request_class_arr) + end + end + + end + + end + + + class << self + + def define_request(request_name, options={ :inherit => [:request] }, &block) + RequestBuilder.define_request self, request_name, options, &block + end + + end # class << self + +end \ No newline at end of file diff --git a/3rdparty/modules/aviator/feature/aviator/core/response.rb b/3rdparty/modules/aviator/feature/aviator/core/response.rb new file mode 100644 index 000000000..8fa63c1d6 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/core/response.rb @@ -0,0 +1,39 @@ +module Aviator + + class Response + extend Forwardable + + def_delegators :@response, :headers, :status + + attr_reader :request + + def initialize(response, request) + @response = response + @request = request + end + + + def body + if raw_body.length > 0 + if Aviator::Compatibility::RUBY_1_8_MODE + clean_body = raw_body.gsub(/\\ /, ' ') + else + clean_body = raw_body + end + + Hashish.new(JSON.parse(clean_body)) + else + Hashish.new({}) + end + end + + + private + + def raw_body + @response.body + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/core/service.rb b/3rdparty/modules/aviator/feature/aviator/core/service.rb new file mode 100644 index 000000000..96a4b464d --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/core/service.rb @@ -0,0 +1,197 @@ +module Aviator + + class Service + + class AccessDetailsNotDefinedError < StandardError + def initialize + super ":access_details is not defined." + end + end + + class ProviderNotDefinedError < StandardError + def initialize + super ":provider is not defined." + end + end + + class ServiceNameNotDefinedError < StandardError + def initialize + super ":service is not defined." + end + end + + class SessionDataNotProvidedError < StandardError + def initialize + super "default_session_data is not initialized and no session data was "\ + "provided in the method call." + end + end + + + class UnknownRequestError < StandardError + def initialize(request_name) + super "Unknown request #{ request_name }." + end + end + + + class MissingServiceEndpointError < StandardError + def initialize(service_name, request_name) + request_name = request_name.to_s.split('::').last.underscore + super "The session's service catalog does not have an entry for the #{ service_name } "\ + "service. Therefore, I don't know to which base URL the request should be sent. "\ + "This may be because you are using a default or unscoped token. If this is not your "\ + "intention, please authenticate with a scoped token. If using a default token is your "\ + "intention, make sure to provide a base url when you call the request. For :example => \n\n"\ + "session.#{ service_name }_service.request :#{ request_name }, :base_url => 'http://myenv.com:9999/v2.0' do |params|\n"\ + " params[:example1] = 'example1'\n"\ + " params[:example2] = 'example2'\n"\ + "end\n\n" + end + end + + attr_accessor :default_session_data + + attr_reader :service, + :provider + + + def initialize(opts={}) + @provider = opts[:provider] || (raise ProviderNotDefinedError.new) + @service = opts[:service] || (raise ServiceNameNotDefinedError.new) + @log_file = opts[:log_file] + + @default_session_data = opts[:default_session_data] + + load_requests + end + + + def request(request_name, options={}, ¶ms) + session_data = options[:session_data] || default_session_data + + raise SessionDataNotProvidedError.new unless session_data + + [:base_url].each do |k| + session_data[k] = options[k] if options[k] + end + + request_class = find_request(request_name, session_data, options[:endpoint_type]) + + raise UnknownRequestError.new(request_name) unless request_class + + request = request_class.new(session_data, ¶ms) + + response = http_connection.send(request.http_method) do |r| + r.url request.url + r.headers.merge!(request.headers) if request.headers? + r.query = request.querystring if request.querystring? + r.body = JSON.generate(request.body) if request.body? + end + + Aviator::Response.send(:new, response, request) + end + + + def request_classes + @request_classes + end + + + private + + + def http_connection + @http_connection ||= Faraday.new do |conn| + conn.use Logger.configure(log_file) if log_file + conn.adapter Faraday.default_adapter + + conn.headers['Content-Type'] = 'application/json' + end + end + + + # Candidate for extraction to aviator/openstack + def find_request(name, session_data, endpoint_type=nil) + endpoint_types = if endpoint_type + [endpoint_type.to_s.camelize] + else + ['Public', 'Admin'] + end + + namespace = Aviator.const_get(provider.camelize) \ + .const_get(service.camelize) + + version = infer_version(session_data, name).to_s.camelize + + return nil unless version && namespace.const_defined?(version) + + namespace = namespace.const_get(version, name) + + endpoint_types.each do |endpoint_type| + name = name.to_s.camelize + + next unless namespace.const_defined?(endpoint_type) + next unless namespace.const_get(endpoint_type).const_defined?(name) + + return namespace.const_get(endpoint_type).const_get(name) + end + + nil + end + + + # Candidate for extraction to aviator/openstack + def infer_version(session_data, request_name='sample_request') + if session_data.has_key?(:auth_service) && session_data[:auth_service][:api_version] + session_data[:auth_service][:api_version].to_sym + + elsif session_data.has_key?(:auth_service) && session_data[:auth_service][:host_uri] + m = session_data[:auth_service][:host_uri].match(/(v\d+)\.?\d*/) + return m[1].to_sym unless m.nil? + + elsif session_data.has_key? :base_url + m = session_data[:base_url].match(/(v\d+)\.?\d*/) + return m[1].to_sym unless m.nil? + + elsif session_data.has_key? :access + service_spec = session_data[:access][:serviceCatalog].find{|s| s[:type] == service } + raise MissingServiceEndpointError.new(service.to_s, request_name) unless service_spec + version = service_spec[:endpoints][0][:publicURL].match(/(v\d+)\.?\d*/) + version ? version[1].to_sym : :v1 + end + end + + + def load_requests + # :TODO => This should be determined by a provider-specific module. + # e.g. Aviator::OpenStack::requests_base_dir + request_file_paths = Dir.glob(Pathname.new(__FILE__).join( + '..', + '..', + provider.to_s, + service.to_s, + '**', + '*.rb' + ).expand_path + ) + + request_file_paths.each{ |path| require path } + + constant_parts = request_file_paths \ + .map{|rf| rf.to_s.match(/#{provider}\/#{service}\/([\w\/]+)\.rb$/) } \ + .map{|rf| rf[1].split('/').map{|c| c.camelize }.join('::') } + + @request_classes = constant_parts.map do |cp| + "Aviator::#{provider.camelize}::#{service.camelize}::#{cp}".constantize + end + end + + + def log_file + @log_file + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/core/session.rb b/3rdparty/modules/aviator/feature/aviator/core/session.rb new file mode 100644 index 000000000..09ebcc731 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/core/session.rb @@ -0,0 +1,204 @@ +module Aviator + + class Session + + class AuthenticationError < StandardError + def initialize(last_auth_body) + super("Authentication failed. The server returned #{ last_auth_body }") + end + end + + + class EnvironmentNotDefinedError < ArgumentError + def initialize(path, env) + super("The environment '#{ env }' is not defined in #{ path }.") + end + end + + class InitializationError < StandardError + def initialize + super("The session could not find :session_dump, :config_file, and " \ + ":config in the constructor arguments provided") + end + end + + class InvalidConfigFilePathError < ArgumentError + def initialize(path) + super("The config file at #{ path } does not exist!") + end + end + + + class NotAuthenticatedError < StandardError + def initialize + super("Session is not authenticated. Please authenticate before proceeding.") + end + end + + + class ValidatorNotDefinedError < StandardError + def initialize + super("The validator request name is not defined for this session object.") + end + end + + + def initialize(opts={}) + if opts.has_key? :session_dump + initialize_with_dump(opts[:session_dump]) + elsif opts.has_key? :config_file + initialize_with_config(opts[:config_file], opts[:environment]) + elsif opts.has_key? :config + initialize_with_hash(opts[:config]) + else + raise InitializationError.new + end + + @log_file = opts[:log_file] + end + + + def authenticate(&block) + block ||= lambda do |params| + environment[:auth_credentials].each do |key, value| + params[key] = value + end + end + + response = auth_service.request environment[:auth_service][:request].to_sym, &block + + if response.status == 200 + @auth_info = response.body + update_services_session_data + else + raise AuthenticationError.new(response.body) + end + end + + + def authenticated? + !auth_info.nil? + end + + + def dump + JSON.generate({ + :environment => environment, + :auth_info => auth_info + }) + end + + + def load(session_dump) + initialize_with_dump(session_dump) + update_services_session_data + self + end + + + def method_missing(name, *args, &block) + service_name_parts = name.to_s.match(/^(\w+)_service$/) + + if service_name_parts + get_service_obj(service_name_parts[1]) + else + super name, *args, &block + end + end + + + def self.load(session_dump, opts={}) + opts[:session_dump] = session_dump + + new(opts) + end + + + def validate + raise NotAuthenticatedError.new unless authenticated? + raise ValidatorNotDefinedError.new unless environment[:auth_service][:validator] + + auth_with_bootstrap = auth_info.merge({ :auth_service => environment[:auth_service] }) + + response = auth_service.request environment[:auth_service][:validator].to_sym, :session_data => auth_with_bootstrap + + response.status == 200 || response.status == 203 + end + + + private + + + def auth_info + @auth_info + end + + + def auth_service + @auth_service ||= Service.new( + :provider => environment[:provider], + :service => environment[:auth_service][:name], + :default_session_data => { :auth_service => environment[:auth_service] }, + :log_file => log_file + ) + end + + + def environment + @environment + end + + + def get_service_obj(service_name) + raise NotAuthenticatedError.new unless self.authenticated? + + @services ||= {} + + @services[service_name] ||= Service.new( + :provider => environment[:provider], + :service => service_name, + :default_session_data => auth_info, + :log_file => log_file + ) + + @services[service_name] + end + + + def initialize_with_config(config_path, environment) + raise InvalidConfigFilePathError.new(config_path) unless Pathname.new(config_path).file? + + config = Hashish.new(YAML.load_file(config_path)) + + raise EnvironmentNotDefinedError.new(config_path, environment) unless config[environment] + + @environment = config[environment] + end + + + def initialize_with_dump(session_dump) + session_info = Hashish.new(JSON.parse(session_dump)) + @environment = session_info[:environment] + @auth_info = session_info[:auth_info] + end + + def initialize_with_hash(hash_obj) + @environment = Hashish.new(hash_obj) + end + + def log_file + @log_file + end + + + def update_services_session_data + return unless @services + + @services.each do |name, obj| + obj.default_session_data = auth_info + end + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/hashish.rb b/3rdparty/modules/aviator/feature/aviator/hashish.rb new file mode 100644 index 000000000..26025af48 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/hashish.rb @@ -0,0 +1,111 @@ +# Hash-ish! +# +# This class is implemented using composition rather than inheritance so +# that we have control over what operations it exposes to peers. +class Hashish + include Enumerable + + def initialize(hash={}) + @hash = hash + hashishify_values + end + + def ==(other_obj) + other_obj.class == self.class && + other_obj.hash == self.hash + end + + def [](key) + @hash[normalize(key)] + end + + def []=(key, value) + @hash[normalize(key)] = value + end + + def each(&block) + @hash.each(&block) + end + + def empty? + @hash.empty? + end + + def has_key?(name) + @hash.has_key? normalize(name) + end + + def hash + @hash + end + + def keys + @hash.keys + end + + def length + @hash.length + end + + def merge(other_hash) + Hashish.new(@hash.merge(other_hash)) + end + + def merge!(other_hash) + @hash.merge! other_hash + self + end + + def to_json(obj) + @hash.to_json(obj) + end + + def to_s + str = "{" + @hash.each do |key, value| + if value.kind_of? String + value = "'#{value}'" + elsif value.nil? + value = "nil" + elsif value.kind_of? Array + value = "[#{value.join(", ")}]" + end + + str += " #{key}: #{value}," + end + + str = str[0...-1] + " }" + str + end + + private + + # Hashishify all the things! + def hashishify_values + @hash.each do |key, value| + if @hash[key].kind_of? Hash + @hash[key] = Hashish.new(value) + elsif @hash[key].kind_of? Array + @hash[key].each_index do |index| + element = @hash[key][index] + if element.kind_of? Hash + @hash[key][index] = Hashish.new(element) + end + end + end + end + end + + def normalize(key) + if @hash.has_key? key + key + elsif key.is_a? String + key.to_sym + elsif key.is_a? Symbol + key.to_s + else + key + end + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/common/v2/admin/base.rb b/3rdparty/modules/aviator/feature/aviator/openstack/common/v2/admin/base.rb new file mode 100644 index 000000000..dd07d2f31 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/common/v2/admin/base.rb @@ -0,0 +1,9 @@ +module Aviator + + define_request :base, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :endpoint_type, :admin + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/common/v2/public/base.rb b/3rdparty/modules/aviator/feature/aviator/openstack/common/v2/public/base.rb new file mode 100644 index 000000000..7871a9f27 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/common/v2/public/base.rb @@ -0,0 +1,47 @@ +module Aviator + + define_request :base do + + meta :provider, :openstack + meta :service, :common + meta :api_version, :v2 + meta :endpoint_type, :public + + def headers + {}.tap do |h| + h['X-Auth-Token'] = session_data[:access][:token][:id] unless self.anonymous? + end + end + + + private + + + def base_url + if session_data[:base_url] + session_data[:base_url] + elsif service_spec = session_data[:access][:serviceCatalog].find { |s| s[:type] == service.to_s } + service_spec[:endpoints][0]["#{ endpoint_type }URL".to_sym] + elsif session_data[:auth_service] && session_data[:auth_service][:host_uri] && session_data[:auth_service][:api_version] + "#{ session_data[:auth_service][:host_uri] }/v2.0" + elsif session_data[:auth_service] && session_data[:auth_service][:host_uri] + session_data[:auth_service][:host_uri] + else + raise Aviator::Service::MissingServiceEndpointError.new(service.to_s, self.class) + end + end + + + def params_to_querystring(param_names) + filters = [] + + param_names.each do |param_name| + filters << "#{ param_name }=#{ params[param_name] }" if params[param_name] + end + + filters.empty? ? "" : "?#{ filters.join('&') }" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/confirm_server_resize.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/confirm_server_resize.rb new file mode 100644 index 000000000..0c672da8a --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/confirm_server_resize.rb @@ -0,0 +1,36 @@ +module Aviator + + define_request :confirm_server_resize, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Confirm_Resized_Server-d1e3868.html' + + param :id, :required => true + + + def body + { + :confirmResize => nil + } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/create_network.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/create_network.rb new file mode 100644 index 000000000..f45ef1a78 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/create_network.rb @@ -0,0 +1,56 @@ +module Aviator + + define_request :create_network, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :compute + + link 'documentation', + 'http://api.openstack.org/api-ref-compute.html#ext-os-networks' + + + param :label, :required => true + param :bridge, :required => false + param :bridge_interface, :required => false + param :cidr, :required => false + param :cidr_v6, :required => false + param :dns1, :required => false + param :dns2, :required => false + param :gateway, :required => false + param :gateway_v6, :required => false + param :multi_host, :required => false + param :project_id, :required => false + param :vlan, :required => false + + + def body + p = { + :network => { + :label => params[:label] + } + } + + optional_params.each do |key| + p[:network][key] = params[key] if params[key] + end + + p + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/os-networks" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/get_host_details.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/get_host_details.rb new file mode 100644 index 000000000..daf25a3cd --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/get_host_details.rb @@ -0,0 +1,29 @@ +module Aviator + + define_request :get_host_details, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :compute + + link 'documentation', + 'http://api.openstack.org/api-ref.html#ext-os-hosts' + + param :host_name, :required => true + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/os-hosts/#{ params[:host_name] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/list_hosts.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/list_hosts.rb new file mode 100644 index 000000000..8c47aa835 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/list_hosts.rb @@ -0,0 +1,44 @@ +module Aviator + + define_request :list_hosts, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :compute + + link 'documentation', + 'http://api.openstack.org/api-ref.html#ext-os-hosts' + + link 'documentation bug', + 'https://bugs.launchpad.net/nova/+bug/1224763' + + param :service, :required => false + param :zone, :required => false + + + def headers + super + end + + + def http_method + :get + end + + + def url + url = "#{ base_url }/os-hosts" + + filters = [] + + optional_params.each do |param_name| + filters << "#{ param_name }=#{ params[param_name] }" if params[param_name] + end + + url += "?#{ filters.join('&') }" unless filters.empty? + + url + end + + end + +end + diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/lock_server.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/lock_server.rb new file mode 100644 index 000000000..6db89fee2 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/lock_server.rb @@ -0,0 +1,34 @@ +module Aviator + + define_request :lock_server, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/POST_lock_v2__tenant_id__servers__server_id__action_ext-os-admin-actions.html' + + param :id, :required => true + + + def body + { :lock => nil } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/migrate_server.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/migrate_server.rb new file mode 100644 index 000000000..56259cdff --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/migrate_server.rb @@ -0,0 +1,34 @@ +module Aviator + + define_request :migrate_server, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/POST_migrate_v2__tenant_id__servers__server_id__action_ext-os-admin-actions.html' + + param :id, :required => true + + + def body + { :migrate => nil } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/reset_server.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/reset_server.rb new file mode 100644 index 000000000..ea8af1f0a --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/reset_server.rb @@ -0,0 +1,39 @@ +module Aviator + + define_request :reset_server, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/POST_os-resetState_v2__tenant_id__servers__server_id__action_ext-os-admin-actions.html' + + param :id, :required => true + param :state, :required => true + + + def body + { + 'os-resetState' => { + 'state' => params[:state] + } + } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/resize_server.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/resize_server.rb new file mode 100644 index 000000000..e4b6582a6 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/resize_server.rb @@ -0,0 +1,41 @@ +module Aviator + + define_request :resize_server, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Resize_Server-d1e3707.html' + + param :id, :required => true + param :name, :required => true + param :flavorRef, :required => true, :alias => :flavor_ref + + + def body + { + :resize => { + :name => params[:name], + :flavorRef => params[:flavorRef] + } + } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/revert_server_resize.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/revert_server_resize.rb new file mode 100644 index 000000000..6d8bec091 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/revert_server_resize.rb @@ -0,0 +1,46 @@ +module Aviator + + define_request :revert_server_resize do + + meta :provider, :openstack + meta :service, :compute + meta :api_version, :v2 + meta :endpoint_type, :admin + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Revert_Resized_Server-d1e4024.html' + + param :id, :required => true + + + def body + { + :revertResize => nil + } + end + + + def headers + h = {} + + unless self.anonymous? + h['X-Auth-Token'] = session_data[:access][:token][:id] + end + + h + end + + + def http_method + :post + end + + + def url + service_spec = session_data[:access][:serviceCatalog].find{|s| s[:type] == service.to_s } + "#{ service_spec[:endpoints][0][:adminURL] }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/unlock_server.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/unlock_server.rb new file mode 100644 index 000000000..eede63524 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/admin/unlock_server.rb @@ -0,0 +1,34 @@ +module Aviator + + define_request :unlock_server, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/POST_unlock_v2__tenant_id__servers__server_id__action_ext-os-admin-actions.html' + + param :id, :required => true + + + def body + { :unlock => nil } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/change_admin_password.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/change_admin_password.rb new file mode 100644 index 000000000..03aced50a --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/change_admin_password.rb @@ -0,0 +1,44 @@ +module Aviator + + define_request :change_admin_password, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Change_Password-d1e3234.html' + + link 'additional spec', + 'https://answers.launchpad.net/nova/+question/228462' + + param :adminPass, :required => true, :alias => :admin_pass + param :id, :required => true + + + def body + p = { + :changePassword => { + :adminPass => params[:adminPass] + } + } + + p + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/create_image.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/create_image.rb new file mode 100644 index 000000000..0a4622370 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/create_image.rb @@ -0,0 +1,46 @@ +module Aviator + + define_request :create_image, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Create_Image-d1e4655.html' + + param :id, :required => true + param :metadata, :required => false + param :name, :required => true + + + def body + p = { + :createImage => { + :name => params[:name] + } + } + + [:metadata].each do |key| + p[:createImage][key] = params[key] if params[key] + end + + p + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/create_server.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/create_server.rb new file mode 100644 index 000000000..b7666414c --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/create_server.rb @@ -0,0 +1,54 @@ +module Aviator + + define_request :create_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/CreateServers.html' + + param :accessIPv4, :required => false, :alias => :access_ipv4 + param :accessIPv6, :required => false, :alias => :access_ipv6 + param :adminPass, :required => false, :alias => :admin_pass + param :imageRef, :required => true, :alias => :image_ref + param :flavorRef, :required => true, :alias => :flavor_ref + param :metadata, :required => false + param :name, :required => true + param :networks, :required => false + param :personality, :required => false + + + def body + p = { + :server => { + :flavorRef => params[:flavorRef], + :imageRef => params[:imageRef], + :name => params[:name] + } + } + + [:adminPass, :metadata, :personality, :networks, :accessIPv4, :accessIPv6].each do |key| + p[:server][key] = params[key] if params[key] + end + + p + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/delete_image.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/delete_image.rb new file mode 100644 index 000000000..35ea8cf40 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/delete_image.rb @@ -0,0 +1,29 @@ +module Aviator + + define_request :delete_image, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Delete_Image-d1e4957.html' + + param :id, :required => true + + + def headers + super + end + + + def http_method + :delete + end + + + def url + "#{ base_url }/images/#{ params[:id]}" + end + + end + +end \ No newline at end of file diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/delete_image_metadata_item.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/delete_image_metadata_item.rb new file mode 100644 index 000000000..7b1fc3d70 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/delete_image_metadata_item.rb @@ -0,0 +1,31 @@ +module Aviator + + define_request :delete_image_metadata_item, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Delete_Metadata_Item-d1e5790.html' + + + param :id, :required => true + param :key, :required => true + + + def headers + super + end + + + def http_method + :delete + end + + + def url + "#{ base_url }/images/#{ params[:id] }/metadata/#{ params[:key] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/delete_server.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/delete_server.rb new file mode 100644 index 000000000..a991efb8e --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/delete_server.rb @@ -0,0 +1,29 @@ +module Aviator + + define_request :delete_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Delete_Server-d1e2883.html' + + param :id, :required => true + + + def headers + super + end + + + def http_method + :delete + end + + + def url + "#{ base_url }/servers/#{ params[:id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/delete_server_metadata_item.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/delete_server_metadata_item.rb new file mode 100644 index 000000000..facbbb537 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/delete_server_metadata_item.rb @@ -0,0 +1,31 @@ +module Aviator + + define_request :delete_server_metadata_item, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Delete_Metadata_Item-d1e5790.html' + + + param :id, :required => true + param :key, :required => true + + + def headers + super + end + + + def http_method + :delete + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/metadata/#{ params[:key] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/get_flavor_details.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/get_flavor_details.rb new file mode 100644 index 000000000..8faeb900e --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/get_flavor_details.rb @@ -0,0 +1,29 @@ +module Aviator + + define_request :get_flavor_details, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Get_Flavor_Details-d1e4317.html' + + param :id, :required => true + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/flavors/#{ params[:id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/get_image_details.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/get_image_details.rb new file mode 100644 index 000000000..b9fd3cce8 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/get_image_details.rb @@ -0,0 +1,29 @@ +module Aviator + + define_request :get_image_details, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Get_Image_Details-d1e4848.html' + + param :id, :required => true + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/images/#{ params[:id]}" + end + + end + +end \ No newline at end of file diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/get_image_metadata_item.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/get_image_metadata_item.rb new file mode 100644 index 000000000..01476744a --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/get_image_metadata_item.rb @@ -0,0 +1,31 @@ +module Aviator + + define_request :get_image_metadata_item, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Get_Metadata_Item-d1e5507.html' + + + param :id, :required => true + param :key, :required => true + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/images/#{ params[:id] }/metadata/#{ params[:key] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/get_network_details.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/get_network_details.rb new file mode 100644 index 000000000..8d4192bfe --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/get_network_details.rb @@ -0,0 +1,30 @@ +module Aviator + + define_request :get_network_details, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://api.openstack.org/api-ref-compute.html#ext-os-networks' + + + param :id, :required => true + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/os-networks/#{ params[:id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/get_server.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/get_server.rb new file mode 100644 index 000000000..e5c391106 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/get_server.rb @@ -0,0 +1,28 @@ +module Aviator + + define_request :get_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Get_Server_Details-d1e2623.html' + + param :id, :required => true + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/servers/#{ params[:id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/get_server_metadata_item.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/get_server_metadata_item.rb new file mode 100644 index 000000000..580320f24 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/get_server_metadata_item.rb @@ -0,0 +1,31 @@ +module Aviator + + define_request :get_server_metadata_item, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Get_Metadata_Item-d1e5507.html' + + + param :id, :required => true + param :key, :required => true + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/metadata/#{ params[:key] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_addresses.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_addresses.rb new file mode 100644 index 000000000..2c6fe60a4 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_addresses.rb @@ -0,0 +1,36 @@ +module Aviator + + define_request :list_addresses, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/List_Addresses-d1e3014.html' + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/List_Addresses_by_Network-d1e3118.html' + + + param :id, :required => true + param :networkID, :required => false, :alias => :network_id + + + def headers + super + end + + + def http_method + :get + end + + + def url + url = "#{ base_url }/servers/#{ params[:id] }/ips" + url += "/#{ params[:networkID] }" if params[:networkID] + url + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_flavors.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_flavors.rb new file mode 100644 index 000000000..9eba13626 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_flavors.rb @@ -0,0 +1,35 @@ +module Aviator + + define_request :list_flavors, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/List_Flavors-d1e4188.html' + + param :details, :required => false + param :minDisk, :required => false, :alias => :min_disk + param :minRam, :required => false, :alias => :min_ram + param :marker, :required => false + param :limit, :required => false + + + def headers + super + end + + + def http_method + :get + end + + + def url + str = "#{ base_url }/flavors" + str += "/detail" if params[:details] + str += params_to_querystring(optional_params + required_params - [:details]) + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_image_metadata.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_image_metadata.rb new file mode 100644 index 000000000..7b176891f --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_image_metadata.rb @@ -0,0 +1,30 @@ +module Aviator + + define_request :list_image_metadata, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/List_Metadata-d1e5089.html' + + + param :id, :required => true + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/images/#{ params[:id] }/metadata" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_images.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_images.rb new file mode 100644 index 000000000..b282aec97 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_images.rb @@ -0,0 +1,38 @@ +module Aviator + + define_request :list_images, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/List_Images-d1e4435.html' + + param :details, :required => false + param :server, :required => false + param :name, :required => false + param :status, :required => false + param 'changes-since', :required => false, :alias => :changes_since + param :marker, :required => false + param :limit, :required => false + param :type, :required => false + + + def headers + super + end + + + def http_method + :get + end + + + def url + str = "#{ base_url }/images" + str += "/detail" if params[:details] + str += params_to_querystring(optional_params + required_params - [:details]) + end + + end + +end \ No newline at end of file diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_networks.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_networks.rb new file mode 100644 index 000000000..472ab1bd0 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_networks.rb @@ -0,0 +1,27 @@ +module Aviator + + define_request :list_networks, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://api.openstack.org/api-ref-compute.html#ext-os-networks' + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/os-networks" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_server_metadata.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_server_metadata.rb new file mode 100644 index 000000000..d90936c1b --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_server_metadata.rb @@ -0,0 +1,30 @@ +module Aviator + + define_request :list_server_metadata, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/List_Metadata-d1e5089.html' + + + param :id, :required => true + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/metadata" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_servers.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_servers.rb new file mode 100644 index 000000000..f8126f0c5 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/list_servers.rb @@ -0,0 +1,58 @@ +module Aviator + + define_request :list_servers, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/List_Servers-d1e2078.html' + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/GET_listServers_v2__tenant_id__servers_compute_servers.html' + + link 'github :issue => getting all servers', + 'https://github.com/aviator/aviator/issues/35' + + link 'related mailing list discussion', + 'https://lists.launchpad.net/openstack/msg24695.html' + + param :all_tenants, :required => false + param :details, :required => false + param :flavor, :required => false + param :image, :required => false + param :limit, :required => false + param :marker, :required => false + param :server, :required => false + param :status, :required => false + param 'changes-since', :required => false, :alias => :changes_since + + + def headers + super + end + + + def http_method + :get + end + + + def url + str = "#{ base_url }/servers" + str += "/detail" if params[:details] + + filters = [] + + (optional_params + required_params - [:details]).each do |param_name| + value = param_name == :all_tenants && params[param_name] ? 1 : params[param_name] + filters << "#{ param_name }=#{ value }" if value + end + + str += "?#{ filters.join('&') }" unless filters.empty? + + str + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/pause_server.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/pause_server.rb new file mode 100644 index 000000000..00e5ec663 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/pause_server.rb @@ -0,0 +1,34 @@ +module Aviator + + define_request :pause_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/POST_pause_v2__tenant_id__servers__server_id__action_ext-os-admin-actions.html' + + param :id, :required => true + + + def body + { :pause => nil } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/reboot_server.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/reboot_server.rb new file mode 100644 index 000000000..8aa2296da --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/reboot_server.rb @@ -0,0 +1,41 @@ +module Aviator + + define_request :reboot_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Reboot_Server-d1e3371.html' + + param :id, :required => true + param :type, :required => false + + + def body + p = { + :reboot => { + :type => params[:type] || 'SOFT' + } + } + + p + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/rebuild_server.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/rebuild_server.rb new file mode 100644 index 000000000..8383f571a --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/rebuild_server.rb @@ -0,0 +1,53 @@ +module Aviator + + define_request :rebuild_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Rebuild_Server-d1e3538.html' + + param :accessIPv4, :required => false, :alias => :access_ipv4 + param :accessIPv6, :required => false, :alias => :access_ipv6 + param :adminPass, :required => true, :alias => :admin_pass + param :id, :required => true + param :imageRef, :required => true, :alias => :image_ref + param :metadata, :required => false + param :name, :required => true + param :personality, :required => false + + + def body + p = { + :rebuild => { + :adminPass => params[:adminPass], + :imageRef => params[:imageRef], + :name => params[:name] + } + } + + [:accessIPv4, :accessIPv6, :metadata, :personality].each do |key| + p[:rebuild][key] = params[key] if params[key] + end + + p + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/resume_server.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/resume_server.rb new file mode 100644 index 000000000..f220b366c --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/resume_server.rb @@ -0,0 +1,34 @@ +module Aviator + + define_request :resume_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/POST_resume_v2__tenant_id__servers__server_id__action_ext-os-admin-actions.html' + + param :id, :required => true + + + def body + { :resume => nil } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/root.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/root.rb new file mode 100644 index 000000000..3a3c4dabc --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/root.rb @@ -0,0 +1,24 @@ +module Aviator + + define_request :root, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + def headers + super + end + + + def http_method + :get + end + + + def url + uri = URI(base_url) + "#{ uri.scheme }://#{ uri.host }:#{ uri.port.to_s }/v2/" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/set_image_metadata.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/set_image_metadata.rb new file mode 100644 index 000000000..c17976f9e --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/set_image_metadata.rb @@ -0,0 +1,38 @@ +module Aviator + + define_request :set_image_metadata, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Create_or_Replace_Metadata-d1e5358.html' + + + param :id, :required => true + param :metadata, :required => true + + + def body + { + :metadata => params[:metadata] + } + end + + + def headers + super + end + + + def http_method + :put + end + + + def url + "#{ base_url }/images/#{ params[:id] }/metadata" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/set_server_metadata.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/set_server_metadata.rb new file mode 100644 index 000000000..8631c0397 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/set_server_metadata.rb @@ -0,0 +1,38 @@ +module Aviator + + define_request :set_server_metadata, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Create_or_Replace_Metadata-d1e5358.html' + + + param :id, :required => true + param :metadata, :required => true + + + def body + { + :metadata => params[:metadata] + } + end + + + def headers + super + end + + + def http_method + :put + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/metadata" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/suspend_server.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/suspend_server.rb new file mode 100644 index 000000000..a9bb9a52e --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/suspend_server.rb @@ -0,0 +1,34 @@ +module Aviator + + define_request :suspend_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/POST_suspend_v2__tenant_id__servers__server_id__action_ext-os-admin-actions.html' + + param :id, :required => true + + + def body + { :suspend => nil } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/unpause_server.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/unpause_server.rb new file mode 100644 index 000000000..e11089a62 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/unpause_server.rb @@ -0,0 +1,34 @@ +module Aviator + + define_request :unpause_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/POST_unpause_v2__tenant_id__servers__server_id__action_ext-os-admin-actions.html' + + param :id, :required => true + + + def body + { :unpause => nil } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/update_image_metadata.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/update_image_metadata.rb new file mode 100644 index 000000000..0ec3694b0 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/update_image_metadata.rb @@ -0,0 +1,38 @@ +module Aviator + + define_request :update_image_metadata, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Update_Metadata-d1e5208.html' + + + param :id, :required => true + param :metadata, :required => true + + + def body + { + :metadata => params[:metadata] + } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/images/#{ params[:id] }/metadata" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/update_server.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/update_server.rb new file mode 100644 index 000000000..453c58329 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/update_server.rb @@ -0,0 +1,45 @@ +module Aviator + + define_request :update_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/ServerUpdate.html' + + param :accessIPv4, :required => false, :alias => :access_ipv4 + param :accessIPv6, :required => false, :alias => :access_ipv6 + param :id, :required => true + param :name, :required => false + + + def body + p = { + :server => { } + } + + [:name, :accessIPv4, :accessIPv6].each do |key| + p[:server][key] = params[key] if params[key] + end + + p + end + + + def headers + super + end + + + def http_method + :put + end + + + def url + "#{ base_url }/servers/#{ params[:id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/update_server_metadata.rb b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/update_server_metadata.rb new file mode 100644 index 000000000..e1e5ad17d --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/compute/v2/public/update_server_metadata.rb @@ -0,0 +1,38 @@ +module Aviator + + define_request :update_server_metadata, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Update_Metadata-d1e5208.html' + + + param :id, :required => true + param :metadata, :required => true + + + def body + { + :metadata => params[:metadata] + } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/metadata" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/add_role_to_user_on_tenant.rb b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/add_role_to_user_on_tenant.rb new file mode 100644 index 000000000..e69b196eb --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/add_role_to_user_on_tenant.rb @@ -0,0 +1,33 @@ +module Aviator + + define_request :add_role_to_user_on_tenant, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :identity + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/PUT_addRolesToUserOnTenant_v2.0_tenants__tenantId__users__userId__roles_OS-KSADM__roleId__.html' + + + param :tenant_id, :required => true + param :user_id, :required => true + param :role_id, :required => true + + + def headers + super + end + + + def http_method + :put + end + + + def url + p = params + "#{ base_url }/tenants/#{ p[:tenant_id] }/users/#{ p[:user_id] }/roles/OS-KSADM/#{ p[:role_id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/create_tenant.rb b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/create_tenant.rb new file mode 100644 index 000000000..6578ae060 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/create_tenant.rb @@ -0,0 +1,43 @@ +module Aviator + + define_request :create_tenant, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :identity + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/' + + + param :name, :required => true + param :description, :required => true + param :enabled, :required => true + + + def body + { + :tenant => { + :name => params[:name], + :description => params[:description], + :enabled => params[:enabled] + } + } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/tenants" + end + + end + +end \ No newline at end of file diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/create_user.rb b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/create_user.rb new file mode 100644 index 000000000..d9d87f77e --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/create_user.rb @@ -0,0 +1,66 @@ +module Aviator + + define_request :create_user do + + meta :provider, :openstack + meta :service, :identity + meta :api_version, :v2 + meta :endpoint_type, :admin + + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/POST_addUser_v2.0_users_.html' + + link 'documentation bug', + 'https://bugs.launchpad.net/keystone/+bug/1110435' + + link 'documentation bug', + 'https://bugs.launchpad.net/keystone/+bug/1226466' + + + param :name, :required => true + param :password, :required => true + + param :email, :required => false + param :enabled, :required => false + param :tenantId, :required => false, :alias => :tenant_id + + + def body + p = { + :user => {} + } + + (required_params + optional_params).each do |key| + p[:user][key] = params[key] if params[key] + end + + p + end + + + def headers + h = {} + + unless self.anonymous? + h['X-Auth-Token'] = session_data[:access][:token][:id] + end + + h + end + + + def http_method + :post + end + + + def url + service_spec = session_data[:access][:serviceCatalog].find{|s| s[:type] == 'identity' } + "#{ service_spec[:endpoints][0][:adminURL] }/users" + end + + end + +end + diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/delete_role_from_user_on_tenant.rb b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/delete_role_from_user_on_tenant.rb new file mode 100644 index 000000000..4d24469a7 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/delete_role_from_user_on_tenant.rb @@ -0,0 +1,34 @@ +module Aviator + + define_request :delete_role_from_user_on_tenant, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :identity + + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/DELETE_deleteRoleFromUserOnTenant_v2.0_tenants__tenantId__users__userId__roles_OS-KSADM__roleId__.html' + + + param :tenant_id, :required => true + param :user_id, :required => true + param :role_id, :required => true + + + def headers + super + end + + + def http_method + :delete + end + + + def url + p = params + "#{ base_url }/tenants/#{ p[:tenant_id] }/users/#{ p[:user_id] }/roles/OS-KSADM/#{ p[:role_id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/delete_tenant.rb b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/delete_tenant.rb new file mode 100644 index 000000000..63ad6437f --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/delete_tenant.rb @@ -0,0 +1,29 @@ +module Aviator + + define_request :delete_tenant, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :identity + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/DELETE_deleteTenant_v2.0_tenants__tenantId__.html' + + param :id, :required => true + + + def headers + super + end + + + def http_method + :delete + end + + + def url + "#{ base_url }/tenants/#{ params[:id]}" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/delete_user.rb b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/delete_user.rb new file mode 100644 index 000000000..f66bbaa4e --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/delete_user.rb @@ -0,0 +1,39 @@ +module Aviator + + define_request :delete_user do + + meta :provider, :openstack + meta :service, :identity + meta :api_version, :v2 + meta :endpoint_type, :admin + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/DELETE_deleteUser_v2.0_users__userId__.html' + + param :id, :required => true + + + def headers + h = {} + + unless self.anonymous? + h['X-Auth-Token'] = session_data[:access][:token][:id] + end + + h + end + + + def http_method + :delete + end + + + def url + service_spec = session_data[:access][:serviceCatalog].find{|s| s[:type] == service.to_s } + "#{ service_spec[:endpoints][0][:adminURL] }/users/#{ params[:id]}" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/get_tenant_by_id.rb b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/get_tenant_by_id.rb new file mode 100644 index 000000000..fe2dcc986 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/get_tenant_by_id.rb @@ -0,0 +1,30 @@ +module Aviator + + define_request :get_tenant_by_id, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :identity + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/GET_listUsers_v2.0_users_.html' + + + param :id, :required => true + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/tenants/#{ params[:id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/list_tenants.rb b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/list_tenants.rb new file mode 100644 index 000000000..48d293062 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/list_tenants.rb @@ -0,0 +1,35 @@ +module Aviator + + define_request :list_tenants, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :identity + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/GET_listTenants_v2.0_tenants_Tenant_Operations.html' + + link 'documentation bug', + 'https://bugs.launchpad.net/keystone/+bug/1218601' + + + param :marker, :required => false + param :limit, :required => false + + + def headers + super + end + + + def http_method + :get + end + + + def url + str = "#{ base_url }/tenants" + str += params_to_querystring(optional_params + required_params) + end + + end + +end \ No newline at end of file diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/list_users.rb b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/list_users.rb new file mode 100644 index 000000000..c17631035 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/list_users.rb @@ -0,0 +1,37 @@ +module Aviator + + define_request :list_users do + + meta :provider, :openstack + meta :service, :identity + meta :api_version, :v2 + meta :endpoint_type, :admin + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/GET_listUsers_v2.0_users_.html' + + + def headers + h = {} + + unless self.anonymous? + h['X-Auth-Token'] = session_data[:access][:token][:id] + end + + h + end + + + def http_method + :get + end + + + def url + service_spec = session_data[:access][:serviceCatalog].find{|s| s[:type] == 'identity' } + "#{ service_spec[:endpoints][0][:adminURL] }/users" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/update_tenant.rb b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/update_tenant.rb new file mode 100644 index 000000000..d3a56cf6b --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/update_tenant.rb @@ -0,0 +1,47 @@ +module Aviator + + define_request :update_tenant, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :identity + + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/POST_updateTenant_v2.0_tenants__tenantId__.html' + + + param :id, :required => true + param :name, :required => false + param :enabled, :required => false + param :description, :required => false + + + def body + p = { + :tenant => {} + } + + [:name, :enabled, :description].each do |key| + p[:tenant][key] = params[key] if params[key] + end + + p + end + + + def headers + super + end + + + def http_method + :put + end + + + def url + "#{ base_url }/tenants/#{ params[:id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/update_user.rb b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/update_user.rb new file mode 100644 index 000000000..4676de4cc --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/admin/update_user.rb @@ -0,0 +1,61 @@ +module Aviator + + define_request :update_user do + + meta :provider, :openstack + meta :service, :identity + meta :api_version, :v2 + meta :endpoint_type, :admin + + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/POST_updateUser_v2.0_users__userId__.html' + + link 'bug', + 'https://bugs.launchpad.net/keystone/+bug/1226475' + + param :id, :required => true + param :name, :required => false + param :password, :required => false + param :email, :required => false + param :enabled, :required => false + param :tenantId, :required => false, :alias => :tenant_id + + + def body + p = { + :user => {} + } + + optional_params.each do |key| + p[:user][key] = params[key] if params[key] + end + + p + end + + + def headers + h = {} + + unless self.anonymous? + h['X-Auth-Token'] = session_data[:access][:token][:id] + end + + h + end + + + def http_method + :put + end + + + def url + service_spec = session_data[:access][:serviceCatalog].find { |s| s[:type] == service.to_s } + "#{ service_spec[:endpoints][0][:adminURL] }/users/#{ params[:id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/public/create_token.rb b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/public/create_token.rb new file mode 100644 index 000000000..91731d462 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/public/create_token.rb @@ -0,0 +1,62 @@ +module Aviator + + define_request :create_token, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :anonymous, true + meta :service, :identity + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/POST_authenticate_v2.0_tokens_.html' + + link 'documentation bug', + 'https://bugs.launchpad.net/keystone/+bug/1208607' + + + param :username, :required => false + param :password, :required => false + param :tokenId, :required => false, :alias => :token_id + param :tenantName, :required => false, :alias => :tenant_name + param :tenantId, :required => false, :alias => :tenant_id + + + def body + p = if params[:tokenId] + { + :auth => { + :token => { + :id => params[:tokenId] + } + } + } + else + { + :auth => { + :passwordCredentials => { + :username => params[:username], + :password => params[:password] + } + } + } + end + + p[:auth][:tenantName] = params[:tenantName] if params[:tenantName] + p[:auth][:tenantId] = params[:tenantId] if params[:tenantId] + + p + end + + + def http_method + :post + end + + + def url + url = session_data[:auth_service][:host_uri] + url += '/v2.0' if (URI(url).path =~ /^\/?\w+/).nil? + url += "/tokens" + end + + end + +end \ No newline at end of file diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/public/list_tenants.rb b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/public/list_tenants.rb new file mode 100644 index 000000000..094032ab0 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/public/list_tenants.rb @@ -0,0 +1,35 @@ +module Aviator + + define_request :list_tenants, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :identity + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/GET_listTenants_v2.0_tokens_tenants_.html' + + link 'documentation bug', + 'https://bugs.launchpad.net/keystone/+bug/1218601' + + + param :marker, :required => false + param :limit, :required => false + + + def url + str = "#{ base_url }/tenants" + str += params_to_querystring(optional_params + required_params) + end + + + def headers + super + end + + + def http_method + :get + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/public/root.rb b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/public/root.rb new file mode 100644 index 000000000..0c6d38358 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/identity/v2/public/root.rb @@ -0,0 +1,25 @@ +module Aviator + + define_request :root, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :identity + + + def headers + super + end + + + def http_method + :get + end + + + def url + uri = URI(base_url) + "#{ uri.scheme }://#{ uri.host }:#{ uri.port.to_s }/v2.0/" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/image/v1/public/list_public_images.rb b/3rdparty/modules/aviator/feature/aviator/openstack/image/v1/public/list_public_images.rb new file mode 100644 index 000000000..2164d73eb --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/image/v1/public/list_public_images.rb @@ -0,0 +1,45 @@ +module Aviator + + define_request :list_public_images, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :image + meta :api_version, :v1 + + link 'documentation', 'http://docs.openstack.org/api/openstack-image-service/1.1/content/requesting-a-list-of-public-vm-images.html' + + param :name, :required => false + param :container_format, :required => false + param :disk_format, :required => false + param :status, :required => false + param :size_min, :required => false + param :size_max, :required => false + param :sort_key, :required => false + param :sort_dir, :required => false + + + def headers + super + end + + def http_method + :get + end + + def url + uri = URI(base_url) + url = "#{ uri.scheme }://#{ uri.host }:#{ uri.port.to_s }/v1/images" + + filters = [] + + optional_params.each do |param_name| + filters << "#{ param_name }=#{ params[param_name] }" if params[param_name] + end + + url += "?#{ filters.join('&') }" unless filters.empty? + + url + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/image/v1/public/root.rb b/3rdparty/modules/aviator/feature/aviator/openstack/image/v1/public/root.rb new file mode 100644 index 000000000..553f5369e --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/image/v1/public/root.rb @@ -0,0 +1,25 @@ +module Aviator + + define_request :root, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :image + meta :api_version, :v1 + + def headers + super + end + + + def http_method + :get + end + + + def url + uri = URI(base_url) + "#{ uri.scheme }://#{ uri.host }:#{ uri.port.to_s }/v1/" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/metering/v1/admin/list_projects.rb b/3rdparty/modules/aviator/feature/aviator/openstack/metering/v1/admin/list_projects.rb new file mode 100644 index 000000000..7ec8e667d --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/metering/v1/admin/list_projects.rb @@ -0,0 +1,27 @@ +module Aviator + + define_request :list_projects, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :metering + meta :api_version, :v1 + meta :endpoint_type, :admin + + + def headers + super + end + + + def http_method + :get + end + + + def url + uri = URI(base_url) + "#{ uri.scheme }://#{ uri.host }:#{ uri.port.to_s }/v1/projects" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/create_volume.rb b/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/create_volume.rb new file mode 100644 index 000000000..f40354d99 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/create_volume.rb @@ -0,0 +1,47 @@ +module Aviator + + define_request :create_volume, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :volume + meta :api_version, :v1 + + link 'documentation', 'http://docs.rackspace.com/cbs/api/v1.0/cbs-devguide/content/POST_createVolume_v1__tenant_id__volumes_v1__tenant_id__volumes.html' + + param :display_name, :required => true + param :display_description, :required => true + param :size, :required => true + param :volume_type, :required => false + param :availability_zone, :required => false + param :snapshot_id, :required => false + param :metadata, :required => false + + def body + p = { + :volume => { + :display_name => params[:display_name], + :display_description => params[:display_description], + :size => params[:size] + } + } + + optional_params.each do |key| + p[:volume][key] = params[key] if params[key] + end + + p + end + + def headers + super + end + + def http_method + :post + end + + def url + "#{ base_url }/volumes" + end + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/delete_volume.rb b/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/delete_volume.rb new file mode 100644 index 000000000..1397959aa --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/delete_volume.rb @@ -0,0 +1,25 @@ +module Aviator + + define_request :delete_volume, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :volume + meta :api_version, :v1 + + link 'documentation', 'http://docs.rackspace.com/cbs/api/v1.0/cbs-devguide/content/DELETE_deleteVolume_v1__tenant_id__volumes__volume_id__v1__tenant_id__volumes.html' + + param :id, :required => true + + def headers + super + end + + def http_method + :delete + end + + def url + "#{ base_url }/volumes/#{ params[:id] }" + end + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/get_volume.rb b/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/get_volume.rb new file mode 100644 index 000000000..991dc4454 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/get_volume.rb @@ -0,0 +1,28 @@ +module Aviator + + define_request :get_volume, :inherit => [:openstack, :common, :v2, :public, :base] do + meta :provider, :openstack + meta :service, :volume + meta :api_version, :v1 + meta :endpoint_type, :public + + link 'documentation', 'http://docs.rackspace.com/cbs/api/v1.0/cbs-devguide/content/GET_getVolume_v1__tenant_id__volumes__volume_id__v1__tenant_id__volumes.html' + + param :id, :required => true + + def headers + super + end + + def http_method + :get + end + + def url + "#{ base_url }/volumes/#{ params[:id] }" + end + + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/list_volume_types.rb b/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/list_volume_types.rb new file mode 100644 index 000000000..d2f0b5c8a --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/list_volume_types.rb @@ -0,0 +1,29 @@ +module Aviator + + define_request :list_volume_types, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :provider, :openstack + meta :service, :volume + meta :api_version, :v1 + meta :endpoint_type, :public + + link 'documentation', 'http://docs.rackspace.com/cbs/api/v1.0/cbs-devguide/content/GET_getVolumeTypes_v1__tenant_id__types_v1__tenant_id__types.html' + + param :extra_specs, :required => false + param :name, :required => false + + def headers + super + end + + def http_method + :get + end + + def url + "#{ base_url }/types" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/list_volumes.rb b/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/list_volumes.rb new file mode 100644 index 000000000..c88cf7500 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/list_volumes.rb @@ -0,0 +1,48 @@ +module Aviator + + define_request :list_volumes, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :volume + meta :api_version, :v1 + + link 'documentation', 'http://docs.rackspace.com/cbs/api/v1.0/cbs-devguide/content/GET_getVolumesSimple_v1__tenant_id__volumes_v1__tenant_id__volumes.html' + + param :all_tenants, :required => false + param :details, :required => false + param :status, :required => false + param :availability_zone, :required => false + param :bootable, :required => false + param :display_name, :required => false + param :display_description, :required => false + param :volume_type, :required => false + param :snapshot_id, :required => false + param :size, :required => false + + + def headers + super + end + + def http_method + :get + end + + def url + str = "#{ base_url }/volumes" + str += "/detail" if params[:details] + + filters = [] + + (optional_params + required_params - [:details]).each do |param_name| + value = param_name == :all_tenants && params[param_name] ? 1 : params[param_name] + filters << "#{ param_name }=#{ value }" if value + end + + str += "?#{ filters.join('&') }" unless filters.empty? + + str + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/root.rb b/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/root.rb new file mode 100644 index 000000000..0e3748c9c --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/root.rb @@ -0,0 +1,26 @@ +module Aviator + + define_request :root, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :volume + meta :api_version, :v1 + + + def headers + super + end + + + def http_method + :get + end + + + def url + uri = URI(base_url) + "#{ uri.scheme }://#{ uri.host }:#{ uri.port.to_s }/v1/" + end + + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/update_volume.rb b/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/update_volume.rb new file mode 100644 index 000000000..67121c36f --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/openstack/volume/v1/public/update_volume.rb @@ -0,0 +1,43 @@ +module Aviator + + define_request :update_volume, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :volume + meta :api_version, :v1 + + link 'documentation', 'http://docs.rackspace.com/cbs/api/v1.0/cbs-devguide/content/PUT_renameVolume_v1__tenant_id__volumes__volume_id__v1__tenant_id__volumes.html' + + param :id, :required => true + param :display_name, :required => false + param :display_description, :required => false + + + def body + p = { :volume => {} } + + [:display_name, :display_description].each do |key| + p[:volume][key] = params[key] if params[key] + end + + p + end + + + def headers + super + end + + + def http_method + :put + end + + + def url + "#{ base_url }/volumes/#{ params[:id] }" + end + + end + + +end diff --git a/3rdparty/modules/aviator/feature/aviator/string.rb b/3rdparty/modules/aviator/feature/aviator/string.rb new file mode 100644 index 000000000..7efa2e1ac --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/string.rb @@ -0,0 +1,18 @@ +class String + + def camelize + word = self.slice(0,1).capitalize + self.slice(1..-1) + word.gsub(/_([a-zA-Z\d])/) { "#{$1.capitalize}" } + end + + def constantize + self.split("::").inject(Object) do |namespace, sym| + namespace.const_get(sym.to_s.camelize, false) + end + end + + def underscore + self.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase + end + +end diff --git a/3rdparty/modules/aviator/feature/aviator/version.rb b/3rdparty/modules/aviator/feature/aviator/version.rb new file mode 100644 index 000000000..5726b3025 --- /dev/null +++ b/3rdparty/modules/aviator/feature/aviator/version.rb @@ -0,0 +1,3 @@ +module Aviator + VERSION = "0.0.7" +end diff --git a/3rdparty/modules/aviator/feature/composite_io.rb b/3rdparty/modules/aviator/feature/composite_io.rb new file mode 100644 index 000000000..4ba7cf5ff --- /dev/null +++ b/3rdparty/modules/aviator/feature/composite_io.rb @@ -0,0 +1,108 @@ +#-- +# Copyright (c) 2007-2012 Nick Sieger. +# See the file README.txt included with the distribution for +# software license details. +#++ + +# Concatenate together multiple IO objects into a single, composite IO object +# for purposes of reading as a single stream. +# +# Usage: +# +# crio = CompositeReadIO.new(StringIO.new('one'), StringIO.new('two'), StringIO.new('three')) +# puts crio.read # => "onetwothree" +# +class CompositeReadIO + # Create a new composite-read IO from the arguments, all of which should + # respond to #read in a manner consistent with IO. + def initialize(*ios) + @ios = ios.flatten + @index = 0 + end + + # Read from IOs in order until `length` bytes have been received. + def read(length = nil, outbuf = nil) + got_result = false + outbuf = outbuf ? outbuf.replace("") : "" + + while io = current_io + if result = io.read(length) + got_result ||= !result.nil? + result.force_encoding("BINARY") if result.respond_to?(:force_encoding) + outbuf << result + length -= result.length if length + break if length == 0 + end + advance_io + end + (!got_result && length) ? nil : outbuf + end + + def rewind + @ios.each { |io| io.rewind } + @index = 0 + end + + private + + def current_io + @ios[@index] + end + + def advance_io + @index += 1 + end +end + +# Convenience methods for dealing with files and IO that are to be uploaded. +class UploadIO + # Create an upload IO suitable for including in the params hash of a + # Net::HTTP::Post::Multipart. + # + # Can take two forms. The first accepts a filename and content type, and + # opens the file for reading (to be closed by finalizer). + # + # The second accepts an already-open IO, but also requires a third argument, + # the filename from which it was opened (particularly useful/recommended if + # uploading directly from a form in a framework, which often save the file to + # an arbitrarily named RackMultipart file in /tmp). + # + # Usage: + # + # UploadIO.new("file.txt", "text/plain") + # UploadIO.new(file_io, "text/plain", "file.txt") + # + attr_reader :content_type, :original_filename, :local_path, :io, :opts + + def initialize(filename_or_io, content_type, filename = nil, opts = {}) + io = filename_or_io + local_path = "" + if io.respond_to? :read + # in Ruby 1.9.2, StringIOs no longer respond to path + # (since they respond to :length, so we don't need their local path, see parts.rb:41) + local_path = filename_or_io.respond_to?(:path) ? filename_or_io.path : "local.path" + else + io = File.open(filename_or_io) + local_path = filename_or_io + end + filename ||= local_path + + @content_type = content_type + @original_filename = File.basename(filename) + @local_path = local_path + @io = io + @opts = opts + end + + def self.convert!(io, content_type, original_filename, local_path) + raise ArgumentError, "convert! has been removed. You must now wrap IOs using:\nUploadIO.new(filename_or_io, content_type, filename=nil)\nPlease update your code." + end + + def method_missing(*args) + @io.send(*args) + end + + def respond_to?(meth, include_all = false) + @io.respond_to?(meth, include_all) || super(meth, include_all) + end +end diff --git a/3rdparty/modules/aviator/feature/faraday.rb b/3rdparty/modules/aviator/feature/faraday.rb new file mode 100644 index 000000000..4b63ec8e9 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday.rb @@ -0,0 +1,268 @@ +require 'thread' +require 'cgi' +require 'set' +require 'forwardable' + +# Public: This is the main namespace for Faraday. You can either use it to +# create Faraday::Connection objects, or access it directly. +# +# Examples +# +# Faraday.get "http://faraday.com" +# +# conn = Faraday.new "http://faraday.com" +# conn.get '/' +# +module Faraday + VERSION = "0.9.0" + + class << self + # Public: Gets or sets the root path that Faraday is being loaded from. + # This is the root from where the libraries are auto-loaded from. + attr_accessor :root_path + + # Public: Gets or sets the path that the Faraday libs are loaded from. + attr_accessor :lib_path + + # Public: Gets or sets the Symbol key identifying a default Adapter to use + # for the default Faraday::Connection. + attr_reader :default_adapter + + # Public: Sets the default Faraday::Connection for simple scripts that + # access the Faraday constant directly. + # + # Faraday.get "https://faraday.com" + attr_writer :default_connection + + # Public: Sets the default options used when calling Faraday#new. + attr_writer :default_connection_options + + # Public: Initializes a new Faraday::Connection. + # + # url - The optional String base URL to use as a prefix for all + # requests. Can also be the options Hash. + # options - The optional Hash used to configure this Faraday::Connection. + # Any of these values will be set on every request made, unless + # overridden for a specific request. + # :url - String base URL. + # :params - Hash of URI query unencoded key/value pairs. + # :headers - Hash of unencoded HTTP header key/value pairs. + # :request - Hash of request options. + # :ssl - Hash of SSL options. + # :proxy - Hash of Proxy options. + # + # Examples + # + # Faraday.new 'http://faraday.com' + # + # # http://faraday.com?page=1 + # Faraday.new 'http://faraday.com', :params => {:page => 1} + # + # # same + # + # Faraday.new :url => 'http://faraday.com', + # :params => {:page => 1} + # + # Returns a Faraday::Connection. + def new(url = nil, options = nil) + block = block_given? ? Proc.new : nil + options = options ? default_connection_options.merge(options) : default_connection_options.dup + Faraday::Connection.new(url, options, &block) + end + + # Internal: Requires internal Faraday libraries. + # + # *libs - One or more relative String names to Faraday classes. + # + # Returns nothing. + def require_libs(*libs) + libs.each do |lib| + require "#{lib_path}/#{lib}" + end + end + + # Public: Updates default adapter while resetting + # #default_connection. + # + # Returns the new default_adapter. + def default_adapter=(adapter) + @default_connection = nil + @default_adapter = adapter + end + + alias require_lib require_libs + + private + # Internal: Proxies method calls on the Faraday constant to + # #default_connection. + def method_missing(name, *args, &block) + default_connection.send(name, *args, &block) + end + end + + self.root_path = File.expand_path "..", __FILE__ + self.lib_path = File.expand_path "../faraday", __FILE__ + self.default_adapter = :net_http + + # Gets the default connection used for simple scripts. + # + # Returns a Faraday::Connection, configured with the #default_adapter. + def self.default_connection + @default_connection ||= Connection.new + end + + # Gets the default connection options used when calling Faraday#new. + # + # Returns a Faraday::ConnectionOptions. + def self.default_connection_options + @default_connection_options ||= ConnectionOptions.new + end + + if (!defined?(RUBY_ENGINE) || "ruby" == RUBY_ENGINE) && RUBY_VERSION < '1.9' + begin + require 'system_timer' + Timer = SystemTimer + rescue LoadError + warn "Faraday: you may want to install system_timer for reliable timeouts" + end + end + + unless const_defined? :Timer + require 'timeout' + Timer = Timeout + end + + # Public: Adds the ability for other modules to register and lookup + # middleware classes. + module MiddlewareRegistry + # Public: Register middleware class(es) on the current module. + # + # mapping - A Hash mapping Symbol keys to classes. Classes can be expressed + # as fully qualified constant, or a Proc that will be lazily + # called to return the former. + # + # Examples + # + # module Faraday + # class Whatever + # # Middleware looked up by :foo returns Faraday::Whatever::Foo. + # register_middleware :foo => Foo + # + # # Middleware looked up by :bar returns Faraday::Whatever.const_get(:Bar) + # register_middleware :bar => :Bar + # + # # Middleware looked up by :baz requires 'baz' and returns Faraday::Whatever.const_get(:Baz) + # register_middleware :baz => [:Baz, 'baz'] + # end + # end + # + # Returns nothing. + def register_middleware(autoload_path = nil, mapping = nil) + if mapping.nil? + mapping = autoload_path + autoload_path = nil + end + middleware_mutex do + @middleware_autoload_path = autoload_path if autoload_path + (@registered_middleware ||= {}).update(mapping) + end + end + + # Public: Lookup middleware class with a registered Symbol shortcut. + # + # key - The Symbol key for the registered middleware. + # + # Examples + # + # module Faraday + # class Whatever + # register_middleware :foo => Foo + # end + # end + # + # Faraday::Whatever.lookup_middleware(:foo) + # # => Faraday::Whatever::Foo + # + # Returns a middleware Class. + def lookup_middleware(key) + load_middleware(key) || + raise(Faraday::Error.new("#{key.inspect} is not registered on #{self}")) + end + + def middleware_mutex(&block) + @middleware_mutex ||= begin + require 'monitor' + Monitor.new + end + @middleware_mutex.synchronize(&block) + end + + def fetch_middleware(key) + defined?(@registered_middleware) && @registered_middleware[key] + end + + def load_middleware(key) + value = fetch_middleware(key) + case value + when Module + value + when Symbol, String + middleware_mutex do + @registered_middleware[key] = const_get(value) + end + when Proc + middleware_mutex do + @registered_middleware[key] = value.call + end + when Array + middleware_mutex do + const, path = value + if root = @middleware_autoload_path + path = "#{root}/#{path}" + end + require(path) + @registered_middleware[key] = const + end + load_middleware(key) + end + end + end + + def self.const_missing(name) + if name.to_sym == :Builder + warn "Faraday::Builder is now Faraday::RackBuilder." + const_set name, RackBuilder + else + super + end + end + + require_libs "utils", "options", "connection", "rack_builder", "parameters", + "middleware", "adapter", "request", "response", "upload_io", "error" + + if !ENV["FARADAY_NO_AUTOLOAD"] + require_lib 'autoload' + end +end + +# not pulling in active-support JUST for this method. And I love this method. +class Object + # The primary purpose of this method is to "tap into" a method chain, + # in order to perform operations on intermediate results within the chain. + # + # Examples + # + # (1..10).tap { |x| puts "original: #{x.inspect}" }.to_a. + # tap { |x| puts "array: #{x.inspect}" }. + # select { |x| x%2 == 0 }. + # tap { |x| puts "evens: #{x.inspect}" }. + # map { |x| x*x }. + # tap { |x| puts "squares: #{x.inspect}" } + # + # Yields self. + # Returns self. + def tap + yield(self) + self + end unless Object.respond_to?(:tap) +end diff --git a/3rdparty/modules/aviator/feature/faraday/adapter.rb b/3rdparty/modules/aviator/feature/faraday/adapter.rb new file mode 100644 index 000000000..f018b509a --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/adapter.rb @@ -0,0 +1,46 @@ +module Faraday + # Public: This is a base class for all Faraday adapters. Adapters are + # responsible for fulfilling a Faraday request. + class Adapter < Middleware + CONTENT_LENGTH = 'Content-Length'.freeze + + register_middleware File.expand_path('../adapter', __FILE__), + :test => [:Test, 'test'], + :net_http => [:NetHttp, 'net_http'], + :net_http_persistent => [:NetHttpPersistent, 'net_http_persistent'], + :typhoeus => [:Typhoeus, 'typhoeus'], + :patron => [:Patron, 'patron'], + :em_synchrony => [:EMSynchrony, 'em_synchrony'], + :em_http => [:EMHttp, 'em_http'], + :excon => [:Excon, 'excon'], + :rack => [:Rack, 'rack'], + :httpclient => [:HTTPClient, 'httpclient'] + + # Public: This module marks an Adapter as supporting parallel requests. + module Parallelism + attr_writer :supports_parallel + def supports_parallel?() @supports_parallel end + + def inherited(subclass) + super + subclass.supports_parallel = self.supports_parallel? + end + end + + extend Parallelism + self.supports_parallel = false + + def call(env) + env.clear_body if env.needs_body? + end + + def save_response(env, status, body, headers = nil) + env.status = status + env.body = body + env.response_headers = Utils::Headers.new.tap do |response_headers| + response_headers.update headers unless headers.nil? + yield(response_headers) if block_given? + end + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/adapter/em_http.rb b/3rdparty/modules/aviator/feature/faraday/adapter/em_http.rb new file mode 100644 index 000000000..a248fcfd2 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/adapter/em_http.rb @@ -0,0 +1,237 @@ +module Faraday + class Adapter + # EventMachine adapter is useful for either asynchronous requests + # when in EM reactor loop or for making parallel requests in + # synchronous code. + class EMHttp < Faraday::Adapter + module Options + def connection_config(env) + options = {} + configure_proxy(options, env) + configure_timeout(options, env) + configure_socket(options, env) + configure_ssl(options, env) + options + end + + def request_config(env) + options = { + :body => read_body(env), + :head => env[:request_headers], + # :keepalive => true, + # :file => 'path/to/file', # stream data off disk + } + configure_compression(options, env) + options + end + + def read_body(env) + body = env[:body] + body.respond_to?(:read) ? body.read : body + end + + def configure_proxy(options, env) + if proxy = request_options(env)[:proxy] + options[:proxy] = { + :host => proxy[:uri].host, + :port => proxy[:uri].port, + :authorization => [proxy[:user], proxy[:password]] + } + end + end + + def configure_socket(options, env) + if bind = request_options(env)[:bind] + options[:bind] = { + :host => bind[:host], + :port => bind[:port] + } + end + end + + def configure_ssl(options, env) + if env[:url].scheme == 'https' && env[:ssl] + options[:ssl] = { + :cert_chain_file => env[:ssl][:ca_file], + :verify_peer => env[:ssl].fetch(:verify, true) + } + end + end + + def configure_timeout(options, env) + timeout, open_timeout = request_options(env).values_at(:timeout, :open_timeout) + options[:connect_timeout] = options[:inactivity_timeout] = timeout + options[:connect_timeout] = open_timeout if open_timeout + end + + def configure_compression(options, env) + if env[:method] == :get and not options[:head].key? 'accept-encoding' + options[:head]['accept-encoding'] = 'gzip, compressed' + end + end + + def request_options(env) + env[:request] + end + end + + include Options + + dependency 'em-http' + + self.supports_parallel = true + + def self.setup_parallel_manager(options = nil) + Manager.new + end + + def call(env) + super + perform_request env + @app.call env + end + + def perform_request(env) + if parallel?(env) + manager = env[:parallel_manager] + manager.add { + perform_single_request(env). + callback { env[:response].finish(env) } + } + else + unless EventMachine.reactor_running? + error = nil + # start EM, block until request is completed + EventMachine.run do + perform_single_request(env). + callback { EventMachine.stop }. + errback { |client| + error = error_message(client) + EventMachine.stop + } + end + raise_error(error) if error + else + # EM is running: instruct upstream that this is an async request + env[:parallel_manager] = true + perform_single_request(env). + callback { env[:response].finish(env) }. + errback { + # TODO: no way to communicate the error in async mode + raise NotImplementedError + } + end + end + rescue EventMachine::Connectify::CONNECTError => err + if err.message.include?("Proxy Authentication Required") + raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "} + else + raise Error::ConnectionFailed, err + end + rescue => err + if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err + raise Faraday::SSLError, err + else + raise + end + end + + # TODO: reuse the connection to support pipelining + def perform_single_request(env) + req = EventMachine::HttpRequest.new(env[:url], connection_config(env)) + req.setup_request(env[:method], request_config(env)).callback { |client| + save_response(env, client.response_header.status, client.response) do |resp_headers| + client.response_header.each do |name, value| + resp_headers[name.to_sym] = value + end + end + } + end + + def error_message(client) + client.error or "request failed" + end + + def raise_error(msg) + errklass = Faraday::Error::ClientError + if msg == Errno::ETIMEDOUT + errklass = Faraday::Error::TimeoutError + msg = "request timed out" + elsif msg == Errno::ECONNREFUSED + errklass = Faraday::Error::ConnectionFailed + msg = "connection refused" + elsif msg == "connection closed by server" + errklass = Faraday::Error::ConnectionFailed + end + raise errklass, msg + end + + def parallel?(env) + !!env[:parallel_manager] + end + + # The parallel manager is designed to start an EventMachine loop + # and block until all registered requests have been completed. + class Manager + def initialize + reset + end + + def reset + @registered_procs = [] + @num_registered = 0 + @num_succeeded = 0 + @errors = [] + @running = false + end + + def running?() @running end + + def add + if running? + perform_request { yield } + else + @registered_procs << Proc.new + end + @num_registered += 1 + end + + def run + if @num_registered > 0 + @running = true + EventMachine.run do + @registered_procs.each do |proc| + perform_request(&proc) + end + end + if @errors.size > 0 + raise Faraday::Error::ClientError, @errors.first || "connection failed" + end + end + ensure + reset + end + + def perform_request + client = yield + client.callback { @num_succeeded += 1; check_finished } + client.errback { @errors << client.error; check_finished } + end + + def check_finished + if @num_succeeded + @errors.size == @num_registered + EventMachine.stop + end + end + end + end + end +end + +begin + require 'openssl' +rescue LoadError + warn "Warning: no such file to load -- openssl. Make sure it is installed if you want HTTPS support" +else + require 'faraday/adapter/em_http_ssl_patch' +end if Faraday::Adapter::EMHttp.loaded? diff --git a/3rdparty/modules/aviator/feature/faraday/adapter/em_http_ssl_patch.rb b/3rdparty/modules/aviator/feature/faraday/adapter/em_http_ssl_patch.rb new file mode 100644 index 000000000..8bbfcbce3 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/adapter/em_http_ssl_patch.rb @@ -0,0 +1,56 @@ +require 'openssl' +require 'em-http' + +module EmHttpSslPatch + def ssl_verify_peer(cert_string) + cert = nil + begin + cert = OpenSSL::X509::Certificate.new(cert_string) + rescue OpenSSL::X509::CertificateError + return false + end + + @last_seen_cert = cert + + if certificate_store.verify(@last_seen_cert) + begin + certificate_store.add_cert(@last_seen_cert) + rescue OpenSSL::X509::StoreError => e + raise e unless e.message == 'cert already in hash table' + end + true + else + raise OpenSSL::SSL::SSLError.new(%(unable to verify the server certificate for "#{host}")) + end + end + + def ssl_handshake_completed + return true unless verify_peer? + + unless OpenSSL::SSL.verify_certificate_identity(@last_seen_cert, host) + raise OpenSSL::SSL::SSLError.new(%(host "#{host}" does not match the server certificate)) + else + true + end + end + + def verify_peer? + parent.connopts.tls[:verify_peer] + end + + def host + parent.connopts.host + end + + def certificate_store + @certificate_store ||= begin + store = OpenSSL::X509::Store.new + store.set_default_paths + ca_file = parent.connopts.tls[:cert_chain_file] + store.add_file(ca_file) if ca_file + store + end + end +end + +EventMachine::HttpStubConnection.send(:include, EmHttpSslPatch) diff --git a/3rdparty/modules/aviator/feature/faraday/adapter/em_synchrony.rb b/3rdparty/modules/aviator/feature/faraday/adapter/em_synchrony.rb new file mode 100644 index 000000000..305e702f8 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/adapter/em_synchrony.rb @@ -0,0 +1,92 @@ +require 'uri' + +module Faraday + class Adapter + class EMSynchrony < Faraday::Adapter + include EMHttp::Options + + dependency do + require 'em-synchrony/em-http' + require 'em-synchrony/em-multi' + require 'fiber' + end + + self.supports_parallel = true + + def self.setup_parallel_manager(options = {}) + ParallelManager.new + end + + def call(env) + super + request = EventMachine::HttpRequest.new(Utils::URI(env[:url].to_s), connection_config(env)) + + http_method = env[:method].to_s.downcase.to_sym + + # Queue requests for parallel execution. + if env[:parallel_manager] + env[:parallel_manager].add(request, http_method, request_config(env)) do |resp| + save_response(env, resp.response_header.status, resp.response) do |resp_headers| + resp.response_header.each do |name, value| + resp_headers[name.to_sym] = value + end + end + + # Finalize the response object with values from `env`. + env[:response].finish(env) + end + + # Execute single request. + else + client = nil + block = lambda { request.send(http_method, request_config(env)) } + + if !EM.reactor_running? + EM.run do + Fiber.new { + client = block.call + EM.stop + }.resume + end + else + client = block.call + end + + raise client.error if client.error + + save_response(env, client.response_header.status, client.response) do |resp_headers| + client.response_header.each do |name, value| + resp_headers[name.to_sym] = value + end + end + end + + @app.call env + rescue Errno::ECONNREFUSED + raise Error::ConnectionFailed, $! + rescue EventMachine::Connectify::CONNECTError => err + if err.message.include?("Proxy Authentication Required") + raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "} + else + raise Error::ConnectionFailed, err + end + rescue => err + if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err + raise Faraday::SSLError, err + else + raise + end + end + end + end +end + +require 'faraday/adapter/em_synchrony/parallel_manager' + +begin + require 'openssl' +rescue LoadError + warn "Warning: no such file to load -- openssl. Make sure it is installed if you want HTTPS support" +else + require 'faraday/adapter/em_http_ssl_patch' +end if Faraday::Adapter::EMSynchrony.loaded? diff --git a/3rdparty/modules/aviator/feature/faraday/adapter/em_synchrony/parallel_manager.rb b/3rdparty/modules/aviator/feature/faraday/adapter/em_synchrony/parallel_manager.rb new file mode 100644 index 000000000..12a1bafa4 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/adapter/em_synchrony/parallel_manager.rb @@ -0,0 +1,66 @@ +module Faraday + class Adapter + class EMSynchrony < Faraday::Adapter + class ParallelManager + + # Add requests to queue. The `request` argument should be a + # `EM::HttpRequest` object. + def add(request, method, *args, &block) + queue << { + :request => request, + :method => method, + :args => args, + :block => block + } + end + + # Run all requests on queue with `EM::Synchrony::Multi`, wrapping + # it in a reactor and fiber if needed. + def run + result = nil + if !EM.reactor_running? + EM.run { + Fiber.new do + result = perform + EM.stop + end.resume + } + else + result = perform + end + result + end + + + private + + # The request queue. + def queue + @queue ||= [] + end + + # Main `EM::Synchrony::Multi` performer. + def perform + multi = ::EM::Synchrony::Multi.new + + queue.each do |item| + method = "a#{item[:method]}".to_sym + + req = item[:request].send(method, *item[:args]) + req.callback(&item[:block]) + + req_name = "req_#{multi.requests.size}".to_sym + multi.add(req_name, req) + end + + # Clear the queue, so parallel manager objects can be reused. + @queue = [] + + # Block fiber until all requests have returned. + multi.perform + end + + end # ParallelManager + end # EMSynchrony + end # Adapter +end # Faraday diff --git a/3rdparty/modules/aviator/feature/faraday/adapter/excon.rb b/3rdparty/modules/aviator/feature/faraday/adapter/excon.rb new file mode 100644 index 000000000..db0c7c352 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/adapter/excon.rb @@ -0,0 +1,80 @@ +module Faraday + class Adapter + class Excon < Faraday::Adapter + dependency 'excon' + + def initialize(app, connection_options = {}) + @connection_options = connection_options + super(app) + end + + def call(env) + super + + opts = {} + if env[:url].scheme == 'https' && ssl = env[:ssl] + opts[:ssl_verify_peer] = !!ssl.fetch(:verify, true) + opts[:ssl_ca_path] = ssl[:ca_path] if ssl[:ca_path] + opts[:ssl_ca_file] = ssl[:ca_file] if ssl[:ca_file] + opts[:client_cert] = ssl[:client_cert] if ssl[:client_cert] + opts[:client_key] = ssl[:client_key] if ssl[:client_key] + opts[:certificate] = ssl[:certificate] if ssl[:certificate] + opts[:private_key] = ssl[:private_key] if ssl[:private_key] + + # https://github.com/geemus/excon/issues/106 + # https://github.com/jruby/jruby-ossl/issues/19 + opts[:nonblock] = false + end + + if ( req = env[:request] ) + if req[:timeout] + opts[:read_timeout] = req[:timeout] + opts[:connect_timeout] = req[:timeout] + opts[:write_timeout] = req[:timeout] + end + + if req[:open_timeout] + opts[:connect_timeout] = req[:open_timeout] + opts[:write_timeout] = req[:open_timeout] + end + + if req[:proxy] + opts[:proxy] = { + :host => req[:proxy][:uri].host, + :port => req[:proxy][:uri].port, + :scheme => req[:proxy][:uri].scheme, + :user => req[:proxy][:user], + :password => req[:proxy][:password] + } + end + end + + conn = ::Excon.new(env[:url].to_s, opts.merge(@connection_options)) + + resp = conn.request \ + :method => env[:method].to_s.upcase, + :headers => env[:request_headers], + :body => read_body(env) + + save_response(env, resp.status.to_i, resp.body, resp.headers) + + @app.call env + rescue ::Excon::Errors::SocketError => err + if err.message =~ /\btimeout\b/ + raise Error::TimeoutError, err + elsif err.message =~ /\bcertificate\b/ + raise Faraday::SSLError, err + else + raise Error::ConnectionFailed, err + end + rescue ::Excon::Errors::Timeout => err + raise Error::TimeoutError, err + end + + # TODO: support streaming requests + def read_body(env) + env[:body].respond_to?(:read) ? env[:body].read : env[:body] + end + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/adapter/httpclient.rb b/3rdparty/modules/aviator/feature/faraday/adapter/httpclient.rb new file mode 100644 index 000000000..06c663f03 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/adapter/httpclient.rb @@ -0,0 +1,106 @@ +module Faraday + class Adapter + class HTTPClient < Faraday::Adapter + dependency 'httpclient' + + def client + @client ||= ::HTTPClient.new + end + + def call(env) + super + + if req = env[:request] + if proxy = req[:proxy] + configure_proxy proxy + end + + if bind = req[:bind] + configure_socket bind + end + + configure_timeouts req + end + + if env[:url].scheme == 'https' && ssl = env[:ssl] + configure_ssl ssl + end + + # TODO Don't stream yet. + # https://github.com/nahi/httpclient/pull/90 + env[:body] = env[:body].read if env[:body].respond_to? :read + + resp = client.request env[:method], env[:url], + :body => env[:body], + :header => env[:request_headers] + + save_response env, resp.status, resp.body, resp.headers + + @app.call env + rescue ::HTTPClient::TimeoutError + raise Faraday::Error::TimeoutError, $! + rescue ::HTTPClient::BadResponseError => err + if err.message.include?('status 407') + raise Faraday::Error::ConnectionFailed, %{407 "Proxy Authentication Required "} + else + raise Faraday::Error::ClientError, $! + end + rescue Errno::ECONNREFUSED, EOFError + raise Faraday::Error::ConnectionFailed, $! + rescue => err + if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err + raise Faraday::SSLError, err + else + raise + end + end + + def configure_socket(bind) + client.socket_local.host = bind[:host] + client.socket_local.port = bind[:port] + end + + def configure_proxy(proxy) + client.proxy = proxy[:uri] + if proxy[:user] && proxy[:password] + client.set_proxy_auth proxy[:user], proxy[:password] + end + end + + def configure_ssl(ssl) + ssl_config = client.ssl_config + + ssl_config.add_trust_ca ssl[:ca_file] if ssl[:ca_file] + ssl_config.add_trust_ca ssl[:ca_path] if ssl[:ca_path] + ssl_config.cert_store = ssl[:cert_store] if ssl[:cert_store] + ssl_config.client_cert = ssl[:client_cert] if ssl[:client_cert] + ssl_config.client_key = ssl[:client_key] if ssl[:client_key] + ssl_config.verify_depth = ssl[:verify_depth] if ssl[:verify_depth] + ssl_config.verify_mode = ssl_verify_mode(ssl) + end + + def configure_timeouts(req) + if req[:timeout] + client.connect_timeout = req[:timeout] + client.receive_timeout = req[:timeout] + client.send_timeout = req[:timeout] + end + + if req[:open_timeout] + client.connect_timeout = req[:open_timeout] + client.send_timeout = req[:open_timeout] + end + end + + def ssl_verify_mode(ssl) + ssl[:verify_mode] || begin + if ssl.fetch(:verify, true) + OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT + else + OpenSSL::SSL::VERIFY_NONE + end + end + end + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/adapter/net_http.rb b/3rdparty/modules/aviator/feature/faraday/adapter/net_http.rb new file mode 100644 index 000000000..449388a7f --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/adapter/net_http.rb @@ -0,0 +1,124 @@ +begin + require 'net/https' +rescue LoadError + warn "Warning: no such file to load -- net/https. Make sure openssl is installed if you want ssl support" + require 'net/http' +end +require 'zlib' + +module Faraday + class Adapter + class NetHttp < Faraday::Adapter + NET_HTTP_EXCEPTIONS = [ + EOFError, + Errno::ECONNABORTED, + Errno::ECONNREFUSED, + Errno::ECONNRESET, + Errno::EHOSTUNREACH, + Errno::EINVAL, + Errno::ENETUNREACH, + Net::HTTPBadResponse, + Net::HTTPHeaderSyntaxError, + Net::ProtocolError, + SocketError, + Zlib::GzipFile::Error, + ] + + NET_HTTP_EXCEPTIONS << OpenSSL::SSL::SSLError if defined?(OpenSSL) + + def call(env) + super + http = net_http_connection(env) + configure_ssl(http, env[:ssl]) if env[:url].scheme == 'https' and env[:ssl] + + req = env[:request] + http.read_timeout = http.open_timeout = req[:timeout] if req[:timeout] + http.open_timeout = req[:open_timeout] if req[:open_timeout] + + begin + http_response = perform_request(http, env) + rescue *NET_HTTP_EXCEPTIONS => err + if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err + raise Faraday::SSLError, err + else + raise Error::ConnectionFailed, err + end + end + + save_response(env, http_response.code.to_i, http_response.body || '') do |response_headers| + http_response.each_header do |key, value| + response_headers[key] = value + end + end + + @app.call env + rescue Timeout::Error => err + raise Faraday::Error::TimeoutError, err + end + + def create_request(env) + request = Net::HTTPGenericRequest.new \ + env[:method].to_s.upcase, # request method + !!env[:body], # is there request body + :head != env[:method], # is there response body + env[:url].request_uri, # request uri path + env[:request_headers] # request headers + + if env[:body].respond_to?(:read) + request.body_stream = env[:body] + else + request.body = env[:body] + end + request + end + + def perform_request(http, env) + if :get == env[:method] and !env[:body] + # prefer `get` to `request` because the former handles gzip (ruby 1.9) + http.get env[:url].request_uri, env[:request_headers] + else + http.request create_request(env) + end + end + + def net_http_connection(env) + if proxy = env[:request][:proxy] + Net::HTTP::Proxy(proxy[:uri].host, proxy[:uri].port, proxy[:user], proxy[:password]) + else + Net::HTTP + end.new(env[:url].host, env[:url].port) + end + + def configure_ssl(http, ssl) + http.use_ssl = true + http.verify_mode = ssl_verify_mode(ssl) + http.cert_store = ssl_cert_store(ssl) + + http.cert = ssl[:client_cert] if ssl[:client_cert] + http.key = ssl[:client_key] if ssl[:client_key] + http.ca_file = ssl[:ca_file] if ssl[:ca_file] + http.ca_path = ssl[:ca_path] if ssl[:ca_path] + http.verify_depth = ssl[:verify_depth] if ssl[:verify_depth] + http.ssl_version = ssl[:version] if ssl[:version] + end + + def ssl_cert_store(ssl) + return ssl[:cert_store] if ssl[:cert_store] + # Use the default cert store by default, i.e. system ca certs + cert_store = OpenSSL::X509::Store.new + cert_store.set_default_paths + cert_store + end + + def ssl_verify_mode(ssl) + ssl[:verify_mode] || begin + if ssl.fetch(:verify, true) + OpenSSL::SSL::VERIFY_PEER + else + OpenSSL::SSL::VERIFY_NONE + end + end + end + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/adapter/net_http_persistent.rb b/3rdparty/modules/aviator/feature/faraday/adapter/net_http_persistent.rb new file mode 100644 index 000000000..e0cc9587e --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/adapter/net_http_persistent.rb @@ -0,0 +1,47 @@ +# Rely on autoloading instead of explicit require; helps avoid the "already +# initialized constant" warning on Ruby 1.8.7 when NetHttp is refereced below. +# require 'faraday/adapter/net_http' + +module Faraday + class Adapter + # Experimental adapter for net-http-persistent + class NetHttpPersistent < NetHttp + dependency 'net/http/persistent' + + def net_http_connection(env) + if proxy = env[:request][:proxy] + proxy_uri = ::URI::HTTP === proxy[:uri] ? proxy[:uri].dup : ::URI.parse(proxy[:uri].to_s) + proxy_uri.user = proxy_uri.password = nil + # awful patch for net-http-persistent 2.8 not unescaping user/password + (class << proxy_uri; self; end).class_eval do + define_method(:user) { proxy[:user] } + define_method(:password) { proxy[:password] } + end if proxy[:user] + end + Net::HTTP::Persistent.new 'Faraday', proxy_uri + end + + def perform_request(http, env) + http.request env[:url], create_request(env) + rescue Net::HTTP::Persistent::Error => error + if error.message.include? 'Timeout' + raise Faraday::Error::TimeoutError, error + elsif error.message.include? 'connection refused' + raise Faraday::Error::ConnectionFailed, error + else + raise + end + end + + def configure_ssl(http, ssl) + http.verify_mode = ssl_verify_mode(ssl) + http.cert_store = ssl_cert_store(ssl) + + http.certificate = ssl[:client_cert] if ssl[:client_cert] + http.private_key = ssl[:client_key] if ssl[:client_key] + http.ca_file = ssl[:ca_file] if ssl[:ca_file] + http.ssl_version = ssl[:version] if ssl[:version] + end + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/adapter/patron.rb b/3rdparty/modules/aviator/feature/faraday/adapter/patron.rb new file mode 100644 index 000000000..cf2d37fbe --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/adapter/patron.rb @@ -0,0 +1,72 @@ +module Faraday + class Adapter + class Patron < Faraday::Adapter + dependency 'patron' + + def initialize(app, &block) + super(app) + @block = block + end + + def call(env) + super + + # TODO: support streaming requests + env[:body] = env[:body].read if env[:body].respond_to? :read + + session = @session ||= create_session + + if req = env[:request] + session.timeout = session.connect_timeout = req[:timeout] if req[:timeout] + session.connect_timeout = req[:open_timeout] if req[:open_timeout] + + if proxy = req[:proxy] + proxy_uri = proxy[:uri].dup + proxy_uri.user = proxy[:user] && Utils.escape(proxy[:user]).gsub('+', '%20') + proxy_uri.password = proxy[:password] && Utils.escape(proxy[:password]).gsub('+', '%20') + session.proxy = proxy_uri.to_s + end + end + + response = begin + data = env[:body] ? env[:body].to_s : nil + session.request(env[:method], env[:url].to_s, env[:request_headers], :data => data) + rescue Errno::ECONNREFUSED, ::Patron::ConnectionFailed + raise Error::ConnectionFailed, $! + end + + save_response(env, response.status, response.body, response.headers) + + @app.call env + rescue ::Patron::TimeoutError => err + if err.message == "Connection time-out" + raise Faraday::Error::ConnectionFailed, err + else + raise Faraday::Error::TimeoutError, err + end + rescue ::Patron::Error => err + if err.message.include?("code 407") + raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "} + else + raise Error::ConnectionFailed, err + end + end + + if loaded? && defined?(::Patron::Request::VALID_ACTIONS) + # HAX: helps but doesn't work completely + # https://github.com/toland/patron/issues/34 + ::Patron::Request::VALID_ACTIONS.tap do |actions| + actions << :patch unless actions.include? :patch + actions << :options unless actions.include? :options + end + end + + def create_session + session = ::Patron::Session.new + session.insecure = true + @block.call(session) if @block + session + end + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/adapter/rack.rb b/3rdparty/modules/aviator/feature/faraday/adapter/rack.rb new file mode 100644 index 000000000..0d2146487 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/adapter/rack.rb @@ -0,0 +1,58 @@ +module Faraday + class Adapter + # Sends requests to a Rack app. + # + # Examples + # + # class MyRackApp + # def call(env) + # [200, {'Content-Type' => 'text/html'}, ["hello world"]] + # end + # end + # + # Faraday.new do |conn| + # conn.adapter :rack, MyRackApp.new + # end + class Rack < Faraday::Adapter + dependency 'rack/test' + + # not prefixed with "HTTP_" + SPECIAL_HEADERS = %w[ CONTENT_LENGTH CONTENT_TYPE ] + + def initialize(faraday_app, rack_app) + super(faraday_app) + mock_session = ::Rack::MockSession.new(rack_app) + @session = ::Rack::Test::Session.new(mock_session) + end + + def call(env) + super + rack_env = { + :method => env[:method], + :input => env[:body].respond_to?(:read) ? env[:body].read : env[:body], + 'rack.url_scheme' => env[:url].scheme + } + + env[:request_headers].each do |name, value| + name = name.upcase.tr('-', '_') + name = "HTTP_#{name}" unless SPECIAL_HEADERS.include? name + rack_env[name] = value + end if env[:request_headers] + + timeout = env[:request][:timeout] || env[:request][:open_timeout] + response = if timeout + Timer.timeout(timeout, Faraday::Error::TimeoutError) { execute_request(env, rack_env) } + else + execute_request(env, rack_env) + end + + save_response(env, response.status, response.body, response.headers) + @app.call env + end + + def execute_request(env, rack_env) + @session.request(env[:url].to_s, rack_env) + end + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/adapter/test.rb b/3rdparty/modules/aviator/feature/faraday/adapter/test.rb new file mode 100644 index 000000000..9a345758e --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/adapter/test.rb @@ -0,0 +1,162 @@ +module Faraday + class Adapter + # test = Faraday::Connection.new do + # use Faraday::Adapter::Test do |stub| + # stub.get '/nigiri/sake.json' do + # [200, {}, 'hi world'] + # end + # end + # end + # + # resp = test.get '/nigiri/sake.json' + # resp.body # => 'hi world' + # + class Test < Faraday::Adapter + attr_accessor :stubs + + class Stubs + class NotFound < StandardError + end + + def initialize + # {:get => [Stub, Stub]} + @stack, @consumed = {}, {} + yield(self) if block_given? + end + + def empty? + @stack.empty? + end + + def match(request_method, path, headers, body) + return false if !@stack.key?(request_method) + stack = @stack[request_method] + consumed = (@consumed[request_method] ||= []) + + if stub = matches?(stack, path, headers, body) + consumed << stack.delete(stub) + stub + else + matches?(consumed, path, headers, body) + end + end + + def get(path, headers = {}, &block) + new_stub(:get, path, headers, &block) + end + + def head(path, headers = {}, &block) + new_stub(:head, path, headers, &block) + end + + def post(path, body=nil, headers = {}, &block) + new_stub(:post, path, headers, body, &block) + end + + def put(path, body=nil, headers = {}, &block) + new_stub(:put, path, headers, body, &block) + end + + def patch(path, body=nil, headers = {}, &block) + new_stub(:patch, path, headers, body, &block) + end + + def delete(path, headers = {}, &block) + new_stub(:delete, path, headers, &block) + end + + def options(path, headers = {}, &block) + new_stub(:options, path, headers, &block) + end + + # Raises an error if any of the stubbed calls have not been made. + def verify_stubbed_calls + failed_stubs = [] + @stack.each do |method, stubs| + unless stubs.size == 0 + failed_stubs.concat(stubs.map {|stub| + "Expected #{method} #{stub}." + }) + end + end + raise failed_stubs.join(" ") unless failed_stubs.size == 0 + end + + protected + + def new_stub(request_method, path, headers = {}, body=nil, &block) + normalized_path = Faraday::Utils.normalize_path(path) + (@stack[request_method] ||= []) << Stub.new(normalized_path, headers, body, block) + end + + def matches?(stack, path, headers, body) + stack.detect { |stub| stub.matches?(path, headers, body) } + end + end + + class Stub < Struct.new(:path, :params, :headers, :body, :block) + def initialize(full, headers, body, block) + path, query = full.split('?') + params = query ? + Faraday::Utils.parse_nested_query(query) : + {} + super(path, params, headers, body, block) + end + + def matches?(request_uri, request_headers, request_body) + request_path, request_query = request_uri.split('?') + request_params = request_query ? + Faraday::Utils.parse_nested_query(request_query) : + {} + request_path == path && + params_match?(request_params) && + (body.to_s.size.zero? || request_body == body) && + headers_match?(request_headers) + end + + def params_match?(request_params) + params.keys.all? do |key| + request_params[key] == params[key] + end + end + + def headers_match?(request_headers) + headers.keys.all? do |key| + request_headers[key] == headers[key] + end + end + + def to_s + "#{path} #{body}" + end + end + + def initialize(app, stubs=nil, &block) + super(app) + @stubs = stubs || Stubs.new + configure(&block) if block + end + + def configure + yield(stubs) + end + + def call(env) + super + normalized_path = Faraday::Utils.normalize_path(env[:url]) + params_encoder = env.request.params_encoder || Faraday::Utils.default_params_encoder + + if stub = stubs.match(env[:method], normalized_path, env.request_headers, env[:body]) + env[:params] = (query = env[:url].query) ? + params_encoder.decode(query) : + {} + status, headers, body = stub.block.call(env) + save_response(env, status, body, headers) + else + raise Stubs::NotFound, "no stubbed request for #{env[:method]} #{normalized_path} #{env[:body]}" + end + @app.call(env) + end + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/adapter/typhoeus.rb b/3rdparty/modules/aviator/feature/faraday/adapter/typhoeus.rb new file mode 100644 index 000000000..69b6a5139 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/adapter/typhoeus.rb @@ -0,0 +1,123 @@ +module Faraday + class Adapter + class Typhoeus < Faraday::Adapter + self.supports_parallel = true + + def self.setup_parallel_manager(options = {}) + options.empty? ? ::Typhoeus::Hydra.hydra : ::Typhoeus::Hydra.new(options) + end + + dependency 'typhoeus' + + def call(env) + super + perform_request env + @app.call env + end + + def perform_request(env) + read_body env + + hydra = env[:parallel_manager] || self.class.setup_parallel_manager + hydra.queue request(env) + hydra.run unless parallel?(env) + rescue Errno::ECONNREFUSED + raise Error::ConnectionFailed, $! + end + + # TODO: support streaming requests + def read_body(env) + env[:body] = env[:body].read if env[:body].respond_to? :read + end + + def request(env) + method = env[:method] + # For some reason, prevents Typhoeus from using "100-continue". + # We want this because Webrick 1.3.1 can't seem to handle it w/ PUT. + method = method.to_s.upcase if method == :put + + req = ::Typhoeus::Request.new env[:url].to_s, + :method => method, + :body => env[:body], + :headers => env[:request_headers], + :disable_ssl_peer_verification => (env[:ssl] && env[:ssl].disable?) + + configure_ssl req, env + configure_proxy req, env + configure_timeout req, env + configure_socket req, env + + req.on_complete do |resp| + if resp.timed_out? + if parallel?(env) + # TODO: error callback in async mode + else + raise Faraday::Error::TimeoutError, "request timed out" + end + end + + case resp.curl_return_code + when 0 + # everything OK + when 7 + raise Error::ConnectionFailed, resp.curl_error_message + when 60 + raise Faraday::SSLError, resp.curl_error_message + else + raise Error::ClientError, resp.curl_error_message + end + + save_response(env, resp.code, resp.body) do |response_headers| + response_headers.parse resp.headers + end + # in async mode, :response is initialized at this point + env[:response].finish(env) if parallel?(env) + end + + req + end + + def configure_ssl(req, env) + ssl = env[:ssl] + + req.ssl_version = ssl[:version] if ssl[:version] + req.ssl_cert = ssl[:client_cert] if ssl[:client_cert] + req.ssl_key = ssl[:client_key] if ssl[:client_key] + req.ssl_cacert = ssl[:ca_file] if ssl[:ca_file] + req.ssl_capath = ssl[:ca_path] if ssl[:ca_path] + end + + def configure_proxy(req, env) + proxy = request_options(env)[:proxy] + return unless proxy + + req.proxy = "#{proxy[:uri].host}:#{proxy[:uri].port}" + + if proxy[:user] && proxy[:password] + req.proxy_username = proxy[:user] + req.proxy_password = proxy[:password] + end + end + + def configure_timeout(req, env) + env_req = request_options(env) + req.timeout = req.connect_timeout = (env_req[:timeout] * 1000) if env_req[:timeout] + req.connect_timeout = (env_req[:open_timeout] * 1000) if env_req[:open_timeout] + end + + def configure_socket(req, env) + if bind = request_options(env)[:bind] + req.interface = bind[:host] + end + end + + def request_options(env) + env[:request] + end + + def parallel?(env) + !!env[:parallel_manager] + end + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/autoload.rb b/3rdparty/modules/aviator/feature/faraday/autoload.rb new file mode 100644 index 000000000..ec413ff84 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/autoload.rb @@ -0,0 +1,85 @@ +module Faraday + # Internal: Adds the ability for other modules to manage autoloadable + # constants. + module AutoloadHelper + # Internal: Registers the constants to be auto loaded. + # + # prefix - The String require prefix. If the path is inside Faraday, then + # it will be prefixed with the root path of this loaded Faraday + # version. + # options - Hash of Symbol => String library names. + # + # Examples. + # + # Faraday.autoload_all 'faraday/foo', + # :Bar => 'bar' + # + # # requires faraday/foo/bar to load Faraday::Bar. + # Faraday::Bar + # + # + # Returns nothing. + def autoload_all(prefix, options) + if prefix =~ /^faraday(\/|$)/i + prefix = File.join(Faraday.root_path, prefix) + end + options.each do |const_name, path| + autoload const_name, File.join(prefix, path) + end + end + + # Internal: Loads each autoloaded constant. If thread safety is a concern, + # wrap this in a Mutex. + # + # Returns nothing. + def load_autoloaded_constants + constants.each do |const| + const_get(const) if autoload?(const) + end + end + + # Internal: Filters the module's contents with those that have been already + # autoloaded. + # + # Returns an Array of Class/Module objects. + def all_loaded_constants + constants.map { |c| const_get(c) }. + select { |a| a.respond_to?(:loaded?) && a.loaded? } + end + end + + class Adapter + extend AutoloadHelper + autoload_all 'faraday/adapter', + :NetHttp => 'net_http', + :NetHttpPersistent => 'net_http_persistent', + :Typhoeus => 'typhoeus', + :EMSynchrony => 'em_synchrony', + :EMHttp => 'em_http', + :Patron => 'patron', + :Excon => 'excon', + :Test => 'test', + :Rack => 'rack', + :HTTPClient => 'httpclient' + end + + class Request + extend AutoloadHelper + autoload_all 'faraday/request', + :UrlEncoded => 'url_encoded', + :Multipart => 'multipart', + :Retry => 'retry', + :Timeout => 'timeout', + :Authorization => 'authorization', + :BasicAuthentication => 'basic_authentication', + :TokenAuthentication => 'token_authentication', + :Instrumentation => 'instrumentation' + end + + class Response + extend AutoloadHelper + autoload_all 'faraday/response', + :RaiseError => 'raise_error', + :Logger => 'logger' + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/connection.rb b/3rdparty/modules/aviator/feature/faraday/connection.rb new file mode 100644 index 000000000..1e408e2c2 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/connection.rb @@ -0,0 +1,432 @@ +module Faraday + # Public: Connection objects manage the default properties and the middleware + # stack for fulfilling an HTTP request. + # + # Examples + # + # conn = Faraday::Connection.new 'http://sushi.com' + # + # # GET http://sushi.com/nigiri + # conn.get 'nigiri' + # # => # + # + class Connection + # A Set of allowed HTTP verbs. + METHODS = Set.new [:get, :post, :put, :delete, :head, :patch, :options] + + # Public: Returns a Hash of URI query unencoded key/value pairs. + attr_reader :params + + # Public: Returns a Hash of unencoded HTTP header key/value pairs. + attr_reader :headers + + # Public: Returns a URI with the prefix used for all requests from this + # Connection. This includes a default host name, scheme, port, and path. + attr_reader :url_prefix + + # Public: Returns the Faraday::Builder for this Connection. + attr_reader :builder + + # Public: Returns a Hash of the request options. + attr_reader :options + + # Public: Returns a Hash of the SSL options. + attr_reader :ssl + + # Public: Returns the parallel manager for this Connection. + attr_reader :parallel_manager + + # Public: Sets the default parallel manager for this connection. + attr_writer :default_parallel_manager + + # Public: Initializes a new Faraday::Connection. + # + # url - URI or String base URL to use as a prefix for all + # requests (optional). + # options - Hash or Faraday::ConnectionOptions. + # :url - URI or String base URL (default: "http:/"). + # :params - Hash of URI query unencoded key/value pairs. + # :headers - Hash of unencoded HTTP header key/value pairs. + # :request - Hash of request options. + # :ssl - Hash of SSL options. + # :proxy - URI, String or Hash of HTTP proxy options + # (default: "http_proxy" environment variable). + # :uri - URI or String + # :user - String (optional) + # :password - String (optional) + def initialize(url = nil, options = nil) + if url.is_a?(Hash) + options = ConnectionOptions.from(url) + url = options.url + else + options = ConnectionOptions.from(options) + end + + @parallel_manager = nil + @headers = Utils::Headers.new + @params = Utils::ParamsHash.new + @options = options.request + @ssl = options.ssl + @default_parallel_manager = options.parallel_manager + + @builder = options.builder || begin + # pass an empty block to Builder so it doesn't assume default middleware + options.new_builder(block_given? ? Proc.new { |b| } : nil) + end + + self.url_prefix = url || 'http:/' + + @params.update(options.params) if options.params + @headers.update(options.headers) if options.headers + + @proxy = nil + proxy(options.fetch(:proxy) { + uri = ENV['http_proxy'] + if uri && !uri.empty? + uri = 'http://' + uri if uri !~ /^http/i + uri + end + }) + + yield(self) if block_given? + + @headers[:user_agent] ||= "Faraday v#{VERSION}" + end + + # Public: Sets the Hash of URI query unencoded key/value pairs. + def params=(hash) + @params.replace hash + end + + # Public: Sets the Hash of unencoded HTTP header key/value pairs. + def headers=(hash) + @headers.replace hash + end + + extend Forwardable + + def_delegators :builder, :build, :use, :request, :response, :adapter, :app + + # Public: Makes an HTTP request without a body. + # + # url - The optional String base URL to use as a prefix for all + # requests. Can also be the options Hash. + # params - Hash of URI query unencoded key/value pairs. + # headers - Hash of unencoded HTTP header key/value pairs. + # + # Examples + # + # conn.get '/items', {:page => 1}, :accept => 'application/json' + # conn.head '/items/1' + # + # # ElasticSearch example sending a body with GET. + # conn.get '/twitter/tweet/_search' do |req| + # req.headers[:content_type] = 'application/json' + # req.params[:routing] = 'kimchy' + # req.body = JSON.generate(:query => {...}) + # end + # + # Yields a Faraday::Response for further request customizations. + # Returns a Faraday::Response. + # + # Signature + # + # (url = nil, params = nil, headers = nil) + # + # verb - An HTTP verb: get, head, or delete. + %w[get head delete].each do |method| + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{method}(url = nil, params = nil, headers = nil) + run_request(:#{method}, url, nil, headers) { |request| + request.params.update(params) if params + yield(request) if block_given? + } + end + RUBY + end + + # Public: Makes an HTTP request with a body. + # + # url - The optional String base URL to use as a prefix for all + # requests. Can also be the options Hash. + # body - The String body for the request. + # headers - Hash of unencoded HTTP header key/value pairs. + # + # Examples + # + # conn.post '/items', data, :content_type => 'application/json' + # + # # Simple ElasticSearch indexing sample. + # conn.post '/twitter/tweet' do |req| + # req.headers[:content_type] = 'application/json' + # req.params[:routing] = 'kimchy' + # req.body = JSON.generate(:user => 'kimchy', ...) + # end + # + # Yields a Faraday::Response for further request customizations. + # Returns a Faraday::Response. + # + # Signature + # + # (url = nil, body = nil, headers = nil) + # + # verb - An HTTP verb: post, put, or patch. + %w[post put patch].each do |method| + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{method}(url = nil, body = nil, headers = nil, &block) + run_request(:#{method}, url, body, headers, &block) + end + RUBY + end + + # Public: Sets up the Authorization header with these credentials, encoded + # with base64. + # + # login - The authentication login. + # pass - The authentication password. + # + # Examples + # + # conn.basic_auth 'Aladdin', 'open sesame' + # conn.headers['Authorization'] + # # => "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" + # + # Returns nothing. + def basic_auth(login, pass) + set_authorization_header(:basic_auth, login, pass) + end + + # Public: Sets up the Authorization header with the given token. + # + # token - The String token. + # options - Optional Hash of extra token options. + # + # Examples + # + # conn.token_auth 'abcdef', :foo => 'bar' + # conn.headers['Authorization'] + # # => "Token token=\"abcdef\", + # foo=\"bar\"" + # + # Returns nothing. + def token_auth(token, options = nil) + set_authorization_header(:token_auth, token, options) + end + + # Public: Sets up a custom Authorization header. + # + # type - The String authorization type. + # token - The String or Hash token. A String value is taken literally, and + # a Hash is encoded into comma separated key/value pairs. + # + # Examples + # + # conn.authorization :Bearer, 'mF_9.B5f-4.1JqM' + # conn.headers['Authorization'] + # # => "Bearer mF_9.B5f-4.1JqM" + # + # conn.authorization :Token, :token => 'abcdef', :foo => 'bar' + # conn.headers['Authorization'] + # # => "Token token=\"abcdef\", + # foo=\"bar\"" + # + # Returns nothing. + def authorization(type, token) + set_authorization_header(:authorization, type, token) + end + + # Internal: Traverse the middleware stack in search of a + # parallel-capable adapter. + # + # Yields in case of not found. + # + # Returns a parallel manager or nil if not found. + def default_parallel_manager + @default_parallel_manager ||= begin + handler = @builder.handlers.detect do |h| + h.klass.respond_to?(:supports_parallel?) and h.klass.supports_parallel? + end + + if handler + handler.klass.setup_parallel_manager + elsif block_given? + yield + end + end + end + + # Public: Determine if this Faraday::Connection can make parallel requests. + # + # Returns true or false. + def in_parallel? + !!@parallel_manager + end + + # Public: Sets up the parallel manager to make a set of requests. + # + # manager - The parallel manager that this Connection's Adapter uses. + # + # Yields a block to execute multiple requests. + # Returns nothing. + def in_parallel(manager = nil) + @parallel_manager = manager || default_parallel_manager { + warn "Warning: `in_parallel` called but no parallel-capable adapter on Faraday stack" + warn caller[2,10].join("\n") + nil + } + yield + @parallel_manager && @parallel_manager.run + ensure + @parallel_manager = nil + end + + # Public: Gets or Sets the Hash proxy options. + def proxy(arg = nil) + return @proxy if arg.nil? + @proxy = ProxyOptions.from(arg) + end + + def_delegators :url_prefix, :scheme, :scheme=, :host, :host=, :port, :port= + def_delegator :url_prefix, :path, :path_prefix + + # Public: Parses the giving url with URI and stores the individual + # components in this connection. These components serve as defaults for + # requests made by this connection. + # + # url - A String or URI. + # + # Examples + # + # conn = Faraday::Connection.new { ... } + # conn.url_prefix = "https://sushi.com/api" + # conn.scheme # => https + # conn.path_prefix # => "/api" + # + # conn.get("nigiri?page=2") # accesses https://sushi.com/api/nigiri + # + # Returns the parsed URI from teh given input.. + def url_prefix=(url, encoder = nil) + uri = @url_prefix = Utils.URI(url) + self.path_prefix = uri.path + + params.merge_query(uri.query, encoder) + uri.query = nil + + with_uri_credentials(uri) do |user, password| + basic_auth user, password + uri.user = uri.password = nil + end + + uri + end + + # Public: Sets the path prefix and ensures that it always has a leading + # slash. + # + # value - A String. + # + # Returns the new String path prefix. + def path_prefix=(value) + url_prefix.path = if value + value = '/' + value unless value[0,1] == '/' + value + end + end + + # Public: Takes a relative url for a request and combines it with the defaults + # set on the connection instance. + # + # conn = Faraday::Connection.new { ... } + # conn.url_prefix = "https://sushi.com/api?token=abc" + # conn.scheme # => https + # conn.path_prefix # => "/api" + # + # conn.build_url("nigiri?page=2") # => https://sushi.com/api/nigiri?token=abc&page=2 + # conn.build_url("nigiri", :page => 2) # => https://sushi.com/api/nigiri?token=abc&page=2 + # + def build_url(url = nil, extra_params = nil) + uri = build_exclusive_url(url) + + query_values = params.dup.merge_query(uri.query, options.params_encoder) + query_values.update extra_params if extra_params + uri.query = query_values.empty? ? nil : query_values.to_query(options.params_encoder) + + uri + end + + # Builds and runs the Faraday::Request. + # + # method - The Symbol HTTP method. + # url - The String or URI to access. + # body - The String body + # headers - Hash of unencoded HTTP header key/value pairs. + # + # Returns a Faraday::Response. + def run_request(method, url, body, headers) + if !METHODS.include?(method) + raise ArgumentError, "unknown http method: #{method}" + end + + request = build_request(method) do |req| + req.url(url) if url + req.headers.update(headers) if headers + req.body = body if body + yield(req) if block_given? + end + + builder.build_response(self, request) + end + + # Creates and configures the request object. + # + # Returns the new Request. + def build_request(method) + Request.create(method) do |req| + req.params = self.params.dup + req.headers = self.headers.dup + req.options = self.options.merge(:proxy => self.proxy) + yield(req) if block_given? + end + end + + # Internal: Build an absolute URL based on url_prefix. + # + # url - A String or URI-like object + # params - A Faraday::Utils::ParamsHash to replace the query values + # of the resulting url (default: nil). + # + # Returns the resulting URI instance. + def build_exclusive_url(url = nil, params = nil) + url = nil if url.respond_to?(:empty?) and url.empty? + base = url_prefix + if url and base.path and base.path !~ /\/$/ + base = base.dup + base.path = base.path + '/' # ensure trailing slash + end + uri = url ? base + url : base + uri.query = params.to_query(options.params_encoder) if params + uri.query = nil if uri.query and uri.query.empty? + uri + end + + # Internal: Creates a duplicate of this Faraday::Connection. + # + # Returns a Faraday::Connection. + def dup + self.class.new(build_exclusive_url, :headers => headers.dup, :params => params.dup, :builder => builder.dup, :ssl => ssl.dup) + end + + # Internal: Yields username and password extracted from a URI if they both exist. + def with_uri_credentials(uri) + if uri.user and uri.password + yield(Utils.unescape(uri.user), Utils.unescape(uri.password)) + end + end + + def set_authorization_header(header_type, *args) + header = Faraday::Request.lookup_middleware(header_type). + header(*args) + headers[Faraday::Request::Authorization::KEY] = header + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/error.rb b/3rdparty/modules/aviator/feature/faraday/error.rb new file mode 100644 index 000000000..17712309d --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/error.rb @@ -0,0 +1,53 @@ +module Faraday + class Error < StandardError; end + class MissingDependency < Error; end + + class ClientError < Error + attr_reader :response + + def initialize(ex, response = nil) + @wrapped_exception = nil + @response = response + + if ex.respond_to?(:backtrace) + super(ex.message) + @wrapped_exception = ex + elsif ex.respond_to?(:each_key) + super("the server responded with status #{ex[:status]}") + @response = ex + else + super(ex.to_s) + end + end + + def backtrace + if @wrapped_exception + @wrapped_exception.backtrace + else + super + end + end + + def inspect + %(#<#{self.class}>) + end + end + + class ConnectionFailed < ClientError; end + class ResourceNotFound < ClientError; end + class ParsingError < ClientError; end + + class TimeoutError < ClientError + def initialize(ex = nil) + super(ex || "timeout") + end + end + + class SSLError < ClientError + end + + [:MissingDependency, :ClientError, :ConnectionFailed, :ResourceNotFound, + :ParsingError, :TimeoutError, :SSLError].each do |const| + Error.const_set(const, Faraday.const_get(const)) + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/middleware.rb b/3rdparty/modules/aviator/feature/faraday/middleware.rb new file mode 100644 index 000000000..c45d51ade --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/middleware.rb @@ -0,0 +1,37 @@ +module Faraday + class Middleware + extend MiddlewareRegistry + + class << self + attr_accessor :load_error + private :load_error= + end + + self.load_error = nil + + # Executes a block which should try to require and reference dependent libraries + def self.dependency(lib = nil) + lib ? require(lib) : yield + rescue LoadError, NameError => error + self.load_error = error + end + + def self.new(*) + raise "missing dependency for #{self}: #{load_error.message}" unless loaded? + super + end + + def self.loaded? + load_error.nil? + end + + def self.inherited(subclass) + super + subclass.send(:load_error=, self.load_error) + end + + def initialize(app = nil) + @app = app + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/options.rb b/3rdparty/modules/aviator/feature/faraday/options.rb new file mode 100644 index 000000000..c1b36f60f --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/options.rb @@ -0,0 +1,350 @@ +module Faraday + # Subclasses Struct with some special helpers for converting from a Hash to + # a Struct. + class Options < Struct + # Public + def self.from(value) + value ? new.update(value) : new + end + + # Public + def each + return to_enum(:each) unless block_given? + members.each do |key| + yield(key.to_sym, send(key)) + end + end + + # Public + def update(obj) + obj.each do |key, value| + if sub_options = self.class.options_for(key) + value = sub_options.from(value) if value + elsif Hash === value + hash = {} + value.each do |hash_key, hash_value| + hash[hash_key] = hash_value + end + value = hash + end + + self.send("#{key}=", value) unless value.nil? + end + self + end + + alias merge! update + + # Public + def delete(key) + value = send(key) + send("#{key}=", nil) + value + end + + # Public + def clear + members.each { |member| delete(member) } + end + + # Public + def merge(value) + dup.update(value) + end + + # Public + def fetch(key, *args) + unless symbolized_key_set.include?(key.to_sym) + key_setter = "#{key}=" + if args.size > 0 + send(key_setter, args.first) + elsif block_given? + send(key_setter, Proc.new.call(key)) + else + raise self.class.fetch_error_class, "key not found: #{key.inspect}" + end + end + send(key) + end + + # Public + def values_at(*keys) + keys.map { |key| send(key) } + end + + # Public + def keys + members.reject { |member| send(member).nil? } + end + + # Public + def empty? + keys.empty? + end + + # Public + def each_key + return to_enum(:each_key) unless block_given? + keys.each do |key| + yield(key) + end + end + + # Public + def key?(key) + keys.include?(key) + end + + alias has_key? key? + + # Public + def each_value + return to_enum(:each_value) unless block_given? + values.each do |value| + yield(value) + end + end + + # Public + def value?(value) + values.include?(value) + end + + alias has_value? value? + + # Public + def to_hash + hash = {} + members.each do |key| + value = send(key) + hash[key.to_sym] = value unless value.nil? + end + hash + end + + # Internal + def inspect + values = [] + members.each do |member| + value = send(member) + values << "#{member}=#{value.inspect}" if value + end + values = values.empty? ? ' (empty)' : (' ' << values.join(", ")) + + %(#<#{self.class}#{values}>) + end + + # Internal + def self.options(mapping) + attribute_options.update(mapping) + end + + # Internal + def self.options_for(key) + attribute_options[key] + end + + # Internal + def self.attribute_options + @attribute_options ||= {} + end + + def self.memoized(key) + memoized_attributes[key.to_sym] = Proc.new + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{key}() self[:#{key}]; end + RUBY + end + + def self.memoized_attributes + @memoized_attributes ||= {} + end + + def [](key) + key = key.to_sym + if method = self.class.memoized_attributes[key] + super(key) || (self[key] = instance_eval(&method)) + else + super + end + end + + def symbolized_key_set + @symbolized_key_set ||= Set.new(keys.map { |k| k.to_sym }) + end + + def self.inherited(subclass) + super + subclass.attribute_options.update(attribute_options) + subclass.memoized_attributes.update(memoized_attributes) + end + + def self.fetch_error_class + @fetch_error_class ||= if Object.const_defined?(:KeyError) + ::KeyError + else + ::IndexError + end + end + end + + class RequestOptions < Options.new(:params_encoder, :proxy, :bind, + :timeout, :open_timeout, :boundary, + :oauth) + + def []=(key, value) + if key && key.to_sym == :proxy + super(key, value ? ProxyOptions.from(value) : nil) + else + super(key, value) + end + end + end + + class SSLOptions < Options.new(:verify, :ca_file, :ca_path, :verify_mode, + :cert_store, :client_cert, :client_key, :certificate, :private_key, :verify_depth, :version) + + def verify? + verify != false + end + + def disable? + !verify? + end + end + + class ProxyOptions < Options.new(:uri, :user, :password) + extend Forwardable + def_delegators :uri, :scheme, :scheme=, :host, :host=, :port, :port=, :path, :path= + + def self.from(value) + case value + when String + value = {:uri => Utils.URI(value)} + when URI + value = {:uri => value} + when Hash, Options + if uri = value.delete(:uri) + value[:uri] = Utils.URI(uri) + end + end + super(value) + end + + memoized(:user) { uri.user && Utils.unescape(uri.user) } + memoized(:password) { uri.password && Utils.unescape(uri.password) } + end + + class ConnectionOptions < Options.new(:request, :proxy, :ssl, :builder, :url, + :parallel_manager, :params, :headers, :builder_class) + + options :request => RequestOptions, :ssl => SSLOptions + + memoized(:request) { self.class.options_for(:request).new } + + memoized(:ssl) { self.class.options_for(:ssl).new } + + memoized(:builder_class) { RackBuilder } + + def new_builder(block) + builder_class.new(&block) + end + end + + class Env < Options.new(:method, :body, :url, :request, :request_headers, + :ssl, :parallel_manager, :params, :response, :response_headers, :status) + + ContentLength = 'Content-Length'.freeze + StatusesWithoutBody = Set.new [204, 304] + SuccessfulStatuses = 200..299 + + # A Set of HTTP verbs that typically send a body. If no body is set for + # these requests, the Content-Length header is set to 0. + MethodsWithBodies = Set.new [:post, :put, :patch, :options] + + options :request => RequestOptions, + :request_headers => Utils::Headers, :response_headers => Utils::Headers + + extend Forwardable + + def_delegators :request, :params_encoder + + # Public + def [](key) + if in_member_set?(key) + super(key) + else + custom_members[key] + end + end + + # Public + def []=(key, value) + if in_member_set?(key) + super(key, value) + else + custom_members[key] = value + end + end + + # Public + def success? + SuccessfulStatuses.include?(status) + end + + # Public + def needs_body? + !body && MethodsWithBodies.include?(method) + end + + # Public + def clear_body + request_headers[ContentLength] = '0' + self.body = '' + end + + # Public + def parse_body? + !StatusesWithoutBody.include?(status) + end + + # Public + def parallel? + !!parallel_manager + end + + def inspect + attrs = [nil] + members.each do |mem| + if value = send(mem) + attrs << "@#{mem}=#{value.inspect}" + end + end + if !custom_members.empty? + attrs << "@custom=#{custom_members.inspect}" + end + %(#<#{self.class}#{attrs.join(" ")}>) + end + + # Internal + def custom_members + @custom_members ||= {} + end + + # Internal + if members.first.is_a?(Symbol) + def in_member_set?(key) + self.class.member_set.include?(key.to_sym) + end + else + def in_member_set?(key) + self.class.member_set.include?(key.to_s) + end + end + + # Internal + def self.member_set + @member_set ||= Set.new(members) + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/parameters.rb b/3rdparty/modules/aviator/feature/faraday/parameters.rb new file mode 100644 index 000000000..136c43bca --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/parameters.rb @@ -0,0 +1,193 @@ +module Faraday + module NestedParamsEncoder + ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/ + + def self.escape(s) + return s.to_s.gsub(ESCAPE_RE) { + '%' + $&.unpack('H2' * $&.bytesize).join('%').upcase + }.tr(' ', '+') + end + + def self.unescape(s) + CGI.unescape(s.to_s) + end + + def self.encode(params) + return nil if params == nil + + if !params.is_a?(Array) + if !params.respond_to?(:to_hash) + raise TypeError, + "Can't convert #{params.class} into Hash." + end + params = params.to_hash + params = params.map do |key, value| + key = key.to_s if key.kind_of?(Symbol) + [key, value] + end + # Useful default for OAuth and caching. + # Only to be used for non-Array inputs. Arrays should preserve order. + params.sort! + end + + # Helper lambda + to_query = lambda do |parent, value| + if value.is_a?(Hash) + value = value.map do |key, val| + key = escape(key) + [key, val] + end + value.sort! + buffer = "" + value.each do |key, val| + new_parent = "#{parent}%5B#{key}%5D" + buffer << "#{to_query.call(new_parent, val)}&" + end + return buffer.chop + elsif value.is_a?(Array) + buffer = "" + value.each_with_index do |val, i| + new_parent = "#{parent}%5B%5D" + buffer << "#{to_query.call(new_parent, val)}&" + end + return buffer.chop + else + encoded_value = escape(value) + return "#{parent}=#{encoded_value}" + end + end + + # The params have form [['key1', 'value1'], ['key2', 'value2']]. + buffer = '' + params.each do |parent, value| + encoded_parent = escape(parent) + buffer << "#{to_query.call(encoded_parent, value)}&" + end + return buffer.chop + end + + def self.decode(query) + return nil if query == nil + # Recursive helper lambda + dehash = lambda do |hash| + hash.each do |(key, value)| + if value.kind_of?(Hash) + hash[key] = dehash.call(value) + end + end + # Numeric keys implies an array + if hash != {} && hash.keys.all? { |key| key =~ /^\d+$/ } + hash.sort.inject([]) do |accu, (_, value)| + accu << value; accu + end + else + hash + end + end + + empty_accumulator = {} + return ((query.split('&').map do |pair| + pair.split('=', 2) if pair && !pair.empty? + end).compact.inject(empty_accumulator.dup) do |accu, (key, value)| + key = unescape(key) + if value.kind_of?(String) + value = unescape(value.gsub(/\+/, ' ')) + end + + array_notation = !!(key =~ /\[\]$/) + subkeys = key.split(/[\[\]]+/) + current_hash = accu + for i in 0...(subkeys.size - 1) + subkey = subkeys[i] + current_hash[subkey] = {} unless current_hash[subkey] + current_hash = current_hash[subkey] + end + if array_notation + current_hash[subkeys.last] = [] unless current_hash[subkeys.last] + current_hash[subkeys.last] << value + else + current_hash[subkeys.last] = value + end + accu + end).inject(empty_accumulator.dup) do |accu, (key, value)| + accu[key] = value.kind_of?(Hash) ? dehash.call(value) : value + accu + end + end + end + + module FlatParamsEncoder + ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/ + + def self.escape(s) + return s.to_s.gsub(ESCAPE_RE) { + '%' + $&.unpack('H2' * $&.bytesize).join('%').upcase + }.tr(' ', '+') + end + + def self.unescape(s) + CGI.unescape(s.to_s) + end + + def self.encode(params) + return nil if params == nil + + if !params.is_a?(Array) + if !params.respond_to?(:to_hash) + raise TypeError, + "Can't convert #{params.class} into Hash." + end + params = params.to_hash + params = params.map do |key, value| + key = key.to_s if key.kind_of?(Symbol) + [key, value] + end + # Useful default for OAuth and caching. + # Only to be used for non-Array inputs. Arrays should preserve order. + params.sort! + end + + # The params have form [['key1', 'value1'], ['key2', 'value2']]. + buffer = '' + params.each do |key, value| + encoded_key = escape(key) + value = value.to_s if value == true || value == false + if value == nil + buffer << "#{encoded_key}&" + elsif value.kind_of?(Array) + value.each do |sub_value| + encoded_value = escape(sub_value) + buffer << "#{encoded_key}=#{encoded_value}&" + end + else + encoded_value = escape(value) + buffer << "#{encoded_key}=#{encoded_value}&" + end + end + return buffer.chop + end + + def self.decode(query) + empty_accumulator = {} + return nil if query == nil + split_query = (query.split('&').map do |pair| + pair.split('=', 2) if pair && !pair.empty? + end).compact + return split_query.inject(empty_accumulator.dup) do |accu, pair| + pair[0] = unescape(pair[0]) + pair[1] = true if pair[1].nil? + if pair[1].respond_to?(:to_str) + pair[1] = unescape(pair[1].to_str.gsub(/\+/, " ")) + end + if accu[pair[0]].kind_of?(Array) + accu[pair[0]] << pair[1] + elsif accu[pair[0]] + accu[pair[0]] = [accu[pair[0]], pair[1]] + else + accu[pair[0]] = pair[1] + end + accu + end + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/rack_builder.rb b/3rdparty/modules/aviator/feature/faraday/rack_builder.rb new file mode 100644 index 000000000..204ce41d1 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/rack_builder.rb @@ -0,0 +1,212 @@ +module Faraday + # A Builder that processes requests into responses by passing through an inner + # middleware stack (heavily inspired by Rack). + # + # Faraday::Connection.new(:url => 'http://sushi.com') do |builder| + # builder.request :url_encoded # Faraday::Request::UrlEncoded + # builder.adapter :net_http # Faraday::Adapter::NetHttp + # end + class RackBuilder + attr_accessor :handlers + + # Error raised when trying to modify the stack after calling `lock!` + class StackLocked < RuntimeError; end + + # borrowed from ActiveSupport::Dependencies::Reference & + # ActionDispatch::MiddlewareStack::Middleware + class Handler + @@constants_mutex = Mutex.new + @@constants = Hash.new { |h, k| + value = k.respond_to?(:constantize) ? k.constantize : Object.const_get(k) + @@constants_mutex.synchronize { h[k] = value } + } + + attr_reader :name + + def initialize(klass, *args, &block) + @name = klass.to_s + if klass.respond_to?(:name) + @@constants_mutex.synchronize { @@constants[@name] = klass } + end + @args, @block = args, block + end + + def klass() @@constants[@name] end + def inspect() @name end + + def ==(other) + if other.is_a? Handler + self.name == other.name + elsif other.respond_to? :name + klass == other + else + @name == other.to_s + end + end + + def build(app) + klass.new(app, *@args, &@block) + end + end + + def initialize(handlers = []) + @handlers = handlers + if block_given? + build(&Proc.new) + elsif @handlers.empty? + # default stack, if nothing else is configured + self.request :url_encoded + self.adapter Faraday.default_adapter + end + end + + def build(options = {}) + raise_if_locked + @handlers.clear unless options[:keep] + yield(self) if block_given? + end + + def [](idx) + @handlers[idx] + end + + # Locks the middleware stack to ensure no further modifications are possible. + def lock! + @handlers.freeze + end + + def locked? + @handlers.frozen? + end + + def use(klass, *args, &block) + if klass.is_a? Symbol + use_symbol(Faraday::Middleware, klass, *args, &block) + else + raise_if_locked + @handlers << self.class::Handler.new(klass, *args, &block) + end + end + + def request(key, *args, &block) + use_symbol(Faraday::Request, key, *args, &block) + end + + def response(key, *args, &block) + use_symbol(Faraday::Response, key, *args, &block) + end + + def adapter(key, *args, &block) + use_symbol(Faraday::Adapter, key, *args, &block) + end + + ## methods to push onto the various positions in the stack: + + def insert(index, *args, &block) + raise_if_locked + index = assert_index(index) + handler = self.class::Handler.new(*args, &block) + @handlers.insert(index, handler) + end + + alias_method :insert_before, :insert + + def insert_after(index, *args, &block) + index = assert_index(index) + insert(index + 1, *args, &block) + end + + def swap(index, *args, &block) + raise_if_locked + index = assert_index(index) + @handlers.delete_at(index) + insert(index, *args, &block) + end + + def delete(handler) + raise_if_locked + @handlers.delete(handler) + end + + # Processes a Request into a Response by passing it through this Builder's + # middleware stack. + # + # connection - Faraday::Connection + # request - Faraday::Request + # + # Returns a Faraday::Response. + def build_response(connection, request) + app.call(build_env(connection, request)) + end + + # The "rack app" wrapped in middleware. All requests are sent here. + # + # The builder is responsible for creating the app object. After this, + # the builder gets locked to ensure no further modifications are made + # to the middleware stack. + # + # Returns an object that responds to `call` and returns a Response. + def app + @app ||= begin + lock! + to_app(lambda { |env| + response = Response.new + response.finish(env) unless env.parallel? + env.response = response + }) + end + end + + def to_app(inner_app) + # last added handler is the deepest and thus closest to the inner app + @handlers.reverse.inject(inner_app) { |app, handler| handler.build(app) } + end + + def ==(other) + other.is_a?(self.class) && @handlers == other.handlers + end + + def dup + self.class.new(@handlers.dup) + end + + # ENV Keys + # :method - a symbolized request method (:get, :post) + # :body - the request body that will eventually be converted to a string. + # :url - URI instance for the current request. + # :status - HTTP response status code + # :request_headers - hash of HTTP Headers to be sent to the server + # :response_headers - Hash of HTTP headers from the server + # :parallel_manager - sent if the connection is in parallel mode + # :request - Hash of options for configuring the request. + # :timeout - open/read timeout Integer in seconds + # :open_timeout - read timeout Integer in seconds + # :proxy - Hash of proxy options + # :uri - Proxy Server URI + # :user - Proxy server username + # :password - Proxy server password + # :ssl - Hash of options for configuring SSL requests. + def build_env(connection, request) + Env.new(request.method, request.body, + connection.build_exclusive_url(request.path, request.params), + request.options, request.headers, connection.ssl, + connection.parallel_manager) + end + + private + + def raise_if_locked + raise StackLocked, "can't modify middleware stack after making a request" if locked? + end + + def use_symbol(mod, key, *args, &block) + use(mod.lookup_middleware(key), *args, &block) + end + + def assert_index(index) + idx = index.is_a?(Integer) ? index : @handlers.index(index) + raise "No such handler: #{index.inspect}" unless idx + idx + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/request.rb b/3rdparty/modules/aviator/feature/faraday/request.rb new file mode 100644 index 000000000..481077f14 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/request.rb @@ -0,0 +1,92 @@ +module Faraday + # Used to setup urls, params, headers, and the request body in a sane manner. + # + # @connection.post do |req| + # req.url 'http://localhost', 'a' => '1' # 'http://localhost?a=1' + # req.headers['b'] = '2' # Header + # req.params['c'] = '3' # GET Param + # req['b'] = '2' # also Header + # req.body = 'abc' + # end + # + class Request < Struct.new(:method, :path, :params, :headers, :body, :options) + extend MiddlewareRegistry + + register_middleware File.expand_path('../request', __FILE__), + :url_encoded => [:UrlEncoded, 'url_encoded'], + :multipart => [:Multipart, 'multipart'], + :retry => [:Retry, 'retry'], + :authorization => [:Authorization, 'authorization'], + :basic_auth => [:BasicAuthentication, 'basic_authentication'], + :token_auth => [:TokenAuthentication, 'token_authentication'], + :instrumentation => [:Instrumentation, 'instrumentation'] + + def self.create(request_method) + new(request_method).tap do |request| + yield(request) if block_given? + end + end + + # Public: Replace params, preserving the existing hash type + def params=(hash) + if params + params.replace hash + else + super + end + end + + # Public: Replace request headers, preserving the existing hash type + def headers=(hash) + if headers + headers.replace hash + else + super + end + end + + def url(path, params = nil) + if path.respond_to? :query + if query = path.query + path = path.dup + path.query = nil + end + else + path, query = path.split('?', 2) + end + self.path = path + self.params.merge_query query, options.params_encoder + self.params.update(params) if params + end + + def [](key) + headers[key] + end + + def []=(key, value) + headers[key] = value + end + + # ENV Keys + # :method - a symbolized request method (:get, :post) + # :body - the request body that will eventually be converted to a string. + # :url - URI instance for the current request. + # :status - HTTP response status code + # :request_headers - hash of HTTP Headers to be sent to the server + # :response_headers - Hash of HTTP headers from the server + # :parallel_manager - sent if the connection is in parallel mode + # :request - Hash of options for configuring the request. + # :timeout - open/read timeout Integer in seconds + # :open_timeout - read timeout Integer in seconds + # :proxy - Hash of proxy options + # :uri - Proxy Server URI + # :user - Proxy server username + # :password - Proxy server password + # :ssl - Hash of options for configuring SSL requests. + def to_env(connection) + Env.new(method, body, connection.build_exclusive_url(path, params), + options, headers, connection.ssl, connection.parallel_manager) + end + end +end + diff --git a/3rdparty/modules/aviator/feature/faraday/request/authorization.rb b/3rdparty/modules/aviator/feature/faraday/request/authorization.rb new file mode 100644 index 000000000..43b452880 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/request/authorization.rb @@ -0,0 +1,42 @@ +module Faraday + class Request::Authorization < Faraday::Middleware + KEY = "Authorization".freeze unless defined? KEY + + # Public + def self.header(type, token) + case token + when String, Symbol + "#{type} #{token}" + when Hash + build_hash(type.to_s, token) + else + raise ArgumentError, "Can't build an Authorization #{type} header from #{token.inspect}" + end + end + + # Internal + def self.build_hash(type, hash) + offset = KEY.size + type.size + 3 + comma = ",\n#{' ' * offset}" + values = [] + hash.each do |key, value| + values << "#{key}=#{value.to_s.inspect}" + end + "#{type} #{values * comma}" + end + + def initialize(app, type, token) + @header_value = self.class.header(type, token) + super(app) + end + + # Public + def call(env) + unless env.request_headers[KEY] + env.request_headers[KEY] = @header_value + end + @app.call(env) + end + end +end + diff --git a/3rdparty/modules/aviator/feature/faraday/request/basic_authentication.rb b/3rdparty/modules/aviator/feature/faraday/request/basic_authentication.rb new file mode 100644 index 000000000..54c8dee97 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/request/basic_authentication.rb @@ -0,0 +1,13 @@ +require 'base64' + +module Faraday + class Request::BasicAuthentication < Request.load_middleware(:authorization) + # Public + def self.header(login, pass) + value = Base64.encode64([login, pass].join(':')) + value.gsub!("\n", '') + super(:Basic, value) + end + end +end + diff --git a/3rdparty/modules/aviator/feature/faraday/request/instrumentation.rb b/3rdparty/modules/aviator/feature/faraday/request/instrumentation.rb new file mode 100644 index 000000000..42af8bc44 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/request/instrumentation.rb @@ -0,0 +1,36 @@ +module Faraday + class Request::Instrumentation < Faraday::Middleware + class Options < Faraday::Options.new(:name, :instrumenter) + def name + self[:name] ||= 'request.faraday' + end + + def instrumenter + self[:instrumenter] ||= ActiveSupport::Notifications + end + end + + # Public: Instruments requests using Active Support. + # + # Measures time spent only for synchronous requests. + # + # Examples + # + # ActiveSupport::Notifications.subscribe('request.faraday') do |name, starts, ends, _, env| + # url = env[:url] + # http_method = env[:method].to_s.upcase + # duration = ends - starts + # $stderr.puts '[%s] %s %s (%.3f s)' % [url.host, http_method, url.request_uri, duration] + # end + def initialize(app, options = nil) + super(app) + @name, @instrumenter = Options.from(options).values_at(:name, :instrumenter) + end + + def call(env) + @instrumenter.instrument(@name, env) do + @app.call(env) + end + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/request/multipart.rb b/3rdparty/modules/aviator/feature/faraday/request/multipart.rb new file mode 100644 index 000000000..38b452af7 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/request/multipart.rb @@ -0,0 +1,63 @@ +require File.expand_path("../url_encoded", __FILE__) + +module Faraday + class Request::Multipart < Request::UrlEncoded + self.mime_type = 'multipart/form-data'.freeze + DEFAULT_BOUNDARY = "-----------RubyMultipartPost".freeze unless defined? DEFAULT_BOUNDARY + + def call(env) + match_content_type(env) do |params| + env.request.boundary ||= DEFAULT_BOUNDARY + env.request_headers[CONTENT_TYPE] += "; boundary=#{env.request.boundary}" + env.body = create_multipart(env, params) + end + @app.call env + end + + def process_request?(env) + type = request_type(env) + env.body.respond_to?(:each_key) and !env.body.empty? and ( + (type.empty? and has_multipart?(env.body)) or + type == self.class.mime_type + ) + end + + def has_multipart?(obj) + # string is an enum in 1.8, returning list of itself + if obj.respond_to?(:each) && !obj.is_a?(String) + (obj.respond_to?(:values) ? obj.values : obj).each do |val| + return true if (val.respond_to?(:content_type) || has_multipart?(val)) + end + end + false + end + + def create_multipart(env, params) + boundary = env.request.boundary + parts = process_params(params) do |key, value| + Faraday::Parts::Part.new(boundary, key, value) + end + parts << Faraday::Parts::EpiloguePart.new(boundary) + + body = Faraday::CompositeReadIO.new(parts) + env.request_headers[Faraday::Env::ContentLength] = body.length.to_s + return body + end + + def process_params(params, prefix = nil, pieces = nil, &block) + params.inject(pieces || []) do |all, (key, value)| + key = "#{prefix}[#{key}]" if prefix + + case value + when Array + values = value.inject([]) { |a,v| a << [nil, v] } + process_params(values, key, all, &block) + when Hash + process_params(value, key, all, &block) + else + all << block.call(key, value) + end + end + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/request/retry.rb b/3rdparty/modules/aviator/feature/faraday/request/retry.rb new file mode 100644 index 000000000..08bc83766 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/request/retry.rb @@ -0,0 +1,140 @@ +module Faraday + # Catches exceptions and retries each request a limited number of times. + # + # By default, it retries 2 times and handles only timeout exceptions. It can + # be configured with an arbitrary number of retries, a list of exceptions to + # handle, a retry interval, a percentage of randomness to add to the retry + # interval, and a backoff factor. + # + # Examples + # + # Faraday.new do |conn| + # conn.request :retry, max: 2, interval: 0.05, + # interval_randomness: 0.5, backoff_factor: 2 + # exceptions: [CustomException, 'Timeout::Error'] + # conn.adapter ... + # end + # + # This example will result in a first interval that is random between 0.05 and 0.075 and a second + # interval that is random between 0.1 and 0.15 + # + class Request::Retry < Faraday::Middleware + + IDEMPOTENT_METHODS = [:delete, :get, :head, :options, :put] + + class Options < Faraday::Options.new(:max, :interval, :interval_randomness, :backoff_factor, :exceptions, :retry_if) + DEFAULT_CHECK = lambda { |env,exception| false } + + def self.from(value) + if Fixnum === value + new(value) + else + super(value) + end + end + + def max + (self[:max] ||= 2).to_i + end + + def interval + (self[:interval] ||= 0).to_f + end + + def interval_randomness + (self[:interval_randomness] ||= 0).to_i + end + + def backoff_factor + (self[:backoff_factor] ||= 1).to_f + end + + def exceptions + Array(self[:exceptions] ||= [Errno::ETIMEDOUT, 'Timeout::Error', + Error::TimeoutError]) + end + + def retry_if + self[:retry_if] ||= DEFAULT_CHECK + end + + end + + # Public: Initialize middleware + # + # Options: + # max - Maximum number of retries (default: 2) + # interval - Pause in seconds between retries (default: 0) + # interval_randomness - The maximum random interval amount expressed + # as a float between 0 and 1 to use in addition to the + # interval. (default: 0) + # backoff_factor - The amount to multiple each successive retry's + # interval amount by in order to provide backoff + # (default: 1) + # exceptions - The list of exceptions to handle. Exceptions can be + # given as Class, Module, or String. (default: + # [Errno::ETIMEDOUT, Timeout::Error, + # Error::TimeoutError]) + # retry_if - block that will receive the env object and the exception raised + # and should decide if the code should retry still the action or + # not independent of the retry count. This would be useful + # if the exception produced is non-recoverable or if the + # the HTTP method called is not idempotent. + # (defaults to return false) + def initialize(app, options = nil) + super(app) + @options = Options.from(options) + @errmatch = build_exception_matcher(@options.exceptions) + end + + def sleep_amount(retries) + retry_index = @options.max - retries + current_interval = @options.interval * (@options.backoff_factor ** retry_index) + random_interval = rand * @options.interval_randomness.to_f * @options.interval + current_interval + random_interval + end + + def call(env) + retries = @options.max + request_body = env[:body] + begin + env[:body] = request_body # after failure env[:body] is set to the response body + @app.call(env) + rescue @errmatch => exception + if retries > 0 && retry_request?(env, exception) + retries -= 1 + sleep sleep_amount(retries + 1) + retry + end + raise + end + end + + # Private: construct an exception matcher object. + # + # An exception matcher for the rescue clause can usually be any object that + # responds to `===`, but for Ruby 1.8 it has to be a Class or Module. + def build_exception_matcher(exceptions) + matcher = Module.new + (class << matcher; self; end).class_eval do + define_method(:===) do |error| + exceptions.any? do |ex| + if ex.is_a? Module + error.is_a? ex + else + error.class.to_s == ex.to_s + end + end + end + end + matcher + end + + private + + def retry_request?(env, exception) + IDEMPOTENT_METHODS.include?(env[:method]) || @options.retry_if.call(env, exception) + end + + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/request/token_authentication.rb b/3rdparty/modules/aviator/feature/faraday/request/token_authentication.rb new file mode 100644 index 000000000..25586080c --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/request/token_authentication.rb @@ -0,0 +1,15 @@ +module Faraday + class Request::TokenAuthentication < Request.load_middleware(:authorization) + # Public + def self.header(token, options = nil) + options ||= {} + options[:token] = token + super(:Token, options) + end + + def initialize(app, token, options = nil) + super(app, token, options) + end + end +end + diff --git a/3rdparty/modules/aviator/feature/faraday/request/url_encoded.rb b/3rdparty/modules/aviator/feature/faraday/request/url_encoded.rb new file mode 100644 index 000000000..b02a26621 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/request/url_encoded.rb @@ -0,0 +1,36 @@ +module Faraday + class Request::UrlEncoded < Faraday::Middleware + CONTENT_TYPE = 'Content-Type'.freeze unless defined? CONTENT_TYPE + + class << self + attr_accessor :mime_type + end + self.mime_type = 'application/x-www-form-urlencoded'.freeze + + def call(env) + match_content_type(env) do |data| + params = Faraday::Utils::ParamsHash[data] + env.body = params.to_query(env.params_encoder) + end + @app.call env + end + + def match_content_type(env) + if process_request?(env) + env.request_headers[CONTENT_TYPE] ||= self.class.mime_type + yield(env.body) unless env.body.respond_to?(:to_str) + end + end + + def process_request?(env) + type = request_type(env) + env.body and (type.empty? or type == self.class.mime_type) + end + + def request_type(env) + type = env.request_headers[CONTENT_TYPE].to_s + type = type.split(';', 2).first if type.index(';') + type + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/response.rb b/3rdparty/modules/aviator/feature/faraday/response.rb new file mode 100644 index 000000000..88ec5310a --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/response.rb @@ -0,0 +1,93 @@ +require 'forwardable' + +module Faraday + class Response + # Used for simple response middleware. + class Middleware < Faraday::Middleware + def call(env) + @app.call(env).on_complete do |environment| + on_complete(environment) + end + end + + # Override this to modify the environment after the response has finished. + # Calls the `parse` method if defined + def on_complete(env) + env.body = parse(env.body) if respond_to?(:parse) && env.parse_body? + end + end + + extend Forwardable + extend MiddlewareRegistry + + register_middleware File.expand_path('../response', __FILE__), + :raise_error => [:RaiseError, 'raise_error'], + :logger => [:Logger, 'logger'] + + def initialize(env = nil) + @env = Env.from(env) if env + @on_complete_callbacks = [] + end + + attr_reader :env + + def_delegators :env, :to_hash + + def status + finished? ? env.status : nil + end + + def headers + finished? ? env.response_headers : {} + end + def_delegator :headers, :[] + + def body + finished? ? env.body : nil + end + + def finished? + !!env + end + + def on_complete + if not finished? + @on_complete_callbacks << Proc.new + else + yield(env) + end + return self + end + + def finish(env) + raise "response already finished" if finished? + @on_complete_callbacks.each { |callback| callback.call(env) } + @env = Env.from(env) + return self + end + + def success? + finished? && env.success? + end + + # because @on_complete_callbacks cannot be marshalled + def marshal_dump + !finished? ? nil : { + :status => @env.status, :body => @env.body, + :response_headers => @env.response_headers + } + end + + def marshal_load(env) + @env = Env.from(env) + end + + # Expand the env with more properties, without overriding existing ones. + # Useful for applying request params after restoring a marshalled Response. + def apply_request(request_env) + raise "response didn't finish yet" unless finished? + @env = Env.from(request_env).update(@env) + return self + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/response/logger.rb b/3rdparty/modules/aviator/feature/faraday/response/logger.rb new file mode 100644 index 000000000..cab7f1b7c --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/response/logger.rb @@ -0,0 +1,34 @@ +require 'forwardable' + +module Faraday + class Response::Logger < Response::Middleware + extend Forwardable + + def initialize(app, logger = nil) + super(app) + @logger = logger || begin + require 'logger' + ::Logger.new(STDOUT) + end + end + + def_delegators :@logger, :debug, :info, :warn, :error, :fatal + + def call(env) + info "#{env.method} #{env.url.to_s}" + debug('request') { dump_headers env.request_headers } + super + end + + def on_complete(env) + info('Status') { env.status.to_s } + debug('response') { dump_headers env.response_headers } + end + + private + + def dump_headers(headers) + headers.map { |k, v| "#{k}: #{v.inspect}" }.join("\n") + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/response/raise_error.rb b/3rdparty/modules/aviator/feature/faraday/response/raise_error.rb new file mode 100644 index 000000000..437762bc1 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/response/raise_error.rb @@ -0,0 +1,21 @@ +module Faraday + class Response::RaiseError < Response::Middleware + ClientErrorStatuses = 400...600 + + def on_complete(env) + case env[:status] + when 404 + raise Faraday::Error::ResourceNotFound, response_values(env) + when 407 + # mimic the behavior that we get with proxy requests with HTTPS + raise Faraday::Error::ConnectionFailed, %{407 "Proxy Authentication Required "} + when ClientErrorStatuses + raise Faraday::Error::ClientError, response_values(env) + end + end + + def response_values(env) + {:status => env.status, :headers => env.response_headers, :body => env.body} + end + end +end diff --git a/3rdparty/modules/aviator/feature/faraday/upload_io.rb b/3rdparty/modules/aviator/feature/faraday/upload_io.rb new file mode 100644 index 000000000..9130d159d --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/upload_io.rb @@ -0,0 +1,67 @@ +begin + require 'composite_io' + require 'parts' + require 'stringio' +rescue LoadError + $stderr.puts "Install the multipart-post gem." + raise +end + +module Faraday + # Similar but not compatible with ::CompositeReadIO provided by multipart-post. + class CompositeReadIO + def initialize(*parts) + @parts = parts.flatten + @ios = @parts.map { |part| part.to_io } + @index = 0 + end + + def length + @parts.inject(0) { |sum, part| sum + part.length } + end + + def rewind + @ios.each { |io| io.rewind } + @index = 0 + end + + # Read from IOs in order until `length` bytes have been received. + def read(length = nil, outbuf = nil) + got_result = false + outbuf = outbuf ? outbuf.replace("") : "" + + while io = current_io + if result = io.read(length) + got_result ||= !result.nil? + result.force_encoding("BINARY") if result.respond_to?(:force_encoding) + outbuf << result + length -= result.length if length + break if length == 0 + end + advance_io + end + (!got_result && length) ? nil : outbuf + end + + def close + @ios.each { |io| io.close } + end + + def ensure_open_and_readable + # Rubinius compatibility + end + + private + + def current_io + @ios[@index] + end + + def advance_io + @index += 1 + end + end + + UploadIO = ::UploadIO + Parts = ::Parts +end diff --git a/3rdparty/modules/aviator/feature/faraday/utils.rb b/3rdparty/modules/aviator/feature/faraday/utils.rb new file mode 100644 index 000000000..1cd6526a6 --- /dev/null +++ b/3rdparty/modules/aviator/feature/faraday/utils.rb @@ -0,0 +1,297 @@ +require 'thread' +Faraday.require_libs 'parameters' + +module Faraday + module Utils + extend self + + # Adapted from Rack::Utils::HeaderHash + class Headers < ::Hash + def self.from(value) + new(value) + end + + def initialize(hash = nil) + super() + @names = {} + self.update(hash || {}) + end + + # need to synchronize concurrent writes to the shared KeyMap + keymap_mutex = Mutex.new + + # symbol -> string mapper + cache + KeyMap = Hash.new do |map, key| + value = if key.respond_to?(:to_str) + key + else + key.to_s.split('_'). # :user_agent => %w(user agent) + each { |w| w.capitalize! }. # => %w(User Agent) + join('-') # => "User-Agent" + end + keymap_mutex.synchronize { map[key] = value } + end + KeyMap[:etag] = "ETag" + + def [](k) + k = KeyMap[k] + super(k) || super(@names[k.downcase]) + end + + def []=(k, v) + k = KeyMap[k] + k = (@names[k.downcase] ||= k) + # join multiple values with a comma + v = v.to_ary.join(', ') if v.respond_to? :to_ary + super(k, v) + end + + def fetch(k, *args, &block) + k = KeyMap[k] + key = @names.fetch(k.downcase, k) + super(key, *args, &block) + end + + def delete(k) + k = KeyMap[k] + if k = @names[k.downcase] + @names.delete k.downcase + super(k) + end + end + + def include?(k) + @names.include? k.downcase + end + + alias_method :has_key?, :include? + alias_method :member?, :include? + alias_method :key?, :include? + + def merge!(other) + other.each { |k, v| self[k] = v } + self + end + alias_method :update, :merge! + + def merge(other) + hash = dup + hash.merge! other + end + + def replace(other) + clear + self.update other + self + end + + def to_hash() ::Hash.new.update(self) end + + def parse(header_string) + return unless header_string && !header_string.empty? + header_string.split(/\r\n/). + tap { |a| a.shift if a.first.index('HTTP/') == 0 }. # drop the HTTP status line + map { |h| h.split(/:\s+/, 2) }.reject { |p| p[0].nil? }. # split key and value, ignore blank lines + each { |key, value| + # join multiple values with a comma + if self[key] + self[key] << ', ' << value + else + self[key] = value + end + } + end + end + + # hash with stringified keys + class ParamsHash < Hash + def [](key) + super(convert_key(key)) + end + + def []=(key, value) + super(convert_key(key), value) + end + + def delete(key) + super(convert_key(key)) + end + + def include?(key) + super(convert_key(key)) + end + + alias_method :has_key?, :include? + alias_method :member?, :include? + alias_method :key?, :include? + + def update(params) + params.each do |key, value| + self[key] = value + end + self + end + alias_method :merge!, :update + + def merge(params) + dup.update(params) + end + + def replace(other) + clear + update(other) + end + + def merge_query(query, encoder = nil) + if query && !query.empty? + update((encoder || Utils.default_params_encoder).decode(query)) + end + self + end + + def to_query(encoder = nil) + (encoder || Utils.default_params_encoder).encode(self) + end + + private + + def convert_key(key) + key.to_s + end + end + + def build_query(params) + FlatParamsEncoder.encode(params) + end + + def build_nested_query(params) + NestedParamsEncoder.encode(params) + end + + ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/ + + def escape(s) + s.to_s.gsub(ESCAPE_RE) {|match| + '%' + match.unpack('H2' * match.bytesize).join('%').upcase + }.tr(' ', '+') + end + + def unescape(s) CGI.unescape s.to_s end + + DEFAULT_SEP = /[&;] */n + + # Adapted from Rack + def parse_query(query) + FlatParamsEncoder.decode(query) + end + + def parse_nested_query(query) + NestedParamsEncoder.decode(query) + end + + def default_params_encoder + @default_params_encoder ||= NestedParamsEncoder + end + + class << self + attr_writer :default_params_encoder + end + + # Stolen from Rack + def normalize_params(params, name, v = nil) + name =~ %r(\A[\[\]]*([^\[\]]+)\]*) + k = $1 || '' + after = $' || '' + + return if k.empty? + + if after == "" + if params[k] + params[k] = Array[params[k]] unless params[k].kind_of?(Array) + params[k] << v + else + params[k] = v + end + elsif after == "[]" + params[k] ||= [] + raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) + params[k] << v + elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$) + child_key = $1 + params[k] ||= [] + raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) + if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key) + normalize_params(params[k].last, child_key, v) + else + params[k] << normalize_params({}, child_key, v) + end + else + params[k] ||= {} + raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Hash) + params[k] = normalize_params(params[k], after, v) + end + + return params + end + + # Normalize URI() behavior across Ruby versions + # + # url - A String or URI. + # + # Returns a parsed URI. + def URI(url) + if url.respond_to?(:host) + url + elsif url.respond_to?(:to_str) + default_uri_parser.call(url) + else + raise ArgumentError, "bad argument (expected URI object or URI string)" + end + end + + def default_uri_parser + @default_uri_parser ||= begin + require 'uri' + Kernel.method(:URI) + end + end + + def default_uri_parser=(parser) + @default_uri_parser = if parser.respond_to?(:call) || parser.nil? + parser + else + parser.method(:parse) + end + end + + # Receives a String or URI and returns just the path with the query string sorted. + def normalize_path(url) + url = URI(url) + (url.path.start_with?('/') ? url.path : '/' + url.path) + + (url.query ? "?#{sort_query_params(url.query)}" : "") + end + + # Recursive hash update + def deep_merge!(target, hash) + hash.each do |key, value| + if Hash === value and Hash === target[key] + target[key] = deep_merge(target[key], value) + else + target[key] = value + end + end + target + end + + # Recursive hash merge + def deep_merge(source, hash) + deep_merge!(source.dup, hash) + end + + protected + + def sort_query_params(query) + query.split('&').sort.join('&') + end + end +end diff --git a/3rdparty/modules/aviator/feature/multipart_post.rb b/3rdparty/modules/aviator/feature/multipart_post.rb new file mode 100644 index 000000000..76540a8b7 --- /dev/null +++ b/3rdparty/modules/aviator/feature/multipart_post.rb @@ -0,0 +1,9 @@ +#-- +# Copyright (c) 2007-2013 Nick Sieger. +# See the file README.txt included with the distribution for +# software license details. +#++ + +module MultipartPost + VERSION = "2.0.0" +end diff --git a/3rdparty/modules/aviator/feature/multipartable.rb b/3rdparty/modules/aviator/feature/multipartable.rb new file mode 100644 index 000000000..28fa41e6d --- /dev/null +++ b/3rdparty/modules/aviator/feature/multipartable.rb @@ -0,0 +1,29 @@ +#-- +# Copyright (c) 2007-2013 Nick Sieger. +# See the file README.txt included with the distribution for +# software license details. +#++ + +require 'parts' + module Multipartable + DEFAULT_BOUNDARY = "-----------RubyMultipartPost" + def initialize(path, params, headers={}, boundary = DEFAULT_BOUNDARY) + headers = headers.clone # don't want to modify the original variable + parts_headers = headers.delete(:parts) || {} + super(path, headers) + parts = params.map do |k,v| + case v + when Array + v.map {|item| Parts::Part.new(boundary, k, item, parts_headers[k]) } + else + Parts::Part.new(boundary, k, v, parts_headers[k]) + end + end.flatten + parts << Parts::EpiloguePart.new(boundary) + ios = parts.map {|p| p.to_io } + self.set_content_type(headers["Content-Type"] || "multipart/form-data", + { "boundary" => boundary }) + self.content_length = parts.inject(0) {|sum,i| sum + i.length } + self.body_stream = CompositeReadIO.new(*ios) + end + end diff --git a/3rdparty/modules/aviator/feature/net/http/post/multipart.rb b/3rdparty/modules/aviator/feature/net/http/post/multipart.rb new file mode 100644 index 000000000..757058220 --- /dev/null +++ b/3rdparty/modules/aviator/feature/net/http/post/multipart.rb @@ -0,0 +1,27 @@ +#-- +# Copyright (c) 2007-2012 Nick Sieger. +# See the file README.txt included with the distribution for +# software license details. +#++ + +require 'net/http' +require 'stringio' +require 'cgi' +require 'composite_io' +require 'multipartable' +require 'parts' + +module Net #:nodoc: + class HTTP #:nodoc: + class Put + class Multipart < Put + include Multipartable + end + end + class Post #:nodoc: + class Multipart < Post + include Multipartable + end + end + end +end diff --git a/3rdparty/modules/aviator/feature/parts.rb b/3rdparty/modules/aviator/feature/parts.rb new file mode 100644 index 000000000..c06cbd95d --- /dev/null +++ b/3rdparty/modules/aviator/feature/parts.rb @@ -0,0 +1,96 @@ +#-- +# Copyright (c) 2007-2013 Nick Sieger. +# See the file README.txt included with the distribution for +# software license details. +#++ + +module Parts + module Part #:nodoc: + def self.new(boundary, name, value, headers = {}) + headers ||= {} # avoid nil values + if file?(value) + FilePart.new(boundary, name, value, headers) + else + ParamPart.new(boundary, name, value, headers) + end + end + + def self.file?(value) + value.respond_to?(:content_type) && value.respond_to?(:original_filename) + end + + def length + @part.length + end + + def to_io + @io + end + end + + class ParamPart + include Part + def initialize(boundary, name, value, headers = {}) + @part = build_part(boundary, name, value, headers) + @io = StringIO.new(@part) + end + + def length + @part.bytesize + end + + def build_part(boundary, name, value, headers = {}) + part = '' + part << "--#{boundary}\r\n" + part << "Content-Disposition: form-data; name=\"#{name.to_s}\"\r\n" + part << "Content-Type: #{headers["Content-Type"]}\r\n" if headers["Content-Type"] + part << "\r\n" + part << "#{value}\r\n" + end + end + + # Represents a part to be filled from file IO. + class FilePart + include Part + attr_reader :length + def initialize(boundary, name, io, headers = {}) + file_length = io.respond_to?(:length) ? io.length : File.size(io.local_path) + @head = build_head(boundary, name, io.original_filename, io.content_type, file_length, + io.respond_to?(:opts) ? io.opts.merge(headers) : headers) + @foot = "\r\n" + @length = @head.bytesize + file_length + @foot.length + @io = CompositeReadIO.new(StringIO.new(@head), io, StringIO.new(@foot)) + end + + def build_head(boundary, name, filename, type, content_len, opts = {}, headers = {}) + trans_encoding = opts["Content-Transfer-Encoding"] || "binary" + content_disposition = opts["Content-Disposition"] || "form-data" + + part = '' + part << "--#{boundary}\r\n" + part << "Content-Disposition: #{content_disposition}; name=\"#{name.to_s}\"; filename=\"#{filename}\"\r\n" + part << "Content-Length: #{content_len}\r\n" + if content_id = opts["Content-ID"] + part << "Content-ID: #{content_id}\r\n" + end + + if headers["Content-Type"] != nil + part << "Content-Type: " + headers["Content-Type"] + "\r\n" + else + part << "Content-Type: #{type}\r\n" + end + + part << "Content-Transfer-Encoding: #{trans_encoding}\r\n" + part << "\r\n" + end + end + + # Represents the epilogue or closing boundary. + class EpiloguePart + include Part + def initialize(boundary) + @part = "--#{boundary}--\r\n\r\n" + @io = StringIO.new(@part) + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator.rb new file mode 100644 index 000000000..e70ba3918 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator.rb @@ -0,0 +1,7 @@ +# Add the parent dir to the load path. This is for when +# Aviator is not installed as a gem +lib_path = File.dirname(__FILE__) +$LOAD_PATH.unshift(lib_path) unless $LOAD_PATH.include? lib_path + +require 'aviator/core' +require "aviator/openstack/provider" diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/core.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core.rb new file mode 100644 index 000000000..73576f914 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core.rb @@ -0,0 +1,15 @@ +require 'yaml' +require 'json' +require 'faraday' +require 'pathname' + +require "aviator/version" +require "aviator/core/utils/string" +require "aviator/core/utils/compatibility" +require "aviator/core/utils/hashish" +require "aviator/core/request" +require "aviator/core/request_builder" +require "aviator/core/response" +require "aviator/core/service" +require "aviator/core/session" +require "aviator/core/logger" diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/cli.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/cli.rb new file mode 100644 index 000000000..cd937d0e7 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/cli.rb @@ -0,0 +1,2 @@ +require "terminal-table" +require "aviator/core/cli/describer" diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/cli/describer.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/cli/describer.rb new file mode 100644 index 000000000..a6ad8507a --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/cli/describer.rb @@ -0,0 +1,161 @@ +module Aviator + + class Describer + + class InvalidProviderNameError < StandardError + def initialize(name) + super "Provider '#{ name }' does not exist." + end + end + + + def self.describe_aviator + str = "Available providers:\n" + + provider_names.each do |provider_name| + str << " #{ provider_name }\n" + end + + str + end + + + def self.describe_provider(provider_name) + str = "Available services for #{ provider_name }:\n" + + service_names(provider_name).each do |service_name| + str << " #{ service_name }\n" + end + + str + end + + + def self.describe_request(provider_name, service_name, api_version, endpoint_type, request_name) + service = Aviator::Service.new :provider => provider_name, :service => service_name + request_class = "Aviator::#{ provider_name.camelize }::#{ service_name.camelize }::Requests::"\ + "#{ api_version.camelize }::#{ endpoint_type.camelize }::#{ request_name.camelize }".constantize + + display = "Request: #{ request_name }\n" + + + # Build the parameters + params = request_class.optional_params.map{|p| [p, false]} + + request_class.required_params.map{|p| [p, true]} + + aliases = request_class.param_aliases + + if params.length > 0 + display << "\n" + + headings = ['NAME', 'REQUIRED?'] + + headings << 'ALIAS' if aliases.length > 0 + + rows = [] + params.sort{|a,b| a[0].to_s <=> b[0].to_s }.each do |param| + row = [ param[0], param[1] ? 'Y' : 'N' ] + + if aliases.length > 0 + row << (aliases.find{|a,p| p == param[0] } || [''])[0] + end + + rows << row + end + + widths = [ + rows.map{|row| row[0].to_s.length }.max, + rows.map{|row| row[1].to_s.length }.max + ] + + widths << rows.map{|row| row[2].to_s.length }.max if aliases.length > 0 + + table = Terminal::Table.new(:headings => headings, :rows => rows) + + table.align_column(1, :center) + + display << "Parameters:\n" + display << " " + table.to_s.split("\n").join("\n ") + display << "\n" + end + + + # Build the sample code + display << "\nSample Code:\n" + + display << " session.request(:#{ service_name }_service, :#{ request_name })" + + if params && params.length > 0 + display << " do |params|\n" + params.each do |pair| + display << " params.#{ (aliases.find{|a,p| p == pair[0] } || pair)[0] } = value\n" + end + display << " end" + end + + display << "\n" + + + # Build the links + if request_class.links && request_class.links.length > 0 + display << "\nLinks:\n" + + request_class.links.each do |link| + display << " #{ link[:rel] }:\n" + display << " #{ link[:href] }\n" + end + end + + display + end + + + def self.describe_service(provider_name, service_name) + requests = request_classes(provider_name, service_name) + + if requests.empty? + str = "No requests found for #{ provider_name } #{ service_name }_service." + else + str = "Available requests for #{ provider_name } #{ service_name }_service:\n" + + requests.each do |klass| + str << " #{ klass.api_version } #{ klass.endpoint_type } #{ klass.name.split('::').last.underscore }\n" + end + + str + end + end + + + class < provider_name, :service => service_name) + service.request_classes + end + + + def service_names(name) + provider = Pathname.new(__FILE__).join('..', '..', '..', name) + + raise InvalidProviderNameError.new(name) unless provider.exist? + + provider.children \ + .select{|c| c.directory? } \ + .map{|c| c.basename.to_s } + end + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/logger.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/logger.rb new file mode 100644 index 000000000..bbb537d7f --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/logger.rb @@ -0,0 +1,55 @@ +module Aviator + + class Logger < Faraday::Response::Middleware + extend Forwardable + + def initialize(app, logger=nil) + super(app) + @logger = logger || begin + require 'logger' + ::Logger.new(self.class::LOG_FILE_PATH) + end + end + + + def_delegators :@logger, :debug, :info, :warn, :error, :fatal + + + def call(env) + info(env[:method].to_s.upcase) { env[:url].to_s } + debug('REQ_HEAD') { dump_headers env[:request_headers] } + debug('REQ_BODY') { dump_body env[:body] } + super + end + + + def on_complete(env) + info('STATUS') { env[:status].to_s } + debug('RES_HEAD') { dump_headers env[:response_headers] } + debug('RES_BODY') { dump_body env[:body] } + end + + + def self.configure(log_file_path) + # Return a subclass with its logfile path set. This + # must be done so that different sessions can log to + # different paths. + Class.new(self) { const_set('LOG_FILE_PATH', log_file_path) } + end + + + private + + def dump_body(body) + return if body.nil? + + # :TODO => Make this configurable + body.gsub(/["']password["']:["']\w*["']/, '"password":[FILTERED_VALUE]') + end + + def dump_headers(headers) + headers.map { |k, v| "#{k}: #{v.inspect}" }.join("; ") + end + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/request.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/request.rb new file mode 100644 index 000000000..ed9c6cef1 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/request.rb @@ -0,0 +1,229 @@ +module Aviator + + class Request + + class ApiVersionNotDefinedError < StandardError + def initialize + super "api_version is not defined." + end + end + + class EndpointTypeNotDefinedError < StandardError + def initialize + super "endpoint_type is not defined." + end + end + + class PathNotDefinedError < StandardError + def initialize + super "path is not defined." + end + end + + + def initialize(session_data=nil) + @session_data = session_data + + params = self.class.params_class.new if self.class.params_class + + if params + yield(params) if block_given? + validate_params(params) + end + + @params = params + end + + + def anonymous? + self.class.anonymous? + end + + + def body? + self.class.body? + end + + + def headers? + self.class.headers? + end + + + def links + self.class.links + end + + + def optional_params + self.class.optional_params + end + + + def params + @params.dup + end + + + def required_params + self.class.required_params + end + + + def session_data + @session_data + end + + + def session_data? + !session_data.nil? + end + + + def querystring? + self.class.querystring? + end + + + def url? + self.class.url? + end + + + private + + + def validate_params(params) + required_params = self.class.required_params + + required_params.each do |name| + raise ArgumentError.new("Missing parameter #{ name }.") if params.send(name).nil? + end + end + + + # NOTE that, because we are defining the following as class methods, when they + # are called, all 'instance' variables are actually defined in the descendant class, + # not in the instance/object. This is by design since we want to keep these attributes + # within the class and because they don't change between instances anyway. + class << self + + def anonymous? + respond_to?(:anonymous) && anonymous == true + end + + + def body? + instance_methods.include? :body + end + + + def headers? + instance_methods.include? :headers + end + + + def links + @links ||= [] + end + + + def param_aliases + @param_aliases ||= {} + end + + + def params_class + all_params = required_params + optional_params + + if all_params.length > 0 && @params_class.nil? + @params_class = build_params_class(all_params, self.param_aliases) + end + + @params_class + end + + + def optional_params + @optional_params ||= [] + end + + + def querystring? + instance_methods.include? :querystring + end + + + def required_params + @required_params ||= [] + end + + + def url? + instance_methods.include? :url + end + + + private + + + def build_params_class(all_params, param_aliases) + Struct.new(*all_params) do + alias :param_getter :[] + alias :param_setter :[]= + + define_method :[] do |key| + key = param_aliases[key.to_sym] if param_aliases.keys.include? key.to_sym + param_getter(key) + end + + define_method :[]= do |key, value| + key = param_aliases[key.to_sym] if param_aliases.keys.include? key.to_sym + param_setter(key, value) + end + + param_aliases.each do |param_alias, param_name| + define_method param_alias do + param_getter(param_name) + end + + define_method "#{ param_alias }=" do |value| + param_setter(param_name, value) + end + end + end + end + + + def link(rel, href) + links << { :rel => rel, :href => href } + end + + + def meta(attr_name, attr_value) + eigenclass = class << self; self; end + eigenclass.send(:define_method, attr_name) do + attr_value + end + + define_method(attr_name) do + self.class.send(attr_name) + end + end + + + def param(param_name, opts={}) + opts = Hashish.new(opts) + list = (opts[:required] == false ? optional_params : required_params) + list << param_name unless optional_params.include?(param_name) + + if opts[:alias] + self.param_aliases[opts[:alias]] = param_name + end + end + + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/request_builder.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/request_builder.rb new file mode 100644 index 000000000..ac5590166 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/request_builder.rb @@ -0,0 +1,102 @@ +module Aviator + + class BaseRequestNotFoundError < StandardError + attr_reader :base_request_hierarchy + + def initialize(base_hierarchy) + @base_request_hierarchy = base_hierarchy + super("#{ base_request_hierarchy } could not be found!") + end + end + + + class RequestAlreadyDefinedError < StandardError + attr_reader :namespace, + :request_name + + def initialize(namespace, request_name) + @namespace = namespace + @request_name = request_name + super("#{ namespace }::#{ request_name } is already defined") + end + end + + + class RequestBuilder + + class << self + + def define_request(root_namespace, request_name, options, &block) + base_klass = get_request_class(root_namespace, options[:inherit]) + + klass = Class.new(base_klass, &block) + + namespace_arr = [ + klass.provider, + klass.service, + 'Requests', + klass.api_version, + klass.endpoint_type + ] + + namespace = namespace_arr.inject(root_namespace) do |namespace, sym| + const_name = sym.to_s.camelize + namespace.const_set(const_name, Module.new) unless namespace.const_defined?(const_name, false) + namespace.const_get(const_name, false) + end + + klassname = request_name.to_s.camelize + + if namespace.const_defined?(klassname, false) + raise RequestAlreadyDefinedError.new(namespace, klassname) + end + + namespace.const_set(klassname, klass) + end + + + def get_request_class(root_namespace, request_class_arr) + provider_specific = request_class_arr != [:request] + + if provider_specific + full_request_class_arr = request_class_arr.dup + full_request_class_arr.insert(2, :requests) if provider_specific + else + full_request_class_arr = request_class_arr + end + + full_request_class_arr.inject(root_namespace) do |namespace, sym| + namespace.const_get(sym.to_s.camelize, false) + end + rescue NameError => e + if Aviator.const_defined?(full_request_class_arr[0].to_s.camelize) + provider = "Aviator::#{ full_request_class_arr[0] }::Provider".constantize + arr = ['..'] + full_request_class_arr + arr[-1,1] = arr.last.to_s + '.rb' + path = Pathname.new(provider.root_dir).join(*arr.map{|i| i.to_s }).expand_path + end + + if provider && path.exist? + require path + full_request_class_arr.inject(root_namespace) do |namespace, sym| + namespace.const_get(sym.to_s.camelize, false) + end + else + raise BaseRequestNotFoundError.new(request_class_arr) + end + end + + end + + end + + + class << self + + def define_request(request_name, options={ :inherit => [:request] }, &block) + RequestBuilder.define_request self, request_name, options, &block + end + + end # class << self + +end \ No newline at end of file diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/response.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/response.rb new file mode 100644 index 000000000..12c9561af --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/response.rb @@ -0,0 +1,52 @@ +module Aviator + + class Response + extend Forwardable + + def_delegators :@response, :status + + attr_reader :request + + def initialize(response, request) + @response = response + @request = request + end + + + def body + @body ||= if raw_body.length > 0 + if Aviator::Compatibility::RUBY_1_8_MODE + clean_body = raw_body.gsub(/\\ /, ' ') + else + clean_body = raw_body + end + + Hashish.new(JSON.parse(clean_body)) + else + Hashish.new({}) + end + end + + + def headers + @headers ||= Hashish.new(@response.headers) + end + + + def to_hash + Hashish.new({ + :status => status, + :headers => headers, + :body => body + }) + end + + private + + def raw_body + @raw_body ||= @response.body + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/service.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/service.rb new file mode 100644 index 000000000..f31645549 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/service.rb @@ -0,0 +1,169 @@ +module Aviator + + # + # Manages a service + # + class Service + + class AccessDetailsNotDefinedError < StandardError + def initialize + super ":access_details is not defined." + end + end + + class ProviderNotDefinedError < StandardError + def initialize + super ":provider is not defined." + end + end + + class ServiceNameNotDefinedError < StandardError + def initialize + super ":service is not defined." + end + end + + class SessionDataNotProvidedError < StandardError + def initialize(service_name, request_name) + super "\n\nERROR: default_session_data is not initialized and no session data was provided in\n"\ + "the method call. You have two ways to fix this:\n\n"\ + " 1) Call Session#authenticate before calling Session##{service_name}_service, or\n\n"\ + " 2) If you're really sure you don't want to authenticate beforehand,\n"\ + " construct the method call this way:\n\n"\ + " service = session.#{service_name}_service\n"\ + " service.request :#{request_name}, :api_version => :v2, :session_data => sessiondatavar\n\n"\ + " Replace :v2 with whatever available version you want to use and make sure sessiondatavar\n"\ + " is a hash that contains, at least, the :base_url key. Other keys, such as :service_token may\n"\ + " be needed depending on what the request class you are calling requires.\n\n" + end + end + + class UnknownRequestError < StandardError + def initialize(request_name, options) + super "Unknown request #{ request_name } #{ options }." + end + end + + + class MissingServiceEndpointError < StandardError + def initialize(service_name, request_name) + request_name = request_name.to_s.split('::').last.underscore + super "The session's service catalog does not have an entry for the #{ service_name } "\ + "service. Therefore, I don't know to which base URL the request should be sent. "\ + "This may be because you are using a default or unscoped token. If this is not your "\ + "intention, please authenticate with a scoped token. If using a default token is your "\ + "intention, make sure to provide a base url when you call the request. For :example => \n\n"\ + "session.#{ service_name }_service.request :#{ request_name }, :base_url => 'http://myenv.com:9999/v2.0' do |params|\n"\ + " params[:example1] = 'example1'\n"\ + " params[:example2] = 'example2'\n"\ + "end\n\n" + end + end + + attr_accessor :default_session_data + + attr_reader :service, + :provider + + + def initialize(opts={}) + @provider = opts[:provider] || (raise ProviderNotDefinedError.new) + @service = opts[:service] || (raise ServiceNameNotDefinedError.new) + @log_file = opts[:log_file] + @default_options = opts[:default_options] || {} + + @default_session_data = opts[:default_session_data] + + load_requests + end + + # + # No longer recommended for public use. Use Aviator::Session#request instead + # + def request(request_name, options={}, ¶ms) + if options[:api_version].nil? && @default_options[:api_version] + options[:api_version] = @default_options[:api_version] + end + + session_data = options[:session_data] || default_session_data + + raise SessionDataNotProvidedError.new(@service, request_name) unless session_data + + [:base_url].each do |k| + session_data[k] = options[k] if options[k] + end + + request_class = provider_module.find_request(service, request_name, session_data, options) + + raise UnknownRequestError.new(request_name, options) unless request_class + + # Always use :params over ¶ms if provided + if options[:params] + params = lambda do |params| + options[:params].each do |key, value| + begin + params[key] = value + rescue NameError => e + raise NameError.new("Unknown param name '#{key}'") + end + end + end + end + + request = request_class.new(session_data, ¶ms) + + response = http_connection.send(request.http_method) do |r| + r.url request.url + r.headers.merge!(request.headers) if request.headers? + r.query = request.querystring if request.querystring? + r.body = JSON.generate(request.body) if request.body? + end + + Aviator::Response.send(:new, response, request) + end + + + def request_classes + @request_classes + end + + + private + + + def http_connection + @http_connection ||= Faraday.new do |conn| + conn.use Logger.configure(log_file) if log_file + conn.adapter Faraday.default_adapter + + conn.headers['Content-Type'] = 'application/json' + end + end + + + def load_requests + request_file_paths = provider_module.request_file_paths(service) + request_file_paths.each{ |path| require path } + + constant_parts = request_file_paths \ + .map{|rf| rf.to_s.match(/#{provider}\/#{service}\/([\w\/]+)\.rb$/) } \ + .map{|rf| rf[1].split('/').map{|c| c.camelize }.join('::') } + + @request_classes = constant_parts.map do |cp| + "Aviator::#{provider.camelize}::#{service.camelize}::#{cp}".constantize + end + end + + + def log_file + @log_file + end + + + def provider_module + @provider_module ||= "Aviator::#{provider.camelize}::Provider".constantize + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/session.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/session.rb new file mode 100644 index 000000000..f93db097c --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/session.rb @@ -0,0 +1,491 @@ +# +# Author:: Mark Maglana (mmaglana@gmail.com) +# Copyright:: Copyright (c) 2014 Mark Maglana +# License:: Distributed under the MIT license +# Homepage:: http://aviator.github.io/www/ +# +module Aviator + + # + # Manages a provider (e.g. OpenStack) session and serves as the entry point + # for a consumer class/object. See Session::new for notes on usage. + # + class Session + + class AuthenticationError < StandardError + def initialize(last_auth_body) + super("Authentication failed. The server returned #{ last_auth_body }") + end + end + + + class EnvironmentNotDefinedError < ArgumentError + def initialize(path, env) + super("The environment '#{ env }' is not defined in #{ path }.") + end + end + + class InitializationError < StandardError + def initialize + super("The session could not find :session_dump, :config_file, and " \ + ":config in the constructor arguments provided") + end + end + + class InvalidConfigFilePathError < ArgumentError + def initialize(path) + super("The config file at #{ path } does not exist!") + end + end + + + class NotAuthenticatedError < StandardError + def initialize + super("Session is not authenticated. Please authenticate before proceeding.") + end + end + + + class ValidatorNotDefinedError < StandardError + def initialize + super("The validator request name is not defined for this session object.") + end + end + + # + # Create a new Session instance. + # + # Initialize with a config file + # + # Aviator::Session.new(:config_file => 'path/to/aviator.yml', :environment => :production) + # + # In the above example, the config file must have the following form: + # + # production: + # provider: openstack + # auth_service: + # name: identity + # host_uri: 'http://my.openstackenv.org:5000' + # request: create_token + # validator: list_tenants + # api_version: v2 + # auth_credentials: + # username: myusername + # password: mypassword + # tenant_name: myproject + # + # SIDENOTE: For more information about the validator member, see Session#validate. + # + # Once the session has been instantiated, you may authenticate against the + # provider as follows: + # + # session.authenticate + # + # The members you put under auth_credentials will depend on the request + # class you declare under auth_service:request and what parameters it + # accepts. To know more about a request class and its parameters, you can use + # the CLI tool aviator describe or view the request definition file directly. + # + # If writing the auth_credentials in the config file is not acceptable, + # you may omit it and just supply the credentials at runtime. For example: + # + # session.authenticate do |params| + # params.username = ARGV[0] + # params.password = ARGV[1] + # params.tenant_name = ARGV[2] + # end + # + # See Session#authenticate for more info. + # + # Note that while the example config file above only has one environment (production), + # you can declare an arbitrary number of environments in your config file. Shifting + # between environments is as simple as changing the :environment to refer to that. + # + # + # Initialize with an in-memory hash + # + # You can create an in-memory hash with a structure similar to the config file but without + # the environment name. For example: + # + # configuration = { + # :provider => 'openstack', + # :auth_service => { + # :name => 'identity', + # :host_uri => 'http://devstack:5000/v2.0', + # :request => 'create_token', + # :validator => 'list_tenants' + # } + # } + # + # Supply this to the initializer using the :config option. For example: + # + # Aviator::Session.new(:config => configuration) + # + # + # Initialize with a session dump + # + # You can create a new Session instance using a dump from another instance. For example: + # + # session_dump = session1.dump + # session2 = Aviator::Session.new(:session_dump => session_dump) + # + # However, Session.load is cleaner and recommended over this method. + # + # + # Optionally supply a log file + # + # In all forms above, you may optionally add a :log_file option to make + # Aviator write all HTTP calls to the given path. For example: + # + # Aviator::Session.new(:config_file => 'path/to/aviator.yml', :environment => :production, :log_file => 'path/to/log') + # + def initialize(opts={}) + if opts.has_key? :session_dump + initialize_with_dump(opts[:session_dump]) + elsif opts.has_key? :config_file + initialize_with_config(opts[:config_file], opts[:environment]) + elsif opts.has_key? :config + initialize_with_hash(opts[:config]) + else + raise InitializationError.new + end + + @log_file = opts[:log_file] + end + + # + # Authenticates against the backend provider using the auth_service request class + # declared in the session's configuration. Please see Session.new for more information + # on declaring the request class to use for authentication. + # + # Request params block + # + # If the auth_service request class accepts parameters, you may supply that + # as a block and it will be directly passed to the request. For example: + # + # session = Aviator::Session.new(:config => config) + # session.authenticate do |params| + # params.username = username + # params.password = password + # params.tenant_name = project + # end + # + # If your configuration happens to have an auth_credentials in it, those + # will be overridden by this block. + # + # Treat parameters as a hash + # + # You can also treat the params struct like a hash with the attribute + # names as the keys. For example, we can rewrite the above as: + # + # session = Aviator::Session.new(:config => config) + # session.authenticate do |params| + # params[:username] = username + # params[:password] = password + # params[:tenant_name] = project + # end + # + # Keys can be symbols or strings. + # + # Use a hash argument instead of a block + # + # You may also provide request params as an argument instead of a block. This is + # especially useful if you want to mock Aviator as it's easier to specify ordinary + # argument expectations over blocks. Further rewriting the example above, + # we end up with: + # + # session = Aviator::Session.new(:config => config) + # session.authenticate :params => { + # :username => username, + # :password => password, + # :tenant_name => project + # } + # + # If both :params and a block are provided, the :params + # values will be used and the block ignored. + # + # Success requirements + # + # Expects an HTTP status 200 or 201 response from the backend. Any other + # status is treated as a failure. + # + def authenticate(opts={}, &block) + block ||= lambda do |params| + config[:auth_credentials].each do |key, value| + begin + params[key] = value + rescue NameError => e + raise NameError.new("Unknown param name '#{key}'") + end + end + end + + response = auth_service.request(config[:auth_service][:request].to_sym, opts, &block) + + if [200, 201].include? response.status + @auth_response = Hashish.new({ + :headers => response.headers, + :body => response.body + }) + update_services_session_data + else + raise AuthenticationError.new(response.body) + end + self + end + + # + # Returns true if the session has been authenticated. Note that this relies on + # cached response from a previous run of Session#authenticate if one was made. + # If you want to check against the backend provider if the session is still valid, + # use Session#validate instead. + # + def authenticated? + !auth_response.nil? + end + + # + # Returns its configuration. + # + def config + @config + end + + # + # Returns a JSON string of its configuration and auth_data. This string can be streamed + # or stored and later re-loaded in another Session instance. For example: + # + # session = Aviator::Session.new(:config => configuration) + # str = session.dump + # + # # time passes... + # + # session = Aviator::Session.load(str) + # + def dump + JSON.generate({ + :config => config, + :auth_response => auth_response + }) + end + + + # + # Same as Session::load but re-uses the Session instance this method is + # called on instead of creating a new one. + # + def load(session_dump) + initialize_with_dump(session_dump) + update_services_session_data + self + end + + + def method_missing(name, *args, &block) # :nodoc: + service_name_parts = name.to_s.match(/^(\w+)_service$/) + + if service_name_parts + get_service_obj(service_name_parts[1]) + else + super name, *args, &block + end + end + + + # + # Creates a new Session object from a previous session's dump. See Session#dump for + # more information. + # + # If you want the newly deserialized session to log its output, add a :log_file + # option. + # + # Aviator::Session.load(session_dump_str, :log_file => 'path/to/aviator.log') + # + def self.load(session_dump, opts={}) + opts[:session_dump] = session_dump + + new(opts) + end + + + # + # Returns the log file path. May be nil if none was provided during initialization. + # + def log_file + @log_file + end + + + # + # Calls the given request of the given service. An example call might look like: + # + # session.request :compute_service, :create_server do |p| + # p.name = "My Server" + # p.image_ref = "7cae8c8e-fb01-4a88-bba3-ae0fcb1dbe29" + # p.flavor_ref = "fa283da1-59a5-4245-8569-b6eadf69f10b" + # end + # + # Note that you can also treat the block's argument like a hash with the attribute + # names as the keys. For example, we can rewrite the above as: + # + # session.request :compute_service, :create_server do |p| + # p[:name] = "My Server" + # p[:image_ref] = "7cae8c8e-fb01-4a88-bba3-ae0fcb1dbe29" + # p[:flavor_ref] = "fa283da1-59a5-4245-8569-b6eadf69f10b" + # end + # + # Keys can be symbols or strings. + # + # You may also provide parameters as an argument instead of a block. This is + # especially useful when mocking Aviator as it's easier to specify ordinary + # argument expectations over blocks. Further rewriting the example above, + # we end up with: + # + # session.request :compute_service, :create_server, :params => { + # :name => "My Server", + # :image_ref => "7cae8c8e-fb01-4a88-bba3-ae0fcb1dbe29", + # :flavor_ref => "fa283da1-59a5-4245-8569-b6eadf69f10b" + # } + # + # If both :params and a block are provided, the values in :params + # will be used and the block ignored. + # + # Return Value + # + # The return value will be an instance of Hashish, a lightweight replacement for + # activesupport's HashWithIndifferentAccess, with the following structure: + # + # { + # :status => 200, + # :headers => { + # 'X-Auth-Token' => 'd9186f45ce5446eaa0adc9def1c46f5f', + # 'Content-Type' => 'application/json' + # }, + # :body => { + # :some_key => :some_value + # } + # } + # + # Note that the members in :headers and :body will vary depending + # on the provider and the request that was made. + # + # --- + # + # Request Options + # + # You can further customize how the method behaves by providing one or more + # options to the call. For example, assuming you are using the openstack + # provider, the following will call the :create_server request of the + # v1 API of :compute_service. + # + # session.request :compute_service, :create_server, :api_version => v1, :params => params + # + # The available options vary depending on the provider. See the documentation + # on the provider's Provider class for more information (e.g. Aviator::Openstack::Provider) + # + def request(service_name, request_name, opts={}, &block) + service = send("#{service_name.to_s}_service") + response = service.request(request_name, opts, &block) + response.to_hash + end + + + # + # Returns true if the session is still valid in the underlying provider. This method calls + # the validator request class declared under auth_service in the + # configuration. The validator can be any request class as long as: + # + # * The request class exists! + # * Is not an anonymous request. Otherwise it will always return true. + # * Does not require any parameters + # * It returns an HTTP status 200 or 203 to indicate auth info validity. + # * It returns any other HTTP status to indicate that the auth info is invalid. + # + # See Session::new for an example on how to specify the request class to use for session validation. + # + # Note that this method requires the session to be previously authenticated otherwise a + # NotAuthenticatedError will be raised. If you just want to check if the session was previously + # authenticated, use Session#authenticated? instead. + # + def validate + raise NotAuthenticatedError.new unless authenticated? + raise ValidatorNotDefinedError.new unless config[:auth_service][:validator] + + auth_with_bootstrap = auth_response.merge({ :auth_service => config[:auth_service] }) + + response = auth_service.request config[:auth_service][:validator].to_sym, :session_data => auth_with_bootstrap + response.status == 200 || response.status == 203 + end + + + private + + + def auth_response + @auth_response + end + + + def auth_service + @auth_service ||= Service.new( + :provider => config[:provider], + :service => config[:auth_service][:name], + :default_session_data => { :auth_service => config[:auth_service] }, + :log_file => log_file + ) + end + + + def get_service_obj(service_name) + @services ||= {} + + if @services[service_name].nil? + default_options = config["#{ service_name }_service"] + + @services[service_name] = Service.new( + :provider => config[:provider], + :service => service_name, + :default_session_data => auth_response, + :default_options => default_options, + :log_file => log_file + ) + end + + @services[service_name] + end + + + def initialize_with_config(config_path, environment) + raise InvalidConfigFilePathError.new(config_path) unless Pathname.new(config_path).file? + + all_config = Hashish.new(YAML.load_file(config_path)) + + raise EnvironmentNotDefinedError.new(config_path, environment) unless all_config[environment] + + @config = all_config[environment] + end + + + def initialize_with_dump(session_dump) + session_info = Hashish.new(JSON.parse(session_dump)) + @config = session_info[:config] + @auth_response = session_info[:auth_response] + end + + + def initialize_with_hash(hash_obj) + @config = Hashish.new(hash_obj) + end + + + def update_services_session_data + return unless @services + + @services.each do |name, obj| + obj.default_session_data = auth_response + end + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/utils/compatibility.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/utils/compatibility.rb new file mode 100644 index 000000000..560fc2b70 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/utils/compatibility.rb @@ -0,0 +1,34 @@ +module Aviator + + module Compatibility + RUBY_1_8_MODE = (not (RUBY_VERSION =~ /1\.8\.\d*/).nil?) + end + +end + +if Aviator::Compatibility::RUBY_1_8_MODE + + class Module + + alias_method :old_const_defined?, :const_defined? + + def const_defined?(sym, ignore=nil) + old_const_defined?(sym) + end + + + alias_method :old_const_get, :const_get + + def const_get(sym, ignore=nil) + old_const_get(sym) + end + + alias_method :old_instance_methods, :instance_methods + + def instance_methods(include_super=true) + old_instance_methods(include_super).map(&:to_sym) + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/utils/hashish.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/utils/hashish.rb new file mode 100644 index 000000000..b50b5bf92 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/utils/hashish.rb @@ -0,0 +1,127 @@ +require 'json' + +# Hash-ish! +# +# This class is implemented using composition rather than inheritance so +# that we have control over what operations it exposes to peers. +class Hashish + include Enumerable + + def initialize(hash={}) + @hash = hash.dup + stringify_keys + hashishify_values + end + + def ==(other_obj) + other_obj.class == self.class && + other_obj.hash == self.hash + end + + def [](key) + @hash[normalize(key)] + end + + def []=(key, value) + @hash[normalize(key)] = value + end + + def dup + Hashish.new(JSON.parse(@hash.to_json)) + end + + def each(&block) + @hash.each(&block) + end + + def empty? + @hash.empty? + end + + def has_key?(name) + @hash.has_key? normalize(name) + end + + def hash + @hash + end + + def keys + @hash.keys + end + + def length + @hash.length + end + + def merge(other_hash) + Hashish.new(@hash.merge(other_hash)) + end + + def merge!(other_hash) + @hash.merge! other_hash + self + end + + def to_json(obj) + @hash.to_json(obj) + end + + def to_s + str = "{" + @hash.each do |key, value| + if value.kind_of? String + value = "'#{value}'" + elsif value.nil? + value = "nil" + elsif value.kind_of? Array + value = "[#{value.join(", ")}]" + end + + str += " #{key}: #{value}," + end + + str = str[0...-1] + " }" + str + end + + private + + # Hashishify all the things! + def hashishify_values + @hash.each do |key, value| + if @hash[key].kind_of? Hash + @hash[key] = Hashish.new(value) + elsif @hash[key].kind_of? Array + @hash[key].each_index do |index| + element = @hash[key][index] + if element.kind_of? Hash + @hash[key][index] = Hashish.new(element) + end + end + end + end + end + + + def normalize(key) + if @hash.has_key? key + key + elsif key.is_a? Symbol + key.to_s + else + key + end + end + + + def stringify_keys + keys = @hash.keys + keys.each do |key| + if key.is_a? Symbol + @hash[key.to_s] = @hash.delete(key) + end + end + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/utils/string.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/utils/string.rb new file mode 100644 index 000000000..25d24b66e --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/core/utils/string.rb @@ -0,0 +1,24 @@ +class String + + unless instance_methods.include? 'camelize' + define_method :camelize do + word = self.slice(0,1).capitalize + self.slice(1..-1) + word.gsub(/_([a-zA-Z\d])/) { "#{$1.capitalize}" } + end + end + + unless instance_methods.include? 'constantize' + define_method :constantize do + self.split("::").inject(Object) do |namespace, sym| + namespace.const_get(sym.to_s.camelize, false) + end + end + end + + unless instance_methods.include? 'underscore' + define_method :underscore do + self.gsub(/([a-z\d])([A-Z])/, '\1_\2').downcase + end + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/common/requests/v0/public/base.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/common/requests/v0/public/base.rb new file mode 100644 index 000000000..a80b8c850 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/common/requests/v0/public/base.rb @@ -0,0 +1,125 @@ +module Aviator + + define_request :base do + + meta :provider, :openstack + meta :service, :common + meta :api_version, :v0 + meta :endpoint_type, :public + + def headers + {}.tap do |h| + if self.anonymous? + # do nothing + + elsif session_data.has_key? :service_token + # service_token is the token that one would bootstrap OpenStack + # with during the installation process. This token can be used + # directly and does not require authentication beforehand. + h['X-Auth-Token'] = session_data[:service_token] + + elsif keystone_v2_style_session_data? + h['X-Auth-Token'] = session_data[:body][:access][:token][:id] + + elsif keystone_v3_style_session_data? + h['X-Auth-Token'] = session_data[:headers]['x-subject-token'] + + else + raise "Unknown session data format!" + + end + end + end + + + private + + def base_url + if session_data[:base_url] + session_data[:base_url] + + elsif keystone_v2_style_session_data? && keystone_v2_style_service_info? + extract_base_url_from_keystone_v2_session_data + + elsif keystone_v3_style_session_data? && keystone_v3_style_service_info? + extract_base_url_from_keystone_v3_session_data + + elsif session_data[:auth_service] && session_data[:auth_service][:host_uri] && session_data[:auth_service][:api_version] + version = session_data[:auth_service][:api_version].to_s == "v2" ? "v2.0" : session_data[:auth_service][:api_version] + "#{ session_data[:auth_service][:host_uri] }/#{ version }" + + elsif session_data[:auth_service] && session_data[:auth_service][:host_uri] + session_data[:auth_service][:host_uri] + + else + raise Aviator::Service::MissingServiceEndpointError.new(service.to_s, self.class) + end + end + + + def build_service_type_string + api_versions_without_a_suffix = [ + [:compute, :v2], + [:ec2, :v1], + [:identity, :v2], + [:image, :v1], + [:metering, :v1], + [:s3, :v1], + [:volume, :v1] + ] + + if api_versions_without_a_suffix.include? [service, api_version] + service.to_s + else + "#{ service }#{ api_version }" + end + end + + + def extract_base_url_from_keystone_v2_session_data + service_info = session_data[:body][:access][:serviceCatalog].find{ |s| s[:type] == build_service_type_string } + service_info[:endpoints][0]["#{ endpoint_type }URL".to_sym] + end + + + def extract_base_url_from_keystone_v3_session_data + service_info = session_data[:body][:token][:catalog].select{ |s| s[:type] == build_service_type_string } + endpoints = service_info.find{ |s| s.keys.include? "endpoints" }['endpoints'] + + endpoints.find{ |s| s['interface'] == endpoint_type.to_s }['url'] + end + + + def keystone_v2_style_service_info? + not session_data[:body][:access][:serviceCatalog].find{ |s| s[:type] == build_service_type_string }.nil? + end + + + def keystone_v2_style_session_data? + session_data.has_key?(:body) && session_data[:body].has_key?(:access) + end + + + def keystone_v3_style_service_info? + not session_data[:body][:token][:catalog].find{ |s| s[:type] == build_service_type_string }.nil? + end + + + def keystone_v3_style_session_data? + session_data.has_key?(:headers) && session_data[:headers].has_key?("x-subject-token") + end + + + def params_to_querystring(param_names) + filters = [] + + param_names.each do |param_name| + filters << "#{ param_name }=#{ params[param_name] }" if params[param_name] + end + + filters.empty? ? "" : "?#{ filters.join('&') }" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/common/requests/v2/admin/base.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/common/requests/v2/admin/base.rb new file mode 100644 index 000000000..dd07d2f31 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/common/requests/v2/admin/base.rb @@ -0,0 +1,9 @@ +module Aviator + + define_request :base, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :endpoint_type, :admin + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/common/requests/v2/public/base.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/common/requests/v2/public/base.rb new file mode 100644 index 000000000..863a1ddc8 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/common/requests/v2/public/base.rb @@ -0,0 +1,9 @@ +module Aviator + + define_request :base, :inherit => [:openstack, :common, :v0, :public, :base] do + + meta :api_version, :v2 + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/common/requests/v3/public/base.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/common/requests/v3/public/base.rb new file mode 100644 index 000000000..1340aeab0 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/common/requests/v3/public/base.rb @@ -0,0 +1,9 @@ +module Aviator + + define_request :base, :inherit => [:openstack, :common, :v0, :public, :base] do + + meta :api_version, :v3 + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/confirm_server_resize.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/confirm_server_resize.rb new file mode 100644 index 000000000..0c672da8a --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/confirm_server_resize.rb @@ -0,0 +1,36 @@ +module Aviator + + define_request :confirm_server_resize, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Confirm_Resized_Server-d1e3868.html' + + param :id, :required => true + + + def body + { + :confirmResize => nil + } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/create_network.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/create_network.rb new file mode 100644 index 000000000..f45ef1a78 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/create_network.rb @@ -0,0 +1,56 @@ +module Aviator + + define_request :create_network, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :compute + + link 'documentation', + 'http://api.openstack.org/api-ref-compute.html#ext-os-networks' + + + param :label, :required => true + param :bridge, :required => false + param :bridge_interface, :required => false + param :cidr, :required => false + param :cidr_v6, :required => false + param :dns1, :required => false + param :dns2, :required => false + param :gateway, :required => false + param :gateway_v6, :required => false + param :multi_host, :required => false + param :project_id, :required => false + param :vlan, :required => false + + + def body + p = { + :network => { + :label => params[:label] + } + } + + optional_params.each do |key| + p[:network][key] = params[key] if params[key] + end + + p + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/os-networks" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/get_host_details.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/get_host_details.rb new file mode 100644 index 000000000..daf25a3cd --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/get_host_details.rb @@ -0,0 +1,29 @@ +module Aviator + + define_request :get_host_details, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :compute + + link 'documentation', + 'http://api.openstack.org/api-ref.html#ext-os-hosts' + + param :host_name, :required => true + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/os-hosts/#{ params[:host_name] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/list_hosts.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/list_hosts.rb new file mode 100644 index 000000000..8c47aa835 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/list_hosts.rb @@ -0,0 +1,44 @@ +module Aviator + + define_request :list_hosts, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :compute + + link 'documentation', + 'http://api.openstack.org/api-ref.html#ext-os-hosts' + + link 'documentation bug', + 'https://bugs.launchpad.net/nova/+bug/1224763' + + param :service, :required => false + param :zone, :required => false + + + def headers + super + end + + + def http_method + :get + end + + + def url + url = "#{ base_url }/os-hosts" + + filters = [] + + optional_params.each do |param_name| + filters << "#{ param_name }=#{ params[param_name] }" if params[param_name] + end + + url += "?#{ filters.join('&') }" unless filters.empty? + + url + end + + end + +end + diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/list_hypervisors.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/list_hypervisors.rb new file mode 100644 index 000000000..5f84de5df --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/list_hypervisors.rb @@ -0,0 +1,27 @@ +module Aviator + + define_request :list_hypervisors, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :compute + + link 'documentation', + 'http://api.openstack.org/api-ref-compute-v2-ext.html#ext-os-hypervisors' + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/os-hypervisors" + end + + end + +end + diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/lock_server.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/lock_server.rb new file mode 100644 index 000000000..6db89fee2 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/lock_server.rb @@ -0,0 +1,34 @@ +module Aviator + + define_request :lock_server, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/POST_lock_v2__tenant_id__servers__server_id__action_ext-os-admin-actions.html' + + param :id, :required => true + + + def body + { :lock => nil } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/migrate_server.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/migrate_server.rb new file mode 100644 index 000000000..56259cdff --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/migrate_server.rb @@ -0,0 +1,34 @@ +module Aviator + + define_request :migrate_server, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/POST_migrate_v2__tenant_id__servers__server_id__action_ext-os-admin-actions.html' + + param :id, :required => true + + + def body + { :migrate => nil } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/reset_server.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/reset_server.rb new file mode 100644 index 000000000..ea8af1f0a --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/reset_server.rb @@ -0,0 +1,39 @@ +module Aviator + + define_request :reset_server, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/POST_os-resetState_v2__tenant_id__servers__server_id__action_ext-os-admin-actions.html' + + param :id, :required => true + param :state, :required => true + + + def body + { + 'os-resetState' => { + 'state' => params[:state] + } + } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/resize_server.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/resize_server.rb new file mode 100644 index 000000000..e4b6582a6 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/resize_server.rb @@ -0,0 +1,41 @@ +module Aviator + + define_request :resize_server, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Resize_Server-d1e3707.html' + + param :id, :required => true + param :name, :required => true + param :flavorRef, :required => true, :alias => :flavor_ref + + + def body + { + :resize => { + :name => params[:name], + :flavorRef => params[:flavorRef] + } + } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/revert_server_resize.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/revert_server_resize.rb new file mode 100644 index 000000000..3eb95164b --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/revert_server_resize.rb @@ -0,0 +1,46 @@ +module Aviator + + define_request :revert_server_resize do + + meta :provider, :openstack + meta :service, :compute + meta :api_version, :v2 + meta :endpoint_type, :admin + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Revert_Resized_Server-d1e4024.html' + + param :id, :required => true + + + def body + { + :revertResize => nil + } + end + + + def headers + h = {} + + unless self.anonymous? + h['X-Auth-Token'] = session_data[:body][:access][:token][:id] + end + + h + end + + + def http_method + :post + end + + + def url + service_spec = session_data[:body][:access][:serviceCatalog].find{|s| s[:type] == service.to_s } + "#{ service_spec[:endpoints][0][:adminURL] }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/unlock_server.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/unlock_server.rb new file mode 100644 index 000000000..eede63524 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/admin/unlock_server.rb @@ -0,0 +1,34 @@ +module Aviator + + define_request :unlock_server, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/POST_unlock_v2__tenant_id__servers__server_id__action_ext-os-admin-actions.html' + + param :id, :required => true + + + def body + { :unlock => nil } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/add_floating_ip.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/add_floating_ip.rb new file mode 100644 index 000000000..56ff62457 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/add_floating_ip.rb @@ -0,0 +1,38 @@ +module Aviator + + define_request :add_floating_ip, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/POST_os-floating-ips-v2_AddFloatingIP__v2__tenant_id__servers__server_id__action_ext-os-floating-ips.html#POST_os-floating-ips-v2_AddFloatingIP__v2__tenant_id__servers__server_id__action_ext-os-floating-ips-Request' + + param :server_id, :required => true + param :address, :required => true + + def body + { + :addFloatingIp => { + :address => params[:address] + } + } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:server_id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/allocate_floating_ip.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/allocate_floating_ip.rb new file mode 100644 index 000000000..92b9c5c37 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/allocate_floating_ip.rb @@ -0,0 +1,35 @@ +module Aviator + + define_request :allocate_floating_ip, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/POST_os-floating-ips-v2_AllocateFloatingIP__v2__tenant_id__os-floating-ips_ext-os-floating-ips.html' + + param :pool, :required => false + + def body + { + :pool => params[:pool] + } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/os-floating-ips" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/change_admin_password.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/change_admin_password.rb new file mode 100644 index 000000000..03aced50a --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/change_admin_password.rb @@ -0,0 +1,44 @@ +module Aviator + + define_request :change_admin_password, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Change_Password-d1e3234.html' + + link 'additional spec', + 'https://answers.launchpad.net/nova/+question/228462' + + param :adminPass, :required => true, :alias => :admin_pass + param :id, :required => true + + + def body + p = { + :changePassword => { + :adminPass => params[:adminPass] + } + } + + p + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/create_image.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/create_image.rb new file mode 100644 index 000000000..0a4622370 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/create_image.rb @@ -0,0 +1,46 @@ +module Aviator + + define_request :create_image, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Create_Image-d1e4655.html' + + param :id, :required => true + param :metadata, :required => false + param :name, :required => true + + + def body + p = { + :createImage => { + :name => params[:name] + } + } + + [:metadata].each do |key| + p[:createImage][key] = params[key] if params[key] + end + + p + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/create_keypair.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/create_keypair.rb new file mode 100644 index 000000000..b90485fb4 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/create_keypair.rb @@ -0,0 +1,39 @@ +module Aviator + + define_request :create_keypair, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/POST_os-keypairs-v2_createKeypair__v2__tenant_id__os-keypairs_ext-os-keypairs.html' + + param :name, :required => true + param :public_key, :required => false + + def body + { + :keypair => { + :name => params[:name], + :public_key => params[:public_key], + } + } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/os-keypairs" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/create_server.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/create_server.rb new file mode 100644 index 000000000..682223543 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/create_server.rb @@ -0,0 +1,55 @@ +module Aviator + + define_request :create_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/CreateServers.html' + + param :accessIPv4, :required => false, :alias => :access_ipv4 + param :accessIPv6, :required => false, :alias => :access_ipv6 + param :adminPass, :required => false, :alias => :admin_pass + param :imageRef, :required => true, :alias => :image_ref + param :flavorRef, :required => true, :alias => :flavor_ref + param :key_name, :required => false + param :metadata, :required => false + param :name, :required => true + param :networks, :required => false + param :personality, :required => false + + + def body + p = { + :server => { + :flavorRef => params[:flavorRef], + :imageRef => params[:imageRef], + :name => params[:name] + } + } + + [:adminPass, :metadata, :personality, :networks, :accessIPv4, :accessIPv6, :key_name].each do |key| + p[:server][key] = params[key] if params[key] + end + + p + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/delete_image.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/delete_image.rb new file mode 100644 index 000000000..35ea8cf40 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/delete_image.rb @@ -0,0 +1,29 @@ +module Aviator + + define_request :delete_image, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Delete_Image-d1e4957.html' + + param :id, :required => true + + + def headers + super + end + + + def http_method + :delete + end + + + def url + "#{ base_url }/images/#{ params[:id]}" + end + + end + +end \ No newline at end of file diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/delete_image_metadata_item.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/delete_image_metadata_item.rb new file mode 100644 index 000000000..7b1fc3d70 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/delete_image_metadata_item.rb @@ -0,0 +1,31 @@ +module Aviator + + define_request :delete_image_metadata_item, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Delete_Metadata_Item-d1e5790.html' + + + param :id, :required => true + param :key, :required => true + + + def headers + super + end + + + def http_method + :delete + end + + + def url + "#{ base_url }/images/#{ params[:id] }/metadata/#{ params[:key] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/delete_server.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/delete_server.rb new file mode 100644 index 000000000..a991efb8e --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/delete_server.rb @@ -0,0 +1,29 @@ +module Aviator + + define_request :delete_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Delete_Server-d1e2883.html' + + param :id, :required => true + + + def headers + super + end + + + def http_method + :delete + end + + + def url + "#{ base_url }/servers/#{ params[:id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/delete_server_metadata_item.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/delete_server_metadata_item.rb new file mode 100644 index 000000000..facbbb537 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/delete_server_metadata_item.rb @@ -0,0 +1,31 @@ +module Aviator + + define_request :delete_server_metadata_item, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Delete_Metadata_Item-d1e5790.html' + + + param :id, :required => true + param :key, :required => true + + + def headers + super + end + + + def http_method + :delete + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/metadata/#{ params[:key] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_flavor_details.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_flavor_details.rb new file mode 100644 index 000000000..8faeb900e --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_flavor_details.rb @@ -0,0 +1,29 @@ +module Aviator + + define_request :get_flavor_details, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Get_Flavor_Details-d1e4317.html' + + param :id, :required => true + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/flavors/#{ params[:id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_image_details.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_image_details.rb new file mode 100644 index 000000000..b9fd3cce8 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_image_details.rb @@ -0,0 +1,29 @@ +module Aviator + + define_request :get_image_details, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Get_Image_Details-d1e4848.html' + + param :id, :required => true + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/images/#{ params[:id]}" + end + + end + +end \ No newline at end of file diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_image_metadata_item.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_image_metadata_item.rb new file mode 100644 index 000000000..01476744a --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_image_metadata_item.rb @@ -0,0 +1,31 @@ +module Aviator + + define_request :get_image_metadata_item, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Get_Metadata_Item-d1e5507.html' + + + param :id, :required => true + param :key, :required => true + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/images/#{ params[:id] }/metadata/#{ params[:key] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_network_details.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_network_details.rb new file mode 100644 index 000000000..8d4192bfe --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_network_details.rb @@ -0,0 +1,30 @@ +module Aviator + + define_request :get_network_details, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://api.openstack.org/api-ref-compute.html#ext-os-networks' + + + param :id, :required => true + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/os-networks/#{ params[:id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_server.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_server.rb new file mode 100644 index 000000000..e5c391106 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_server.rb @@ -0,0 +1,28 @@ +module Aviator + + define_request :get_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Get_Server_Details-d1e2623.html' + + param :id, :required => true + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/servers/#{ params[:id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_server_metadata_item.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_server_metadata_item.rb new file mode 100644 index 000000000..580320f24 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/get_server_metadata_item.rb @@ -0,0 +1,31 @@ +module Aviator + + define_request :get_server_metadata_item, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Get_Metadata_Item-d1e5507.html' + + + param :id, :required => true + param :key, :required => true + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/metadata/#{ params[:key] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_addresses.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_addresses.rb new file mode 100644 index 000000000..2c6fe60a4 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_addresses.rb @@ -0,0 +1,36 @@ +module Aviator + + define_request :list_addresses, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/List_Addresses-d1e3014.html' + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/List_Addresses_by_Network-d1e3118.html' + + + param :id, :required => true + param :networkID, :required => false, :alias => :network_id + + + def headers + super + end + + + def http_method + :get + end + + + def url + url = "#{ base_url }/servers/#{ params[:id] }/ips" + url += "/#{ params[:networkID] }" if params[:networkID] + url + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_flavors.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_flavors.rb new file mode 100644 index 000000000..9eba13626 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_flavors.rb @@ -0,0 +1,35 @@ +module Aviator + + define_request :list_flavors, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/List_Flavors-d1e4188.html' + + param :details, :required => false + param :minDisk, :required => false, :alias => :min_disk + param :minRam, :required => false, :alias => :min_ram + param :marker, :required => false + param :limit, :required => false + + + def headers + super + end + + + def http_method + :get + end + + + def url + str = "#{ base_url }/flavors" + str += "/detail" if params[:details] + str += params_to_querystring(optional_params + required_params - [:details]) + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_floating_ips.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_floating_ips.rb new file mode 100644 index 000000000..54f07be3a --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_floating_ips.rb @@ -0,0 +1,26 @@ +module Aviator + + define_request :list_floating_ips, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/GET_os-floating-ips-v2_ListFloatingIPs__v2__tenant_id__os-floating-ips_ext-os-floating-ips.html' + + def headers + super + end + + + def http_method + :get + end + + + def url + str = "#{ base_url }/os-floating-ips" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_image_metadata.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_image_metadata.rb new file mode 100644 index 000000000..7b176891f --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_image_metadata.rb @@ -0,0 +1,30 @@ +module Aviator + + define_request :list_image_metadata, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/List_Metadata-d1e5089.html' + + + param :id, :required => true + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/images/#{ params[:id] }/metadata" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_images.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_images.rb new file mode 100644 index 000000000..b282aec97 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_images.rb @@ -0,0 +1,38 @@ +module Aviator + + define_request :list_images, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/List_Images-d1e4435.html' + + param :details, :required => false + param :server, :required => false + param :name, :required => false + param :status, :required => false + param 'changes-since', :required => false, :alias => :changes_since + param :marker, :required => false + param :limit, :required => false + param :type, :required => false + + + def headers + super + end + + + def http_method + :get + end + + + def url + str = "#{ base_url }/images" + str += "/detail" if params[:details] + str += params_to_querystring(optional_params + required_params - [:details]) + end + + end + +end \ No newline at end of file diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_keypairs.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_keypairs.rb new file mode 100644 index 000000000..f01ce0bd6 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_keypairs.rb @@ -0,0 +1,26 @@ +module Aviator + + define_request :list_keypairs, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/GET_os-keypairs-v2_getKeypair__v2__tenant_id__os-keypairs_ext-os-keypairs.html' + + def headers + super + end + + + def http_method + :get + end + + + def url + str = "#{ base_url }/os-keypairs" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_networks.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_networks.rb new file mode 100644 index 000000000..472ab1bd0 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_networks.rb @@ -0,0 +1,27 @@ +module Aviator + + define_request :list_networks, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://api.openstack.org/api-ref-compute.html#ext-os-networks' + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/os-networks" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_server_metadata.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_server_metadata.rb new file mode 100644 index 000000000..d90936c1b --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_server_metadata.rb @@ -0,0 +1,30 @@ +module Aviator + + define_request :list_server_metadata, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/List_Metadata-d1e5089.html' + + + param :id, :required => true + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/metadata" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_servers.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_servers.rb new file mode 100644 index 000000000..f8126f0c5 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/list_servers.rb @@ -0,0 +1,58 @@ +module Aviator + + define_request :list_servers, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/List_Servers-d1e2078.html' + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/GET_listServers_v2__tenant_id__servers_compute_servers.html' + + link 'github :issue => getting all servers', + 'https://github.com/aviator/aviator/issues/35' + + link 'related mailing list discussion', + 'https://lists.launchpad.net/openstack/msg24695.html' + + param :all_tenants, :required => false + param :details, :required => false + param :flavor, :required => false + param :image, :required => false + param :limit, :required => false + param :marker, :required => false + param :server, :required => false + param :status, :required => false + param 'changes-since', :required => false, :alias => :changes_since + + + def headers + super + end + + + def http_method + :get + end + + + def url + str = "#{ base_url }/servers" + str += "/detail" if params[:details] + + filters = [] + + (optional_params + required_params - [:details]).each do |param_name| + value = param_name == :all_tenants && params[param_name] ? 1 : params[param_name] + filters << "#{ param_name }=#{ value }" if value + end + + str += "?#{ filters.join('&') }" unless filters.empty? + + str + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/pause_server.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/pause_server.rb new file mode 100644 index 000000000..00e5ec663 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/pause_server.rb @@ -0,0 +1,34 @@ +module Aviator + + define_request :pause_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/POST_pause_v2__tenant_id__servers__server_id__action_ext-os-admin-actions.html' + + param :id, :required => true + + + def body + { :pause => nil } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/reboot_server.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/reboot_server.rb new file mode 100644 index 000000000..8aa2296da --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/reboot_server.rb @@ -0,0 +1,41 @@ +module Aviator + + define_request :reboot_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Reboot_Server-d1e3371.html' + + param :id, :required => true + param :type, :required => false + + + def body + p = { + :reboot => { + :type => params[:type] || 'SOFT' + } + } + + p + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/rebuild_server.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/rebuild_server.rb new file mode 100644 index 000000000..8383f571a --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/rebuild_server.rb @@ -0,0 +1,53 @@ +module Aviator + + define_request :rebuild_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Rebuild_Server-d1e3538.html' + + param :accessIPv4, :required => false, :alias => :access_ipv4 + param :accessIPv6, :required => false, :alias => :access_ipv6 + param :adminPass, :required => true, :alias => :admin_pass + param :id, :required => true + param :imageRef, :required => true, :alias => :image_ref + param :metadata, :required => false + param :name, :required => true + param :personality, :required => false + + + def body + p = { + :rebuild => { + :adminPass => params[:adminPass], + :imageRef => params[:imageRef], + :name => params[:name] + } + } + + [:accessIPv4, :accessIPv6, :metadata, :personality].each do |key| + p[:rebuild][key] = params[key] if params[key] + end + + p + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/resume_server.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/resume_server.rb new file mode 100644 index 000000000..f220b366c --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/resume_server.rb @@ -0,0 +1,34 @@ +module Aviator + + define_request :resume_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/POST_resume_v2__tenant_id__servers__server_id__action_ext-os-admin-actions.html' + + param :id, :required => true + + + def body + { :resume => nil } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/root.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/root.rb new file mode 100644 index 000000000..3a3c4dabc --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/root.rb @@ -0,0 +1,24 @@ +module Aviator + + define_request :root, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + def headers + super + end + + + def http_method + :get + end + + + def url + uri = URI(base_url) + "#{ uri.scheme }://#{ uri.host }:#{ uri.port.to_s }/v2/" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/set_image_metadata.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/set_image_metadata.rb new file mode 100644 index 000000000..c17976f9e --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/set_image_metadata.rb @@ -0,0 +1,38 @@ +module Aviator + + define_request :set_image_metadata, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Create_or_Replace_Metadata-d1e5358.html' + + + param :id, :required => true + param :metadata, :required => true + + + def body + { + :metadata => params[:metadata] + } + end + + + def headers + super + end + + + def http_method + :put + end + + + def url + "#{ base_url }/images/#{ params[:id] }/metadata" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/set_server_metadata.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/set_server_metadata.rb new file mode 100644 index 000000000..8631c0397 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/set_server_metadata.rb @@ -0,0 +1,38 @@ +module Aviator + + define_request :set_server_metadata, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Create_or_Replace_Metadata-d1e5358.html' + + + param :id, :required => true + param :metadata, :required => true + + + def body + { + :metadata => params[:metadata] + } + end + + + def headers + super + end + + + def http_method + :put + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/metadata" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/suspend_server.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/suspend_server.rb new file mode 100644 index 000000000..a9bb9a52e --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/suspend_server.rb @@ -0,0 +1,34 @@ +module Aviator + + define_request :suspend_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/POST_suspend_v2__tenant_id__servers__server_id__action_ext-os-admin-actions.html' + + param :id, :required => true + + + def body + { :suspend => nil } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/unpause_server.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/unpause_server.rb new file mode 100644 index 000000000..e11089a62 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/unpause_server.rb @@ -0,0 +1,34 @@ +module Aviator + + define_request :unpause_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/POST_unpause_v2__tenant_id__servers__server_id__action_ext-os-admin-actions.html' + + param :id, :required => true + + + def body + { :unpause => nil } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/action" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/update_image_metadata.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/update_image_metadata.rb new file mode 100644 index 000000000..0ec3694b0 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/update_image_metadata.rb @@ -0,0 +1,38 @@ +module Aviator + + define_request :update_image_metadata, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Update_Metadata-d1e5208.html' + + + param :id, :required => true + param :metadata, :required => true + + + def body + { + :metadata => params[:metadata] + } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/images/#{ params[:id] }/metadata" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/update_server.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/update_server.rb new file mode 100644 index 000000000..453c58329 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/update_server.rb @@ -0,0 +1,45 @@ +module Aviator + + define_request :update_server, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/ServerUpdate.html' + + param :accessIPv4, :required => false, :alias => :access_ipv4 + param :accessIPv6, :required => false, :alias => :access_ipv6 + param :id, :required => true + param :name, :required => false + + + def body + p = { + :server => { } + } + + [:name, :accessIPv4, :accessIPv6].each do |key| + p[:server][key] = params[key] if params[key] + end + + p + end + + + def headers + super + end + + + def http_method + :put + end + + + def url + "#{ base_url }/servers/#{ params[:id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/update_server_metadata.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/update_server_metadata.rb new file mode 100644 index 000000000..e1e5ad17d --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/compute/requests/v2/public/update_server_metadata.rb @@ -0,0 +1,38 @@ +module Aviator + + define_request :update_server_metadata, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :compute + + link 'documentation', + 'http://docs.openstack.org/api/openstack-compute/2/content/Update_Metadata-d1e5208.html' + + + param :id, :required => true + param :metadata, :required => true + + + def body + { + :metadata => params[:metadata] + } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/servers/#{ params[:id] }/metadata" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/add_role_to_user_on_tenant.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/add_role_to_user_on_tenant.rb new file mode 100644 index 000000000..e69b196eb --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/add_role_to_user_on_tenant.rb @@ -0,0 +1,33 @@ +module Aviator + + define_request :add_role_to_user_on_tenant, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :identity + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/PUT_addRolesToUserOnTenant_v2.0_tenants__tenantId__users__userId__roles_OS-KSADM__roleId__.html' + + + param :tenant_id, :required => true + param :user_id, :required => true + param :role_id, :required => true + + + def headers + super + end + + + def http_method + :put + end + + + def url + p = params + "#{ base_url }/tenants/#{ p[:tenant_id] }/users/#{ p[:user_id] }/roles/OS-KSADM/#{ p[:role_id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/create_tenant.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/create_tenant.rb new file mode 100644 index 000000000..6578ae060 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/create_tenant.rb @@ -0,0 +1,43 @@ +module Aviator + + define_request :create_tenant, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :identity + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/' + + + param :name, :required => true + param :description, :required => true + param :enabled, :required => true + + + def body + { + :tenant => { + :name => params[:name], + :description => params[:description], + :enabled => params[:enabled] + } + } + end + + + def headers + super + end + + + def http_method + :post + end + + + def url + "#{ base_url }/tenants" + end + + end + +end \ No newline at end of file diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/create_user.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/create_user.rb new file mode 100644 index 000000000..bf82b64e4 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/create_user.rb @@ -0,0 +1,67 @@ +module Aviator + + define_request :create_user do + + meta :provider, :openstack + meta :service, :identity + meta :api_version, :v2 + meta :endpoint_type, :admin + + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/POST_addUser_v2.0_users_.html' + + link 'documentation bug', + 'https://bugs.launchpad.net/keystone/+bug/1110435' + + link 'documentation bug', + 'https://bugs.launchpad.net/keystone/+bug/1226466' + + + param :name, :required => true + param :password, :required => true + + param :email, :required => false + param :enabled, :required => false + param :tenantId, :required => false, :alias => :tenant_id + param :extras, :required => false + + + def body + p = { + :user => {} + } + + (required_params + optional_params).each do |key| + p[:user][key] = params[key] if params[key] + end + + p + end + + + def headers + h = {} + + unless self.anonymous? + h['X-Auth-Token'] = session_data[:body][:access][:token][:id] + end + + h + end + + + def http_method + :post + end + + + def url + service_spec = session_data[:body][:access][:serviceCatalog].find{|s| s[:type] == 'identity' } + "#{ service_spec[:endpoints][0][:adminURL] }/users" + end + + end + +end + diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/delete_role_from_user_on_tenant.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/delete_role_from_user_on_tenant.rb new file mode 100644 index 000000000..4d24469a7 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/delete_role_from_user_on_tenant.rb @@ -0,0 +1,34 @@ +module Aviator + + define_request :delete_role_from_user_on_tenant, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :identity + + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/DELETE_deleteRoleFromUserOnTenant_v2.0_tenants__tenantId__users__userId__roles_OS-KSADM__roleId__.html' + + + param :tenant_id, :required => true + param :user_id, :required => true + param :role_id, :required => true + + + def headers + super + end + + + def http_method + :delete + end + + + def url + p = params + "#{ base_url }/tenants/#{ p[:tenant_id] }/users/#{ p[:user_id] }/roles/OS-KSADM/#{ p[:role_id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/delete_tenant.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/delete_tenant.rb new file mode 100644 index 000000000..63ad6437f --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/delete_tenant.rb @@ -0,0 +1,29 @@ +module Aviator + + define_request :delete_tenant, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :identity + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/DELETE_deleteTenant_v2.0_tenants__tenantId__.html' + + param :id, :required => true + + + def headers + super + end + + + def http_method + :delete + end + + + def url + "#{ base_url }/tenants/#{ params[:id]}" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/delete_user.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/delete_user.rb new file mode 100644 index 000000000..0bee46951 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/delete_user.rb @@ -0,0 +1,39 @@ +module Aviator + + define_request :delete_user do + + meta :provider, :openstack + meta :service, :identity + meta :api_version, :v2 + meta :endpoint_type, :admin + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/DELETE_deleteUser_v2.0_users__userId__.html' + + param :id, :required => true + + + def headers + h = {} + + unless self.anonymous? + h['X-Auth-Token'] = session_data[:body][:access][:token][:id] + end + + h + end + + + def http_method + :delete + end + + + def url + service_spec = session_data[:body][:access][:serviceCatalog].find{|s| s[:type] == service.to_s } + "#{ service_spec[:endpoints][0][:adminURL] }/users/#{ params[:id]}" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/get_tenant_by_id.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/get_tenant_by_id.rb new file mode 100644 index 000000000..fe2dcc986 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/get_tenant_by_id.rb @@ -0,0 +1,30 @@ +module Aviator + + define_request :get_tenant_by_id, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :identity + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/GET_listUsers_v2.0_users_.html' + + + param :id, :required => true + + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/tenants/#{ params[:id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/get_user.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/get_user.rb new file mode 100644 index 000000000..9a1e1431a --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/get_user.rb @@ -0,0 +1,33 @@ +require 'cgi' + +module Aviator + + define_request :get_user, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :provider, :openstack + meta :service, :identity + meta :api_version, :v2 + meta :endpoint_type, :admin + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/GET_getUserByName_v2.0_users__User_Operations.html' + + param :name, :required => true + + def headers + super + end + + + def http_method + :get + end + + + def url + "#{ base_url }/users?name=#{ CGI::escape(params.name) }" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/list_tenants.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/list_tenants.rb new file mode 100644 index 000000000..48d293062 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/list_tenants.rb @@ -0,0 +1,35 @@ +module Aviator + + define_request :list_tenants, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :identity + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/GET_listTenants_v2.0_tenants_Tenant_Operations.html' + + link 'documentation bug', + 'https://bugs.launchpad.net/keystone/+bug/1218601' + + + param :marker, :required => false + param :limit, :required => false + + + def headers + super + end + + + def http_method + :get + end + + + def url + str = "#{ base_url }/tenants" + str += params_to_querystring(optional_params + required_params) + end + + end + +end \ No newline at end of file diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/list_users.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/list_users.rb new file mode 100644 index 000000000..2debeddc6 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/list_users.rb @@ -0,0 +1,37 @@ +module Aviator + + define_request :list_users do + + meta :provider, :openstack + meta :service, :identity + meta :api_version, :v2 + meta :endpoint_type, :admin + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/GET_listUsers_v2.0_users_.html' + + + def headers + h = {} + + unless self.anonymous? + h['X-Auth-Token'] = session_data[:body][:access][:token][:id] + end + + h + end + + + def http_method + :get + end + + + def url + service_spec = session_data[:body][:access][:serviceCatalog].find{|s| s[:type] == 'identity' } + "#{ service_spec[:endpoints][0][:adminURL] }/users" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/update_tenant.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/update_tenant.rb new file mode 100644 index 000000000..91ae3573d --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/update_tenant.rb @@ -0,0 +1,47 @@ +module Aviator + + define_request :update_tenant, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :identity + + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/POST_updateTenant_v2.0_tenants__tenantId__.html' + + + param :id, :required => true + param :name, :required => false + param :enabled, :required => false + param :description, :required => false + + + def body + p = { + :tenant => {} + } + + [:name, :enabled, :description].each do |key| + p[:tenant][key] = params[key] unless params[key].nil? + end + + p + end + + + def headers + super + end + + + def http_method + :put + end + + + def url + "#{ base_url }/tenants/#{ params[:id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/update_user.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/update_user.rb new file mode 100644 index 000000000..31f8fb213 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/admin/update_user.rb @@ -0,0 +1,62 @@ +module Aviator + + define_request :update_user do + + meta :provider, :openstack + meta :service, :identity + meta :api_version, :v2 + meta :endpoint_type, :admin + + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/POST_updateUser_v2.0_users__userId__.html' + + link 'bug', + 'https://bugs.launchpad.net/keystone/+bug/1226475' + + param :id, :required => true + param :name, :required => false + param :password, :required => false + param :email, :required => false + param :enabled, :required => false + param :tenantId, :required => false, :alias => :tenant_id + param :extras, :required => false + + + def body + p = { + :user => {} + } + + optional_params.each do |key| + p[:user][key] = params[key] if params[key] + end + + p + end + + + def headers + h = {} + + unless self.anonymous? + h['X-Auth-Token'] = session_data[:body][:access][:token][:id] + end + + h + end + + + def http_method + :put + end + + + def url + service_spec = session_data[:body][:access][:serviceCatalog].find { |s| s[:type] == service.to_s } + "#{ service_spec[:endpoints][0][:adminURL] }/users/#{ params[:id] }" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/public/create_token.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/public/create_token.rb new file mode 100644 index 000000000..91731d462 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/public/create_token.rb @@ -0,0 +1,62 @@ +module Aviator + + define_request :create_token, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :anonymous, true + meta :service, :identity + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/POST_authenticate_v2.0_tokens_.html' + + link 'documentation bug', + 'https://bugs.launchpad.net/keystone/+bug/1208607' + + + param :username, :required => false + param :password, :required => false + param :tokenId, :required => false, :alias => :token_id + param :tenantName, :required => false, :alias => :tenant_name + param :tenantId, :required => false, :alias => :tenant_id + + + def body + p = if params[:tokenId] + { + :auth => { + :token => { + :id => params[:tokenId] + } + } + } + else + { + :auth => { + :passwordCredentials => { + :username => params[:username], + :password => params[:password] + } + } + } + end + + p[:auth][:tenantName] = params[:tenantName] if params[:tenantName] + p[:auth][:tenantId] = params[:tenantId] if params[:tenantId] + + p + end + + + def http_method + :post + end + + + def url + url = session_data[:auth_service][:host_uri] + url += '/v2.0' if (URI(url).path =~ /^\/?\w+/).nil? + url += "/tokens" + end + + end + +end \ No newline at end of file diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/public/list_tenants.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/public/list_tenants.rb new file mode 100644 index 000000000..094032ab0 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/public/list_tenants.rb @@ -0,0 +1,35 @@ +module Aviator + + define_request :list_tenants, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :identity + + link 'documentation', + 'http://docs.openstack.org/api/openstack-identity-service/2.0/content/GET_listTenants_v2.0_tokens_tenants_.html' + + link 'documentation bug', + 'https://bugs.launchpad.net/keystone/+bug/1218601' + + + param :marker, :required => false + param :limit, :required => false + + + def url + str = "#{ base_url }/tenants" + str += params_to_querystring(optional_params + required_params) + end + + + def headers + super + end + + + def http_method + :get + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/public/root.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/public/root.rb new file mode 100644 index 000000000..0c6d38358 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v2/public/root.rb @@ -0,0 +1,25 @@ +module Aviator + + define_request :root, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :identity + + + def headers + super + end + + + def http_method + :get + end + + + def url + uri = URI(base_url) + "#{ uri.scheme }://#{ uri.host }:#{ uri.port.to_s }/v2.0/" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v3/public/create_token.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v3/public/create_token.rb new file mode 100644 index 000000000..17d8bb078 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/identity/requests/v3/public/create_token.rb @@ -0,0 +1,125 @@ +module Aviator + # Original work by Stephen Paul Suarez + # https://github.com/musashi-dev/aviator/blob/develop/lib/aviator/openstack/identity/v3/public/create_token.rb + + define_request :create_token, :inherit => [:openstack, :common, :v3, :public, :base] do + + meta :anonymous, true + meta :service, :identity + meta :api_version, :v3 + + link 'documentation', + 'http://api.openstack.org/api-ref-identity-v3.html#Token_Calls' + + param :domainId, :required => false, :alias => :domain_id + param :domainName, :required => false, :alias => :domain_name + param :password, :required => false + param :tenantId, :required => false, :alias => :tenant_id + param :tenantName, :required => false, :alias => :tenant_name + param :tokenId, :required => false, :alias => :token_id + param :userId, :required => false, :alias => :user_id + param :username, :required => false + + + def body + params[:token_id] ? token_auth_body : password_auth_body + end + + + def http_method + :post + end + + + def url + url = session_data[:auth_service][:host_uri] + url += '/v3' if (URI(url).path =~ /^\/?\w+/).nil? + url += "/auth/tokens" + end + + + private + + # Removes nil elements from hash + # Adapted from http://stackoverflow.com/a/14773555/402145 + def compact_hash(hash, opts = {}) + opts[:recurse] ||= true + hash.inject({}) do |new_hash, (k,v)| + if !v.nil? + new_hash[k] = opts[:recurse] && v.kind_of?(Hash) ? compact_hash(v, opts) : v + end + new_hash + end + end + + + def domain_hash + compact_hash({ + :id => params[:domain_id], + :name => params[:domain_name] + }) + end + + + def password_auth_body + p = { + :auth => { + :identity => { + :methods => ['password'], + :password => { + :user => compact_hash({ + :id => params[:user_id], + :name => params[:username], + :password => params[:password] + }) + } + } + } + } + + if params[:domain_name] || params[:domain_id] + p[:auth][:identity][:password][:user][:domain] = domain_hash + end + + if params[:tenant_name] || params[:tenant_id] || params[:domain_name] || params[:domain_id] + p[:auth][:scope] = scope_hash + end + p + end + + + def scope_hash + p = {} + + if params[:tenant_name] || params[:tenant_id] + p[:project] = compact_hash({ + :id => params[:tenant_id], + :name => params[:tenant_name] + }) + p[:project][:domain] = domain_hash if params[:domain_name] || params[:domain_id] + + elsif params[:domain_name] || params[:domain_id] + p[:domain] = domain_hash + end + + p + end + + + def token_auth_body + p = { + :auth => { + :identity => { + :methods => ['token'], + :token => { :id => params[:token_id] } + } + } + } + p[:auth][:scope] = scope_hash if params[:tenant_name] || params[:tenant_id] + p + end + + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/image/requests/v1/public/list_public_images.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/image/requests/v1/public/list_public_images.rb new file mode 100644 index 000000000..2164d73eb --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/image/requests/v1/public/list_public_images.rb @@ -0,0 +1,45 @@ +module Aviator + + define_request :list_public_images, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :image + meta :api_version, :v1 + + link 'documentation', 'http://docs.openstack.org/api/openstack-image-service/1.1/content/requesting-a-list-of-public-vm-images.html' + + param :name, :required => false + param :container_format, :required => false + param :disk_format, :required => false + param :status, :required => false + param :size_min, :required => false + param :size_max, :required => false + param :sort_key, :required => false + param :sort_dir, :required => false + + + def headers + super + end + + def http_method + :get + end + + def url + uri = URI(base_url) + url = "#{ uri.scheme }://#{ uri.host }:#{ uri.port.to_s }/v1/images" + + filters = [] + + optional_params.each do |param_name| + filters << "#{ param_name }=#{ params[param_name] }" if params[param_name] + end + + url += "?#{ filters.join('&') }" unless filters.empty? + + url + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/image/requests/v1/public/root.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/image/requests/v1/public/root.rb new file mode 100644 index 000000000..553f5369e --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/image/requests/v1/public/root.rb @@ -0,0 +1,25 @@ +module Aviator + + define_request :root, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :image + meta :api_version, :v1 + + def headers + super + end + + + def http_method + :get + end + + + def url + uri = URI(base_url) + "#{ uri.scheme }://#{ uri.host }:#{ uri.port.to_s }/v1/" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/metering/requests/v1/admin/list_projects.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/metering/requests/v1/admin/list_projects.rb new file mode 100644 index 000000000..7ec8e667d --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/metering/requests/v1/admin/list_projects.rb @@ -0,0 +1,27 @@ +module Aviator + + define_request :list_projects, :inherit => [:openstack, :common, :v2, :admin, :base] do + + meta :service, :metering + meta :api_version, :v1 + meta :endpoint_type, :admin + + + def headers + super + end + + + def http_method + :get + end + + + def url + uri = URI(base_url) + "#{ uri.scheme }://#{ uri.host }:#{ uri.port.to_s }/v1/projects" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/provider.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/provider.rb new file mode 100644 index 000000000..a4c64e806 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/provider.rb @@ -0,0 +1,187 @@ +module Aviator +module Openstack + + # + # Request Options + # + # The following options may be used in combination with each other when calling + # an OpenStack request class + # + # :api_version => :v2:: + # Forces Aviator to use the request class for the v2 API. For any other + # version, replace :v2 with the desired one. Note that this may throw an + # error if no such request class for the given api version exists. If you + # want to globally specify the API version to use for a specific service, + # declare it in your config file under the correct environment. For example: + # + # production: + # provider: openstack + # ... + # compute_service: + # api_version: v2 + # + # Note that the :api_version option overrides whatever is declared in the + # configuration. + # + # :endpoint_type => (:public|:admin):: + # This allows you to be specific about the endpoint type in cases where two + # request classes under admin and public endpoints of the same service share + # the same name. This is true, for example, for the :list_tenants request of + # the identity service's v2 API. Its public endpoint will return only the tenants + # the user is a member of whereas the admin endpoint will return all tenants + # in the system. + # + # :session_data => Hash:: + # Under normal situations, you wouldn't need to use this as it is automatically populated + # by the Session object provided it is authenticated. The specific use case when you'd + # need to set thsi optin is when you want to use Aviator to seed your OpenStack installation. + # In such a scenario, you would need to use a service token since no usernames and tenants + # would exist yet in the environment. To use a service token with Aviator, you will need to + # write something similar to the following example: + # + # openstack = Aviator::Session.new(:config => { :provider => 'openstack'}) + # + # session_data = {:base_url => 'http://example.com', + # :service_token => 'service-token-created-at-openstack-install-time'} + # + # openstack.request :identity, :create_tenant, :api_version => :v2, :session_data => session_data) do |params| + # params.name = 'Tenant A' + # params.description = 'First Tenant!' + # params.enabled = true + # end + # + # Notice how the above code skips authentication. This is because the service token is + # pre-validated and ready for use with any request. Also note how we're providing a :base_url + # member in our session data. This is necessary since we normally get the service endpoints from + # Keystone when we authenticate. Now since we are not authenticating against Keystone, we don't have + # that catalogue to begin with. Thus the need to hardcode it in the request. + # + module Provider + + class MultipleServiceApisError < StandardError + def initialize(service, entries, request_name) + types = entries.map{|e| e[:type] }.join("\n - ") + msg = < :v2 { ... } + +If you combine the two methods, method #2 will override method #1 + +EOF + super(msg) + end + end + + class << self + + #:nodoc: + def find_request(service, name, session_data, options) + service = service.to_s + endpoint_type = options[:endpoint_type] + endpoint_types = if endpoint_type + [endpoint_type.to_s.camelize] + else + ['Public', 'Admin'] + end + + namespace = Aviator.const_get('Openstack') \ + .const_get(service.camelize) \ + .const_get('Requests') + + if options[:api_version] + m = options[:api_version].to_s.match(/(v\d+)\.?\d*/) + version = m[1].to_s.camelize unless m.nil? + end + + version ||= infer_version(session_data, name, service) + + unless version.nil? + version = version.to_s.camelize + end + + return nil unless version && namespace.const_defined?(version) + + namespace = namespace.const_get(version, name) + + endpoint_types.each do |endpoint_type| + name = name.to_s.camelize + + next unless namespace.const_defined?(endpoint_type) + next unless namespace.const_get(endpoint_type).const_defined?(name) + + return namespace.const_get(endpoint_type).const_get(name) + end + + nil + end + + + def root_dir + Pathname.new(__FILE__).join('..').expand_path + end + + + def request_file_paths(service) + Dir.glob(Pathname.new(__FILE__).join( + '..', + service.to_s, + 'requests', + '**', + '*.rb' + ).expand_path + ) + end + + + private + + def infer_version(session_data, request_name, service) + if session_data.has_key?(:auth_service) && session_data[:auth_service][:api_version] + session_data[:auth_service][:api_version].to_sym + + elsif session_data.has_key?(:auth_service) && session_data[:auth_service][:host_uri] + m = session_data[:auth_service][:host_uri].match(/(v\d+)\.?\d*/) + return m[1].to_sym unless m.nil? + + elsif session_data.has_key? :base_url + m = session_data[:base_url].match(/(v\d+)\.?\d*/) + return m[1].to_sym unless m.nil? + + elsif session_data.has_key?(:body) && session_data[:body].has_key?(:access) + service_specs = session_data[:body][:access][:serviceCatalog].select{|s| s[:type].match("#{ service }(v\d+)?") } + raise MultipleServiceApisError.new(service, service_specs, request_name) unless service_specs.length <= 1 + raise Aviator::Service::MissingServiceEndpointError.new(service.to_s, request_name) unless service_specs.length > 0 + version = service_specs[0][:endpoints][0][:publicURL].match(/(v\d+)\.?\d*/) + version ? version[1].to_sym : :v1 + + elsif session_data.has_key?(:headers) && session_data[:headers].has_key?("x-subject-token") + service_specs = session_data[:body][:token][:catalog].select{|s| s[:type].match("#{ service }(v\d+)?") } + raise MultipleServiceApisError.new(service, service_specs, request_name) unless service_specs.length <= 1 + raise Aviator::Service::MissingServiceEndpointError.new(service.to_s, request_name) unless service_specs.length > 0 + version = service_specs[0][:endpoints][0][:url].match(/(v\d+)\.?\d*/) + version ? version[1].to_sym : :v1 + end + end + + end # class << self + + end # module Provider + +end # module Openstack +end # module Aviator diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/create_volume.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/create_volume.rb new file mode 100644 index 000000000..f40354d99 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/create_volume.rb @@ -0,0 +1,47 @@ +module Aviator + + define_request :create_volume, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :volume + meta :api_version, :v1 + + link 'documentation', 'http://docs.rackspace.com/cbs/api/v1.0/cbs-devguide/content/POST_createVolume_v1__tenant_id__volumes_v1__tenant_id__volumes.html' + + param :display_name, :required => true + param :display_description, :required => true + param :size, :required => true + param :volume_type, :required => false + param :availability_zone, :required => false + param :snapshot_id, :required => false + param :metadata, :required => false + + def body + p = { + :volume => { + :display_name => params[:display_name], + :display_description => params[:display_description], + :size => params[:size] + } + } + + optional_params.each do |key| + p[:volume][key] = params[key] if params[key] + end + + p + end + + def headers + super + end + + def http_method + :post + end + + def url + "#{ base_url }/volumes" + end + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/delete_volume.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/delete_volume.rb new file mode 100644 index 000000000..1397959aa --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/delete_volume.rb @@ -0,0 +1,25 @@ +module Aviator + + define_request :delete_volume, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :volume + meta :api_version, :v1 + + link 'documentation', 'http://docs.rackspace.com/cbs/api/v1.0/cbs-devguide/content/DELETE_deleteVolume_v1__tenant_id__volumes__volume_id__v1__tenant_id__volumes.html' + + param :id, :required => true + + def headers + super + end + + def http_method + :delete + end + + def url + "#{ base_url }/volumes/#{ params[:id] }" + end + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/get_volume.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/get_volume.rb new file mode 100644 index 000000000..991dc4454 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/get_volume.rb @@ -0,0 +1,28 @@ +module Aviator + + define_request :get_volume, :inherit => [:openstack, :common, :v2, :public, :base] do + meta :provider, :openstack + meta :service, :volume + meta :api_version, :v1 + meta :endpoint_type, :public + + link 'documentation', 'http://docs.rackspace.com/cbs/api/v1.0/cbs-devguide/content/GET_getVolume_v1__tenant_id__volumes__volume_id__v1__tenant_id__volumes.html' + + param :id, :required => true + + def headers + super + end + + def http_method + :get + end + + def url + "#{ base_url }/volumes/#{ params[:id] }" + end + + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/list_volume_types.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/list_volume_types.rb new file mode 100644 index 000000000..d2f0b5c8a --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/list_volume_types.rb @@ -0,0 +1,29 @@ +module Aviator + + define_request :list_volume_types, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :provider, :openstack + meta :service, :volume + meta :api_version, :v1 + meta :endpoint_type, :public + + link 'documentation', 'http://docs.rackspace.com/cbs/api/v1.0/cbs-devguide/content/GET_getVolumeTypes_v1__tenant_id__types_v1__tenant_id__types.html' + + param :extra_specs, :required => false + param :name, :required => false + + def headers + super + end + + def http_method + :get + end + + def url + "#{ base_url }/types" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/list_volumes.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/list_volumes.rb new file mode 100644 index 000000000..c88cf7500 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/list_volumes.rb @@ -0,0 +1,48 @@ +module Aviator + + define_request :list_volumes, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :volume + meta :api_version, :v1 + + link 'documentation', 'http://docs.rackspace.com/cbs/api/v1.0/cbs-devguide/content/GET_getVolumesSimple_v1__tenant_id__volumes_v1__tenant_id__volumes.html' + + param :all_tenants, :required => false + param :details, :required => false + param :status, :required => false + param :availability_zone, :required => false + param :bootable, :required => false + param :display_name, :required => false + param :display_description, :required => false + param :volume_type, :required => false + param :snapshot_id, :required => false + param :size, :required => false + + + def headers + super + end + + def http_method + :get + end + + def url + str = "#{ base_url }/volumes" + str += "/detail" if params[:details] + + filters = [] + + (optional_params + required_params - [:details]).each do |param_name| + value = param_name == :all_tenants && params[param_name] ? 1 : params[param_name] + filters << "#{ param_name }=#{ value }" if value + end + + str += "?#{ filters.join('&') }" unless filters.empty? + + str + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/root.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/root.rb new file mode 100644 index 000000000..0e3748c9c --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/root.rb @@ -0,0 +1,26 @@ +module Aviator + + define_request :root, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :volume + meta :api_version, :v1 + + + def headers + super + end + + + def http_method + :get + end + + + def url + uri = URI(base_url) + "#{ uri.scheme }://#{ uri.host }:#{ uri.port.to_s }/v1/" + end + + end + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/update_volume.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/update_volume.rb new file mode 100644 index 000000000..67121c36f --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/openstack/volume/requests/v1/public/update_volume.rb @@ -0,0 +1,43 @@ +module Aviator + + define_request :update_volume, :inherit => [:openstack, :common, :v2, :public, :base] do + + meta :service, :volume + meta :api_version, :v1 + + link 'documentation', 'http://docs.rackspace.com/cbs/api/v1.0/cbs-devguide/content/PUT_renameVolume_v1__tenant_id__volumes__volume_id__v1__tenant_id__volumes.html' + + param :id, :required => true + param :display_name, :required => false + param :display_description, :required => false + + + def body + p = { :volume => {} } + + [:display_name, :display_description].each do |key| + p[:volume][key] = params[key] if params[key] + end + + p + end + + + def headers + super + end + + + def http_method + :put + end + + + def url + "#{ base_url }/volumes/#{ params[:id] }" + end + + end + + +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/aviator/version.rb b/3rdparty/modules/aviator/lib/puppet/feature/aviator/version.rb new file mode 100644 index 000000000..faa1543f9 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/aviator/version.rb @@ -0,0 +1,3 @@ +module Aviator + VERSION = "0.2.1" +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/composite_io.rb b/3rdparty/modules/aviator/lib/puppet/feature/composite_io.rb new file mode 100644 index 000000000..4ba7cf5ff --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/composite_io.rb @@ -0,0 +1,108 @@ +#-- +# Copyright (c) 2007-2012 Nick Sieger. +# See the file README.txt included with the distribution for +# software license details. +#++ + +# Concatenate together multiple IO objects into a single, composite IO object +# for purposes of reading as a single stream. +# +# Usage: +# +# crio = CompositeReadIO.new(StringIO.new('one'), StringIO.new('two'), StringIO.new('three')) +# puts crio.read # => "onetwothree" +# +class CompositeReadIO + # Create a new composite-read IO from the arguments, all of which should + # respond to #read in a manner consistent with IO. + def initialize(*ios) + @ios = ios.flatten + @index = 0 + end + + # Read from IOs in order until `length` bytes have been received. + def read(length = nil, outbuf = nil) + got_result = false + outbuf = outbuf ? outbuf.replace("") : "" + + while io = current_io + if result = io.read(length) + got_result ||= !result.nil? + result.force_encoding("BINARY") if result.respond_to?(:force_encoding) + outbuf << result + length -= result.length if length + break if length == 0 + end + advance_io + end + (!got_result && length) ? nil : outbuf + end + + def rewind + @ios.each { |io| io.rewind } + @index = 0 + end + + private + + def current_io + @ios[@index] + end + + def advance_io + @index += 1 + end +end + +# Convenience methods for dealing with files and IO that are to be uploaded. +class UploadIO + # Create an upload IO suitable for including in the params hash of a + # Net::HTTP::Post::Multipart. + # + # Can take two forms. The first accepts a filename and content type, and + # opens the file for reading (to be closed by finalizer). + # + # The second accepts an already-open IO, but also requires a third argument, + # the filename from which it was opened (particularly useful/recommended if + # uploading directly from a form in a framework, which often save the file to + # an arbitrarily named RackMultipart file in /tmp). + # + # Usage: + # + # UploadIO.new("file.txt", "text/plain") + # UploadIO.new(file_io, "text/plain", "file.txt") + # + attr_reader :content_type, :original_filename, :local_path, :io, :opts + + def initialize(filename_or_io, content_type, filename = nil, opts = {}) + io = filename_or_io + local_path = "" + if io.respond_to? :read + # in Ruby 1.9.2, StringIOs no longer respond to path + # (since they respond to :length, so we don't need their local path, see parts.rb:41) + local_path = filename_or_io.respond_to?(:path) ? filename_or_io.path : "local.path" + else + io = File.open(filename_or_io) + local_path = filename_or_io + end + filename ||= local_path + + @content_type = content_type + @original_filename = File.basename(filename) + @local_path = local_path + @io = io + @opts = opts + end + + def self.convert!(io, content_type, original_filename, local_path) + raise ArgumentError, "convert! has been removed. You must now wrap IOs using:\nUploadIO.new(filename_or_io, content_type, filename=nil)\nPlease update your code." + end + + def method_missing(*args) + @io.send(*args) + end + + def respond_to?(meth, include_all = false) + @io.respond_to?(meth, include_all) || super(meth, include_all) + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday.rb new file mode 100644 index 000000000..4b63ec8e9 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday.rb @@ -0,0 +1,268 @@ +require 'thread' +require 'cgi' +require 'set' +require 'forwardable' + +# Public: This is the main namespace for Faraday. You can either use it to +# create Faraday::Connection objects, or access it directly. +# +# Examples +# +# Faraday.get "http://faraday.com" +# +# conn = Faraday.new "http://faraday.com" +# conn.get '/' +# +module Faraday + VERSION = "0.9.0" + + class << self + # Public: Gets or sets the root path that Faraday is being loaded from. + # This is the root from where the libraries are auto-loaded from. + attr_accessor :root_path + + # Public: Gets or sets the path that the Faraday libs are loaded from. + attr_accessor :lib_path + + # Public: Gets or sets the Symbol key identifying a default Adapter to use + # for the default Faraday::Connection. + attr_reader :default_adapter + + # Public: Sets the default Faraday::Connection for simple scripts that + # access the Faraday constant directly. + # + # Faraday.get "https://faraday.com" + attr_writer :default_connection + + # Public: Sets the default options used when calling Faraday#new. + attr_writer :default_connection_options + + # Public: Initializes a new Faraday::Connection. + # + # url - The optional String base URL to use as a prefix for all + # requests. Can also be the options Hash. + # options - The optional Hash used to configure this Faraday::Connection. + # Any of these values will be set on every request made, unless + # overridden for a specific request. + # :url - String base URL. + # :params - Hash of URI query unencoded key/value pairs. + # :headers - Hash of unencoded HTTP header key/value pairs. + # :request - Hash of request options. + # :ssl - Hash of SSL options. + # :proxy - Hash of Proxy options. + # + # Examples + # + # Faraday.new 'http://faraday.com' + # + # # http://faraday.com?page=1 + # Faraday.new 'http://faraday.com', :params => {:page => 1} + # + # # same + # + # Faraday.new :url => 'http://faraday.com', + # :params => {:page => 1} + # + # Returns a Faraday::Connection. + def new(url = nil, options = nil) + block = block_given? ? Proc.new : nil + options = options ? default_connection_options.merge(options) : default_connection_options.dup + Faraday::Connection.new(url, options, &block) + end + + # Internal: Requires internal Faraday libraries. + # + # *libs - One or more relative String names to Faraday classes. + # + # Returns nothing. + def require_libs(*libs) + libs.each do |lib| + require "#{lib_path}/#{lib}" + end + end + + # Public: Updates default adapter while resetting + # #default_connection. + # + # Returns the new default_adapter. + def default_adapter=(adapter) + @default_connection = nil + @default_adapter = adapter + end + + alias require_lib require_libs + + private + # Internal: Proxies method calls on the Faraday constant to + # #default_connection. + def method_missing(name, *args, &block) + default_connection.send(name, *args, &block) + end + end + + self.root_path = File.expand_path "..", __FILE__ + self.lib_path = File.expand_path "../faraday", __FILE__ + self.default_adapter = :net_http + + # Gets the default connection used for simple scripts. + # + # Returns a Faraday::Connection, configured with the #default_adapter. + def self.default_connection + @default_connection ||= Connection.new + end + + # Gets the default connection options used when calling Faraday#new. + # + # Returns a Faraday::ConnectionOptions. + def self.default_connection_options + @default_connection_options ||= ConnectionOptions.new + end + + if (!defined?(RUBY_ENGINE) || "ruby" == RUBY_ENGINE) && RUBY_VERSION < '1.9' + begin + require 'system_timer' + Timer = SystemTimer + rescue LoadError + warn "Faraday: you may want to install system_timer for reliable timeouts" + end + end + + unless const_defined? :Timer + require 'timeout' + Timer = Timeout + end + + # Public: Adds the ability for other modules to register and lookup + # middleware classes. + module MiddlewareRegistry + # Public: Register middleware class(es) on the current module. + # + # mapping - A Hash mapping Symbol keys to classes. Classes can be expressed + # as fully qualified constant, or a Proc that will be lazily + # called to return the former. + # + # Examples + # + # module Faraday + # class Whatever + # # Middleware looked up by :foo returns Faraday::Whatever::Foo. + # register_middleware :foo => Foo + # + # # Middleware looked up by :bar returns Faraday::Whatever.const_get(:Bar) + # register_middleware :bar => :Bar + # + # # Middleware looked up by :baz requires 'baz' and returns Faraday::Whatever.const_get(:Baz) + # register_middleware :baz => [:Baz, 'baz'] + # end + # end + # + # Returns nothing. + def register_middleware(autoload_path = nil, mapping = nil) + if mapping.nil? + mapping = autoload_path + autoload_path = nil + end + middleware_mutex do + @middleware_autoload_path = autoload_path if autoload_path + (@registered_middleware ||= {}).update(mapping) + end + end + + # Public: Lookup middleware class with a registered Symbol shortcut. + # + # key - The Symbol key for the registered middleware. + # + # Examples + # + # module Faraday + # class Whatever + # register_middleware :foo => Foo + # end + # end + # + # Faraday::Whatever.lookup_middleware(:foo) + # # => Faraday::Whatever::Foo + # + # Returns a middleware Class. + def lookup_middleware(key) + load_middleware(key) || + raise(Faraday::Error.new("#{key.inspect} is not registered on #{self}")) + end + + def middleware_mutex(&block) + @middleware_mutex ||= begin + require 'monitor' + Monitor.new + end + @middleware_mutex.synchronize(&block) + end + + def fetch_middleware(key) + defined?(@registered_middleware) && @registered_middleware[key] + end + + def load_middleware(key) + value = fetch_middleware(key) + case value + when Module + value + when Symbol, String + middleware_mutex do + @registered_middleware[key] = const_get(value) + end + when Proc + middleware_mutex do + @registered_middleware[key] = value.call + end + when Array + middleware_mutex do + const, path = value + if root = @middleware_autoload_path + path = "#{root}/#{path}" + end + require(path) + @registered_middleware[key] = const + end + load_middleware(key) + end + end + end + + def self.const_missing(name) + if name.to_sym == :Builder + warn "Faraday::Builder is now Faraday::RackBuilder." + const_set name, RackBuilder + else + super + end + end + + require_libs "utils", "options", "connection", "rack_builder", "parameters", + "middleware", "adapter", "request", "response", "upload_io", "error" + + if !ENV["FARADAY_NO_AUTOLOAD"] + require_lib 'autoload' + end +end + +# not pulling in active-support JUST for this method. And I love this method. +class Object + # The primary purpose of this method is to "tap into" a method chain, + # in order to perform operations on intermediate results within the chain. + # + # Examples + # + # (1..10).tap { |x| puts "original: #{x.inspect}" }.to_a. + # tap { |x| puts "array: #{x.inspect}" }. + # select { |x| x%2 == 0 }. + # tap { |x| puts "evens: #{x.inspect}" }. + # map { |x| x*x }. + # tap { |x| puts "squares: #{x.inspect}" } + # + # Yields self. + # Returns self. + def tap + yield(self) + self + end unless Object.respond_to?(:tap) +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter.rb new file mode 100644 index 000000000..f018b509a --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter.rb @@ -0,0 +1,46 @@ +module Faraday + # Public: This is a base class for all Faraday adapters. Adapters are + # responsible for fulfilling a Faraday request. + class Adapter < Middleware + CONTENT_LENGTH = 'Content-Length'.freeze + + register_middleware File.expand_path('../adapter', __FILE__), + :test => [:Test, 'test'], + :net_http => [:NetHttp, 'net_http'], + :net_http_persistent => [:NetHttpPersistent, 'net_http_persistent'], + :typhoeus => [:Typhoeus, 'typhoeus'], + :patron => [:Patron, 'patron'], + :em_synchrony => [:EMSynchrony, 'em_synchrony'], + :em_http => [:EMHttp, 'em_http'], + :excon => [:Excon, 'excon'], + :rack => [:Rack, 'rack'], + :httpclient => [:HTTPClient, 'httpclient'] + + # Public: This module marks an Adapter as supporting parallel requests. + module Parallelism + attr_writer :supports_parallel + def supports_parallel?() @supports_parallel end + + def inherited(subclass) + super + subclass.supports_parallel = self.supports_parallel? + end + end + + extend Parallelism + self.supports_parallel = false + + def call(env) + env.clear_body if env.needs_body? + end + + def save_response(env, status, body, headers = nil) + env.status = status + env.body = body + env.response_headers = Utils::Headers.new.tap do |response_headers| + response_headers.update headers unless headers.nil? + yield(response_headers) if block_given? + end + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/em_http.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/em_http.rb new file mode 100644 index 000000000..a248fcfd2 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/em_http.rb @@ -0,0 +1,237 @@ +module Faraday + class Adapter + # EventMachine adapter is useful for either asynchronous requests + # when in EM reactor loop or for making parallel requests in + # synchronous code. + class EMHttp < Faraday::Adapter + module Options + def connection_config(env) + options = {} + configure_proxy(options, env) + configure_timeout(options, env) + configure_socket(options, env) + configure_ssl(options, env) + options + end + + def request_config(env) + options = { + :body => read_body(env), + :head => env[:request_headers], + # :keepalive => true, + # :file => 'path/to/file', # stream data off disk + } + configure_compression(options, env) + options + end + + def read_body(env) + body = env[:body] + body.respond_to?(:read) ? body.read : body + end + + def configure_proxy(options, env) + if proxy = request_options(env)[:proxy] + options[:proxy] = { + :host => proxy[:uri].host, + :port => proxy[:uri].port, + :authorization => [proxy[:user], proxy[:password]] + } + end + end + + def configure_socket(options, env) + if bind = request_options(env)[:bind] + options[:bind] = { + :host => bind[:host], + :port => bind[:port] + } + end + end + + def configure_ssl(options, env) + if env[:url].scheme == 'https' && env[:ssl] + options[:ssl] = { + :cert_chain_file => env[:ssl][:ca_file], + :verify_peer => env[:ssl].fetch(:verify, true) + } + end + end + + def configure_timeout(options, env) + timeout, open_timeout = request_options(env).values_at(:timeout, :open_timeout) + options[:connect_timeout] = options[:inactivity_timeout] = timeout + options[:connect_timeout] = open_timeout if open_timeout + end + + def configure_compression(options, env) + if env[:method] == :get and not options[:head].key? 'accept-encoding' + options[:head]['accept-encoding'] = 'gzip, compressed' + end + end + + def request_options(env) + env[:request] + end + end + + include Options + + dependency 'em-http' + + self.supports_parallel = true + + def self.setup_parallel_manager(options = nil) + Manager.new + end + + def call(env) + super + perform_request env + @app.call env + end + + def perform_request(env) + if parallel?(env) + manager = env[:parallel_manager] + manager.add { + perform_single_request(env). + callback { env[:response].finish(env) } + } + else + unless EventMachine.reactor_running? + error = nil + # start EM, block until request is completed + EventMachine.run do + perform_single_request(env). + callback { EventMachine.stop }. + errback { |client| + error = error_message(client) + EventMachine.stop + } + end + raise_error(error) if error + else + # EM is running: instruct upstream that this is an async request + env[:parallel_manager] = true + perform_single_request(env). + callback { env[:response].finish(env) }. + errback { + # TODO: no way to communicate the error in async mode + raise NotImplementedError + } + end + end + rescue EventMachine::Connectify::CONNECTError => err + if err.message.include?("Proxy Authentication Required") + raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "} + else + raise Error::ConnectionFailed, err + end + rescue => err + if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err + raise Faraday::SSLError, err + else + raise + end + end + + # TODO: reuse the connection to support pipelining + def perform_single_request(env) + req = EventMachine::HttpRequest.new(env[:url], connection_config(env)) + req.setup_request(env[:method], request_config(env)).callback { |client| + save_response(env, client.response_header.status, client.response) do |resp_headers| + client.response_header.each do |name, value| + resp_headers[name.to_sym] = value + end + end + } + end + + def error_message(client) + client.error or "request failed" + end + + def raise_error(msg) + errklass = Faraday::Error::ClientError + if msg == Errno::ETIMEDOUT + errklass = Faraday::Error::TimeoutError + msg = "request timed out" + elsif msg == Errno::ECONNREFUSED + errklass = Faraday::Error::ConnectionFailed + msg = "connection refused" + elsif msg == "connection closed by server" + errklass = Faraday::Error::ConnectionFailed + end + raise errklass, msg + end + + def parallel?(env) + !!env[:parallel_manager] + end + + # The parallel manager is designed to start an EventMachine loop + # and block until all registered requests have been completed. + class Manager + def initialize + reset + end + + def reset + @registered_procs = [] + @num_registered = 0 + @num_succeeded = 0 + @errors = [] + @running = false + end + + def running?() @running end + + def add + if running? + perform_request { yield } + else + @registered_procs << Proc.new + end + @num_registered += 1 + end + + def run + if @num_registered > 0 + @running = true + EventMachine.run do + @registered_procs.each do |proc| + perform_request(&proc) + end + end + if @errors.size > 0 + raise Faraday::Error::ClientError, @errors.first || "connection failed" + end + end + ensure + reset + end + + def perform_request + client = yield + client.callback { @num_succeeded += 1; check_finished } + client.errback { @errors << client.error; check_finished } + end + + def check_finished + if @num_succeeded + @errors.size == @num_registered + EventMachine.stop + end + end + end + end + end +end + +begin + require 'openssl' +rescue LoadError + warn "Warning: no such file to load -- openssl. Make sure it is installed if you want HTTPS support" +else + require 'faraday/adapter/em_http_ssl_patch' +end if Faraday::Adapter::EMHttp.loaded? diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/em_http_ssl_patch.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/em_http_ssl_patch.rb new file mode 100644 index 000000000..8bbfcbce3 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/em_http_ssl_patch.rb @@ -0,0 +1,56 @@ +require 'openssl' +require 'em-http' + +module EmHttpSslPatch + def ssl_verify_peer(cert_string) + cert = nil + begin + cert = OpenSSL::X509::Certificate.new(cert_string) + rescue OpenSSL::X509::CertificateError + return false + end + + @last_seen_cert = cert + + if certificate_store.verify(@last_seen_cert) + begin + certificate_store.add_cert(@last_seen_cert) + rescue OpenSSL::X509::StoreError => e + raise e unless e.message == 'cert already in hash table' + end + true + else + raise OpenSSL::SSL::SSLError.new(%(unable to verify the server certificate for "#{host}")) + end + end + + def ssl_handshake_completed + return true unless verify_peer? + + unless OpenSSL::SSL.verify_certificate_identity(@last_seen_cert, host) + raise OpenSSL::SSL::SSLError.new(%(host "#{host}" does not match the server certificate)) + else + true + end + end + + def verify_peer? + parent.connopts.tls[:verify_peer] + end + + def host + parent.connopts.host + end + + def certificate_store + @certificate_store ||= begin + store = OpenSSL::X509::Store.new + store.set_default_paths + ca_file = parent.connopts.tls[:cert_chain_file] + store.add_file(ca_file) if ca_file + store + end + end +end + +EventMachine::HttpStubConnection.send(:include, EmHttpSslPatch) diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/em_synchrony.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/em_synchrony.rb new file mode 100644 index 000000000..305e702f8 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/em_synchrony.rb @@ -0,0 +1,92 @@ +require 'uri' + +module Faraday + class Adapter + class EMSynchrony < Faraday::Adapter + include EMHttp::Options + + dependency do + require 'em-synchrony/em-http' + require 'em-synchrony/em-multi' + require 'fiber' + end + + self.supports_parallel = true + + def self.setup_parallel_manager(options = {}) + ParallelManager.new + end + + def call(env) + super + request = EventMachine::HttpRequest.new(Utils::URI(env[:url].to_s), connection_config(env)) + + http_method = env[:method].to_s.downcase.to_sym + + # Queue requests for parallel execution. + if env[:parallel_manager] + env[:parallel_manager].add(request, http_method, request_config(env)) do |resp| + save_response(env, resp.response_header.status, resp.response) do |resp_headers| + resp.response_header.each do |name, value| + resp_headers[name.to_sym] = value + end + end + + # Finalize the response object with values from `env`. + env[:response].finish(env) + end + + # Execute single request. + else + client = nil + block = lambda { request.send(http_method, request_config(env)) } + + if !EM.reactor_running? + EM.run do + Fiber.new { + client = block.call + EM.stop + }.resume + end + else + client = block.call + end + + raise client.error if client.error + + save_response(env, client.response_header.status, client.response) do |resp_headers| + client.response_header.each do |name, value| + resp_headers[name.to_sym] = value + end + end + end + + @app.call env + rescue Errno::ECONNREFUSED + raise Error::ConnectionFailed, $! + rescue EventMachine::Connectify::CONNECTError => err + if err.message.include?("Proxy Authentication Required") + raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "} + else + raise Error::ConnectionFailed, err + end + rescue => err + if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err + raise Faraday::SSLError, err + else + raise + end + end + end + end +end + +require 'faraday/adapter/em_synchrony/parallel_manager' + +begin + require 'openssl' +rescue LoadError + warn "Warning: no such file to load -- openssl. Make sure it is installed if you want HTTPS support" +else + require 'faraday/adapter/em_http_ssl_patch' +end if Faraday::Adapter::EMSynchrony.loaded? diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/em_synchrony/parallel_manager.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/em_synchrony/parallel_manager.rb new file mode 100644 index 000000000..12a1bafa4 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/em_synchrony/parallel_manager.rb @@ -0,0 +1,66 @@ +module Faraday + class Adapter + class EMSynchrony < Faraday::Adapter + class ParallelManager + + # Add requests to queue. The `request` argument should be a + # `EM::HttpRequest` object. + def add(request, method, *args, &block) + queue << { + :request => request, + :method => method, + :args => args, + :block => block + } + end + + # Run all requests on queue with `EM::Synchrony::Multi`, wrapping + # it in a reactor and fiber if needed. + def run + result = nil + if !EM.reactor_running? + EM.run { + Fiber.new do + result = perform + EM.stop + end.resume + } + else + result = perform + end + result + end + + + private + + # The request queue. + def queue + @queue ||= [] + end + + # Main `EM::Synchrony::Multi` performer. + def perform + multi = ::EM::Synchrony::Multi.new + + queue.each do |item| + method = "a#{item[:method]}".to_sym + + req = item[:request].send(method, *item[:args]) + req.callback(&item[:block]) + + req_name = "req_#{multi.requests.size}".to_sym + multi.add(req_name, req) + end + + # Clear the queue, so parallel manager objects can be reused. + @queue = [] + + # Block fiber until all requests have returned. + multi.perform + end + + end # ParallelManager + end # EMSynchrony + end # Adapter +end # Faraday diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/excon.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/excon.rb new file mode 100644 index 000000000..db0c7c352 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/excon.rb @@ -0,0 +1,80 @@ +module Faraday + class Adapter + class Excon < Faraday::Adapter + dependency 'excon' + + def initialize(app, connection_options = {}) + @connection_options = connection_options + super(app) + end + + def call(env) + super + + opts = {} + if env[:url].scheme == 'https' && ssl = env[:ssl] + opts[:ssl_verify_peer] = !!ssl.fetch(:verify, true) + opts[:ssl_ca_path] = ssl[:ca_path] if ssl[:ca_path] + opts[:ssl_ca_file] = ssl[:ca_file] if ssl[:ca_file] + opts[:client_cert] = ssl[:client_cert] if ssl[:client_cert] + opts[:client_key] = ssl[:client_key] if ssl[:client_key] + opts[:certificate] = ssl[:certificate] if ssl[:certificate] + opts[:private_key] = ssl[:private_key] if ssl[:private_key] + + # https://github.com/geemus/excon/issues/106 + # https://github.com/jruby/jruby-ossl/issues/19 + opts[:nonblock] = false + end + + if ( req = env[:request] ) + if req[:timeout] + opts[:read_timeout] = req[:timeout] + opts[:connect_timeout] = req[:timeout] + opts[:write_timeout] = req[:timeout] + end + + if req[:open_timeout] + opts[:connect_timeout] = req[:open_timeout] + opts[:write_timeout] = req[:open_timeout] + end + + if req[:proxy] + opts[:proxy] = { + :host => req[:proxy][:uri].host, + :port => req[:proxy][:uri].port, + :scheme => req[:proxy][:uri].scheme, + :user => req[:proxy][:user], + :password => req[:proxy][:password] + } + end + end + + conn = ::Excon.new(env[:url].to_s, opts.merge(@connection_options)) + + resp = conn.request \ + :method => env[:method].to_s.upcase, + :headers => env[:request_headers], + :body => read_body(env) + + save_response(env, resp.status.to_i, resp.body, resp.headers) + + @app.call env + rescue ::Excon::Errors::SocketError => err + if err.message =~ /\btimeout\b/ + raise Error::TimeoutError, err + elsif err.message =~ /\bcertificate\b/ + raise Faraday::SSLError, err + else + raise Error::ConnectionFailed, err + end + rescue ::Excon::Errors::Timeout => err + raise Error::TimeoutError, err + end + + # TODO: support streaming requests + def read_body(env) + env[:body].respond_to?(:read) ? env[:body].read : env[:body] + end + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/httpclient.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/httpclient.rb new file mode 100644 index 000000000..06c663f03 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/httpclient.rb @@ -0,0 +1,106 @@ +module Faraday + class Adapter + class HTTPClient < Faraday::Adapter + dependency 'httpclient' + + def client + @client ||= ::HTTPClient.new + end + + def call(env) + super + + if req = env[:request] + if proxy = req[:proxy] + configure_proxy proxy + end + + if bind = req[:bind] + configure_socket bind + end + + configure_timeouts req + end + + if env[:url].scheme == 'https' && ssl = env[:ssl] + configure_ssl ssl + end + + # TODO Don't stream yet. + # https://github.com/nahi/httpclient/pull/90 + env[:body] = env[:body].read if env[:body].respond_to? :read + + resp = client.request env[:method], env[:url], + :body => env[:body], + :header => env[:request_headers] + + save_response env, resp.status, resp.body, resp.headers + + @app.call env + rescue ::HTTPClient::TimeoutError + raise Faraday::Error::TimeoutError, $! + rescue ::HTTPClient::BadResponseError => err + if err.message.include?('status 407') + raise Faraday::Error::ConnectionFailed, %{407 "Proxy Authentication Required "} + else + raise Faraday::Error::ClientError, $! + end + rescue Errno::ECONNREFUSED, EOFError + raise Faraday::Error::ConnectionFailed, $! + rescue => err + if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err + raise Faraday::SSLError, err + else + raise + end + end + + def configure_socket(bind) + client.socket_local.host = bind[:host] + client.socket_local.port = bind[:port] + end + + def configure_proxy(proxy) + client.proxy = proxy[:uri] + if proxy[:user] && proxy[:password] + client.set_proxy_auth proxy[:user], proxy[:password] + end + end + + def configure_ssl(ssl) + ssl_config = client.ssl_config + + ssl_config.add_trust_ca ssl[:ca_file] if ssl[:ca_file] + ssl_config.add_trust_ca ssl[:ca_path] if ssl[:ca_path] + ssl_config.cert_store = ssl[:cert_store] if ssl[:cert_store] + ssl_config.client_cert = ssl[:client_cert] if ssl[:client_cert] + ssl_config.client_key = ssl[:client_key] if ssl[:client_key] + ssl_config.verify_depth = ssl[:verify_depth] if ssl[:verify_depth] + ssl_config.verify_mode = ssl_verify_mode(ssl) + end + + def configure_timeouts(req) + if req[:timeout] + client.connect_timeout = req[:timeout] + client.receive_timeout = req[:timeout] + client.send_timeout = req[:timeout] + end + + if req[:open_timeout] + client.connect_timeout = req[:open_timeout] + client.send_timeout = req[:open_timeout] + end + end + + def ssl_verify_mode(ssl) + ssl[:verify_mode] || begin + if ssl.fetch(:verify, true) + OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT + else + OpenSSL::SSL::VERIFY_NONE + end + end + end + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/net_http.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/net_http.rb new file mode 100644 index 000000000..449388a7f --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/net_http.rb @@ -0,0 +1,124 @@ +begin + require 'net/https' +rescue LoadError + warn "Warning: no such file to load -- net/https. Make sure openssl is installed if you want ssl support" + require 'net/http' +end +require 'zlib' + +module Faraday + class Adapter + class NetHttp < Faraday::Adapter + NET_HTTP_EXCEPTIONS = [ + EOFError, + Errno::ECONNABORTED, + Errno::ECONNREFUSED, + Errno::ECONNRESET, + Errno::EHOSTUNREACH, + Errno::EINVAL, + Errno::ENETUNREACH, + Net::HTTPBadResponse, + Net::HTTPHeaderSyntaxError, + Net::ProtocolError, + SocketError, + Zlib::GzipFile::Error, + ] + + NET_HTTP_EXCEPTIONS << OpenSSL::SSL::SSLError if defined?(OpenSSL) + + def call(env) + super + http = net_http_connection(env) + configure_ssl(http, env[:ssl]) if env[:url].scheme == 'https' and env[:ssl] + + req = env[:request] + http.read_timeout = http.open_timeout = req[:timeout] if req[:timeout] + http.open_timeout = req[:open_timeout] if req[:open_timeout] + + begin + http_response = perform_request(http, env) + rescue *NET_HTTP_EXCEPTIONS => err + if defined?(OpenSSL) && OpenSSL::SSL::SSLError === err + raise Faraday::SSLError, err + else + raise Error::ConnectionFailed, err + end + end + + save_response(env, http_response.code.to_i, http_response.body || '') do |response_headers| + http_response.each_header do |key, value| + response_headers[key] = value + end + end + + @app.call env + rescue Timeout::Error => err + raise Faraday::Error::TimeoutError, err + end + + def create_request(env) + request = Net::HTTPGenericRequest.new \ + env[:method].to_s.upcase, # request method + !!env[:body], # is there request body + :head != env[:method], # is there response body + env[:url].request_uri, # request uri path + env[:request_headers] # request headers + + if env[:body].respond_to?(:read) + request.body_stream = env[:body] + else + request.body = env[:body] + end + request + end + + def perform_request(http, env) + if :get == env[:method] and !env[:body] + # prefer `get` to `request` because the former handles gzip (ruby 1.9) + http.get env[:url].request_uri, env[:request_headers] + else + http.request create_request(env) + end + end + + def net_http_connection(env) + if proxy = env[:request][:proxy] + Net::HTTP::Proxy(proxy[:uri].host, proxy[:uri].port, proxy[:user], proxy[:password]) + else + Net::HTTP + end.new(env[:url].host, env[:url].port) + end + + def configure_ssl(http, ssl) + http.use_ssl = true + http.verify_mode = ssl_verify_mode(ssl) + http.cert_store = ssl_cert_store(ssl) + + http.cert = ssl[:client_cert] if ssl[:client_cert] + http.key = ssl[:client_key] if ssl[:client_key] + http.ca_file = ssl[:ca_file] if ssl[:ca_file] + http.ca_path = ssl[:ca_path] if ssl[:ca_path] + http.verify_depth = ssl[:verify_depth] if ssl[:verify_depth] + http.ssl_version = ssl[:version] if ssl[:version] + end + + def ssl_cert_store(ssl) + return ssl[:cert_store] if ssl[:cert_store] + # Use the default cert store by default, i.e. system ca certs + cert_store = OpenSSL::X509::Store.new + cert_store.set_default_paths + cert_store + end + + def ssl_verify_mode(ssl) + ssl[:verify_mode] || begin + if ssl.fetch(:verify, true) + OpenSSL::SSL::VERIFY_PEER + else + OpenSSL::SSL::VERIFY_NONE + end + end + end + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/net_http_persistent.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/net_http_persistent.rb new file mode 100644 index 000000000..e0cc9587e --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/net_http_persistent.rb @@ -0,0 +1,47 @@ +# Rely on autoloading instead of explicit require; helps avoid the "already +# initialized constant" warning on Ruby 1.8.7 when NetHttp is refereced below. +# require 'faraday/adapter/net_http' + +module Faraday + class Adapter + # Experimental adapter for net-http-persistent + class NetHttpPersistent < NetHttp + dependency 'net/http/persistent' + + def net_http_connection(env) + if proxy = env[:request][:proxy] + proxy_uri = ::URI::HTTP === proxy[:uri] ? proxy[:uri].dup : ::URI.parse(proxy[:uri].to_s) + proxy_uri.user = proxy_uri.password = nil + # awful patch for net-http-persistent 2.8 not unescaping user/password + (class << proxy_uri; self; end).class_eval do + define_method(:user) { proxy[:user] } + define_method(:password) { proxy[:password] } + end if proxy[:user] + end + Net::HTTP::Persistent.new 'Faraday', proxy_uri + end + + def perform_request(http, env) + http.request env[:url], create_request(env) + rescue Net::HTTP::Persistent::Error => error + if error.message.include? 'Timeout' + raise Faraday::Error::TimeoutError, error + elsif error.message.include? 'connection refused' + raise Faraday::Error::ConnectionFailed, error + else + raise + end + end + + def configure_ssl(http, ssl) + http.verify_mode = ssl_verify_mode(ssl) + http.cert_store = ssl_cert_store(ssl) + + http.certificate = ssl[:client_cert] if ssl[:client_cert] + http.private_key = ssl[:client_key] if ssl[:client_key] + http.ca_file = ssl[:ca_file] if ssl[:ca_file] + http.ssl_version = ssl[:version] if ssl[:version] + end + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/patron.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/patron.rb new file mode 100644 index 000000000..cf2d37fbe --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/patron.rb @@ -0,0 +1,72 @@ +module Faraday + class Adapter + class Patron < Faraday::Adapter + dependency 'patron' + + def initialize(app, &block) + super(app) + @block = block + end + + def call(env) + super + + # TODO: support streaming requests + env[:body] = env[:body].read if env[:body].respond_to? :read + + session = @session ||= create_session + + if req = env[:request] + session.timeout = session.connect_timeout = req[:timeout] if req[:timeout] + session.connect_timeout = req[:open_timeout] if req[:open_timeout] + + if proxy = req[:proxy] + proxy_uri = proxy[:uri].dup + proxy_uri.user = proxy[:user] && Utils.escape(proxy[:user]).gsub('+', '%20') + proxy_uri.password = proxy[:password] && Utils.escape(proxy[:password]).gsub('+', '%20') + session.proxy = proxy_uri.to_s + end + end + + response = begin + data = env[:body] ? env[:body].to_s : nil + session.request(env[:method], env[:url].to_s, env[:request_headers], :data => data) + rescue Errno::ECONNREFUSED, ::Patron::ConnectionFailed + raise Error::ConnectionFailed, $! + end + + save_response(env, response.status, response.body, response.headers) + + @app.call env + rescue ::Patron::TimeoutError => err + if err.message == "Connection time-out" + raise Faraday::Error::ConnectionFailed, err + else + raise Faraday::Error::TimeoutError, err + end + rescue ::Patron::Error => err + if err.message.include?("code 407") + raise Error::ConnectionFailed, %{407 "Proxy Authentication Required "} + else + raise Error::ConnectionFailed, err + end + end + + if loaded? && defined?(::Patron::Request::VALID_ACTIONS) + # HAX: helps but doesn't work completely + # https://github.com/toland/patron/issues/34 + ::Patron::Request::VALID_ACTIONS.tap do |actions| + actions << :patch unless actions.include? :patch + actions << :options unless actions.include? :options + end + end + + def create_session + session = ::Patron::Session.new + session.insecure = true + @block.call(session) if @block + session + end + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/rack.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/rack.rb new file mode 100644 index 000000000..0d2146487 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/rack.rb @@ -0,0 +1,58 @@ +module Faraday + class Adapter + # Sends requests to a Rack app. + # + # Examples + # + # class MyRackApp + # def call(env) + # [200, {'Content-Type' => 'text/html'}, ["hello world"]] + # end + # end + # + # Faraday.new do |conn| + # conn.adapter :rack, MyRackApp.new + # end + class Rack < Faraday::Adapter + dependency 'rack/test' + + # not prefixed with "HTTP_" + SPECIAL_HEADERS = %w[ CONTENT_LENGTH CONTENT_TYPE ] + + def initialize(faraday_app, rack_app) + super(faraday_app) + mock_session = ::Rack::MockSession.new(rack_app) + @session = ::Rack::Test::Session.new(mock_session) + end + + def call(env) + super + rack_env = { + :method => env[:method], + :input => env[:body].respond_to?(:read) ? env[:body].read : env[:body], + 'rack.url_scheme' => env[:url].scheme + } + + env[:request_headers].each do |name, value| + name = name.upcase.tr('-', '_') + name = "HTTP_#{name}" unless SPECIAL_HEADERS.include? name + rack_env[name] = value + end if env[:request_headers] + + timeout = env[:request][:timeout] || env[:request][:open_timeout] + response = if timeout + Timer.timeout(timeout, Faraday::Error::TimeoutError) { execute_request(env, rack_env) } + else + execute_request(env, rack_env) + end + + save_response(env, response.status, response.body, response.headers) + @app.call env + end + + def execute_request(env, rack_env) + @session.request(env[:url].to_s, rack_env) + end + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/test.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/test.rb new file mode 100644 index 000000000..9a345758e --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/test.rb @@ -0,0 +1,162 @@ +module Faraday + class Adapter + # test = Faraday::Connection.new do + # use Faraday::Adapter::Test do |stub| + # stub.get '/nigiri/sake.json' do + # [200, {}, 'hi world'] + # end + # end + # end + # + # resp = test.get '/nigiri/sake.json' + # resp.body # => 'hi world' + # + class Test < Faraday::Adapter + attr_accessor :stubs + + class Stubs + class NotFound < StandardError + end + + def initialize + # {:get => [Stub, Stub]} + @stack, @consumed = {}, {} + yield(self) if block_given? + end + + def empty? + @stack.empty? + end + + def match(request_method, path, headers, body) + return false if !@stack.key?(request_method) + stack = @stack[request_method] + consumed = (@consumed[request_method] ||= []) + + if stub = matches?(stack, path, headers, body) + consumed << stack.delete(stub) + stub + else + matches?(consumed, path, headers, body) + end + end + + def get(path, headers = {}, &block) + new_stub(:get, path, headers, &block) + end + + def head(path, headers = {}, &block) + new_stub(:head, path, headers, &block) + end + + def post(path, body=nil, headers = {}, &block) + new_stub(:post, path, headers, body, &block) + end + + def put(path, body=nil, headers = {}, &block) + new_stub(:put, path, headers, body, &block) + end + + def patch(path, body=nil, headers = {}, &block) + new_stub(:patch, path, headers, body, &block) + end + + def delete(path, headers = {}, &block) + new_stub(:delete, path, headers, &block) + end + + def options(path, headers = {}, &block) + new_stub(:options, path, headers, &block) + end + + # Raises an error if any of the stubbed calls have not been made. + def verify_stubbed_calls + failed_stubs = [] + @stack.each do |method, stubs| + unless stubs.size == 0 + failed_stubs.concat(stubs.map {|stub| + "Expected #{method} #{stub}." + }) + end + end + raise failed_stubs.join(" ") unless failed_stubs.size == 0 + end + + protected + + def new_stub(request_method, path, headers = {}, body=nil, &block) + normalized_path = Faraday::Utils.normalize_path(path) + (@stack[request_method] ||= []) << Stub.new(normalized_path, headers, body, block) + end + + def matches?(stack, path, headers, body) + stack.detect { |stub| stub.matches?(path, headers, body) } + end + end + + class Stub < Struct.new(:path, :params, :headers, :body, :block) + def initialize(full, headers, body, block) + path, query = full.split('?') + params = query ? + Faraday::Utils.parse_nested_query(query) : + {} + super(path, params, headers, body, block) + end + + def matches?(request_uri, request_headers, request_body) + request_path, request_query = request_uri.split('?') + request_params = request_query ? + Faraday::Utils.parse_nested_query(request_query) : + {} + request_path == path && + params_match?(request_params) && + (body.to_s.size.zero? || request_body == body) && + headers_match?(request_headers) + end + + def params_match?(request_params) + params.keys.all? do |key| + request_params[key] == params[key] + end + end + + def headers_match?(request_headers) + headers.keys.all? do |key| + request_headers[key] == headers[key] + end + end + + def to_s + "#{path} #{body}" + end + end + + def initialize(app, stubs=nil, &block) + super(app) + @stubs = stubs || Stubs.new + configure(&block) if block + end + + def configure + yield(stubs) + end + + def call(env) + super + normalized_path = Faraday::Utils.normalize_path(env[:url]) + params_encoder = env.request.params_encoder || Faraday::Utils.default_params_encoder + + if stub = stubs.match(env[:method], normalized_path, env.request_headers, env[:body]) + env[:params] = (query = env[:url].query) ? + params_encoder.decode(query) : + {} + status, headers, body = stub.block.call(env) + save_response(env, status, body, headers) + else + raise Stubs::NotFound, "no stubbed request for #{env[:method]} #{normalized_path} #{env[:body]}" + end + @app.call(env) + end + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/typhoeus.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/typhoeus.rb new file mode 100644 index 000000000..69b6a5139 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/adapter/typhoeus.rb @@ -0,0 +1,123 @@ +module Faraday + class Adapter + class Typhoeus < Faraday::Adapter + self.supports_parallel = true + + def self.setup_parallel_manager(options = {}) + options.empty? ? ::Typhoeus::Hydra.hydra : ::Typhoeus::Hydra.new(options) + end + + dependency 'typhoeus' + + def call(env) + super + perform_request env + @app.call env + end + + def perform_request(env) + read_body env + + hydra = env[:parallel_manager] || self.class.setup_parallel_manager + hydra.queue request(env) + hydra.run unless parallel?(env) + rescue Errno::ECONNREFUSED + raise Error::ConnectionFailed, $! + end + + # TODO: support streaming requests + def read_body(env) + env[:body] = env[:body].read if env[:body].respond_to? :read + end + + def request(env) + method = env[:method] + # For some reason, prevents Typhoeus from using "100-continue". + # We want this because Webrick 1.3.1 can't seem to handle it w/ PUT. + method = method.to_s.upcase if method == :put + + req = ::Typhoeus::Request.new env[:url].to_s, + :method => method, + :body => env[:body], + :headers => env[:request_headers], + :disable_ssl_peer_verification => (env[:ssl] && env[:ssl].disable?) + + configure_ssl req, env + configure_proxy req, env + configure_timeout req, env + configure_socket req, env + + req.on_complete do |resp| + if resp.timed_out? + if parallel?(env) + # TODO: error callback in async mode + else + raise Faraday::Error::TimeoutError, "request timed out" + end + end + + case resp.curl_return_code + when 0 + # everything OK + when 7 + raise Error::ConnectionFailed, resp.curl_error_message + when 60 + raise Faraday::SSLError, resp.curl_error_message + else + raise Error::ClientError, resp.curl_error_message + end + + save_response(env, resp.code, resp.body) do |response_headers| + response_headers.parse resp.headers + end + # in async mode, :response is initialized at this point + env[:response].finish(env) if parallel?(env) + end + + req + end + + def configure_ssl(req, env) + ssl = env[:ssl] + + req.ssl_version = ssl[:version] if ssl[:version] + req.ssl_cert = ssl[:client_cert] if ssl[:client_cert] + req.ssl_key = ssl[:client_key] if ssl[:client_key] + req.ssl_cacert = ssl[:ca_file] if ssl[:ca_file] + req.ssl_capath = ssl[:ca_path] if ssl[:ca_path] + end + + def configure_proxy(req, env) + proxy = request_options(env)[:proxy] + return unless proxy + + req.proxy = "#{proxy[:uri].host}:#{proxy[:uri].port}" + + if proxy[:user] && proxy[:password] + req.proxy_username = proxy[:user] + req.proxy_password = proxy[:password] + end + end + + def configure_timeout(req, env) + env_req = request_options(env) + req.timeout = req.connect_timeout = (env_req[:timeout] * 1000) if env_req[:timeout] + req.connect_timeout = (env_req[:open_timeout] * 1000) if env_req[:open_timeout] + end + + def configure_socket(req, env) + if bind = request_options(env)[:bind] + req.interface = bind[:host] + end + end + + def request_options(env) + env[:request] + end + + def parallel?(env) + !!env[:parallel_manager] + end + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/autoload.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/autoload.rb new file mode 100644 index 000000000..ec413ff84 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/autoload.rb @@ -0,0 +1,85 @@ +module Faraday + # Internal: Adds the ability for other modules to manage autoloadable + # constants. + module AutoloadHelper + # Internal: Registers the constants to be auto loaded. + # + # prefix - The String require prefix. If the path is inside Faraday, then + # it will be prefixed with the root path of this loaded Faraday + # version. + # options - Hash of Symbol => String library names. + # + # Examples. + # + # Faraday.autoload_all 'faraday/foo', + # :Bar => 'bar' + # + # # requires faraday/foo/bar to load Faraday::Bar. + # Faraday::Bar + # + # + # Returns nothing. + def autoload_all(prefix, options) + if prefix =~ /^faraday(\/|$)/i + prefix = File.join(Faraday.root_path, prefix) + end + options.each do |const_name, path| + autoload const_name, File.join(prefix, path) + end + end + + # Internal: Loads each autoloaded constant. If thread safety is a concern, + # wrap this in a Mutex. + # + # Returns nothing. + def load_autoloaded_constants + constants.each do |const| + const_get(const) if autoload?(const) + end + end + + # Internal: Filters the module's contents with those that have been already + # autoloaded. + # + # Returns an Array of Class/Module objects. + def all_loaded_constants + constants.map { |c| const_get(c) }. + select { |a| a.respond_to?(:loaded?) && a.loaded? } + end + end + + class Adapter + extend AutoloadHelper + autoload_all 'faraday/adapter', + :NetHttp => 'net_http', + :NetHttpPersistent => 'net_http_persistent', + :Typhoeus => 'typhoeus', + :EMSynchrony => 'em_synchrony', + :EMHttp => 'em_http', + :Patron => 'patron', + :Excon => 'excon', + :Test => 'test', + :Rack => 'rack', + :HTTPClient => 'httpclient' + end + + class Request + extend AutoloadHelper + autoload_all 'faraday/request', + :UrlEncoded => 'url_encoded', + :Multipart => 'multipart', + :Retry => 'retry', + :Timeout => 'timeout', + :Authorization => 'authorization', + :BasicAuthentication => 'basic_authentication', + :TokenAuthentication => 'token_authentication', + :Instrumentation => 'instrumentation' + end + + class Response + extend AutoloadHelper + autoload_all 'faraday/response', + :RaiseError => 'raise_error', + :Logger => 'logger' + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/connection.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/connection.rb new file mode 100644 index 000000000..1e408e2c2 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/connection.rb @@ -0,0 +1,432 @@ +module Faraday + # Public: Connection objects manage the default properties and the middleware + # stack for fulfilling an HTTP request. + # + # Examples + # + # conn = Faraday::Connection.new 'http://sushi.com' + # + # # GET http://sushi.com/nigiri + # conn.get 'nigiri' + # # => # + # + class Connection + # A Set of allowed HTTP verbs. + METHODS = Set.new [:get, :post, :put, :delete, :head, :patch, :options] + + # Public: Returns a Hash of URI query unencoded key/value pairs. + attr_reader :params + + # Public: Returns a Hash of unencoded HTTP header key/value pairs. + attr_reader :headers + + # Public: Returns a URI with the prefix used for all requests from this + # Connection. This includes a default host name, scheme, port, and path. + attr_reader :url_prefix + + # Public: Returns the Faraday::Builder for this Connection. + attr_reader :builder + + # Public: Returns a Hash of the request options. + attr_reader :options + + # Public: Returns a Hash of the SSL options. + attr_reader :ssl + + # Public: Returns the parallel manager for this Connection. + attr_reader :parallel_manager + + # Public: Sets the default parallel manager for this connection. + attr_writer :default_parallel_manager + + # Public: Initializes a new Faraday::Connection. + # + # url - URI or String base URL to use as a prefix for all + # requests (optional). + # options - Hash or Faraday::ConnectionOptions. + # :url - URI or String base URL (default: "http:/"). + # :params - Hash of URI query unencoded key/value pairs. + # :headers - Hash of unencoded HTTP header key/value pairs. + # :request - Hash of request options. + # :ssl - Hash of SSL options. + # :proxy - URI, String or Hash of HTTP proxy options + # (default: "http_proxy" environment variable). + # :uri - URI or String + # :user - String (optional) + # :password - String (optional) + def initialize(url = nil, options = nil) + if url.is_a?(Hash) + options = ConnectionOptions.from(url) + url = options.url + else + options = ConnectionOptions.from(options) + end + + @parallel_manager = nil + @headers = Utils::Headers.new + @params = Utils::ParamsHash.new + @options = options.request + @ssl = options.ssl + @default_parallel_manager = options.parallel_manager + + @builder = options.builder || begin + # pass an empty block to Builder so it doesn't assume default middleware + options.new_builder(block_given? ? Proc.new { |b| } : nil) + end + + self.url_prefix = url || 'http:/' + + @params.update(options.params) if options.params + @headers.update(options.headers) if options.headers + + @proxy = nil + proxy(options.fetch(:proxy) { + uri = ENV['http_proxy'] + if uri && !uri.empty? + uri = 'http://' + uri if uri !~ /^http/i + uri + end + }) + + yield(self) if block_given? + + @headers[:user_agent] ||= "Faraday v#{VERSION}" + end + + # Public: Sets the Hash of URI query unencoded key/value pairs. + def params=(hash) + @params.replace hash + end + + # Public: Sets the Hash of unencoded HTTP header key/value pairs. + def headers=(hash) + @headers.replace hash + end + + extend Forwardable + + def_delegators :builder, :build, :use, :request, :response, :adapter, :app + + # Public: Makes an HTTP request without a body. + # + # url - The optional String base URL to use as a prefix for all + # requests. Can also be the options Hash. + # params - Hash of URI query unencoded key/value pairs. + # headers - Hash of unencoded HTTP header key/value pairs. + # + # Examples + # + # conn.get '/items', {:page => 1}, :accept => 'application/json' + # conn.head '/items/1' + # + # # ElasticSearch example sending a body with GET. + # conn.get '/twitter/tweet/_search' do |req| + # req.headers[:content_type] = 'application/json' + # req.params[:routing] = 'kimchy' + # req.body = JSON.generate(:query => {...}) + # end + # + # Yields a Faraday::Response for further request customizations. + # Returns a Faraday::Response. + # + # Signature + # + # (url = nil, params = nil, headers = nil) + # + # verb - An HTTP verb: get, head, or delete. + %w[get head delete].each do |method| + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{method}(url = nil, params = nil, headers = nil) + run_request(:#{method}, url, nil, headers) { |request| + request.params.update(params) if params + yield(request) if block_given? + } + end + RUBY + end + + # Public: Makes an HTTP request with a body. + # + # url - The optional String base URL to use as a prefix for all + # requests. Can also be the options Hash. + # body - The String body for the request. + # headers - Hash of unencoded HTTP header key/value pairs. + # + # Examples + # + # conn.post '/items', data, :content_type => 'application/json' + # + # # Simple ElasticSearch indexing sample. + # conn.post '/twitter/tweet' do |req| + # req.headers[:content_type] = 'application/json' + # req.params[:routing] = 'kimchy' + # req.body = JSON.generate(:user => 'kimchy', ...) + # end + # + # Yields a Faraday::Response for further request customizations. + # Returns a Faraday::Response. + # + # Signature + # + # (url = nil, body = nil, headers = nil) + # + # verb - An HTTP verb: post, put, or patch. + %w[post put patch].each do |method| + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{method}(url = nil, body = nil, headers = nil, &block) + run_request(:#{method}, url, body, headers, &block) + end + RUBY + end + + # Public: Sets up the Authorization header with these credentials, encoded + # with base64. + # + # login - The authentication login. + # pass - The authentication password. + # + # Examples + # + # conn.basic_auth 'Aladdin', 'open sesame' + # conn.headers['Authorization'] + # # => "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==" + # + # Returns nothing. + def basic_auth(login, pass) + set_authorization_header(:basic_auth, login, pass) + end + + # Public: Sets up the Authorization header with the given token. + # + # token - The String token. + # options - Optional Hash of extra token options. + # + # Examples + # + # conn.token_auth 'abcdef', :foo => 'bar' + # conn.headers['Authorization'] + # # => "Token token=\"abcdef\", + # foo=\"bar\"" + # + # Returns nothing. + def token_auth(token, options = nil) + set_authorization_header(:token_auth, token, options) + end + + # Public: Sets up a custom Authorization header. + # + # type - The String authorization type. + # token - The String or Hash token. A String value is taken literally, and + # a Hash is encoded into comma separated key/value pairs. + # + # Examples + # + # conn.authorization :Bearer, 'mF_9.B5f-4.1JqM' + # conn.headers['Authorization'] + # # => "Bearer mF_9.B5f-4.1JqM" + # + # conn.authorization :Token, :token => 'abcdef', :foo => 'bar' + # conn.headers['Authorization'] + # # => "Token token=\"abcdef\", + # foo=\"bar\"" + # + # Returns nothing. + def authorization(type, token) + set_authorization_header(:authorization, type, token) + end + + # Internal: Traverse the middleware stack in search of a + # parallel-capable adapter. + # + # Yields in case of not found. + # + # Returns a parallel manager or nil if not found. + def default_parallel_manager + @default_parallel_manager ||= begin + handler = @builder.handlers.detect do |h| + h.klass.respond_to?(:supports_parallel?) and h.klass.supports_parallel? + end + + if handler + handler.klass.setup_parallel_manager + elsif block_given? + yield + end + end + end + + # Public: Determine if this Faraday::Connection can make parallel requests. + # + # Returns true or false. + def in_parallel? + !!@parallel_manager + end + + # Public: Sets up the parallel manager to make a set of requests. + # + # manager - The parallel manager that this Connection's Adapter uses. + # + # Yields a block to execute multiple requests. + # Returns nothing. + def in_parallel(manager = nil) + @parallel_manager = manager || default_parallel_manager { + warn "Warning: `in_parallel` called but no parallel-capable adapter on Faraday stack" + warn caller[2,10].join("\n") + nil + } + yield + @parallel_manager && @parallel_manager.run + ensure + @parallel_manager = nil + end + + # Public: Gets or Sets the Hash proxy options. + def proxy(arg = nil) + return @proxy if arg.nil? + @proxy = ProxyOptions.from(arg) + end + + def_delegators :url_prefix, :scheme, :scheme=, :host, :host=, :port, :port= + def_delegator :url_prefix, :path, :path_prefix + + # Public: Parses the giving url with URI and stores the individual + # components in this connection. These components serve as defaults for + # requests made by this connection. + # + # url - A String or URI. + # + # Examples + # + # conn = Faraday::Connection.new { ... } + # conn.url_prefix = "https://sushi.com/api" + # conn.scheme # => https + # conn.path_prefix # => "/api" + # + # conn.get("nigiri?page=2") # accesses https://sushi.com/api/nigiri + # + # Returns the parsed URI from teh given input.. + def url_prefix=(url, encoder = nil) + uri = @url_prefix = Utils.URI(url) + self.path_prefix = uri.path + + params.merge_query(uri.query, encoder) + uri.query = nil + + with_uri_credentials(uri) do |user, password| + basic_auth user, password + uri.user = uri.password = nil + end + + uri + end + + # Public: Sets the path prefix and ensures that it always has a leading + # slash. + # + # value - A String. + # + # Returns the new String path prefix. + def path_prefix=(value) + url_prefix.path = if value + value = '/' + value unless value[0,1] == '/' + value + end + end + + # Public: Takes a relative url for a request and combines it with the defaults + # set on the connection instance. + # + # conn = Faraday::Connection.new { ... } + # conn.url_prefix = "https://sushi.com/api?token=abc" + # conn.scheme # => https + # conn.path_prefix # => "/api" + # + # conn.build_url("nigiri?page=2") # => https://sushi.com/api/nigiri?token=abc&page=2 + # conn.build_url("nigiri", :page => 2) # => https://sushi.com/api/nigiri?token=abc&page=2 + # + def build_url(url = nil, extra_params = nil) + uri = build_exclusive_url(url) + + query_values = params.dup.merge_query(uri.query, options.params_encoder) + query_values.update extra_params if extra_params + uri.query = query_values.empty? ? nil : query_values.to_query(options.params_encoder) + + uri + end + + # Builds and runs the Faraday::Request. + # + # method - The Symbol HTTP method. + # url - The String or URI to access. + # body - The String body + # headers - Hash of unencoded HTTP header key/value pairs. + # + # Returns a Faraday::Response. + def run_request(method, url, body, headers) + if !METHODS.include?(method) + raise ArgumentError, "unknown http method: #{method}" + end + + request = build_request(method) do |req| + req.url(url) if url + req.headers.update(headers) if headers + req.body = body if body + yield(req) if block_given? + end + + builder.build_response(self, request) + end + + # Creates and configures the request object. + # + # Returns the new Request. + def build_request(method) + Request.create(method) do |req| + req.params = self.params.dup + req.headers = self.headers.dup + req.options = self.options.merge(:proxy => self.proxy) + yield(req) if block_given? + end + end + + # Internal: Build an absolute URL based on url_prefix. + # + # url - A String or URI-like object + # params - A Faraday::Utils::ParamsHash to replace the query values + # of the resulting url (default: nil). + # + # Returns the resulting URI instance. + def build_exclusive_url(url = nil, params = nil) + url = nil if url.respond_to?(:empty?) and url.empty? + base = url_prefix + if url and base.path and base.path !~ /\/$/ + base = base.dup + base.path = base.path + '/' # ensure trailing slash + end + uri = url ? base + url : base + uri.query = params.to_query(options.params_encoder) if params + uri.query = nil if uri.query and uri.query.empty? + uri + end + + # Internal: Creates a duplicate of this Faraday::Connection. + # + # Returns a Faraday::Connection. + def dup + self.class.new(build_exclusive_url, :headers => headers.dup, :params => params.dup, :builder => builder.dup, :ssl => ssl.dup) + end + + # Internal: Yields username and password extracted from a URI if they both exist. + def with_uri_credentials(uri) + if uri.user and uri.password + yield(Utils.unescape(uri.user), Utils.unescape(uri.password)) + end + end + + def set_authorization_header(header_type, *args) + header = Faraday::Request.lookup_middleware(header_type). + header(*args) + headers[Faraday::Request::Authorization::KEY] = header + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/error.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/error.rb new file mode 100644 index 000000000..17712309d --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/error.rb @@ -0,0 +1,53 @@ +module Faraday + class Error < StandardError; end + class MissingDependency < Error; end + + class ClientError < Error + attr_reader :response + + def initialize(ex, response = nil) + @wrapped_exception = nil + @response = response + + if ex.respond_to?(:backtrace) + super(ex.message) + @wrapped_exception = ex + elsif ex.respond_to?(:each_key) + super("the server responded with status #{ex[:status]}") + @response = ex + else + super(ex.to_s) + end + end + + def backtrace + if @wrapped_exception + @wrapped_exception.backtrace + else + super + end + end + + def inspect + %(#<#{self.class}>) + end + end + + class ConnectionFailed < ClientError; end + class ResourceNotFound < ClientError; end + class ParsingError < ClientError; end + + class TimeoutError < ClientError + def initialize(ex = nil) + super(ex || "timeout") + end + end + + class SSLError < ClientError + end + + [:MissingDependency, :ClientError, :ConnectionFailed, :ResourceNotFound, + :ParsingError, :TimeoutError, :SSLError].each do |const| + Error.const_set(const, Faraday.const_get(const)) + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/middleware.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/middleware.rb new file mode 100644 index 000000000..c45d51ade --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/middleware.rb @@ -0,0 +1,37 @@ +module Faraday + class Middleware + extend MiddlewareRegistry + + class << self + attr_accessor :load_error + private :load_error= + end + + self.load_error = nil + + # Executes a block which should try to require and reference dependent libraries + def self.dependency(lib = nil) + lib ? require(lib) : yield + rescue LoadError, NameError => error + self.load_error = error + end + + def self.new(*) + raise "missing dependency for #{self}: #{load_error.message}" unless loaded? + super + end + + def self.loaded? + load_error.nil? + end + + def self.inherited(subclass) + super + subclass.send(:load_error=, self.load_error) + end + + def initialize(app = nil) + @app = app + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/options.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/options.rb new file mode 100644 index 000000000..c1b36f60f --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/options.rb @@ -0,0 +1,350 @@ +module Faraday + # Subclasses Struct with some special helpers for converting from a Hash to + # a Struct. + class Options < Struct + # Public + def self.from(value) + value ? new.update(value) : new + end + + # Public + def each + return to_enum(:each) unless block_given? + members.each do |key| + yield(key.to_sym, send(key)) + end + end + + # Public + def update(obj) + obj.each do |key, value| + if sub_options = self.class.options_for(key) + value = sub_options.from(value) if value + elsif Hash === value + hash = {} + value.each do |hash_key, hash_value| + hash[hash_key] = hash_value + end + value = hash + end + + self.send("#{key}=", value) unless value.nil? + end + self + end + + alias merge! update + + # Public + def delete(key) + value = send(key) + send("#{key}=", nil) + value + end + + # Public + def clear + members.each { |member| delete(member) } + end + + # Public + def merge(value) + dup.update(value) + end + + # Public + def fetch(key, *args) + unless symbolized_key_set.include?(key.to_sym) + key_setter = "#{key}=" + if args.size > 0 + send(key_setter, args.first) + elsif block_given? + send(key_setter, Proc.new.call(key)) + else + raise self.class.fetch_error_class, "key not found: #{key.inspect}" + end + end + send(key) + end + + # Public + def values_at(*keys) + keys.map { |key| send(key) } + end + + # Public + def keys + members.reject { |member| send(member).nil? } + end + + # Public + def empty? + keys.empty? + end + + # Public + def each_key + return to_enum(:each_key) unless block_given? + keys.each do |key| + yield(key) + end + end + + # Public + def key?(key) + keys.include?(key) + end + + alias has_key? key? + + # Public + def each_value + return to_enum(:each_value) unless block_given? + values.each do |value| + yield(value) + end + end + + # Public + def value?(value) + values.include?(value) + end + + alias has_value? value? + + # Public + def to_hash + hash = {} + members.each do |key| + value = send(key) + hash[key.to_sym] = value unless value.nil? + end + hash + end + + # Internal + def inspect + values = [] + members.each do |member| + value = send(member) + values << "#{member}=#{value.inspect}" if value + end + values = values.empty? ? ' (empty)' : (' ' << values.join(", ")) + + %(#<#{self.class}#{values}>) + end + + # Internal + def self.options(mapping) + attribute_options.update(mapping) + end + + # Internal + def self.options_for(key) + attribute_options[key] + end + + # Internal + def self.attribute_options + @attribute_options ||= {} + end + + def self.memoized(key) + memoized_attributes[key.to_sym] = Proc.new + class_eval <<-RUBY, __FILE__, __LINE__ + 1 + def #{key}() self[:#{key}]; end + RUBY + end + + def self.memoized_attributes + @memoized_attributes ||= {} + end + + def [](key) + key = key.to_sym + if method = self.class.memoized_attributes[key] + super(key) || (self[key] = instance_eval(&method)) + else + super + end + end + + def symbolized_key_set + @symbolized_key_set ||= Set.new(keys.map { |k| k.to_sym }) + end + + def self.inherited(subclass) + super + subclass.attribute_options.update(attribute_options) + subclass.memoized_attributes.update(memoized_attributes) + end + + def self.fetch_error_class + @fetch_error_class ||= if Object.const_defined?(:KeyError) + ::KeyError + else + ::IndexError + end + end + end + + class RequestOptions < Options.new(:params_encoder, :proxy, :bind, + :timeout, :open_timeout, :boundary, + :oauth) + + def []=(key, value) + if key && key.to_sym == :proxy + super(key, value ? ProxyOptions.from(value) : nil) + else + super(key, value) + end + end + end + + class SSLOptions < Options.new(:verify, :ca_file, :ca_path, :verify_mode, + :cert_store, :client_cert, :client_key, :certificate, :private_key, :verify_depth, :version) + + def verify? + verify != false + end + + def disable? + !verify? + end + end + + class ProxyOptions < Options.new(:uri, :user, :password) + extend Forwardable + def_delegators :uri, :scheme, :scheme=, :host, :host=, :port, :port=, :path, :path= + + def self.from(value) + case value + when String + value = {:uri => Utils.URI(value)} + when URI + value = {:uri => value} + when Hash, Options + if uri = value.delete(:uri) + value[:uri] = Utils.URI(uri) + end + end + super(value) + end + + memoized(:user) { uri.user && Utils.unescape(uri.user) } + memoized(:password) { uri.password && Utils.unescape(uri.password) } + end + + class ConnectionOptions < Options.new(:request, :proxy, :ssl, :builder, :url, + :parallel_manager, :params, :headers, :builder_class) + + options :request => RequestOptions, :ssl => SSLOptions + + memoized(:request) { self.class.options_for(:request).new } + + memoized(:ssl) { self.class.options_for(:ssl).new } + + memoized(:builder_class) { RackBuilder } + + def new_builder(block) + builder_class.new(&block) + end + end + + class Env < Options.new(:method, :body, :url, :request, :request_headers, + :ssl, :parallel_manager, :params, :response, :response_headers, :status) + + ContentLength = 'Content-Length'.freeze + StatusesWithoutBody = Set.new [204, 304] + SuccessfulStatuses = 200..299 + + # A Set of HTTP verbs that typically send a body. If no body is set for + # these requests, the Content-Length header is set to 0. + MethodsWithBodies = Set.new [:post, :put, :patch, :options] + + options :request => RequestOptions, + :request_headers => Utils::Headers, :response_headers => Utils::Headers + + extend Forwardable + + def_delegators :request, :params_encoder + + # Public + def [](key) + if in_member_set?(key) + super(key) + else + custom_members[key] + end + end + + # Public + def []=(key, value) + if in_member_set?(key) + super(key, value) + else + custom_members[key] = value + end + end + + # Public + def success? + SuccessfulStatuses.include?(status) + end + + # Public + def needs_body? + !body && MethodsWithBodies.include?(method) + end + + # Public + def clear_body + request_headers[ContentLength] = '0' + self.body = '' + end + + # Public + def parse_body? + !StatusesWithoutBody.include?(status) + end + + # Public + def parallel? + !!parallel_manager + end + + def inspect + attrs = [nil] + members.each do |mem| + if value = send(mem) + attrs << "@#{mem}=#{value.inspect}" + end + end + if !custom_members.empty? + attrs << "@custom=#{custom_members.inspect}" + end + %(#<#{self.class}#{attrs.join(" ")}>) + end + + # Internal + def custom_members + @custom_members ||= {} + end + + # Internal + if members.first.is_a?(Symbol) + def in_member_set?(key) + self.class.member_set.include?(key.to_sym) + end + else + def in_member_set?(key) + self.class.member_set.include?(key.to_s) + end + end + + # Internal + def self.member_set + @member_set ||= Set.new(members) + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/parameters.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/parameters.rb new file mode 100644 index 000000000..136c43bca --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/parameters.rb @@ -0,0 +1,193 @@ +module Faraday + module NestedParamsEncoder + ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/ + + def self.escape(s) + return s.to_s.gsub(ESCAPE_RE) { + '%' + $&.unpack('H2' * $&.bytesize).join('%').upcase + }.tr(' ', '+') + end + + def self.unescape(s) + CGI.unescape(s.to_s) + end + + def self.encode(params) + return nil if params == nil + + if !params.is_a?(Array) + if !params.respond_to?(:to_hash) + raise TypeError, + "Can't convert #{params.class} into Hash." + end + params = params.to_hash + params = params.map do |key, value| + key = key.to_s if key.kind_of?(Symbol) + [key, value] + end + # Useful default for OAuth and caching. + # Only to be used for non-Array inputs. Arrays should preserve order. + params.sort! + end + + # Helper lambda + to_query = lambda do |parent, value| + if value.is_a?(Hash) + value = value.map do |key, val| + key = escape(key) + [key, val] + end + value.sort! + buffer = "" + value.each do |key, val| + new_parent = "#{parent}%5B#{key}%5D" + buffer << "#{to_query.call(new_parent, val)}&" + end + return buffer.chop + elsif value.is_a?(Array) + buffer = "" + value.each_with_index do |val, i| + new_parent = "#{parent}%5B%5D" + buffer << "#{to_query.call(new_parent, val)}&" + end + return buffer.chop + else + encoded_value = escape(value) + return "#{parent}=#{encoded_value}" + end + end + + # The params have form [['key1', 'value1'], ['key2', 'value2']]. + buffer = '' + params.each do |parent, value| + encoded_parent = escape(parent) + buffer << "#{to_query.call(encoded_parent, value)}&" + end + return buffer.chop + end + + def self.decode(query) + return nil if query == nil + # Recursive helper lambda + dehash = lambda do |hash| + hash.each do |(key, value)| + if value.kind_of?(Hash) + hash[key] = dehash.call(value) + end + end + # Numeric keys implies an array + if hash != {} && hash.keys.all? { |key| key =~ /^\d+$/ } + hash.sort.inject([]) do |accu, (_, value)| + accu << value; accu + end + else + hash + end + end + + empty_accumulator = {} + return ((query.split('&').map do |pair| + pair.split('=', 2) if pair && !pair.empty? + end).compact.inject(empty_accumulator.dup) do |accu, (key, value)| + key = unescape(key) + if value.kind_of?(String) + value = unescape(value.gsub(/\+/, ' ')) + end + + array_notation = !!(key =~ /\[\]$/) + subkeys = key.split(/[\[\]]+/) + current_hash = accu + for i in 0...(subkeys.size - 1) + subkey = subkeys[i] + current_hash[subkey] = {} unless current_hash[subkey] + current_hash = current_hash[subkey] + end + if array_notation + current_hash[subkeys.last] = [] unless current_hash[subkeys.last] + current_hash[subkeys.last] << value + else + current_hash[subkeys.last] = value + end + accu + end).inject(empty_accumulator.dup) do |accu, (key, value)| + accu[key] = value.kind_of?(Hash) ? dehash.call(value) : value + accu + end + end + end + + module FlatParamsEncoder + ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/ + + def self.escape(s) + return s.to_s.gsub(ESCAPE_RE) { + '%' + $&.unpack('H2' * $&.bytesize).join('%').upcase + }.tr(' ', '+') + end + + def self.unescape(s) + CGI.unescape(s.to_s) + end + + def self.encode(params) + return nil if params == nil + + if !params.is_a?(Array) + if !params.respond_to?(:to_hash) + raise TypeError, + "Can't convert #{params.class} into Hash." + end + params = params.to_hash + params = params.map do |key, value| + key = key.to_s if key.kind_of?(Symbol) + [key, value] + end + # Useful default for OAuth and caching. + # Only to be used for non-Array inputs. Arrays should preserve order. + params.sort! + end + + # The params have form [['key1', 'value1'], ['key2', 'value2']]. + buffer = '' + params.each do |key, value| + encoded_key = escape(key) + value = value.to_s if value == true || value == false + if value == nil + buffer << "#{encoded_key}&" + elsif value.kind_of?(Array) + value.each do |sub_value| + encoded_value = escape(sub_value) + buffer << "#{encoded_key}=#{encoded_value}&" + end + else + encoded_value = escape(value) + buffer << "#{encoded_key}=#{encoded_value}&" + end + end + return buffer.chop + end + + def self.decode(query) + empty_accumulator = {} + return nil if query == nil + split_query = (query.split('&').map do |pair| + pair.split('=', 2) if pair && !pair.empty? + end).compact + return split_query.inject(empty_accumulator.dup) do |accu, pair| + pair[0] = unescape(pair[0]) + pair[1] = true if pair[1].nil? + if pair[1].respond_to?(:to_str) + pair[1] = unescape(pair[1].to_str.gsub(/\+/, " ")) + end + if accu[pair[0]].kind_of?(Array) + accu[pair[0]] << pair[1] + elsif accu[pair[0]] + accu[pair[0]] = [accu[pair[0]], pair[1]] + else + accu[pair[0]] = pair[1] + end + accu + end + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/rack_builder.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/rack_builder.rb new file mode 100644 index 000000000..204ce41d1 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/rack_builder.rb @@ -0,0 +1,212 @@ +module Faraday + # A Builder that processes requests into responses by passing through an inner + # middleware stack (heavily inspired by Rack). + # + # Faraday::Connection.new(:url => 'http://sushi.com') do |builder| + # builder.request :url_encoded # Faraday::Request::UrlEncoded + # builder.adapter :net_http # Faraday::Adapter::NetHttp + # end + class RackBuilder + attr_accessor :handlers + + # Error raised when trying to modify the stack after calling `lock!` + class StackLocked < RuntimeError; end + + # borrowed from ActiveSupport::Dependencies::Reference & + # ActionDispatch::MiddlewareStack::Middleware + class Handler + @@constants_mutex = Mutex.new + @@constants = Hash.new { |h, k| + value = k.respond_to?(:constantize) ? k.constantize : Object.const_get(k) + @@constants_mutex.synchronize { h[k] = value } + } + + attr_reader :name + + def initialize(klass, *args, &block) + @name = klass.to_s + if klass.respond_to?(:name) + @@constants_mutex.synchronize { @@constants[@name] = klass } + end + @args, @block = args, block + end + + def klass() @@constants[@name] end + def inspect() @name end + + def ==(other) + if other.is_a? Handler + self.name == other.name + elsif other.respond_to? :name + klass == other + else + @name == other.to_s + end + end + + def build(app) + klass.new(app, *@args, &@block) + end + end + + def initialize(handlers = []) + @handlers = handlers + if block_given? + build(&Proc.new) + elsif @handlers.empty? + # default stack, if nothing else is configured + self.request :url_encoded + self.adapter Faraday.default_adapter + end + end + + def build(options = {}) + raise_if_locked + @handlers.clear unless options[:keep] + yield(self) if block_given? + end + + def [](idx) + @handlers[idx] + end + + # Locks the middleware stack to ensure no further modifications are possible. + def lock! + @handlers.freeze + end + + def locked? + @handlers.frozen? + end + + def use(klass, *args, &block) + if klass.is_a? Symbol + use_symbol(Faraday::Middleware, klass, *args, &block) + else + raise_if_locked + @handlers << self.class::Handler.new(klass, *args, &block) + end + end + + def request(key, *args, &block) + use_symbol(Faraday::Request, key, *args, &block) + end + + def response(key, *args, &block) + use_symbol(Faraday::Response, key, *args, &block) + end + + def adapter(key, *args, &block) + use_symbol(Faraday::Adapter, key, *args, &block) + end + + ## methods to push onto the various positions in the stack: + + def insert(index, *args, &block) + raise_if_locked + index = assert_index(index) + handler = self.class::Handler.new(*args, &block) + @handlers.insert(index, handler) + end + + alias_method :insert_before, :insert + + def insert_after(index, *args, &block) + index = assert_index(index) + insert(index + 1, *args, &block) + end + + def swap(index, *args, &block) + raise_if_locked + index = assert_index(index) + @handlers.delete_at(index) + insert(index, *args, &block) + end + + def delete(handler) + raise_if_locked + @handlers.delete(handler) + end + + # Processes a Request into a Response by passing it through this Builder's + # middleware stack. + # + # connection - Faraday::Connection + # request - Faraday::Request + # + # Returns a Faraday::Response. + def build_response(connection, request) + app.call(build_env(connection, request)) + end + + # The "rack app" wrapped in middleware. All requests are sent here. + # + # The builder is responsible for creating the app object. After this, + # the builder gets locked to ensure no further modifications are made + # to the middleware stack. + # + # Returns an object that responds to `call` and returns a Response. + def app + @app ||= begin + lock! + to_app(lambda { |env| + response = Response.new + response.finish(env) unless env.parallel? + env.response = response + }) + end + end + + def to_app(inner_app) + # last added handler is the deepest and thus closest to the inner app + @handlers.reverse.inject(inner_app) { |app, handler| handler.build(app) } + end + + def ==(other) + other.is_a?(self.class) && @handlers == other.handlers + end + + def dup + self.class.new(@handlers.dup) + end + + # ENV Keys + # :method - a symbolized request method (:get, :post) + # :body - the request body that will eventually be converted to a string. + # :url - URI instance for the current request. + # :status - HTTP response status code + # :request_headers - hash of HTTP Headers to be sent to the server + # :response_headers - Hash of HTTP headers from the server + # :parallel_manager - sent if the connection is in parallel mode + # :request - Hash of options for configuring the request. + # :timeout - open/read timeout Integer in seconds + # :open_timeout - read timeout Integer in seconds + # :proxy - Hash of proxy options + # :uri - Proxy Server URI + # :user - Proxy server username + # :password - Proxy server password + # :ssl - Hash of options for configuring SSL requests. + def build_env(connection, request) + Env.new(request.method, request.body, + connection.build_exclusive_url(request.path, request.params), + request.options, request.headers, connection.ssl, + connection.parallel_manager) + end + + private + + def raise_if_locked + raise StackLocked, "can't modify middleware stack after making a request" if locked? + end + + def use_symbol(mod, key, *args, &block) + use(mod.lookup_middleware(key), *args, &block) + end + + def assert_index(index) + idx = index.is_a?(Integer) ? index : @handlers.index(index) + raise "No such handler: #{index.inspect}" unless idx + idx + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/request.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/request.rb new file mode 100644 index 000000000..481077f14 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/request.rb @@ -0,0 +1,92 @@ +module Faraday + # Used to setup urls, params, headers, and the request body in a sane manner. + # + # @connection.post do |req| + # req.url 'http://localhost', 'a' => '1' # 'http://localhost?a=1' + # req.headers['b'] = '2' # Header + # req.params['c'] = '3' # GET Param + # req['b'] = '2' # also Header + # req.body = 'abc' + # end + # + class Request < Struct.new(:method, :path, :params, :headers, :body, :options) + extend MiddlewareRegistry + + register_middleware File.expand_path('../request', __FILE__), + :url_encoded => [:UrlEncoded, 'url_encoded'], + :multipart => [:Multipart, 'multipart'], + :retry => [:Retry, 'retry'], + :authorization => [:Authorization, 'authorization'], + :basic_auth => [:BasicAuthentication, 'basic_authentication'], + :token_auth => [:TokenAuthentication, 'token_authentication'], + :instrumentation => [:Instrumentation, 'instrumentation'] + + def self.create(request_method) + new(request_method).tap do |request| + yield(request) if block_given? + end + end + + # Public: Replace params, preserving the existing hash type + def params=(hash) + if params + params.replace hash + else + super + end + end + + # Public: Replace request headers, preserving the existing hash type + def headers=(hash) + if headers + headers.replace hash + else + super + end + end + + def url(path, params = nil) + if path.respond_to? :query + if query = path.query + path = path.dup + path.query = nil + end + else + path, query = path.split('?', 2) + end + self.path = path + self.params.merge_query query, options.params_encoder + self.params.update(params) if params + end + + def [](key) + headers[key] + end + + def []=(key, value) + headers[key] = value + end + + # ENV Keys + # :method - a symbolized request method (:get, :post) + # :body - the request body that will eventually be converted to a string. + # :url - URI instance for the current request. + # :status - HTTP response status code + # :request_headers - hash of HTTP Headers to be sent to the server + # :response_headers - Hash of HTTP headers from the server + # :parallel_manager - sent if the connection is in parallel mode + # :request - Hash of options for configuring the request. + # :timeout - open/read timeout Integer in seconds + # :open_timeout - read timeout Integer in seconds + # :proxy - Hash of proxy options + # :uri - Proxy Server URI + # :user - Proxy server username + # :password - Proxy server password + # :ssl - Hash of options for configuring SSL requests. + def to_env(connection) + Env.new(method, body, connection.build_exclusive_url(path, params), + options, headers, connection.ssl, connection.parallel_manager) + end + end +end + diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/authorization.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/authorization.rb new file mode 100644 index 000000000..43b452880 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/authorization.rb @@ -0,0 +1,42 @@ +module Faraday + class Request::Authorization < Faraday::Middleware + KEY = "Authorization".freeze unless defined? KEY + + # Public + def self.header(type, token) + case token + when String, Symbol + "#{type} #{token}" + when Hash + build_hash(type.to_s, token) + else + raise ArgumentError, "Can't build an Authorization #{type} header from #{token.inspect}" + end + end + + # Internal + def self.build_hash(type, hash) + offset = KEY.size + type.size + 3 + comma = ",\n#{' ' * offset}" + values = [] + hash.each do |key, value| + values << "#{key}=#{value.to_s.inspect}" + end + "#{type} #{values * comma}" + end + + def initialize(app, type, token) + @header_value = self.class.header(type, token) + super(app) + end + + # Public + def call(env) + unless env.request_headers[KEY] + env.request_headers[KEY] = @header_value + end + @app.call(env) + end + end +end + diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/basic_authentication.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/basic_authentication.rb new file mode 100644 index 000000000..54c8dee97 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/basic_authentication.rb @@ -0,0 +1,13 @@ +require 'base64' + +module Faraday + class Request::BasicAuthentication < Request.load_middleware(:authorization) + # Public + def self.header(login, pass) + value = Base64.encode64([login, pass].join(':')) + value.gsub!("\n", '') + super(:Basic, value) + end + end +end + diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/instrumentation.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/instrumentation.rb new file mode 100644 index 000000000..42af8bc44 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/instrumentation.rb @@ -0,0 +1,36 @@ +module Faraday + class Request::Instrumentation < Faraday::Middleware + class Options < Faraday::Options.new(:name, :instrumenter) + def name + self[:name] ||= 'request.faraday' + end + + def instrumenter + self[:instrumenter] ||= ActiveSupport::Notifications + end + end + + # Public: Instruments requests using Active Support. + # + # Measures time spent only for synchronous requests. + # + # Examples + # + # ActiveSupport::Notifications.subscribe('request.faraday') do |name, starts, ends, _, env| + # url = env[:url] + # http_method = env[:method].to_s.upcase + # duration = ends - starts + # $stderr.puts '[%s] %s %s (%.3f s)' % [url.host, http_method, url.request_uri, duration] + # end + def initialize(app, options = nil) + super(app) + @name, @instrumenter = Options.from(options).values_at(:name, :instrumenter) + end + + def call(env) + @instrumenter.instrument(@name, env) do + @app.call(env) + end + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/multipart.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/multipart.rb new file mode 100644 index 000000000..38b452af7 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/multipart.rb @@ -0,0 +1,63 @@ +require File.expand_path("../url_encoded", __FILE__) + +module Faraday + class Request::Multipart < Request::UrlEncoded + self.mime_type = 'multipart/form-data'.freeze + DEFAULT_BOUNDARY = "-----------RubyMultipartPost".freeze unless defined? DEFAULT_BOUNDARY + + def call(env) + match_content_type(env) do |params| + env.request.boundary ||= DEFAULT_BOUNDARY + env.request_headers[CONTENT_TYPE] += "; boundary=#{env.request.boundary}" + env.body = create_multipart(env, params) + end + @app.call env + end + + def process_request?(env) + type = request_type(env) + env.body.respond_to?(:each_key) and !env.body.empty? and ( + (type.empty? and has_multipart?(env.body)) or + type == self.class.mime_type + ) + end + + def has_multipart?(obj) + # string is an enum in 1.8, returning list of itself + if obj.respond_to?(:each) && !obj.is_a?(String) + (obj.respond_to?(:values) ? obj.values : obj).each do |val| + return true if (val.respond_to?(:content_type) || has_multipart?(val)) + end + end + false + end + + def create_multipart(env, params) + boundary = env.request.boundary + parts = process_params(params) do |key, value| + Faraday::Parts::Part.new(boundary, key, value) + end + parts << Faraday::Parts::EpiloguePart.new(boundary) + + body = Faraday::CompositeReadIO.new(parts) + env.request_headers[Faraday::Env::ContentLength] = body.length.to_s + return body + end + + def process_params(params, prefix = nil, pieces = nil, &block) + params.inject(pieces || []) do |all, (key, value)| + key = "#{prefix}[#{key}]" if prefix + + case value + when Array + values = value.inject([]) { |a,v| a << [nil, v] } + process_params(values, key, all, &block) + when Hash + process_params(value, key, all, &block) + else + all << block.call(key, value) + end + end + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/retry.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/retry.rb new file mode 100644 index 000000000..08bc83766 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/retry.rb @@ -0,0 +1,140 @@ +module Faraday + # Catches exceptions and retries each request a limited number of times. + # + # By default, it retries 2 times and handles only timeout exceptions. It can + # be configured with an arbitrary number of retries, a list of exceptions to + # handle, a retry interval, a percentage of randomness to add to the retry + # interval, and a backoff factor. + # + # Examples + # + # Faraday.new do |conn| + # conn.request :retry, max: 2, interval: 0.05, + # interval_randomness: 0.5, backoff_factor: 2 + # exceptions: [CustomException, 'Timeout::Error'] + # conn.adapter ... + # end + # + # This example will result in a first interval that is random between 0.05 and 0.075 and a second + # interval that is random between 0.1 and 0.15 + # + class Request::Retry < Faraday::Middleware + + IDEMPOTENT_METHODS = [:delete, :get, :head, :options, :put] + + class Options < Faraday::Options.new(:max, :interval, :interval_randomness, :backoff_factor, :exceptions, :retry_if) + DEFAULT_CHECK = lambda { |env,exception| false } + + def self.from(value) + if Fixnum === value + new(value) + else + super(value) + end + end + + def max + (self[:max] ||= 2).to_i + end + + def interval + (self[:interval] ||= 0).to_f + end + + def interval_randomness + (self[:interval_randomness] ||= 0).to_i + end + + def backoff_factor + (self[:backoff_factor] ||= 1).to_f + end + + def exceptions + Array(self[:exceptions] ||= [Errno::ETIMEDOUT, 'Timeout::Error', + Error::TimeoutError]) + end + + def retry_if + self[:retry_if] ||= DEFAULT_CHECK + end + + end + + # Public: Initialize middleware + # + # Options: + # max - Maximum number of retries (default: 2) + # interval - Pause in seconds between retries (default: 0) + # interval_randomness - The maximum random interval amount expressed + # as a float between 0 and 1 to use in addition to the + # interval. (default: 0) + # backoff_factor - The amount to multiple each successive retry's + # interval amount by in order to provide backoff + # (default: 1) + # exceptions - The list of exceptions to handle. Exceptions can be + # given as Class, Module, or String. (default: + # [Errno::ETIMEDOUT, Timeout::Error, + # Error::TimeoutError]) + # retry_if - block that will receive the env object and the exception raised + # and should decide if the code should retry still the action or + # not independent of the retry count. This would be useful + # if the exception produced is non-recoverable or if the + # the HTTP method called is not idempotent. + # (defaults to return false) + def initialize(app, options = nil) + super(app) + @options = Options.from(options) + @errmatch = build_exception_matcher(@options.exceptions) + end + + def sleep_amount(retries) + retry_index = @options.max - retries + current_interval = @options.interval * (@options.backoff_factor ** retry_index) + random_interval = rand * @options.interval_randomness.to_f * @options.interval + current_interval + random_interval + end + + def call(env) + retries = @options.max + request_body = env[:body] + begin + env[:body] = request_body # after failure env[:body] is set to the response body + @app.call(env) + rescue @errmatch => exception + if retries > 0 && retry_request?(env, exception) + retries -= 1 + sleep sleep_amount(retries + 1) + retry + end + raise + end + end + + # Private: construct an exception matcher object. + # + # An exception matcher for the rescue clause can usually be any object that + # responds to `===`, but for Ruby 1.8 it has to be a Class or Module. + def build_exception_matcher(exceptions) + matcher = Module.new + (class << matcher; self; end).class_eval do + define_method(:===) do |error| + exceptions.any? do |ex| + if ex.is_a? Module + error.is_a? ex + else + error.class.to_s == ex.to_s + end + end + end + end + matcher + end + + private + + def retry_request?(env, exception) + IDEMPOTENT_METHODS.include?(env[:method]) || @options.retry_if.call(env, exception) + end + + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/token_authentication.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/token_authentication.rb new file mode 100644 index 000000000..25586080c --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/token_authentication.rb @@ -0,0 +1,15 @@ +module Faraday + class Request::TokenAuthentication < Request.load_middleware(:authorization) + # Public + def self.header(token, options = nil) + options ||= {} + options[:token] = token + super(:Token, options) + end + + def initialize(app, token, options = nil) + super(app, token, options) + end + end +end + diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/url_encoded.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/url_encoded.rb new file mode 100644 index 000000000..b02a26621 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/request/url_encoded.rb @@ -0,0 +1,36 @@ +module Faraday + class Request::UrlEncoded < Faraday::Middleware + CONTENT_TYPE = 'Content-Type'.freeze unless defined? CONTENT_TYPE + + class << self + attr_accessor :mime_type + end + self.mime_type = 'application/x-www-form-urlencoded'.freeze + + def call(env) + match_content_type(env) do |data| + params = Faraday::Utils::ParamsHash[data] + env.body = params.to_query(env.params_encoder) + end + @app.call env + end + + def match_content_type(env) + if process_request?(env) + env.request_headers[CONTENT_TYPE] ||= self.class.mime_type + yield(env.body) unless env.body.respond_to?(:to_str) + end + end + + def process_request?(env) + type = request_type(env) + env.body and (type.empty? or type == self.class.mime_type) + end + + def request_type(env) + type = env.request_headers[CONTENT_TYPE].to_s + type = type.split(';', 2).first if type.index(';') + type + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/response.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/response.rb new file mode 100644 index 000000000..88ec5310a --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/response.rb @@ -0,0 +1,93 @@ +require 'forwardable' + +module Faraday + class Response + # Used for simple response middleware. + class Middleware < Faraday::Middleware + def call(env) + @app.call(env).on_complete do |environment| + on_complete(environment) + end + end + + # Override this to modify the environment after the response has finished. + # Calls the `parse` method if defined + def on_complete(env) + env.body = parse(env.body) if respond_to?(:parse) && env.parse_body? + end + end + + extend Forwardable + extend MiddlewareRegistry + + register_middleware File.expand_path('../response', __FILE__), + :raise_error => [:RaiseError, 'raise_error'], + :logger => [:Logger, 'logger'] + + def initialize(env = nil) + @env = Env.from(env) if env + @on_complete_callbacks = [] + end + + attr_reader :env + + def_delegators :env, :to_hash + + def status + finished? ? env.status : nil + end + + def headers + finished? ? env.response_headers : {} + end + def_delegator :headers, :[] + + def body + finished? ? env.body : nil + end + + def finished? + !!env + end + + def on_complete + if not finished? + @on_complete_callbacks << Proc.new + else + yield(env) + end + return self + end + + def finish(env) + raise "response already finished" if finished? + @on_complete_callbacks.each { |callback| callback.call(env) } + @env = Env.from(env) + return self + end + + def success? + finished? && env.success? + end + + # because @on_complete_callbacks cannot be marshalled + def marshal_dump + !finished? ? nil : { + :status => @env.status, :body => @env.body, + :response_headers => @env.response_headers + } + end + + def marshal_load(env) + @env = Env.from(env) + end + + # Expand the env with more properties, without overriding existing ones. + # Useful for applying request params after restoring a marshalled Response. + def apply_request(request_env) + raise "response didn't finish yet" unless finished? + @env = Env.from(request_env).update(@env) + return self + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/response/logger.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/response/logger.rb new file mode 100644 index 000000000..cab7f1b7c --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/response/logger.rb @@ -0,0 +1,34 @@ +require 'forwardable' + +module Faraday + class Response::Logger < Response::Middleware + extend Forwardable + + def initialize(app, logger = nil) + super(app) + @logger = logger || begin + require 'logger' + ::Logger.new(STDOUT) + end + end + + def_delegators :@logger, :debug, :info, :warn, :error, :fatal + + def call(env) + info "#{env.method} #{env.url.to_s}" + debug('request') { dump_headers env.request_headers } + super + end + + def on_complete(env) + info('Status') { env.status.to_s } + debug('response') { dump_headers env.response_headers } + end + + private + + def dump_headers(headers) + headers.map { |k, v| "#{k}: #{v.inspect}" }.join("\n") + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/response/raise_error.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/response/raise_error.rb new file mode 100644 index 000000000..437762bc1 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/response/raise_error.rb @@ -0,0 +1,21 @@ +module Faraday + class Response::RaiseError < Response::Middleware + ClientErrorStatuses = 400...600 + + def on_complete(env) + case env[:status] + when 404 + raise Faraday::Error::ResourceNotFound, response_values(env) + when 407 + # mimic the behavior that we get with proxy requests with HTTPS + raise Faraday::Error::ConnectionFailed, %{407 "Proxy Authentication Required "} + when ClientErrorStatuses + raise Faraday::Error::ClientError, response_values(env) + end + end + + def response_values(env) + {:status => env.status, :headers => env.response_headers, :body => env.body} + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/upload_io.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/upload_io.rb new file mode 100644 index 000000000..9130d159d --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/upload_io.rb @@ -0,0 +1,67 @@ +begin + require 'composite_io' + require 'parts' + require 'stringio' +rescue LoadError + $stderr.puts "Install the multipart-post gem." + raise +end + +module Faraday + # Similar but not compatible with ::CompositeReadIO provided by multipart-post. + class CompositeReadIO + def initialize(*parts) + @parts = parts.flatten + @ios = @parts.map { |part| part.to_io } + @index = 0 + end + + def length + @parts.inject(0) { |sum, part| sum + part.length } + end + + def rewind + @ios.each { |io| io.rewind } + @index = 0 + end + + # Read from IOs in order until `length` bytes have been received. + def read(length = nil, outbuf = nil) + got_result = false + outbuf = outbuf ? outbuf.replace("") : "" + + while io = current_io + if result = io.read(length) + got_result ||= !result.nil? + result.force_encoding("BINARY") if result.respond_to?(:force_encoding) + outbuf << result + length -= result.length if length + break if length == 0 + end + advance_io + end + (!got_result && length) ? nil : outbuf + end + + def close + @ios.each { |io| io.close } + end + + def ensure_open_and_readable + # Rubinius compatibility + end + + private + + def current_io + @ios[@index] + end + + def advance_io + @index += 1 + end + end + + UploadIO = ::UploadIO + Parts = ::Parts +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/faraday/utils.rb b/3rdparty/modules/aviator/lib/puppet/feature/faraday/utils.rb new file mode 100644 index 000000000..1cd6526a6 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/faraday/utils.rb @@ -0,0 +1,297 @@ +require 'thread' +Faraday.require_libs 'parameters' + +module Faraday + module Utils + extend self + + # Adapted from Rack::Utils::HeaderHash + class Headers < ::Hash + def self.from(value) + new(value) + end + + def initialize(hash = nil) + super() + @names = {} + self.update(hash || {}) + end + + # need to synchronize concurrent writes to the shared KeyMap + keymap_mutex = Mutex.new + + # symbol -> string mapper + cache + KeyMap = Hash.new do |map, key| + value = if key.respond_to?(:to_str) + key + else + key.to_s.split('_'). # :user_agent => %w(user agent) + each { |w| w.capitalize! }. # => %w(User Agent) + join('-') # => "User-Agent" + end + keymap_mutex.synchronize { map[key] = value } + end + KeyMap[:etag] = "ETag" + + def [](k) + k = KeyMap[k] + super(k) || super(@names[k.downcase]) + end + + def []=(k, v) + k = KeyMap[k] + k = (@names[k.downcase] ||= k) + # join multiple values with a comma + v = v.to_ary.join(', ') if v.respond_to? :to_ary + super(k, v) + end + + def fetch(k, *args, &block) + k = KeyMap[k] + key = @names.fetch(k.downcase, k) + super(key, *args, &block) + end + + def delete(k) + k = KeyMap[k] + if k = @names[k.downcase] + @names.delete k.downcase + super(k) + end + end + + def include?(k) + @names.include? k.downcase + end + + alias_method :has_key?, :include? + alias_method :member?, :include? + alias_method :key?, :include? + + def merge!(other) + other.each { |k, v| self[k] = v } + self + end + alias_method :update, :merge! + + def merge(other) + hash = dup + hash.merge! other + end + + def replace(other) + clear + self.update other + self + end + + def to_hash() ::Hash.new.update(self) end + + def parse(header_string) + return unless header_string && !header_string.empty? + header_string.split(/\r\n/). + tap { |a| a.shift if a.first.index('HTTP/') == 0 }. # drop the HTTP status line + map { |h| h.split(/:\s+/, 2) }.reject { |p| p[0].nil? }. # split key and value, ignore blank lines + each { |key, value| + # join multiple values with a comma + if self[key] + self[key] << ', ' << value + else + self[key] = value + end + } + end + end + + # hash with stringified keys + class ParamsHash < Hash + def [](key) + super(convert_key(key)) + end + + def []=(key, value) + super(convert_key(key), value) + end + + def delete(key) + super(convert_key(key)) + end + + def include?(key) + super(convert_key(key)) + end + + alias_method :has_key?, :include? + alias_method :member?, :include? + alias_method :key?, :include? + + def update(params) + params.each do |key, value| + self[key] = value + end + self + end + alias_method :merge!, :update + + def merge(params) + dup.update(params) + end + + def replace(other) + clear + update(other) + end + + def merge_query(query, encoder = nil) + if query && !query.empty? + update((encoder || Utils.default_params_encoder).decode(query)) + end + self + end + + def to_query(encoder = nil) + (encoder || Utils.default_params_encoder).encode(self) + end + + private + + def convert_key(key) + key.to_s + end + end + + def build_query(params) + FlatParamsEncoder.encode(params) + end + + def build_nested_query(params) + NestedParamsEncoder.encode(params) + end + + ESCAPE_RE = /[^a-zA-Z0-9 .~_-]/ + + def escape(s) + s.to_s.gsub(ESCAPE_RE) {|match| + '%' + match.unpack('H2' * match.bytesize).join('%').upcase + }.tr(' ', '+') + end + + def unescape(s) CGI.unescape s.to_s end + + DEFAULT_SEP = /[&;] */n + + # Adapted from Rack + def parse_query(query) + FlatParamsEncoder.decode(query) + end + + def parse_nested_query(query) + NestedParamsEncoder.decode(query) + end + + def default_params_encoder + @default_params_encoder ||= NestedParamsEncoder + end + + class << self + attr_writer :default_params_encoder + end + + # Stolen from Rack + def normalize_params(params, name, v = nil) + name =~ %r(\A[\[\]]*([^\[\]]+)\]*) + k = $1 || '' + after = $' || '' + + return if k.empty? + + if after == "" + if params[k] + params[k] = Array[params[k]] unless params[k].kind_of?(Array) + params[k] << v + else + params[k] = v + end + elsif after == "[]" + params[k] ||= [] + raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) + params[k] << v + elsif after =~ %r(^\[\]\[([^\[\]]+)\]$) || after =~ %r(^\[\](.+)$) + child_key = $1 + params[k] ||= [] + raise TypeError, "expected Array (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Array) + if params[k].last.is_a?(Hash) && !params[k].last.key?(child_key) + normalize_params(params[k].last, child_key, v) + else + params[k] << normalize_params({}, child_key, v) + end + else + params[k] ||= {} + raise TypeError, "expected Hash (got #{params[k].class.name}) for param `#{k}'" unless params[k].is_a?(Hash) + params[k] = normalize_params(params[k], after, v) + end + + return params + end + + # Normalize URI() behavior across Ruby versions + # + # url - A String or URI. + # + # Returns a parsed URI. + def URI(url) + if url.respond_to?(:host) + url + elsif url.respond_to?(:to_str) + default_uri_parser.call(url) + else + raise ArgumentError, "bad argument (expected URI object or URI string)" + end + end + + def default_uri_parser + @default_uri_parser ||= begin + require 'uri' + Kernel.method(:URI) + end + end + + def default_uri_parser=(parser) + @default_uri_parser = if parser.respond_to?(:call) || parser.nil? + parser + else + parser.method(:parse) + end + end + + # Receives a String or URI and returns just the path with the query string sorted. + def normalize_path(url) + url = URI(url) + (url.path.start_with?('/') ? url.path : '/' + url.path) + + (url.query ? "?#{sort_query_params(url.query)}" : "") + end + + # Recursive hash update + def deep_merge!(target, hash) + hash.each do |key, value| + if Hash === value and Hash === target[key] + target[key] = deep_merge(target[key], value) + else + target[key] = value + end + end + target + end + + # Recursive hash merge + def deep_merge(source, hash) + deep_merge!(source.dup, hash) + end + + protected + + def sort_query_params(query) + query.split('&').sort.join('&') + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/multipart_post.rb b/3rdparty/modules/aviator/lib/puppet/feature/multipart_post.rb new file mode 100644 index 000000000..76540a8b7 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/multipart_post.rb @@ -0,0 +1,9 @@ +#-- +# Copyright (c) 2007-2013 Nick Sieger. +# See the file README.txt included with the distribution for +# software license details. +#++ + +module MultipartPost + VERSION = "2.0.0" +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/multipartable.rb b/3rdparty/modules/aviator/lib/puppet/feature/multipartable.rb new file mode 100644 index 000000000..28fa41e6d --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/multipartable.rb @@ -0,0 +1,29 @@ +#-- +# Copyright (c) 2007-2013 Nick Sieger. +# See the file README.txt included with the distribution for +# software license details. +#++ + +require 'parts' + module Multipartable + DEFAULT_BOUNDARY = "-----------RubyMultipartPost" + def initialize(path, params, headers={}, boundary = DEFAULT_BOUNDARY) + headers = headers.clone # don't want to modify the original variable + parts_headers = headers.delete(:parts) || {} + super(path, headers) + parts = params.map do |k,v| + case v + when Array + v.map {|item| Parts::Part.new(boundary, k, item, parts_headers[k]) } + else + Parts::Part.new(boundary, k, v, parts_headers[k]) + end + end.flatten + parts << Parts::EpiloguePart.new(boundary) + ios = parts.map {|p| p.to_io } + self.set_content_type(headers["Content-Type"] || "multipart/form-data", + { "boundary" => boundary }) + self.content_length = parts.inject(0) {|sum,i| sum + i.length } + self.body_stream = CompositeReadIO.new(*ios) + end + end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/net/http/post/multipart.rb b/3rdparty/modules/aviator/lib/puppet/feature/net/http/post/multipart.rb new file mode 100644 index 000000000..757058220 --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/net/http/post/multipart.rb @@ -0,0 +1,27 @@ +#-- +# Copyright (c) 2007-2012 Nick Sieger. +# See the file README.txt included with the distribution for +# software license details. +#++ + +require 'net/http' +require 'stringio' +require 'cgi' +require 'composite_io' +require 'multipartable' +require 'parts' + +module Net #:nodoc: + class HTTP #:nodoc: + class Put + class Multipart < Put + include Multipartable + end + end + class Post #:nodoc: + class Multipart < Post + include Multipartable + end + end + end +end diff --git a/3rdparty/modules/aviator/lib/puppet/feature/parts.rb b/3rdparty/modules/aviator/lib/puppet/feature/parts.rb new file mode 100644 index 000000000..c06cbd95d --- /dev/null +++ b/3rdparty/modules/aviator/lib/puppet/feature/parts.rb @@ -0,0 +1,96 @@ +#-- +# Copyright (c) 2007-2013 Nick Sieger. +# See the file README.txt included with the distribution for +# software license details. +#++ + +module Parts + module Part #:nodoc: + def self.new(boundary, name, value, headers = {}) + headers ||= {} # avoid nil values + if file?(value) + FilePart.new(boundary, name, value, headers) + else + ParamPart.new(boundary, name, value, headers) + end + end + + def self.file?(value) + value.respond_to?(:content_type) && value.respond_to?(:original_filename) + end + + def length + @part.length + end + + def to_io + @io + end + end + + class ParamPart + include Part + def initialize(boundary, name, value, headers = {}) + @part = build_part(boundary, name, value, headers) + @io = StringIO.new(@part) + end + + def length + @part.bytesize + end + + def build_part(boundary, name, value, headers = {}) + part = '' + part << "--#{boundary}\r\n" + part << "Content-Disposition: form-data; name=\"#{name.to_s}\"\r\n" + part << "Content-Type: #{headers["Content-Type"]}\r\n" if headers["Content-Type"] + part << "\r\n" + part << "#{value}\r\n" + end + end + + # Represents a part to be filled from file IO. + class FilePart + include Part + attr_reader :length + def initialize(boundary, name, io, headers = {}) + file_length = io.respond_to?(:length) ? io.length : File.size(io.local_path) + @head = build_head(boundary, name, io.original_filename, io.content_type, file_length, + io.respond_to?(:opts) ? io.opts.merge(headers) : headers) + @foot = "\r\n" + @length = @head.bytesize + file_length + @foot.length + @io = CompositeReadIO.new(StringIO.new(@head), io, StringIO.new(@foot)) + end + + def build_head(boundary, name, filename, type, content_len, opts = {}, headers = {}) + trans_encoding = opts["Content-Transfer-Encoding"] || "binary" + content_disposition = opts["Content-Disposition"] || "form-data" + + part = '' + part << "--#{boundary}\r\n" + part << "Content-Disposition: #{content_disposition}; name=\"#{name.to_s}\"; filename=\"#{filename}\"\r\n" + part << "Content-Length: #{content_len}\r\n" + if content_id = opts["Content-ID"] + part << "Content-ID: #{content_id}\r\n" + end + + if headers["Content-Type"] != nil + part << "Content-Type: " + headers["Content-Type"] + "\r\n" + else + part << "Content-Type: #{type}\r\n" + end + + part << "Content-Transfer-Encoding: #{trans_encoding}\r\n" + part << "\r\n" + end + end + + # Represents the epilogue or closing boundary. + class EpiloguePart + include Part + def initialize(boundary) + @part = "--#{boundary}--\r\n\r\n" + @io = StringIO.new(@part) + end + end +end diff --git a/3rdparty/modules/aviator/metadata.json b/3rdparty/modules/aviator/metadata.json new file mode 100644 index 000000000..7eff1a6c0 --- /dev/null +++ b/3rdparty/modules/aviator/metadata.json @@ -0,0 +1,14 @@ +{ + "name": "aimonb-aviator", + "version": "0.5.1", + "author": "aimonb", + "summary": "Puppet feature wrapper for the Aviator OpenStack API library for Ruby", + "license": "MIT License", + "source": "https://github.com/aimonb/puppet_aviator", + "project_page": "https://github.com/aimonb/puppet_aviator", + "issues_url": "https://github.com/aimonb/puppet_aviator/issues", + "description": "UNKNOWN", + "dependencies": [ + + ] +} diff --git a/3rdparty/modules/cinder/Gemfile b/3rdparty/modules/cinder/Gemfile new file mode 100644 index 000000000..f3182fde2 --- /dev/null +++ b/3rdparty/modules/cinder/Gemfile @@ -0,0 +1,19 @@ +source 'https://rubygems.org' + +group :development, :test do + gem 'puppetlabs_spec_helper', :require => false + gem 'puppet-lint', '~> 0.3.2' + gem 'rspec-puppet', '~> 1.0.1' + gem 'rake', '10.1.1' + gem 'rspec', '< 2.99' + gem 'json' + gem 'webmock' +end + +if puppetversion = ENV['PUPPET_GEM_VERSION'] + gem 'puppet', puppetversion, :require => false +else + gem 'puppet', :require => false +end + +# vim:ft=ruby diff --git a/3rdparty/modules/cinder/LICENSE b/3rdparty/modules/cinder/LICENSE new file mode 100644 index 000000000..8d968b6cb --- /dev/null +++ b/3rdparty/modules/cinder/LICENSE @@ -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. diff --git a/3rdparty/modules/cinder/README.md b/3rdparty/modules/cinder/README.md new file mode 100644 index 000000000..04c1abfee --- /dev/null +++ b/3rdparty/modules/cinder/README.md @@ -0,0 +1,300 @@ +cinder +======= + +5.1.0 - 2014.2 - Juno + +#### Table of Contents + +1. [Overview - What is the cinder module?](#overview) +2. [Module Description - What does the module do?](#module-description) +3. [Setup - The basics of getting started with cinder](#setup) +4. [Implementation - An under-the-hood peek at what the module is doing](#implementation) +5. [Limitations - OS compatibility, etc.](#limitations) +6. [Development - Guide for contributing to the module](#development) +7. [Contributors - Those with commits](#contributors) +8. [Release Notes - Notes on the most recent updates to the module](#release-notes) + +Overview +-------- + +The cinder module is a part of [Stackforge](https://github.com/stackfoge), an effort by the Openstack infrastructure team to provide continuous integration testing and code review for Openstack and Openstack community projects not part of the core software. The module its self is used to flexibly configure and manage the block storage service for Openstack. + +Module Description +------------------ + +The cinder module is a thorough attempt to make Puppet capable of managing the entirety of cinder. This includes manifests to provision such things as keystone endpoints, RPC configurations specific to cinder, and database connections. Types are shipped as part of the cinder module to assist in manipulation of configuration files. + +This module is tested in combination with other modules needed to build and leverage an entire Openstack software stack. These modules can be found, all pulled together in the [openstack module](https://github.com/stackfoge/puppet-openstack). + +Setup +----- + +**What the cinder module affects** + +* cinder, the block storage service for Openstack. + +### Installing cinder + + puppet module install puppetlabs/cinder + +### Beginning with cinder + +To utilize the cinder module's functionality you will need to declare multiple resources. The following is a modified excerpt from the [openstack module](https://github.com/stackfoge/puppet-openstack). This is not an exhaustive list of all the components needed, we recommend you consult and understand the [openstack module](https://github.com/stackforge/puppet-openstack) and the [core openstack](http://docs.openstack.org) documentation. + +**Define a cinder control node** + +```puppet +class { 'cinder': + database_connection => 'mysql://cinder:secret_block_password@openstack-controller.example.com/cinder', + rabbit_password => 'secret_rpc_password_for_blocks', + rabbit_host => 'openstack-controller.example.com', + verbose => true, +} + +class { 'cinder::api': + keystone_password => $keystone_password, + keystone_enabled => $keystone_enabled, + keystone_user => $keystone_user, + keystone_auth_host => $keystone_auth_host, + keystone_auth_port => $keystone_auth_port, + keystone_auth_protocol => $keystone_auth_protocol, + service_port => $keystone_service_port, + package_ensure => $cinder_api_package_ensure, + bind_host => $cinder_bind_host, + enabled => $cinder_api_enabled, +} + +class { 'cinder::scheduler': + scheduler_driver => 'cinder.scheduler.simple.SimpleScheduler', +} +``` + +**Define a cinder storage node** + +```puppet +class { 'cinder': + database_connection => 'mysql://cinder:secret_block_password@openstack-controller.example.com/cinder', + rabbit_password => 'secret_rpc_password_for_blocks', + rabbit_host => 'openstack-controller.example.com', + verbose => true, +} + +class { 'cinder::volume': } + +class { 'cinder::volume::iscsi': + iscsi_ip_address => '10.0.0.2', +} +``` + +**Define a cinder storage node with multiple backends ** + +```puppet +class { 'cinder': + database_connection => 'mysql://cinder:secret_block_password@openstack-controller.example.com/cinder', + rabbit_password => 'secret_rpc_password_for_blocks', + rabbit_host => 'openstack-controller.example.com', + verbose => true, +} + +class { 'cinder::volume': } + +cinder::backend::iscsi {'iscsi1': + iscsi_ip_address => '10.0.0.2', +} + +cinder::backend::iscsi {'iscsi2': + iscsi_ip_address => '10.0.0.3', +} + +cinder::backend::iscsi {'iscsi3': + iscsi_ip_address => '10.0.0.4', + volume_backend_name => 'iscsi', +} + +cinder::backend::iscsi {'iscsi4': + iscsi_ip_address => '10.0.0.5', + volume_backend_name => 'iscsi', +} + +cinder::backend::rbd {'rbd-images': + rbd_pool => 'images', + rbd_user => 'images', +} + +# Cinder::Type requires keystone credentials +Cinder::Type { + os_password => 'admin', + os_tenant_name => 'admin', + os_username => 'admin', + os_auth_url => 'http://127.0.0.1:5000/v2.0/', +} + +cinder::type {'iscsi': + set_key => 'volume_backend_name', + set_value => ['iscsi1', 'iscsi2', 'iscsi'] +} + +cinder::type {'rbd': + set_key => 'volume_backend_name', + set_value => 'rbd-images', +} + +class { 'cinder::backends': + enabled_backends => ['iscsi1', 'iscsi2', 'rbd-images'] +} +``` + +Note: that the name passed to any backend resource must be unique accross all backends otherwise a duplicate resource will be defined. + +** Using type and type_set ** + +Cinder allows for the usage of type to set extended information that can be used for various reasons. We have resource provider for ``type`` and ``type_set`` Since types are rarely defined with out also setting attributes with it, the resource for ``type`` can also call ``type_set`` if you pass ``set_key`` and ``set_value`` + + +Implementation +-------------- + +### cinder + +cinder is a combination of Puppet manifest and ruby code to delivery configuration and extra functionality through types and providers. + +Limitations +------------ + +* Setup of storage nodes is limited to Linux and LVM, i.e. Puppet won't configure a Nexenta appliance but nova can be configured to use the Nexenta driver with Class['cinder::volume::nexenta']. + +Development +----------- + +Developer documentation for the entire puppet-openstack project. + +* https://wiki.openstack.org/wiki/Puppet-openstack#Developer_documentation + +Contributors +------------ + +* https://github.com/stackforge/puppet-cinder/graphs/contributors + +Release Notes +------------- + +**5.1.0** + +* Service Validation for Cinder-API +* Automates generation of NFS config file +* spec: pin rspec-puppet to 1.0.1 +* Switch to using the new SolidFire driver name +* Makes kombu_ssl_* parameters optional when rabbit_use_ssl => true +* Switch to TLSv1 +* Create type-key only if it doesn't exist +* use lioadm on Fedora +* Pin puppetlabs-concat to 1.2.1 in fixtures +* Add nfs_mount_options variable when backend is NetApp +* Change default MySQL collate to utf8_general_ci +* Add configuration helpers for Quobyte +* Implement HP 3par iscsi backend module +* Update .gitreview file for project rename + +**5.0.0** + +* Stable Juno release +* Added class to manage policy.json +* Changed the default value of the san_thin_provision parameter for eqlx +* Added database tuning parameters +* Made keystone user creation optional when creating a service +* Added ability to hide secrets from logs +* Added parameters for netapp and and cinder-api workers +* Corrected the package name for cinder backup +* Added support for the EMC VNX direct driver +* Migrated the mysql backend to use openstacklib::db::mysql +* Added support for availability zones + +**4.2.0** + +* Added parameters to set cinder volume driver +* Added class for extended logging options +* Added option to specify endpoint protocol +* Fixed cinder type path issues +* Added option to specify cinder volume path +* Fixed targetcli package dependency on target service +* Fixed os version fact comparison for RedHat-based operating systems + for specifying service provider +* Added option to configure os_region_name in the cinder config + +**4.1.0** + +* Added Cinder v2 endpoint support. +* Added SSL support for Cinder API. +* Added RabbitMQ SSL support. +* Moved default_volume_type to cinder::api +* Removed warnings for existing Cinder volumes. +* Pinned major gems. + +**4.0.0** + +* Stable Icehouse release. +* Updated NetApp unified driver config options. +* Updated support for latest RabbitMQ module. +* Added Glance support. +* Added GlusterFS driver support. +* Added region support. +* Added support for MySQL module (>= 2.2). +* Added support for Swift and Ceph backup backend. +* Added cinder::config to handle additional custom options. +* Refactored duplicate code for single and multiple backends. +* Removed control exchange flag. +* Removed deprecated cinder::base class. + +**3.1.1** + +* Fixed resource duplication bug. + +**3.1.0** + +* Added default_volume_type as a Cinder API parameter. +* Added parameter for endpoint procols. +* Deprecated glance_api_version. +* Added support for VMDK. +* Added support for Cinder multi backend. +* Added support for https authentication endpoints. +* Replaced pip with native package manager (VMDK). + +**3.0.0** + +* Major release for OpenStack Havana. +* Added support for SolidFire. +* Added support for ceilometer. +* Fixed bug for cinder-volume requirement. + +**2.2.0** + +* Added support for rate limiting via api-paste.ini +* Added support to configure control_exchange. +* Added parameter check to enable or disable db_sync. +* Added syslog support. +* Added default auth_uri setting for auth token. +* Set package defaults to present. +* Fixed a bug to create empty init script when necessary. +* Various lint fixes. + +**2.1.0** + +* Added configuration of Cinder quotas. +* Added support for NetApp direct driver backend. +* Added support for ceph backend. +* Added support for SQL idle timeout. +* Added support for RabbitMQ clustering with single IP. +* Fixed allowed_hosts/database connection bug. +* Fixed lvm2 setup failure for Ubuntu. +* Removed unnecessary mysql::server dependency. +* Pinned RabbitMQ and database module versions. +* Various lint and bug fixes. + +**2.0.0** + +* Upstream is now part of stackfoge. +* Nexenta, NFS, and SAN support added as cinder volume drivers. +* Postgres support added. +* The Apache Qpid and the RabbitMQ message brokers available as RPC backends. +* Configurability of scheduler_driver. +* Various cleanups and bug fixes. diff --git a/3rdparty/modules/cinder/Rakefile b/3rdparty/modules/cinder/Rakefile new file mode 100644 index 000000000..4c2b2ed07 --- /dev/null +++ b/3rdparty/modules/cinder/Rakefile @@ -0,0 +1,6 @@ +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' + +PuppetLint.configuration.fail_on_warnings = true +PuppetLint.configuration.send('disable_80chars') +PuppetLint.configuration.send('disable_class_parameter_defaults') diff --git a/3rdparty/modules/cinder/checksums.json b/3rdparty/modules/cinder/checksums.json new file mode 100644 index 000000000..7825d2f5f --- /dev/null +++ b/3rdparty/modules/cinder/checksums.json @@ -0,0 +1,117 @@ +{ + "Gemfile": "4a83c46a2bb3896cf81852501819bb3a", + "LICENSE": "0e5ccf641e613489e66aa98271dbe798", + "README.md": "0e0569932e2c324871001de92ad95549", + "Rakefile": "2ca4ff31c946a19edd44348fbfdc2aab", + "examples/cinder_volume_with_pacemaker.pp": "75bacb7c20b71a20efbe91a554f76c09", + "lib/puppet/provider/cinder_api_paste_ini/ini_setting.rb": "36cc1e3e4d0256e901debdc225f6c595", + "lib/puppet/provider/cinder_config/ini_setting.rb": "6092e3d7d75015613402cfa65570dacc", + "lib/puppet/type/cinder_api_paste_ini.rb": "55163fa05e23c979b4108c223d853385", + "lib/puppet/type/cinder_config.rb": "6c85cc4d1843a74e5f6887c34941129c", + "manifests/api.pp": "d9ed098009f7b693297951d182357dea", + "manifests/backend/emc_vnx.pp": "68c5d247f553881439fcca9fa4a0f1ed", + "manifests/backend/eqlx.pp": "0c2cf278ac78e634e7721c674b13b3b1", + "manifests/backend/glusterfs.pp": "24f3e592e57deb57743dd61db0d11b17", + "manifests/backend/hp3par_iscsi.pp": "e75a90a4db9822e2ec376e114524f8e2", + "manifests/backend/iscsi.pp": "c9ecca91a49acad5eab2296db06d4cc7", + "manifests/backend/netapp.pp": "d5f809d53ba0f7b629bfacbe98ff48c7", + "manifests/backend/nexenta.pp": "cd1736a508ad96040ef5f62bdedbc025", + "manifests/backend/nfs.pp": "027883893efead73f75c967d377869b7", + "manifests/backend/quobyte.pp": "aa9ceff6e703e5e0c7d658d937f13e64", + "manifests/backend/rbd.pp": "013f69ba5e894c810aecc1d1eb7a898b", + "manifests/backend/san.pp": "d00414e364946808cdcf2ec8d53df9f4", + "manifests/backend/solidfire.pp": "9b3971152b9e38e2e4cf4091275c95f9", + "manifests/backend/vmdk.pp": "74b7065d68083d98fc61addcc13882b1", + "manifests/backends.pp": "822f49e9bfc597a2f6f48be66de77409", + "manifests/backup/ceph.pp": "c2ef28b6e154e5e06f6c2f4de6783217", + "manifests/backup/swift.pp": "fa47a95eb75c330c80da87902a95dca3", + "manifests/backup.pp": "a8bed951fb1d183d11f754ae1063675e", + "manifests/ceilometer.pp": "f7fa133f351bf1d61135f6ae77a46428", + "manifests/client.pp": "60bbbb501d637a061ade75e102db6fad", + "manifests/config.pp": "7810b00bedeba0b2645940eb44302066", + "manifests/db/mysql.pp": "2d933079b5e42a681e264d501b9d97aa", + "manifests/db/postgresql.pp": "11cc604fd9e18d05f4e87af16e9d2d99", + "manifests/db/sync.pp": "a476ce6f80bda469461b428c825bf501", + "manifests/glance.pp": "62c7aff6b9065575c78787e0df04e989", + "manifests/init.pp": "c5a6e5be401b8137d8fc3da157e67f8d", + "manifests/keystone/auth.pp": "3f71cd0b73fb6afc851b7b8477f58b99", + "manifests/logging.pp": "a62ec6a2e4232846d396a5f01b4ebbc6", + "manifests/params.pp": "f68ef8e43251c73ac0b7fac81770e21a", + "manifests/policy.pp": "7defd8d2a488748d075dd034aca6ccc6", + "manifests/qpid.pp": "158cde34d6edf5fbcb528e7843c128b3", + "manifests/quota.pp": "ea68035f4df47e22cc6ad76a9b29725e", + "manifests/rabbitmq.pp": "da81944ca711cc1541d302b946d69cf5", + "manifests/scheduler.pp": "1f3b9f8ab3f436b9ca9cbdce4f0cf0f0", + "manifests/setup_test_volume.pp": "ddda84f851babcf9e0a11cea30453fb4", + "manifests/type.pp": "21a1bf1a37218a582c712f2fafc3a052", + "manifests/type_set.pp": "bb159f8927300b3b0a4a07566a424215", + "manifests/vmware.pp": "95d11ec6e3778c5985450a6d8c60e1c9", + "manifests/volume/emc_vnx.pp": "ba9f679720daf7abd0ea1cfd9cf3ee24", + "manifests/volume/eqlx.pp": "d9c1a06e01e4ca3367a5723e7a227c60", + "manifests/volume/glusterfs.pp": "05fb9ae32b4a67091188e1024f4ffc98", + "manifests/volume/hp3par_iscsi.pp": "5c73ceb17c8661f3b098763a5e24d7e8", + "manifests/volume/iscsi.pp": "73e8ad8b890c60bc86179a251ff360bd", + "manifests/volume/netapp.pp": "72ae30d853c5913dde150e1fa792ad02", + "manifests/volume/nexenta.pp": "776be67d3c1f5857c3ab41f259b0fac6", + "manifests/volume/nfs.pp": "463931737f8445f4162b88d37b320734", + "manifests/volume/quobyte.pp": "d11ea50a1a724c6e8bec9523f8a13eba", + "manifests/volume/rbd.pp": "ab2353c80a3b7b4252819d37e0b4faca", + "manifests/volume/san.pp": "097eef73d77be8e18656532a36f50b77", + "manifests/volume/solidfire.pp": "559dcd4fb6219de5028d5e9833dcb74d", + "manifests/volume/vmdk.pp": "1a3a340050a79580ed240b520226dd5a", + "manifests/volume.pp": "00a9b942349380e5b6670c2201e592be", + "metadata.json": "b446a9a9761c8056e356921990564fd7", + "spec/classes/cinder_api_spec.rb": "591bc5ad64fc025744f3a49eaee53a3a", + "spec/classes/cinder_backends_spec.rb": "41a96dae2a725be22057563bc8993857", + "spec/classes/cinder_backup_ceph_spec.rb": "eab8ee3cf9f98858ab6a6ec43d7f4ff7", + "spec/classes/cinder_backup_spec.rb": "9cd4cf939d32709ef27a690faafb0387", + "spec/classes/cinder_backup_swift_spec.rb": "e9bcee8a9831c518ea0d579e66328fb4", + "spec/classes/cinder_ceilometer_spec.rb": "7a77d9e30b14fd224d81367f52397d97", + "spec/classes/cinder_client_spec.rb": "8fe786f35ec630fad496252954ab0c17", + "spec/classes/cinder_db_mysql_spec.rb": "093abcacc57f1f4bab5eaa8f386b6a26", + "spec/classes/cinder_db_postgresql_spec.rb": "9b48f1b12ea4b7a6f06faab479d021f9", + "spec/classes/cinder_db_sync_spec.rb": "4c1b003008e7c9ac7820441bc5f7090c", + "spec/classes/cinder_glance_spec.rb": "0662e7a087e8e66c04293c429dd7604b", + "spec/classes/cinder_keystone_auth_spec.rb": "67599b94e197e1b84a82487525ede4a9", + "spec/classes/cinder_logging_spec.rb": "2f15b19c1d5eb681c3c868202ce67969", + "spec/classes/cinder_params_spec.rb": "38b96442d287e4491c68dd2891be38cd", + "spec/classes/cinder_policy_spec.rb": "2f23bae05187b2def377515a641f25fa", + "spec/classes/cinder_qpid_spec.rb": "e575bdc1cb0fa0083cc126a4250629d3", + "spec/classes/cinder_quota_spec.rb": "325e2d51fbdeb695581b01b0b20d5120", + "spec/classes/cinder_rabbitmq_spec.rb": "167165c9ea4b766bf9a90ba94f922c19", + "spec/classes/cinder_scheduler_spec.rb": "8e41759924936ecc0458e2d6267df628", + "spec/classes/cinder_setup_test_volume_spec.rb": "5f7ee336b3f9eca0db938e4f3d07931f", + "spec/classes/cinder_spec.rb": "650a40e68016f0081ce5f950cfc514d7", + "spec/classes/cinder_vmware_spec.rb": "72f2d8809f6d43858ff45196be3e2013", + "spec/classes/cinder_volume_emc_vnx_spec.rb": "06b84f1072fe9b9dc74ba288502caf33", + "spec/classes/cinder_volume_eqlx_spec.rb": "3e8676efa3576013b5eed02bc5ae2094", + "spec/classes/cinder_volume_glusterfs_spec.rb": "b93bd07f1fb68f8cda8c868c5615a95c", + "spec/classes/cinder_volume_hp3par_iscsi_spec.rb": "df9f6f90a2228b8f0092af3c9fd80ab1", + "spec/classes/cinder_volume_iscsi_spec.rb": "4bcc5a7fc26160f1b791d0c271d8ccc2", + "spec/classes/cinder_volume_netapp_spec.rb": "e901d350c23d29910e062276a38c011e", + "spec/classes/cinder_volume_nexenta_spec.rb": "7b6dd3d6b359a9dd127c06828537cc22", + "spec/classes/cinder_volume_nfs_spec.rb": "4249241caf670ab10f89ee2c06fc6cbf", + "spec/classes/cinder_volume_quobyte_spec.rb": "fc42259369e1086bb384046588abea5f", + "spec/classes/cinder_volume_rbd_spec.rb": "21991b1b92f5791b1b4315bc81487510", + "spec/classes/cinder_volume_san_spec.rb": "44f94a09358a63325a85125ff5bee5e8", + "spec/classes/cinder_volume_solidfire_spec.rb": "ad1aed1fd07dd9b981885573ec73f73a", + "spec/classes/cinder_volume_spec.rb": "7020a1af0a29da79648295216e1679e9", + "spec/classes/cinder_volume_vmdk_spec.rb": "cf2f26d3c34319a5b6127f387edd5a8e", + "spec/defines/cinder_backend_emc_vnx_spec.rb": "934f719465ab0248de65094fbd58f867", + "spec/defines/cinder_backend_eqlx_spec.rb": "540d7fb5da310ecafc11fbbff22abc8d", + "spec/defines/cinder_backend_glusterfs_spec.rb": "db44a4ae16a430e1a5886328325fb889", + "spec/defines/cinder_backend_hp3par_iscsi_spec.rb": "46a246c7af0f64d1799d891731d1d1cc", + "spec/defines/cinder_backend_iscsi_spec.rb": "9d24b94aa7c2af4029fb1fbbdd57a073", + "spec/defines/cinder_backend_netapp_spec.rb": "05f506853bbdb77d6fe868a69f954143", + "spec/defines/cinder_backend_nexenta_spec.rb": "b03cb789019a6d162626512832ce5c3d", + "spec/defines/cinder_backend_nfs_spec.rb": "83e0931597fea5ce36d55a50524ffae6", + "spec/defines/cinder_backend_quobyte_spec.rb": "146169cd2c7db99d569df993839a227e", + "spec/defines/cinder_backend_rbd_spec.rb": "7cafb457241a8f8b6ac54b5a35f867bf", + "spec/defines/cinder_backend_san_spec.rb": "4cdfb5c7a0c98370da9342849ea339df", + "spec/defines/cinder_backend_solidfire_spec.rb": "e0073c1baa953bd65fdb8a973a2171ae", + "spec/defines/cinder_backend_vmdk_spec.rb": "7c6e416cee782aa002caf2f3055e4f38", + "spec/defines/cinder_type_set_spec.rb": "2d9fb41a1db9e3828909fec46e49d3a4", + "spec/defines/cinder_type_spec.rb": "cc745ca0d223a5e51f93bc2047a859f8", + "spec/shared_examples.rb": "172c63c57efca8c741f297494ed9ef0f", + "spec/spec_helper.rb": "41d71ed92d01bb23d52397572e9b24bb" +} \ No newline at end of file diff --git a/3rdparty/modules/cinder/examples/cinder_volume_with_pacemaker.pp b/3rdparty/modules/cinder/examples/cinder_volume_with_pacemaker.pp new file mode 100644 index 000000000..4a38db7f7 --- /dev/null +++ b/3rdparty/modules/cinder/examples/cinder_volume_with_pacemaker.pp @@ -0,0 +1,40 @@ +# Example: managing cinder controller services with pacemaker +# +# By setting enabled to false, these services will not be started at boot. By setting +# manage_service to false, puppet will not kill these services on every run. This +# allows the Pacemaker resource manager to dynamically determine on which node each +# service should run. +# +# The puppet commands below would ideally be applied to at least three nodes. +# +# Note that cinder-api is associated with the virtual IP address as +# it is called from external services. The remaining services connect to the +# database and/or message broker independently. +# +# Example pacemaker resource configuration commands (configured once per cluster): +# +# sudo pcs resource create cinder_vip ocf:heartbeat:IPaddr2 params ip=192.0.2.3 \ +# cidr_netmask=24 op monitor interval=10s +# +# sudo pcs resource create cinder_api_service lsb:openstack-cinder-api +# sudo pcs resource create cinder_scheduler_service lsb:openstack-cinder-scheduler +# +# sudo pcs constraint colocation add cinder_api_service with cinder_vip + +class { 'cinder': + database_connection => 'mysql://cinder:secret_block_password@openstack-controller.example.com/cinder', +} + +class { 'cinder::api': + keystone_password => 'CINDER_PW', + keystone_user => 'cinder', + enabled => false, + manage_service => false, +} + +class { 'cinder::scheduler': + scheduler_driver => 'cinder.scheduler.simple.SimpleScheduler', + enabled => false, + manage_service => false, +} + diff --git a/3rdparty/modules/cinder/lib/puppet/provider/cinder_api_paste_ini/ini_setting.rb b/3rdparty/modules/cinder/lib/puppet/provider/cinder_api_paste_ini/ini_setting.rb new file mode 100644 index 000000000..26c3b528d --- /dev/null +++ b/3rdparty/modules/cinder/lib/puppet/provider/cinder_api_paste_ini/ini_setting.rb @@ -0,0 +1,27 @@ +Puppet::Type.type(:cinder_api_paste_ini).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def self.file_path + '/etc/cinder/api-paste.ini' + end + + # added for backwards compatibility with older versions of inifile + def file_path + self.class.file_path + end + +end diff --git a/3rdparty/modules/cinder/lib/puppet/provider/cinder_config/ini_setting.rb b/3rdparty/modules/cinder/lib/puppet/provider/cinder_config/ini_setting.rb new file mode 100644 index 000000000..6dcd95597 --- /dev/null +++ b/3rdparty/modules/cinder/lib/puppet/provider/cinder_config/ini_setting.rb @@ -0,0 +1,27 @@ +Puppet::Type.type(:cinder_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def self.file_path + '/etc/cinder/cinder.conf' + end + + # added for backwards compatibility with older versions of inifile + def file_path + self.class.file_path + end + +end diff --git a/3rdparty/modules/cinder/lib/puppet/type/cinder_api_paste_ini.rb b/3rdparty/modules/cinder/lib/puppet/type/cinder_api_paste_ini.rb new file mode 100644 index 000000000..d895b4a3c --- /dev/null +++ b/3rdparty/modules/cinder/lib/puppet/type/cinder_api_paste_ini.rb @@ -0,0 +1,42 @@ +Puppet::Type.newtype(:cinder_api_paste_ini) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from /etc/cinder/api-paste.ini' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end +end diff --git a/3rdparty/modules/cinder/lib/puppet/type/cinder_config.rb b/3rdparty/modules/cinder/lib/puppet/type/cinder_config.rb new file mode 100644 index 000000000..62d38256b --- /dev/null +++ b/3rdparty/modules/cinder/lib/puppet/type/cinder_config.rb @@ -0,0 +1,42 @@ +Puppet::Type.newtype(:cinder_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from /etc/cinder/cinder.conf' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end +end diff --git a/3rdparty/modules/cinder/manifests/api.pp b/3rdparty/modules/cinder/manifests/api.pp new file mode 100644 index 000000000..f9102c4cd --- /dev/null +++ b/3rdparty/modules/cinder/manifests/api.pp @@ -0,0 +1,251 @@ +# == Class: cinder::api +# +# Setup and configure the cinder API endpoint +# +# === Parameters +# +# [*keystone_password*] +# The password to use for authentication (keystone) +# +# [*keystone_enabled*] +# (optional) Use keystone for authentification +# Defaults to true +# +# [*keystone_tenant*] +# (optional) The tenant of the auth user +# Defaults to services +# +# [*keystone_user*] +# (optional) The name of the auth user +# Defaults to cinder +# +# [*keystone_auth_host*] +# (optional) The keystone host +# Defaults to localhost +# +# [*keystone_auth_port*] +# (optional) The keystone auth port +# Defaults to 35357 +# +# [*keystone_auth_protocol*] +# (optional) The protocol used to access the auth host +# Defaults to http. +# +# [*os_region_name*] +# (optional) Some operations require cinder to make API requests +# to Nova. This sets the keystone region to be used for these +# requests. For example, boot-from-volume. +# Defaults to undef. +# +# [*keystone_auth_admin_prefix*] +# (optional) The admin_prefix used to admin endpoint of the auth host +# This allow admin auth URIs like http://auth_host:35357/keystone. +# (where '/keystone' is the admin prefix) +# Defaults to false for empty. If defined, should be a string with a +# leading '/' and no trailing '/'. +# +# [*service_port*] +# (optional) The cinder api port +# Defaults to 5000 +# +# [*service_workers*] +# (optional) Number of cinder-api workers +# Defaults to $::processorcount +# +# [*package_ensure*] +# (optional) The state of the package +# Defaults to present +# +# [*bind_host*] +# (optional) The cinder api bind address +# Defaults to 0.0.0.0 +# +# [*enabled*] +# (optional) The state of the service +# Defaults to true +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*ratelimits*] +# (optional) The state of the service +# Defaults to undef. If undefined the default ratelimiting values are used. +# +# [*ratelimits_factory*] +# (optional) Factory to use for ratelimiting +# Defaults to 'cinder.api.v1.limits:RateLimitingMiddleware.factory' +# +# [*default_volume_type*] +# (optional) default volume type to use. +# This should contain the name of the default volume type to use. +# If not configured, it produces an error when creating a volume +# without specifying a type. +# Defaults to 'false'. +# +# [*validate*] +# (optional) Whether to validate the service is working after any service refreshes +# Defaults to false +# +# [*validation_options*] +# (optional) Service validation options +# Should be a hash of options defined in openstacklib::service_validation +# If empty, defaults values are taken from openstacklib function. +# Default command list volumes. +# Require validate set at True. +# Example: +# glance::api::validation_options: +# glance-api: +# command: check_cinder-api.py +# path: /usr/bin:/bin:/usr/sbin:/sbin +# provider: shell +# tries: 5 +# try_sleep: 10 +# Defaults to {} +# +class cinder::api ( + $keystone_password, + $keystone_enabled = true, + $keystone_tenant = 'services', + $keystone_user = 'cinder', + $keystone_auth_host = 'localhost', + $keystone_auth_port = '35357', + $keystone_auth_protocol = 'http', + $keystone_auth_admin_prefix = false, + $keystone_auth_uri = false, + $os_region_name = undef, + $service_port = '5000', + $service_workers = $::processorcount, + $package_ensure = 'present', + $bind_host = '0.0.0.0', + $enabled = true, + $manage_service = true, + $ratelimits = undef, + $default_volume_type = false, + $ratelimits_factory = + 'cinder.api.v1.limits:RateLimitingMiddleware.factory', + $validate = false, + $validation_options = {}, +) { + + include cinder::params + include cinder::policy + + Cinder_config<||> ~> Service['cinder-api'] + Cinder_api_paste_ini<||> ~> Service['cinder-api'] + Class['cinder::policy'] ~> Service['cinder-api'] + + if $::cinder::params::api_package { + Package['cinder-api'] -> Class['cinder::policy'] + Package['cinder-api'] -> Cinder_config<||> + Package['cinder-api'] -> Cinder_api_paste_ini<||> + Package['cinder-api'] -> Service['cinder-api'] + package { 'cinder-api': + ensure => $package_ensure, + name => $::cinder::params::api_package, + } + } + + if $enabled { + + Cinder_config<||> ~> Exec['cinder-manage db_sync'] + + exec { 'cinder-manage db_sync': + command => $::cinder::params::db_sync_command, + path => '/usr/bin', + user => 'cinder', + refreshonly => true, + logoutput => 'on_failure', + require => Package['cinder'], + } + if $manage_service { + $ensure = 'running' + } + } else { + if $manage_service { + $ensure = 'stopped' + } + } + + service { 'cinder-api': + ensure => $ensure, + name => $::cinder::params::api_service, + enable => $enabled, + hasstatus => true, + require => Package['cinder'], + } + + cinder_config { + 'DEFAULT/osapi_volume_listen': value => $bind_host; + 'DEFAULT/osapi_volume_workers': value => $service_workers; + } + + if $os_region_name { + cinder_config { + 'DEFAULT/os_region_name': value => $os_region_name; + } + } + + if $keystone_auth_uri { + $auth_uri = $keystone_auth_uri + } else { + $auth_uri = "${keystone_auth_protocol}://${keystone_auth_host}:${service_port}/" + } + cinder_api_paste_ini { 'filter:authtoken/auth_uri': value => $auth_uri; } + + if $keystone_enabled { + cinder_config { + 'DEFAULT/auth_strategy': value => 'keystone' ; + } + cinder_api_paste_ini { + 'filter:authtoken/service_protocol': value => $keystone_auth_protocol; + 'filter:authtoken/service_host': value => $keystone_auth_host; + 'filter:authtoken/service_port': value => $service_port; + 'filter:authtoken/auth_protocol': value => $keystone_auth_protocol; + 'filter:authtoken/auth_host': value => $keystone_auth_host; + 'filter:authtoken/auth_port': value => $keystone_auth_port; + 'filter:authtoken/admin_tenant_name': value => $keystone_tenant; + 'filter:authtoken/admin_user': value => $keystone_user; + 'filter:authtoken/admin_password': value => $keystone_password, secret => true; + } + + if ($ratelimits != undef) { + cinder_api_paste_ini { + 'filter:ratelimit/paste.filter_factory': value => $ratelimits_factory; + 'filter:ratelimit/limits': value => $ratelimits; + } + } + + if $keystone_auth_admin_prefix { + validate_re($keystone_auth_admin_prefix, '^(/.+[^/])?$') + cinder_api_paste_ini { + 'filter:authtoken/auth_admin_prefix': value => $keystone_auth_admin_prefix; + } + } else { + cinder_api_paste_ini { + 'filter:authtoken/auth_admin_prefix': ensure => absent; + } + } + } + + if $default_volume_type { + cinder_config { + 'DEFAULT/default_volume_type': value => $default_volume_type; + } + } else { + cinder_config { + 'DEFAULT/default_volume_type': ensure => absent; + } + } + + if $validate { + $defaults = { + 'cinder-api' => { + 'command' => "cinder --os-auth-url ${auth_uri} --os-tenant-name ${keystone_tenant} --os-username ${keystone_user} --os-password ${keystone_password} list", + } + } + $validation_options_hash = merge ($defaults, $validation_options) + create_resources('openstacklib::service_validation', $validation_options_hash, {'subscribe' => 'Service[cinder-api]'}) + } + +} diff --git a/3rdparty/modules/cinder/manifests/backend/emc_vnx.pp b/3rdparty/modules/cinder/manifests/backend/emc_vnx.pp new file mode 100644 index 000000000..5b060d39f --- /dev/null +++ b/3rdparty/modules/cinder/manifests/backend/emc_vnx.pp @@ -0,0 +1,65 @@ +# +# == Define: cinder::backend::emc_vnx +# +# Setup Cinder to use the EMC VNX driver. +# Compatible for multiple backends +# +# == Parameters +# +# [*volume_backend_name*] +# (optional) Allows for the volume_backend_name to be separate of $name. +# Defaults to: $name +# +# [*san_ip*] +# (required) IP address of SAN controller. +# +# [*san_password*] +# (required) Password of SAN controller. +# +# [*san_login*] +# (optional) Login of SAN controller. +# Defaults to : 'admin' +# +# [*storage_vnx_pool_name*] +# (required) Storage pool name. +# +# [*default_timeout*] +# (optional) Default timeout for CLI operations in minutes. +# Defaults to: '10' +# +# [*max_luns_per_storage_group*] +# (optional) Default max number of LUNs in a storage group. +# Defaults to: '256' +# +# [*package_ensure*] +# (optional) The state of the package +# Defaults to: 'present' +# +define cinder::backend::emc_vnx ( + $iscsi_ip_address, + $san_ip, + $san_password, + $storage_vnx_pool_name, + $default_timeout = '10', + $max_luns_per_storage_group = '256', + $package_ensure = 'present', + $san_login = 'admin', + $volume_backend_name = $name, +) { + + include cinder::params + + cinder_config { + "${name}/default_timeout": value => $default_timeout; + "${name}/iscsi_ip_address": value => $iscsi_ip_address; + "${name}/max_luns_per_storage_group": value => $max_luns_per_storage_group; + "${name}/naviseccli_path": value => '/opt/Navisphere/bin/naviseccli'; + "${name}/san_ip": value => $san_ip; + "${name}/san_login": value => $san_login; + "${name}/san_password": value => $san_password; + "${name}/storage_vnx_pool_name": value => $storage_vnx_pool_name; + "${name}/volume_backend_name": value => $volume_backend_name; + "${name}/volume_driver": value => 'cinder.volume.drivers.emc.emc_cli_iscsi.EMCCLIISCSIDriver'; + } + +} diff --git a/3rdparty/modules/cinder/manifests/backend/eqlx.pp b/3rdparty/modules/cinder/manifests/backend/eqlx.pp new file mode 100644 index 000000000..b2d47eaab --- /dev/null +++ b/3rdparty/modules/cinder/manifests/backend/eqlx.pp @@ -0,0 +1,86 @@ +# == define: cinder::backend::eqlx +# +# Configure the Dell EqualLogic driver for cinder. +# +# === Parameters +# +# [*san_ip*] +# (required) The IP address of the Dell EqualLogic array. +# +# [*san_login*] +# (required) The account to use for issuing SSH commands. +# +# [*san_password*] +# (required) The password for the specified SSH account. +# +# [*san_thin_provision*] +# (optional) Whether or not to use thin provisioning for volumes. +# Defaults to true +# +# [*volume_backend_name*] +# (optional) The backend name. +# Defaults to the name of the resource +# +# [*eqlx_group_name*] +# (optional) The CLI prompt message without '>'. +# Defaults to 'group-0' +# +# [*eqlx_pool*] +# (optional) The pool in which volumes will be created. +# Defaults to 'default' +# +# [*eqlx_use_chap*] +# (optional) Use CHAP authentification for targets? +# Defaults to false +# +# [*eqlx_chap_login*] +# (optional) An existing CHAP account name. +# Defaults to 'chapadmin' +# +# [*eqlx_chap_password*] +# (optional) The password for the specified CHAP account name. +# Defaults to '12345' +# +# [*eqlx_cli_timeout*] +# (optional) The timeout for the Group Manager cli command execution. +# Defaults to 30 seconds +# +# [*eqlx_cli_max_retries*] +# (optional) The maximum retry count for reconnection. +# Defaults to 5 +# +define cinder::backend::eqlx ( + $san_ip, + $san_login, + $san_password, + $san_thin_provision = true, + $volume_backend_name = $name, + $eqlx_group_name = 'group-0', + $eqlx_pool = 'default', + $eqlx_use_chap = false, + $eqlx_chap_login = 'chapadmin', + $eqlx_chap_password = '12345', + $eqlx_cli_timeout = 30, + $eqlx_cli_max_retries = 5, +) { + cinder_config { + "${name}/volume_backend_name": value => $volume_backend_name; + "${name}/volume_driver": value => 'cinder.volume.drivers.eqlx.DellEQLSanISCSIDriver'; + "${name}/san_ip": value => $san_ip; + "${name}/san_login": value => $san_login; + "${name}/san_password": value => $san_password, secret => true; + "${name}/san_thin_provision": value => $san_thin_provision; + "${name}/eqlx_group_name": value => $eqlx_group_name; + "${name}/eqlx_use_chap": value => $eqlx_use_chap; + "${name}/eqlx_cli_timeout": value => $eqlx_cli_timeout; + "${name}/eqlx_cli_max_retries": value => $eqlx_cli_max_retries; + "${name}/eqlx_pool": value => $eqlx_pool; + } + + if(str2bool($eqlx_use_chap)) { + cinder_config { + "${name}/eqlx_chap_login": value => $eqlx_chap_login; + "${name}/eqlx_chap_password": value => $eqlx_chap_password, secret => true; + } + } +} diff --git a/3rdparty/modules/cinder/manifests/backend/glusterfs.pp b/3rdparty/modules/cinder/manifests/backend/glusterfs.pp new file mode 100644 index 000000000..5121bb1ac --- /dev/null +++ b/3rdparty/modules/cinder/manifests/backend/glusterfs.pp @@ -0,0 +1,66 @@ +# +# == Class: cinder::backend::glusterfs +# +# Configures Cinder to use GlusterFS as a volume driver +# +# === Parameters +# +# [*glusterfs_shares*] +# (required) An array of GlusterFS volume locations. +# Must be an array even if there is only one volume. +# +# [*volume_backend_name*] +# (optional) Allows for the volume_backend_name to be separate of $name. +# Defaults to: $name +# +# [*glusterfs_disk_util*] +# Removed in Icehouse. +# +# [*glusterfs_sparsed_volumes*] +# (optional) Whether or not to use sparse (thin) volumes. +# Defaults to undef which uses the driver's default of "true". +# +# [*glusterfs_mount_point_base*] +# (optional) Where to mount the Gluster volumes. +# Defaults to undef which uses the driver's default of "$state_path/mnt". +# +# [*glusterfs_shares_config*] +# (optional) The config file to store the given $glusterfs_shares. +# Defaults to '/etc/cinder/shares.conf' +# +# === Examples +# +# cinder::backend::glusterfs { 'myGluster': +# glusterfs_shares = ['192.168.1.1:/volumes'], +# } +# +define cinder::backend::glusterfs ( + $glusterfs_shares, + $volume_backend_name = $name, + $glusterfs_disk_util = false, + $glusterfs_sparsed_volumes = undef, + $glusterfs_mount_point_base = undef, + $glusterfs_shares_config = '/etc/cinder/shares.conf' +) { + + if $glusterfs_disk_util { + fail('glusterfs_disk_util is removed in Icehouse.') + } + + $content = join($glusterfs_shares, "\n") + + file { $glusterfs_shares_config: + content => "${content}\n", + require => Package['cinder'], + notify => Service['cinder-volume'] + } + + cinder_config { + "${name}/volume_backend_name": value => $volume_backend_name; + "${name}/volume_driver": value => + 'cinder.volume.drivers.glusterfs.GlusterfsDriver'; + "${name}/glusterfs_shares_config": value => $glusterfs_shares_config; + "${name}/glusterfs_sparsed_volumes": value => $glusterfs_sparsed_volumes; + "${name}/glusterfs_mount_point_base": value => $glusterfs_mount_point_base; + } +} diff --git a/3rdparty/modules/cinder/manifests/backend/hp3par_iscsi.pp b/3rdparty/modules/cinder/manifests/backend/hp3par_iscsi.pp new file mode 100644 index 000000000..9d1090b3c --- /dev/null +++ b/3rdparty/modules/cinder/manifests/backend/hp3par_iscsi.pp @@ -0,0 +1,90 @@ +# == Define: cinder::backend::hp3par_iscsi +# +# Configures Cinder volume HP 3par ISCSI driver. +# Parameters are particular to each volume driver. +# +# === Parameters +# +# [*hp3par_api_url*] +# (required) url for api access to 3par - example https://10.x.x.x:8080/api/v1 +# +# [*hp3par_username*] +# (required) Username for HP3par admin user +# +# [*hp3par_password*] +# (required) Password for hp3par_username +# +# [*san_ip*] +# (required) IP address of HP 3par service processor. +# +# [*san_login*] +# (required) Username for HP 3par account. +# +# [*san_password*] +# (required) Password for HP 3par account. +# +# [*hp3par_iscsi_ips*] +# (required) iscsi IP addresses for the HP 3par array +# This is a list of IPs with ports in a string, for example: +# '1.2.3.4:3261, 5.6.7.8:3261' +# +# [*volume_backend_name*] +# (optional) Allows for the volume_backend_name to be separate of $name. +# Defaults to: $name +# +# [*volume_driver*] +# (optional) Setup cinder-volume to use HP 3par volume driver. +# Defaults to 'cinder.volume.drivers.san.hp.hp_3par_iscsi.HP3PARISCSIDriver' +# +# [*hp3par_iscsi_chap_enabled +# (required) setting to false by default +# +# [*hp3par_snap_cpg*] +# (optional) set to hp3par_cfg by default in the cinder driver +# +# [*hp3par_snapshot_retention*] +# (required) Time in hours for snapshot retention. Must be less +# than hp3par_snapshot_expiration. +# Defaults to 48. +# +# [*hp3par_snapshot_expiration*] +# (required) Time in hours until a snapshot expires. Must be more +# than hp3par_snapshot_retention. +# Defaults to 72. + +define cinder::backend::hp3par_iscsi( + $hp3par_api_url, + $hp3par_username, + $hp3par_password, + $san_ip, + $san_login, + $san_password, + $hp3par_iscsi_ips, + $volume_backend_name = $name, + $volume_driver = 'cinder.volume.drivers.san.hp.hp_3par_iscsi.HP3PARISCSIDriver', + $hp3par_iscsi_chap_enabled = false, + $hp3par_snap_cpg = 'OpenstackCPG', + $hp3par_snapshot_retention = 48, + $hp3par_snapshot_expiration = 72, +) { + + if ($hp3par_snapshot_expiration <= $hp3par_snapshot_retention) { + fail ('hp3par_snapshot_expiration must be greater than hp3par_snapshot_retention') + } + + cinder_config { + "${name}/volume_backend_name": value => $volume_backend_name; + "${name}/volume_driver": value => $volume_driver; + "${name}/hp3par_username": value => $hp3par_username; + "${name}/hp3par_password": value => $hp3par_password, secret => true; + "${name}/san_ip": value => $san_ip; + "${name}/san_login": value => $san_login; + "${name}/san_password": value => $san_password, secret => true; + "${name}/hp3par_iscsi_ips": value => $hp3par_iscsi_ips; + "${name}/hp3par_api_url": value => $hp3par_api_url; + "${name}/hp3par_iscsi_chap_enabled": value => $hp3par_iscsi_chap_enabled; + "${name}/hp3par_snap_cpg": value => $hp3par_snap_cpg; + "${name}/hp3par_snapshot_retention": value => $hp3par_snapshot_retention; + "${name}/hp3par_snapshot_expiration": value => $hp3par_snapshot_expiration; + } +} diff --git a/3rdparty/modules/cinder/manifests/backend/iscsi.pp b/3rdparty/modules/cinder/manifests/backend/iscsi.pp new file mode 100644 index 000000000..2d03fa5f3 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/backend/iscsi.pp @@ -0,0 +1,71 @@ +# +# Define: cinder::backend::iscsi +# Parameters: +# +# [*volume_backend_name*] +# (optional) Allows for the volume_backend_name to be separate of $name. +# Defaults to: $name +# +# +define cinder::backend::iscsi ( + $iscsi_ip_address, + $volume_backend_name = $name, + $volume_driver = 'cinder.volume.drivers.lvm.LVMISCSIDriver', + $volume_group = 'cinder-volumes', + $iscsi_helper = $::cinder::params::iscsi_helper, +) { + + include cinder::params + + cinder_config { + "${name}/volume_backend_name": value => $volume_backend_name; + "${name}/volume_driver": value => $volume_driver; + "${name}/iscsi_ip_address": value => $iscsi_ip_address; + "${name}/iscsi_helper": value => $iscsi_helper; + "${name}/volume_group": value => $volume_group; + } + + case $iscsi_helper { + 'tgtadm': { + package { 'tgt': + ensure => present, + name => $::cinder::params::tgt_package_name, + } + + if($::osfamily == 'RedHat') { + file_line { 'cinder include': + path => '/etc/tgt/targets.conf', + line => 'include /etc/cinder/volumes/*', + match => '#?include /', + require => Package['tgt'], + notify => Service['tgtd'], + } + } + + service { 'tgtd': + ensure => running, + name => $::cinder::params::tgt_service_name, + enable => true, + require => Class['cinder::volume'], + } + } + + 'lioadm': { + service { 'target': + ensure => running, + enable => true, + require => Package['targetcli'], + } + + package { 'targetcli': + ensure => present, + name => $::cinder::params::lio_package_name, + } + } + + default: { + fail("Unsupported iscsi helper: ${iscsi_helper}.") + } + } + +} diff --git a/3rdparty/modules/cinder/manifests/backend/netapp.pp b/3rdparty/modules/cinder/manifests/backend/netapp.pp new file mode 100644 index 000000000..cccea8bdb --- /dev/null +++ b/3rdparty/modules/cinder/manifests/backend/netapp.pp @@ -0,0 +1,238 @@ +# == define: cinder::backend::netapp +# +# Configures Cinder to use the NetApp unified volume driver +# Compatible for multiple backends +# +# === Parameters +# +# [*netapp_login*] +# (required) Administrative user account name used to access the storage +# system or proxy server. +# +# [*netapp_password*] +# (required) Password for the administrative user account specified in the +# netapp_login parameter. +# +# [*netapp_server_hostname*] +# (required) The hostname (or IP address) for the storage system or proxy +# server. +# +# [*netapp_server_port*] +# (optional) The TCP port to use for communication with ONTAPI on the +# storage system. Traditionally, port 80 is used for HTTP and port 443 is +# used for HTTPS; however, this value should be changed if an alternate +# port has been configured on the storage system or proxy server. +# Defaults to 80 +# +# [*netapp_size_multiplier*] +# (optional) The quantity to be multiplied by the requested volume size to +# ensure enough space is available on the virtual storage server (Vserver) to +# fulfill the volume creation request. +# Defaults to 1.2 +# +# [*netapp_storage_family*] +# (optional) The storage family type used on the storage system; valid values +# are ontap_7mode for using Data ONTAP operating in 7-Mode or ontap_cluster +# for using clustered Data ONTAP, or eseries for NetApp E-Series. +# Defaults to ontap_cluster +# +# [*netapp_storage_protocol*] +# (optional) The storage protocol to be used on the data path with the storage +# system; valid values are iscsi or nfs. +# Defaults to nfs +# +# [*netapp_transport_type*] +# (optional) The transport protocol used when communicating with ONTAPI on the +# storage system or proxy server. Valid values are http or https. +# Defaults to http +# +# [*netapp_vfiler*] +# (optional) The vFiler unit on which provisioning of block storage volumes +# will be done. This parameter is only used by the driver when connecting to +# an instance with a storage family of Data ONTAP operating in 7-Mode and the +# storage protocol selected is iSCSI. Only use this parameter when utilizing +# the MultiStore feature on the NetApp storage system. +# Defaults to '' +# +# [*netapp_volume_list*] +# (optional) This parameter is only utilized when the storage protocol is +# configured to use iSCSI. This parameter is used to restrict provisioning to +# the specified controller volumes. Specify the value of this parameter to be +# a comma separated list of NetApp controller volume names to be used for +# provisioning. +# Defaults to '' +# +# [*netapp_vserver*] +# (optional) This parameter specifies the virtual storage server (Vserver) +# name on the storage cluster on which provisioning of block storage volumes +# should occur. If using the NFS storage protocol, this parameter is mandatory +# for storage service catalog support (utilized by Cinder volume type +# extra_specs support). If this parameter is specified, the exports belonging +# to the Vserver will only be used for provisioning in the future. Block +# storage volumes on exports not belonging to the Vserver specified by +# this parameter will continue to function normally. +# Defaults to '' +# +# [*expiry_thres_minutes*] +# (optional) This parameter specifies the threshold for last access time for +# images in the NFS image cache. When a cache cleaning cycle begins, images +# in the cache that have not been accessed in the last M minutes, where M is +# the value of this parameter, will be deleted from the cache to create free +# space on the NFS share. +# Defaults to 720 +# +# [*thres_avl_size_perc_start*] +# (optional) If the percentage of available space for an NFS share has +# dropped below the value specified by this parameter, the NFS image cache +# will be cleaned. +# Defaults to 20 +# +# [*thres_avl_size_perc_stop*] +# (optional) When the percentage of available space on an NFS share has +# reached the percentage specified by this parameter, the driver will stop +# clearing files from the NFS image cache that have not been accessed in the +# last M minutes, where M is the value of the expiry_thres_minutes parameter. +# Defaults to 60 +# +# [*nfs_shares*] +# (optional) Array of NFS exports in the form of host:/share; will be written into +# file specified in nfs_shares_config +# Defaults to undef +# +# [*nfs_shares_config*] +# (optional) File with the list of available NFS shares +# Defaults to '/etc/cinder/shares.conf' +# +# [*nfs_mount_options*] +# (optional) Mount options passed to the nfs client. See section +# of the nfs man page for details. +# Defaults to undef +# +# [*netapp_copyoffload_tool_path*] +# (optional) This option specifies the path of the NetApp Copy Offload tool +# binary. Ensure that the binary has execute permissions set which allow the +# effective user of the cinder-volume process to execute the file. +# Defaults to '' +# +# [*netapp_controller_ips*] +# (optional) This option is only utilized when the storage family is +# configured to eseries. This option is used to restrict provisioning to the +# specified controllers. Specify the value of this option to be a comma +# separated list of controller hostnames or IP addresses to be used for +# provisioning. +# Defaults to '' +# +# [*netapp_sa_password*] +# (optional) Password for the NetApp E-Series storage array. +# Defaults to '' +# +# [*netapp_storage_pools*] +# (optional) This option is used to restrict provisioning to the specified +# storage pools. Only dynamic disk pools are currently supported. Specify the +# value of this option to be a comma separated list of disk pool names to be +# used for provisioning. +# Defaults to '' +# +# [*netapp_webservice_path*] +# (optional) This option is used to specify the path to the E-Series proxy +# application on a proxy server. The value is combined with the value of the +# netapp_transport_type, netapp_server_hostname, and netapp_server_port +# options to create the URL used by the driver to connect to the proxy +# application. +# Defaults to '/devmgr/v2' +# +# === Examples +# +# cinder::backend::netapp { 'myBackend': +# netapp_login => 'clusterAdmin', +# netapp_password => 'password', +# netapp_server_hostname => 'netapp.mycorp.com', +# netapp_server_port => '443', +# netapp_transport_type => 'https', +# netapp_vserver => 'openstack-vserver', +# } +# +# === Authors +# +# Bob Callaway +# +# === Copyright +# +# Copyright 2014 NetApp, Inc. +# +define cinder::backend::netapp ( + $netapp_login, + $netapp_password, + $netapp_server_hostname, + $volume_backend_name = $name, + $netapp_server_port = '80', + $netapp_size_multiplier = '1.2', + $netapp_storage_family = 'ontap_cluster', + $netapp_storage_protocol = 'nfs', + $netapp_transport_type = 'http', + $netapp_vfiler = '', + $netapp_volume_list = '', + $netapp_vserver = '', + $expiry_thres_minutes = '720', + $thres_avl_size_perc_start = '20', + $thres_avl_size_perc_stop = '60', + $nfs_shares = undef, + $nfs_shares_config = '/etc/cinder/shares.conf', + $netapp_copyoffload_tool_path = '', + $netapp_controller_ips = '', + $netapp_sa_password = '', + $netapp_storage_pools = '', + $nfs_mount_options = undef, + $netapp_webservice_path = '/devmgr/v2', +) { + + if $nfs_shares { + validate_array($nfs_shares) + file {$nfs_shares_config: + content => join($nfs_shares, "\n"), + require => Package['cinder'], + notify => Service['cinder-volume'] + } + } + + if $nfs_mount_options { + cinder_config { + "${volume_backend_name}/nfs_mount_options": value => $nfs_mount_options; + } + } else { + cinder_config { + "${volume_backend_name}/nfs_mount_options": ensure => absent; + } + } + + cinder_config { + "${volume_backend_name}/volume_backend_name": value => $volume_backend_name; + "${volume_backend_name}/volume_driver": value => 'cinder.volume.drivers.netapp.common.NetAppDriver'; + "${volume_backend_name}/netapp_login": value => $netapp_login; + "${volume_backend_name}/netapp_password": value => $netapp_password, secret => true; + "${volume_backend_name}/netapp_server_hostname": value => $netapp_server_hostname; + "${volume_backend_name}/netapp_server_port": value => $netapp_server_port; + "${volume_backend_name}/netapp_size_multiplier": value => $netapp_size_multiplier; + "${volume_backend_name}/netapp_storage_family": value => $netapp_storage_family; + "${volume_backend_name}/netapp_storage_protocol": value => $netapp_storage_protocol; + "${volume_backend_name}/netapp_transport_type": value => $netapp_transport_type; + "${volume_backend_name}/netapp_vfiler": value => $netapp_vfiler; + "${volume_backend_name}/netapp_volume_list": value => $netapp_volume_list; + "${volume_backend_name}/netapp_vserver": value => $netapp_vserver; + "${volume_backend_name}/expiry_thres_minutes": value => $expiry_thres_minutes; + "${volume_backend_name}/thres_avl_size_perc_start": value => $thres_avl_size_perc_start; + "${volume_backend_name}/thres_avl_size_perc_stop": value => $thres_avl_size_perc_stop; + "${volume_backend_name}/nfs_shares_config": value => $nfs_shares_config; + "${volume_backend_name}/netapp_copyoffload_tool_path": value => $netapp_copyoffload_tool_path; + "${volume_backend_name}/netapp_controller_ips": value => $netapp_controller_ips; + "${volume_backend_name}/netapp_sa_password": value => $netapp_sa_password, secret => true; + "${volume_backend_name}/netapp_storage_pools": value => $netapp_storage_pools; + "${volume_backend_name}/netapp_webservice_path": value => $netapp_webservice_path; + } + + if $netapp_storage_family == 'eseries' { + cinder_config { + "${volume_backend_name}/use_multipath_for_image_xfer": value => true; + } + } +} diff --git a/3rdparty/modules/cinder/manifests/backend/nexenta.pp b/3rdparty/modules/cinder/manifests/backend/nexenta.pp new file mode 100644 index 000000000..0124726ad --- /dev/null +++ b/3rdparty/modules/cinder/manifests/backend/nexenta.pp @@ -0,0 +1,59 @@ +# == Class: cinder::backend::nexenta +# +# Setups Cinder with Nexenta volume driver. +# +# === Parameters +# +# [*nexenta_user*] +# (required) User name to connect to Nexenta SA. +# +# [*nexenta_password*] +# (required) Password to connect to Nexenta SA. +# +# [*nexenta_host*] +# (required) IP address of Nexenta SA. +# +# [*volume_backend_name*] +# (optional) Allows for the volume_backend_name to be separate of $name. +# Defaults to: $name +# +# [*nexenta_volume*] +# (optional) Pool on SA that will hold all volumes. Defaults to 'cinder'. +# +# [*nexenta_target_prefix*] +# (optional) IQN prefix for iSCSI targets. Defaults to 'iqn:'. +# +# [*nexenta_target_group_prefix*] +# (optional) Prefix for iSCSI target groups on SA. Defaults to 'cinder/'. +# +# [*nexenta_blocksize*] +# (optional) Block size for volumes. Defaults to '8k'. +# +# [*nexenta_sparse*] +# (optional) Flag to create sparse volumes. Defaults to true. +# +define cinder::backend::nexenta ( + $nexenta_user, + $nexenta_password, + $nexenta_host, + $volume_backend_name = $name, + $nexenta_volume = 'cinder', + $nexenta_target_prefix = 'iqn:', + $nexenta_target_group_prefix = 'cinder/', + $nexenta_blocksize = '8k', + $nexenta_sparse = true +) { + + cinder_config { + "${name}/volume_backend_name": value => $volume_backend_name; + "${name}/nexenta_user": value => $nexenta_user; + "${name}/nexenta_password": value => $nexenta_password, secret => true; + "${name}/nexenta_host": value => $nexenta_host; + "${name}/nexenta_volume": value => $nexenta_volume; + "${name}/nexenta_target_prefix": value => $nexenta_target_prefix; + "${name}/nexenta_target_group_prefix": value => $nexenta_target_group_prefix; + "${name}/nexenta_blocksize": value => $nexenta_blocksize; + "${name}/nexenta_sparse": value => $nexenta_sparse; + "${name}/volume_driver": value => 'cinder.volume.drivers.nexenta.volume.NexentaDriver'; + } +} diff --git a/3rdparty/modules/cinder/manifests/backend/nfs.pp b/3rdparty/modules/cinder/manifests/backend/nfs.pp new file mode 100644 index 000000000..137f2697d --- /dev/null +++ b/3rdparty/modules/cinder/manifests/backend/nfs.pp @@ -0,0 +1,39 @@ +# ==define cinder::backend::nfs +# +# ===Paramiters +# [*volume_backend_name*] +# (optional) Allows for the volume_backend_name to be separate of $name. +# Defaults to: $name +# +# +define cinder::backend::nfs ( + $volume_backend_name = $name, + $nfs_servers = [], + $nfs_mount_options = undef, + $nfs_disk_util = undef, + $nfs_sparsed_volumes = undef, + $nfs_mount_point_base = undef, + $nfs_shares_config = '/etc/cinder/shares.conf', + $nfs_used_ratio = '0.95', + $nfs_oversub_ratio = '1.0', +) { + + file {$nfs_shares_config: + content => join($nfs_servers, "\n"), + require => Package['cinder'], + notify => Service['cinder-volume'] + } + + cinder_config { + "${name}/volume_backend_name": value => $volume_backend_name; + "${name}/volume_driver": value => + 'cinder.volume.drivers.nfs.NfsDriver'; + "${name}/nfs_shares_config": value => $nfs_shares_config; + "${name}/nfs_mount_options": value => $nfs_mount_options; + "${name}/nfs_disk_util": value => $nfs_disk_util; + "${name}/nfs_sparsed_volumes": value => $nfs_sparsed_volumes; + "${name}/nfs_mount_point_base": value => $nfs_mount_point_base; + "${name}/nfs_used_ratio": value => $nfs_used_ratio; + "${name}/nfs_oversub_ratio": value => $nfs_oversub_ratio; + } +} diff --git a/3rdparty/modules/cinder/manifests/backend/quobyte.pp b/3rdparty/modules/cinder/manifests/backend/quobyte.pp new file mode 100644 index 000000000..234c5334a --- /dev/null +++ b/3rdparty/modules/cinder/manifests/backend/quobyte.pp @@ -0,0 +1,63 @@ +# +# == Class: cinder::backend::quobyte +# +# Configures Cinder to use Quobyte USP as a volume driver +# +# === Parameters +# +# [*quobyte_volume_url*] +# (required) The URL of the Quobyte volume to use. +# Not an array as a Quobyte driver instance supports exactly one volume +# at a time - but you can load the driver more than once. +# Example: quobyte://quobyte.cluster.example.com/volume-name +# +# [*quobyte_client_cfg*] +# (optional) Path to a Quobyte client configuration file. +# This is needed if client certificate authentication is enabled on the +# Quobyte cluster. The config file includes the certificate and key. +# +# [*quobyte_qcow2_volumes*] +# (optional) Boolean if volumes should be created as qcow2 volumes. +# Defaults to True. qcow2 volumes allow snapshots, at the cost of a small +# performance penalty. If False, raw volumes will be used. +# +# [*quobyte_sparsed_volumes*] +# (optional) Boolean if raw volumes should be created as sparse files. +# Defaults to True. Non-sparse volumes may have a very small performance +# benefit, but take a long time to create. +# +# [*quobyte_mount_point_base*] +# (optional) Path where the driver should create mountpoints. +# Defaults to a subdirectory "mnt" under the Cinder state directory. +# +# [*volume_backend_name*] +# (optional) Allows for the volume_backend_name to be separate of $name. +# Defaults to: $name +# +# === Examples +# +# cinder::backend::quobyte { 'quobyte1': +# quobyte_volume_url => 'quobyte://quobyte.cluster.example.com/volume-name', +# } +# +define cinder::backend::quobyte ( + $quobyte_volume_url, + $quobyte_client_cfg = undef, + $quobyte_qcow2_volumes = undef, + $quobyte_sparsed_volumes = undef, + $quobyte_mount_point_base = undef, + $volume_backend_name = $name, +) { + + cinder_config { + "${name}/volume_backend_name": value => $volume_backend_name; + "${name}/volume_driver": value => + 'cinder.volume.drivers.quobyte.QuobyteDriver'; + "${name}/quobyte_volume_url": value => $quobyte_volume_url; + "${name}/quobyte_client_cfg": value => $quobyte_client_cfg; + "${name}/quobyte_qcow2_volumes": value => $quobyte_qcow2_volumes; + "${name}/quobyte_sparsed_volumes": value => $quobyte_sparsed_volumes; + "${name}/quobyte_mount_point_base": value => $quobyte_mount_point_base; + } + +} diff --git a/3rdparty/modules/cinder/manifests/backend/rbd.pp b/3rdparty/modules/cinder/manifests/backend/rbd.pp new file mode 100644 index 000000000..5678940d2 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/backend/rbd.pp @@ -0,0 +1,112 @@ +# == define: cinder::backend::rbd +# +# Setup Cinder to use the RBD driver. +# Compatible for multiple backends +# +# === Parameters +# +# [*rbd_pool*] +# (required) Specifies the pool name for the block device driver. +# +# [*rbd_user*] +# (required) A required parameter to configure OS init scripts and cephx. +# +# [*volume_backend_name*] +# (optional) Allows for the volume_backend_name to be separate of $name. +# Defaults to: $name +# +# [*rbd_ceph_conf*] +# (optional) Path to the ceph configuration file to use +# Defaults to '/etc/ceph/ceph.conf' +# +# [*rbd_flatten_volume_from_snapshot*] +# (optional) Enable flatten volumes created from snapshots. +# Defaults to false +# +# [*rbd_secret_uuid*] +# (optional) A required parameter to use cephx. +# Defaults to false +# +# [*volume_tmp_dir*] +# (optional) Location to store temporary image files if the volume +# driver does not write them directly to the volume +# Defaults to false +# +# [*rbd_max_clone_depth*] +# (optional) Maximum number of nested clones that can be taken of a +# volume before enforcing a flatten prior to next clone. +# A value of zero disables cloning +# Defaults to '5' +# +# [*glance_api_version*] +# (optional) DEPRECATED: Use cinder::glance Class instead. +# Glance API version. (Defaults to '2') +# Setting this parameter cause a duplicate resource declaration +# with cinder::glance +# +define cinder::backend::rbd ( + $rbd_pool, + $rbd_user, + $volume_backend_name = $name, + $rbd_ceph_conf = '/etc/ceph/ceph.conf', + $rbd_flatten_volume_from_snapshot = false, + $rbd_secret_uuid = false, + $volume_tmp_dir = false, + $rbd_max_clone_depth = '5', + # DEPRECATED PARAMETERS + $glance_api_version = undef, +) { + + include cinder::params + + if $glance_api_version { + warning('The glance_api_version parameter is deprecated, use glance_api_version of cinder::glance class instead.') + } + + cinder_config { + "${name}/volume_backend_name": value => $volume_backend_name; + "${name}/volume_driver": value => 'cinder.volume.drivers.rbd.RBDDriver'; + "${name}/rbd_ceph_conf": value => $rbd_ceph_conf; + "${name}/rbd_user": value => $rbd_user; + "${name}/rbd_pool": value => $rbd_pool; + "${name}/rbd_max_clone_depth": value => $rbd_max_clone_depth; + "${name}/rbd_flatten_volume_from_snapshot": value => $rbd_flatten_volume_from_snapshot; + } + + if $rbd_secret_uuid { + cinder_config {"${name}/rbd_secret_uuid": value => $rbd_secret_uuid;} + } else { + cinder_config {"${name}/rbd_secret_uuid": ensure => absent;} + } + + if $volume_tmp_dir { + cinder_config {"${name}/volume_tmp_dir": value => $volume_tmp_dir;} + } else { + cinder_config {"${name}/volume_tmp_dir": ensure => absent;} + } + + case $::osfamily { + 'Debian': { + $override_line = "env CEPH_ARGS=\"--id ${rbd_user}\"" + $override_match = '^env CEPH_ARGS=' + } + 'RedHat': { + $override_line = "export CEPH_ARGS=\"--id ${rbd_user}\"" + $override_match = '^export CEPH_ARGS=' + } + default: { + fail("unsuported osfamily ${::osfamily}, currently Debian and Redhat are the only supported platforms") + } + } + + # Creates an empty file if it doesn't yet exist + ensure_resource('file', $::cinder::params::ceph_init_override, {'ensure' => 'present'}) + + ensure_resource('file_line', 'set initscript env', { + line => $override_line, + path => $::cinder::params::ceph_init_override, + match => $override_match, + notify => Service['cinder-volume'] + }) + +} diff --git a/3rdparty/modules/cinder/manifests/backend/san.pp b/3rdparty/modules/cinder/manifests/backend/san.pp new file mode 100644 index 000000000..4ad000edd --- /dev/null +++ b/3rdparty/modules/cinder/manifests/backend/san.pp @@ -0,0 +1,80 @@ +# == Class: cinder::backend::san +# +# Configures Cinder volume SAN driver. +# Parameters are particular to each volume driver. +# +# === Parameters +# +# [*volume_driver*] +# (required) Setup cinder-volume to use volume driver. +# +# [*volume_backend_name*] +# (optional) Allows for the volume_backend_name to be separate of $name. +# Defaults to: $name +# +# [*san_thin_provision*] +# (optional) Use thin provisioning for SAN volumes? Defaults to true. +# +# [*san_ip*] +# (optional) IP address of SAN controller. +# +# [*san_login*] +# (optional) Username for SAN controller. Defaults to 'admin'. +# +# [*san_password*] +# (optional) Password for SAN controller. +# +# [*san_private_key*] +# (optional) Filename of private key to use for SSH authentication. +# +# [*san_clustername*] +# (optional) Cluster name to use for creating volumes. +# +# [*san_ssh_port*] +# (optional) SSH port to use with SAN. Defaults to 22. +# +# [*san_is_local*] +# (optional) Execute commands locally instead of over SSH +# use if the volume service is running on the SAN device. +# +# [*ssh_conn_timeout*] +# (optional) SSH connection timeout in seconds. Defaults to 30. +# +# [*ssh_min_pool_conn*] +# (optional) Minimum ssh connections in the pool. +# +# [*ssh_min_pool_conn*] +# (optional) Maximum ssh connections in the pool. +# +define cinder::backend::san ( + $volume_driver, + $volume_backend_name = $name, + $san_thin_provision = true, + $san_ip = undef, + $san_login = 'admin', + $san_password = undef, + $san_private_key = undef, + $san_clustername = undef, + $san_ssh_port = 22, + $san_is_local = false, + $ssh_conn_timeout = 30, + $ssh_min_pool_conn = 1, + $ssh_max_pool_conn = 5 +) { + + cinder_config { + "${name}/volume_backend_name": value => $volume_backend_name; + "${name}/volume_driver": value => $volume_driver; + "${name}/san_thin_provision": value => $san_thin_provision; + "${name}/san_ip": value => $san_ip; + "${name}/san_login": value => $san_login; + "${name}/san_password": value => $san_password, secret => true; + "${name}/san_private_key": value => $san_private_key; + "${name}/san_clustername": value => $san_clustername; + "${name}/san_ssh_port": value => $san_ssh_port; + "${name}/san_is_local": value => $san_is_local; + "${name}/ssh_conn_timeout": value => $ssh_conn_timeout; + "${name}/ssh_min_pool_conn": value => $ssh_min_pool_conn; + "${name}/ssh_max_pool_conn": value => $ssh_max_pool_conn; + } +} diff --git a/3rdparty/modules/cinder/manifests/backend/solidfire.pp b/3rdparty/modules/cinder/manifests/backend/solidfire.pp new file mode 100644 index 000000000..81abfe918 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/backend/solidfire.pp @@ -0,0 +1,64 @@ +# == Class: cinder::backend::solidfire +# +# Configures Cinder volume SolidFire driver. +# Parameters are particular to each volume driver. +# +# === Parameters +# +# [*volume_backend_name*] +# (optional) Allows for the volume_backend_name to be separate of $name. +# Defaults to: $name +# +# [*volume_driver*] +# (optional) Setup cinder-volume to use SolidFire volume driver. +# Defaults to 'cinder.volume.drivers.solidfire.SolidFireDriver' +# +# [*san_ip*] +# (required) IP address of SolidFire clusters MVIP. +# +# [*san_login*] +# (required) Username for SolidFire admin account. +# +# [*san_password*] +# (required) Password for SolidFire admin account. +# +# [*sf_emulate_512*] +# (optional) Use 512 byte emulation for volumes. +# Defaults to True +# +# [*sf_allow_tenant_qos*] +# (optional) Allow tenants to specify QoS via volume metadata. +# Defaults to False +# +# [*sf_account_prefix*] +# (optional) Prefix to use when creating tenant accounts on SolidFire Cluster. +# Defaults to None, so account name is simply the tenant-uuid +# +# [*sf_api_port*] +# (optional) Port ID to use to connect to SolidFire API. +# Defaults to 443 +# +define cinder::backend::solidfire( + $san_ip, + $san_login, + $san_password, + $volume_backend_name = $name, + $volume_driver = 'cinder.volume.drivers.solidfire.SolidFireDriver', + $sf_emulate_512 = true, + $sf_allow_tenant_qos = false, + $sf_account_prefix = '', + $sf_api_port = '443' +) { + + cinder_config { + "${name}/volume_backend_name": value => $volume_backend_name; + "${name}/volume_driver": value => $volume_driver; + "${name}/san_ip": value => $san_ip; + "${name}/san_login": value => $san_login; + "${name}/san_password": value => $san_password, secret => true; + "${name}/sf_emulate_512": value => $sf_emulate_512; + "${name}/sf_allow_tenant_qos": value => $sf_allow_tenant_qos; + "${name}/sf_account_prefix": value => $sf_account_prefix; + "${name}/sf_api_port": value => $sf_api_port; + } +} diff --git a/3rdparty/modules/cinder/manifests/backend/vmdk.pp b/3rdparty/modules/cinder/manifests/backend/vmdk.pp new file mode 100644 index 000000000..6ce4dba0c --- /dev/null +++ b/3rdparty/modules/cinder/manifests/backend/vmdk.pp @@ -0,0 +1,87 @@ +# == define: cinder::backend::vmdk +# +# Configure the VMware VMDK driver for cinder. +# +# === Parameters +# +# [*host_ip*] +# The IP address of the VMware vCenter server. +# +# [*host_username*] +# The username for connection to VMware vCenter server. +# +# [*host_password*] +# The password for connection to VMware vCenter server. +# +# [*volume_backend_name*] +# Used to set the volume_backend_name in multiple backends. +# Defaults to $name as passed in the title. +# +# [*api_retry_count*] +# (optional) The number of times we retry on failures, +# e.g., socket error, etc. +# Defaults to 10. +# +# [*$max_object_retrieval*] +# (optional) The maximum number of ObjectContent data objects that should +# be returned in a single result. A positive value will cause +# the operation to suspend the retrieval when the count of +# objects reaches the specified maximum. The server may still +# limit the count to something less than the configured value. +# Any remaining objects may be retrieved with additional requests. +# Defaults to 100. +# +# [*task_poll_interval*] +# (optional) The interval in seconds used for polling of remote tasks. +# Defaults to 5. +# +# [*image_transfer_timeout_secs*] +# (optional) The timeout in seconds for VMDK volume transfer between Cinder and Glance. +# Defaults to 7200. +# +# [*wsdl_location*] +# (optional) VIM Service WSDL Location e.g +# http:///vimService.wsdl. Optional over-ride to +# default location for bug work-arounds. +# Defaults to None. +# +# [*volume_folder*] +# (optional) The name for the folder in the VC datacenter that will contain cinder volumes. +# Defaults to 'cinder-volumes'. +# +define cinder::backend::vmdk ( + $host_ip, + $host_username, + $host_password, + $volume_backend_name = $name, + $volume_folder = 'cinder-volumes', + $api_retry_count = 10, + $max_object_retrieval = 100, + $task_poll_interval = 5, + $image_transfer_timeout_secs = 7200, + $wsdl_location = undef + ) { + + cinder_config { + "${name}/volume_backend_name": value => $volume_backend_name; + "${name}/volume_driver": value => 'cinder.volume.drivers.vmware.vmdk.VMwareVcVmdkDriver'; + "${name}/vmware_host_ip": value => $host_ip; + "${name}/vmware_host_username": value => $host_username; + "${name}/vmware_host_password": value => $host_password, secret => true; + "${name}/vmware_volume_folder": value => $volume_folder; + "${name}/vmware_api_retry_count": value => $api_retry_count; + "${name}/vmware_max_object_retrieval": value => $max_object_retrieval; + "${name}/vmware_task_poll_interval": value => $task_poll_interval; + "${name}/vmware_image_transfer_timeout_secs": value => $image_transfer_timeout_secs; + } + + if $wsdl_location { + cinder_config { + "${name}/vmware_wsdl_location": value => $wsdl_location; + } + } + + package { 'python-suds': + ensure => present + } +} diff --git a/3rdparty/modules/cinder/manifests/backends.pp b/3rdparty/modules/cinder/manifests/backends.pp new file mode 100644 index 000000000..7c6971938 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/backends.pp @@ -0,0 +1,28 @@ +# == Class: cinder::backends +# +# Class to set the enabled_backends list +# +# === Parameters +# +# [*enabled_backends*] +# (required) a list of ini sections to enable. +# This should contain names used in ceph::backend::* resources. +# Example: ['volume1', 'volume2', 'sata3'] +# +# Author: Andrew Woodward +class cinder::backends ( + $enabled_backends = undef, + # DEPRECATED + $default_volume_type = false + ){ + + # Maybe this could be extented to dynamicly find the enabled names + cinder_config { + 'DEFAULT/enabled_backends': value => join($enabled_backends, ','); + } + + if $default_volume_type { + fail('The default_volume_type parameter is deprecated in this class, you should declare it in cinder::api.') + } + +} diff --git a/3rdparty/modules/cinder/manifests/backup.pp b/3rdparty/modules/cinder/manifests/backup.pp new file mode 100644 index 000000000..a8c575a09 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/backup.pp @@ -0,0 +1,84 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Class: cinder::backup +# +# Setup Cinder backup service +# +# === Parameters +# +# [*backup_topic*] +# (optional) The topic volume backup nodes listen on. +# Defaults to 'cinder-backup' +# +# [*backup_manager*] +# (optional) Full class name for the Manager for volume backup. +# Defaults to 'cinder.backup.manager.BackupManager' +# +# [*backup_api_class*] +# (optional) The full class name of the volume backup API class. +# Defaults to 'cinder.backup.api.API' +# +# [*backup_name_template*] +# (optional) Template string to be used to generate backup names. +# Defaults to 'backup-%s' +# + +class cinder::backup ( + $enabled = true, + $package_ensure = 'present', + $backup_topic = 'cinder-backup', + $backup_manager = 'cinder.backup.manager.BackupManager', + $backup_api_class = 'cinder.backup.api.API', + $backup_name_template = 'backup-%s' +) { + + include cinder::params + + Cinder_config<||> ~> Service['cinder-backup'] + + if $::cinder::params::backup_package { + Package['cinder-backup'] -> Cinder_config<||> + Package['cinder-backup'] -> Service['cinder-backup'] + package { 'cinder-backup': + ensure => $package_ensure, + name => $::cinder::params::backup_package, + } + } + + if $enabled { + $ensure = 'running' + } else { + $ensure = 'stopped' + } + + service { 'cinder-backup': + ensure => $ensure, + name => $::cinder::params::backup_service, + enable => $enabled, + hasstatus => true, + require => Package['cinder'], + } + + cinder_config { + 'DEFAULT/backup_topic': value => $backup_topic; + 'DEFAULT/backup_manager': value => $backup_manager; + 'DEFAULT/backup_api_class': value => $backup_api_class; + 'DEFAULT/backup_name_template': value => $backup_name_template; + } + +} diff --git a/3rdparty/modules/cinder/manifests/backup/ceph.pp b/3rdparty/modules/cinder/manifests/backup/ceph.pp new file mode 100644 index 000000000..dac0adc8b --- /dev/null +++ b/3rdparty/modules/cinder/manifests/backup/ceph.pp @@ -0,0 +1,80 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Class: cinder::backup::ceph +# +# Setup Cinder to backup volumes into Ceph +# +# === Parameters +# +# [*backup_driver*] +# (optional) Which cinder backup driver to use +# Defaults to 'cinder.backup.drivers.ceph' +# +# [*backup_ceph_conf*] +# (optional) Ceph config file to use. +# Should be a valid ceph configuration file +# Defaults to '/etc/ceph/ceph.conf' +# +# [*backup_ceph_user*] +# (optional) The Ceph user to connect with. +# Should be a valid user +# Defaults to 'cinder' +# +# [*backup_ceph_chunk_size*] +# (optional) The chunk size in bytes that a backup will be broken into +# before transfer to backup store. +# Should be a valid integer +# Defaults to '134217728' +# +# [*backup_ceph_pool*] +# (optional) The Ceph pool to backup to. +# Should be a valid ceph pool +# Defaults to 'backups' +# +# [*backup_ceph_stripe_unit*] +# (optional) RBD stripe unit to use when creating a backup image. +# Should be a valid integer +# Defaults to '0' +# +# [*backup_ceph_stripe_count*] +# (optional) RBD stripe count to use when creating a backup image. +# Should be a valid integer +# Defaults to '0' +# + +class cinder::backup::ceph ( + $backup_driver = 'cinder.backup.drivers.ceph', + $backup_ceph_conf = '/etc/ceph/ceph.conf', + $backup_ceph_user = 'cinder', + $backup_ceph_chunk_size = '134217728', + $backup_ceph_pool = 'backups', + $backup_ceph_stripe_unit = '0', + $backup_ceph_stripe_count = '0' +) { + + cinder_config { + 'DEFAULT/backup_driver': value => $backup_driver; + 'DEFAULT/backup_ceph_conf': value => $backup_ceph_conf; + 'DEFAULT/backup_ceph_user': value => $backup_ceph_user; + 'DEFAULT/backup_ceph_chunk_size': value => $backup_ceph_chunk_size; + 'DEFAULT/backup_ceph_pool': value => $backup_ceph_pool; + 'DEFAULT/backup_ceph_stripe_unit': value => $backup_ceph_stripe_unit; + 'DEFAULT/backup_ceph_stripe_count': value => $backup_ceph_stripe_count; + } + +} diff --git a/3rdparty/modules/cinder/manifests/backup/swift.pp b/3rdparty/modules/cinder/manifests/backup/swift.pp new file mode 100644 index 000000000..5b1fedfb8 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/backup/swift.pp @@ -0,0 +1,64 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Class: cinder::backup::swift +# +# Setup Cinder to backup volumes into Swift +# +# === Parameters +# +# [*backup_swift_url*] +# (optional) The URL of the Swift endpoint. +# Should be a valid Swift URL +# Defaults to 'http://localhost:8080/v1/AUTH_' +# +# [*backup_swift_container*] +# (optional) The default Swift container to use. +# Defaults to 'volumes_backup' +# +# [*backup_swift_object_size*] +# (optional) The size in bytes of Swift backup objects. +# Defaults to '52428800' +# +# [*backup_swift_retry_attempts*] +# (optional) The number of retries to make for Swift operations. +# Defaults to '3' +# +# [*backup_swift_retry_backoff*] +# (optional) The backoff time in seconds between Swift retries. +# Defaults to '2' +# + +class cinder::backup::swift ( + $backup_driver = 'cinder.backup.drivers.swift', + $backup_swift_url = 'http://localhost:8080/v1/AUTH_', + $backup_swift_container = 'volumes_backup', + $backup_swift_object_size = '52428800', + $backup_swift_retry_attempts = '3', + $backup_swift_retry_backoff = '2' +) { + + cinder_config { + 'DEFAULT/backup_driver': value => $backup_driver; + 'DEFAULT/backup_swift_url': value => $backup_swift_url; + 'DEFAULT/backup_swift_container': value => $backup_swift_container; + 'DEFAULT/backup_swift_object_size': value => $backup_swift_object_size; + 'DEFAULT/backup_swift_retry_attempts': value => $backup_swift_retry_attempts; + 'DEFAULT/backup_swift_retry_backoff': value => $backup_swift_retry_backoff; + } + +} diff --git a/3rdparty/modules/cinder/manifests/ceilometer.pp b/3rdparty/modules/cinder/manifests/ceilometer.pp new file mode 100644 index 000000000..813ea687d --- /dev/null +++ b/3rdparty/modules/cinder/manifests/ceilometer.pp @@ -0,0 +1,22 @@ +# == Class: cinder::ceilometer +# +# Setup Cinder to enable ceilometer can retrieve volume samples +# Ref: http://docs.openstack.org/developer/ceilometer/install/manual.html +# +# === Parameters +# +# [*notification_driver*] +# (option) Driver or drivers to handle sending notifications. +# Notice: rabbit_notifier has been deprecated in Grizzly, use rpc_notifier instead. +# + + +class cinder::ceilometer ( + $notification_driver = 'cinder.openstack.common.notifier.rpc_notifier' +) { + + cinder_config { + 'DEFAULT/notification_driver': value => $notification_driver; + } +} + diff --git a/3rdparty/modules/cinder/manifests/client.pp b/3rdparty/modules/cinder/manifests/client.pp new file mode 100644 index 000000000..1b6ad8226 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/client.pp @@ -0,0 +1,20 @@ +# == Class: cinder::client +# +# Installs Cinder python client. +# +# === Parameters +# +# [*ensure*] +# Ensure state for package. Defaults to 'present'. +# +class cinder::client( + $package_ensure = 'present' +) { + + include cinder::params + + package { 'python-cinderclient': + ensure => $package_ensure, + name => $::cinder::params::client_package, + } +} diff --git a/3rdparty/modules/cinder/manifests/config.pp b/3rdparty/modules/cinder/manifests/config.pp new file mode 100644 index 000000000..0fa29a3e9 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/config.pp @@ -0,0 +1,39 @@ +# == Class: cinder::config +# +# This class is used to manage arbitrary cinder configurations. +# +# === Parameters +# +# [*xxx_config*] +# (optional) Allow configuration of arbitrary cinder configurations. +# The value is an hash of xxx_config resources. Example: +# { 'DEFAULT/foo' => { value => 'fooValue'}, +# 'DEFAULT/bar' => { value => 'barValue'} +# } +# +# In yaml format, Example: +# xxx_config: +# DEFAULT/foo: +# value: fooValue +# DEFAULT/bar: +# value: barValue +# +# [**cinder_config**] +# (optional) Allow configuration of cinder.conf configurations. +# +# [**api_paste_ini_config**] +# (optional) Allow configuration of /etc/cinder/api-paste.ini configurations. +# +# NOTE: The configuration MUST NOT be already handled by this module +# or Puppet catalog compilation will fail with duplicate resources. +# +class cinder::config ( + $cinder_config = {}, + $api_paste_ini_config = {}, +) { + validate_hash($cinder_config) + validate_hash($api_paste_ini_config) + + create_resources('cinder_config', $cinder_config) + create_resources('cinder_api_paste_ini', $api_paste_ini_config) +} diff --git a/3rdparty/modules/cinder/manifests/db/mysql.pp b/3rdparty/modules/cinder/manifests/db/mysql.pp new file mode 100644 index 000000000..3acf5dc4b --- /dev/null +++ b/3rdparty/modules/cinder/manifests/db/mysql.pp @@ -0,0 +1,61 @@ +# The cinder::db::mysql class creates a MySQL database for cinder. +# It must be used on the MySQL server +# +# == Parameters +# +# [*password*] +# password to connect to the database. Mandatory. +# +# [*dbname*] +# name of the database. Optional. Defaults to cinder. +# +# [*user*] +# user to connect to the database. Optional. Defaults to cinder. +# +# [*host*] +# the default source host user is allowed to connect from. +# Optional. Defaults to 'localhost' +# +# [*allowed_hosts*] +# other hosts the user is allowd to connect from. +# Optional. Defaults to undef. +# +# [*charset*] +# the database charset. Optional. Defaults to 'utf8' +# +# [*collate*] +# the database collation. Optional. Defaults to 'utf8_unicode_ci' +# +# [*mysql_module*] +# (optional) Deprecated. Does nothing. +# +class cinder::db::mysql ( + $password, + $dbname = 'cinder', + $user = 'cinder', + $host = '127.0.0.1', + $allowed_hosts = undef, + $charset = 'utf8', + $collate = 'utf8_general_ci', + $cluster_id = 'localzone', + $mysql_module = undef, +) { + + if $mysql_module { + warning('The mysql_module parameter is deprecated. The latest 2.x mysql module will be used.') + } + + validate_string($password) + + ::openstacklib::db::mysql { 'cinder': + user => $user, + password_hash => mysql_password($password), + dbname => $dbname, + host => $host, + charset => $charset, + collate => $collate, + allowed_hosts => $allowed_hosts, + } + + ::Openstacklib::Db::Mysql['cinder'] ~> Exec<| title == 'cinder-manage db_sync' |> +} diff --git a/3rdparty/modules/cinder/manifests/db/postgresql.pp b/3rdparty/modules/cinder/manifests/db/postgresql.pp new file mode 100644 index 000000000..52aa15bb7 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/db/postgresql.pp @@ -0,0 +1,21 @@ +# +# Class that configures postgresql for cinder +# +# Requires the Puppetlabs postgresql module. +class cinder::db::postgresql( + $password, + $dbname = 'cinder', + $user = 'cinder' +) { + + require postgresql::python + + Postgresql::Db[$dbname] ~> Exec<| title == 'cinder-manage db_sync' |> + Package['python-psycopg2'] -> Exec<| title == 'cinder-manage db_sync' |> + + postgresql::db { $dbname: + user => $user, + password => $password, + } + +} diff --git a/3rdparty/modules/cinder/manifests/db/sync.pp b/3rdparty/modules/cinder/manifests/db/sync.pp new file mode 100644 index 000000000..942f25213 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/db/sync.pp @@ -0,0 +1,14 @@ +# +class cinder::db::sync { + + include cinder::params + + exec { 'cinder-manage db_sync': + command => $::cinder::params::db_sync_command, + path => '/usr/bin', + user => 'cinder', + refreshonly => true, + require => [File[$::cinder::params::cinder_conf], Class['cinder']], + logoutput => 'on_failure', + } +} diff --git a/3rdparty/modules/cinder/manifests/glance.pp b/3rdparty/modules/cinder/manifests/glance.pp new file mode 100644 index 000000000..a9f570784 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/glance.pp @@ -0,0 +1,82 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Class: cinder::glance +# +# Glance drive Cinder as a block storage backend to store image data. +# +# === Parameters +# +# [*glance_api_servers*] +# (optional) A list of the glance api servers available to cinder. +# Should be an array with [hostname|ip]:port +# Defaults to undef +# +# [*glance_api_version*] +# (optional) Glance API version. +# Should be 1 or 2 +# Defaults to 2 (current version) +# +# [*glance_num_retries*] +# (optional) Number retries when downloading an image from glance. +# Defaults to 0 +# +# [*glance_api_insecure*] +# (optional) Allow to perform insecure SSL (https) requests to glance. +# Defaults to false +# +# [*glance_api_ssl_compression*] +# (optional) Whether to attempt to negotiate SSL layer compression when +# using SSL (https) requests. Set to False to disable SSL +# layer compression. In some cases disabling this may improve +# data throughput, eg when high network bandwidth is available +# and you are using already compressed image formats such as qcow2. +# Defaults to false +# +# [*glance_request_timeout*] +# (optional) http/https timeout value for glance operations. +# Defaults to undef +# + +class cinder::glance ( + $glance_api_servers = undef, + $glance_api_version = '2', + $glance_num_retries = '0', + $glance_api_insecure = false, + $glance_api_ssl_compression = false, + $glance_request_timeout = undef +) { + + if is_array($glance_api_servers) { + cinder_config { + 'DEFAULT/glance_api_servers': value => join($glance_api_servers, ','); + } + } elsif is_string($glance_api_servers) { + cinder_config { + 'DEFAULT/glance_api_servers': value => $glance_api_servers; + } + } + + cinder_config { + 'DEFAULT/glance_api_version': value => $glance_api_version; + 'DEFAULT/glance_num_retries': value => $glance_num_retries; + 'DEFAULT/glance_api_insecure': value => $glance_api_insecure; + 'DEFAULT/glance_api_ssl_compression': value => $glance_api_ssl_compression; + 'DEFAULT/glance_request_timeout': value => $glance_request_timeout; + } + +} diff --git a/3rdparty/modules/cinder/manifests/init.pp b/3rdparty/modules/cinder/manifests/init.pp new file mode 100644 index 000000000..daddf4e5c --- /dev/null +++ b/3rdparty/modules/cinder/manifests/init.pp @@ -0,0 +1,410 @@ +# +# == Parameters +# [database_connection] +# Url used to connect to database. +# (Optional) Defaults to +# 'sqlite:////var/lib/cinder/cinder.sqlite' +# +# [database_idle_timeout] +# Timeout when db connections should be reaped. +# (Optional) Defaults to 3600. +# +# [database_min_pool_size] +# Minimum number of SQL connections to keep open in a pool. +# (Optional) Defaults to 1. +# +# [database_max_pool_size] +# Maximum number of SQL connections to keep open in a pool. +# (Optional) Defaults to undef. +# +# [database_max_retries] +# Maximum db connection retries during startup. +# Setting -1 implies an infinite retry count. +# (Optional) Defaults to 10. +# +# [database_retry_interval] +# Interval between retries of opening a sql connection. +# (Optional) Defaults to 10. +# +# [database_max_overflow] +# If set, use this value for max_overflow with sqlalchemy. +# (Optional) Defaults to undef. +# +# [*rabbit_use_ssl*] +# (optional) Connect over SSL for RabbitMQ +# Defaults to false +# +# [*kombu_ssl_ca_certs*] +# (optional) SSL certification authority file (valid only if SSL enabled). +# Defaults to undef +# +# [*kombu_ssl_certfile*] +# (optional) SSL cert file (valid only if SSL enabled). +# Defaults to undef +# +# [*kombu_ssl_keyfile*] +# (optional) SSL key file (valid only if SSL enabled). +# Defaults to undef +# +# [*kombu_ssl_version*] +# (optional) SSL version to use (valid only if SSL enabled). +# Valid values are TLSv1, SSLv23 and SSLv3. SSLv2 may be +# available on some distributions. +# Defaults to 'TLSv1' +# +# [amqp_durable_queues] +# Use durable queues in amqp. +# (Optional) Defaults to false. +# +# [use_syslog] +# Use syslog for logging. +# (Optional) Defaults to false. +# +# [log_facility] +# Syslog facility to receive log lines. +# (Optional) Defaults to LOG_USER. +# +# [*log_dir*] +# (optional) Directory where logs should be stored. +# If set to boolean false, it will not log to any directory. +# Defaults to '/var/log/cinder' +# +# [*use_ssl*] +# (optional) Enable SSL on the API server +# Defaults to false, not set +# +# [*cert_file*] +# (optinal) Certificate file to use when starting API server securely +# Defaults to false, not set +# +# [*key_file*] +# (optional) Private key file to use when starting API server securely +# Defaults to false, not set +# +# [*ca_file*] +# (optional) CA certificate file to use to verify connecting clients +# Defaults to false, not set_ +# +# [*mysql_module*] +# (optional) Deprecated. Does nothing. +# +# [*storage_availability_zone*] +# (optional) Availability zone of the node. +# Defaults to 'nova' +# +# [*default_availability_zone*] +# (optional) Default availability zone for new volumes. +# If not set, the storage_availability_zone option value is used as +# the default for new volumes. +# Defaults to false +# +# [sql_connection] +# DEPRECATED +# [sql_idle_timeout] +# DEPRECATED +# +class cinder ( + $database_connection = 'sqlite:////var/lib/cinder/cinder.sqlite', + $database_idle_timeout = '3600', + $database_min_pool_size = '1', + $database_max_pool_size = undef, + $database_max_retries = '10', + $database_retry_interval = '10', + $database_max_overflow = undef, + $rpc_backend = 'cinder.openstack.common.rpc.impl_kombu', + $control_exchange = 'openstack', + $rabbit_host = '127.0.0.1', + $rabbit_port = 5672, + $rabbit_hosts = false, + $rabbit_virtual_host = '/', + $rabbit_userid = 'guest', + $rabbit_password = false, + $rabbit_use_ssl = false, + $kombu_ssl_ca_certs = undef, + $kombu_ssl_certfile = undef, + $kombu_ssl_keyfile = undef, + $kombu_ssl_version = 'TLSv1', + $amqp_durable_queues = false, + $qpid_hostname = 'localhost', + $qpid_port = '5672', + $qpid_username = 'guest', + $qpid_password = false, + $qpid_sasl_mechanisms = false, + $qpid_reconnect = true, + $qpid_reconnect_timeout = 0, + $qpid_reconnect_limit = 0, + $qpid_reconnect_interval_min = 0, + $qpid_reconnect_interval_max = 0, + $qpid_reconnect_interval = 0, + $qpid_heartbeat = 60, + $qpid_protocol = 'tcp', + $qpid_tcp_nodelay = true, + $package_ensure = 'present', + $use_ssl = false, + $ca_file = false, + $cert_file = false, + $key_file = false, + $api_paste_config = '/etc/cinder/api-paste.ini', + $use_syslog = false, + $log_facility = 'LOG_USER', + $log_dir = '/var/log/cinder', + $verbose = false, + $debug = false, + $storage_availability_zone = 'nova', + $default_availability_zone = false, + # DEPRECATED PARAMETERS + $mysql_module = undef, + $sql_connection = undef, + $sql_idle_timeout = undef, +) { + + include cinder::params + + Package['cinder'] -> Cinder_config<||> + Package['cinder'] -> Cinder_api_paste_ini<||> + + if $mysql_module { + warning('The mysql_module parameter is deprecated. The latest 2.x mysql module will be used.') + } + + if $sql_connection { + warning('The sql_connection parameter is deprecated, use database_connection instead.') + $database_connection_real = $sql_connection + } else { + $database_connection_real = $database_connection + } + + if $sql_idle_timeout { + warning('The sql_idle_timeout parameter is deprecated, use database_idle_timeout instead.') + $database_idle_timeout_real = $sql_idle_timeout + } else { + $database_idle_timeout_real = $database_idle_timeout + } + + if $use_ssl { + if !$cert_file { + fail('The cert_file parameter is required when use_ssl is set to true') + } + if !$key_file { + fail('The key_file parameter is required when use_ssl is set to true') + } + } + + # this anchor is used to simplify the graph between cinder components by + # allowing a resource to serve as a point where the configuration of cinder begins + anchor { 'cinder-start': } + + package { 'cinder': + ensure => $package_ensure, + name => $::cinder::params::package_name, + require => Anchor['cinder-start'], + } + + file { $::cinder::params::cinder_conf: + ensure => present, + owner => 'cinder', + group => 'cinder', + mode => '0600', + require => Package['cinder'], + } + + file { $::cinder::params::cinder_paste_api_ini: + ensure => present, + owner => 'cinder', + group => 'cinder', + mode => '0600', + require => Package['cinder'], + } + + if $rpc_backend == 'cinder.openstack.common.rpc.impl_kombu' { + + if ! $rabbit_password { + fail('Please specify a rabbit_password parameter.') + } + + cinder_config { + 'DEFAULT/rabbit_password': value => $rabbit_password, secret => true; + 'DEFAULT/rabbit_userid': value => $rabbit_userid; + 'DEFAULT/rabbit_virtual_host': value => $rabbit_virtual_host; + 'DEFAULT/rabbit_use_ssl': value => $rabbit_use_ssl; + 'DEFAULT/control_exchange': value => $control_exchange; + 'DEFAULT/amqp_durable_queues': value => $amqp_durable_queues; + } + + if $rabbit_hosts { + cinder_config { 'DEFAULT/rabbit_hosts': value => join($rabbit_hosts, ',') } + cinder_config { 'DEFAULT/rabbit_ha_queues': value => true } + cinder_config { 'DEFAULT/rabbit_host': ensure => absent } + cinder_config { 'DEFAULT/rabbit_port': ensure => absent } + } else { + cinder_config { 'DEFAULT/rabbit_host': value => $rabbit_host } + cinder_config { 'DEFAULT/rabbit_port': value => $rabbit_port } + cinder_config { 'DEFAULT/rabbit_hosts': value => "${rabbit_host}:${rabbit_port}" } + cinder_config { 'DEFAULT/rabbit_ha_queues': value => false } + } + + if $rabbit_use_ssl { + cinder_config { 'DEFAULT/kombu_ssl_version': value => $kombu_ssl_version } + + if $kombu_ssl_ca_certs { + cinder_config { 'DEFAULT/kombu_ssl_ca_certs': value => $kombu_ssl_ca_certs } + } else { + cinder_config { 'DEFAULT/kombu_ssl_ca_certs': ensure => absent} + } + + if $kombu_ssl_certfile { + cinder_config { 'DEFAULT/kombu_ssl_certfile': value => $kombu_ssl_certfile } + } else { + cinder_config { 'DEFAULT/kombu_ssl_certfile': ensure => absent} + } + + if $kombu_ssl_keyfile { + cinder_config { 'DEFAULT/kombu_ssl_keyfile': value => $kombu_ssl_keyfile } + } else { + cinder_config { 'DEFAULT/kombu_ssl_keyfile': ensure => absent} + } + } else { + cinder_config { + 'DEFAULT/kombu_ssl_ca_certs': ensure => absent; + 'DEFAULT/kombu_ssl_certfile': ensure => absent; + 'DEFAULT/kombu_ssl_keyfile': ensure => absent; + 'DEFAULT/kombu_ssl_version': ensure => absent; + } + } + + } + + if $rpc_backend == 'cinder.openstack.common.rpc.impl_qpid' { + + if ! $qpid_password { + fail('Please specify a qpid_password parameter.') + } + + cinder_config { + 'DEFAULT/qpid_hostname': value => $qpid_hostname; + 'DEFAULT/qpid_port': value => $qpid_port; + 'DEFAULT/qpid_username': value => $qpid_username; + 'DEFAULT/qpid_password': value => $qpid_password, secret => true; + 'DEFAULT/qpid_reconnect': value => $qpid_reconnect; + 'DEFAULT/qpid_reconnect_timeout': value => $qpid_reconnect_timeout; + 'DEFAULT/qpid_reconnect_limit': value => $qpid_reconnect_limit; + 'DEFAULT/qpid_reconnect_interval_min': value => $qpid_reconnect_interval_min; + 'DEFAULT/qpid_reconnect_interval_max': value => $qpid_reconnect_interval_max; + 'DEFAULT/qpid_reconnect_interval': value => $qpid_reconnect_interval; + 'DEFAULT/qpid_heartbeat': value => $qpid_heartbeat; + 'DEFAULT/qpid_protocol': value => $qpid_protocol; + 'DEFAULT/qpid_tcp_nodelay': value => $qpid_tcp_nodelay; + 'DEFAULT/amqp_durable_queues': value => $amqp_durable_queues; + } + + if is_array($qpid_sasl_mechanisms) { + cinder_config { + 'DEFAULT/qpid_sasl_mechanisms': value => join($qpid_sasl_mechanisms, ' '); + } + } elsif $qpid_sasl_mechanisms { + cinder_config { + 'DEFAULT/qpid_sasl_mechanisms': value => $qpid_sasl_mechanisms; + } + } else { + cinder_config { + 'DEFAULT/qpid_sasl_mechanisms': ensure => absent; + } + } + } + + if ! $default_availability_zone { + $default_availability_zone_real = $storage_availability_zone + } else { + $default_availability_zone_real = $default_availability_zone + } + + cinder_config { + 'database/connection': value => $database_connection_real, secret => true; + 'database/idle_timeout': value => $database_idle_timeout_real; + 'database/min_pool_size': value => $database_min_pool_size; + 'database/max_retries': value => $database_max_retries; + 'database/retry_interval': value => $database_retry_interval; + 'DEFAULT/verbose': value => $verbose; + 'DEFAULT/debug': value => $debug; + 'DEFAULT/api_paste_config': value => $api_paste_config; + 'DEFAULT/rpc_backend': value => $rpc_backend; + 'DEFAULT/storage_availability_zone': value => $storage_availability_zone; + 'DEFAULT/default_availability_zone': value => $default_availability_zone_real; + } + + if $database_max_pool_size { + cinder_config { + 'database/max_pool_size': value => $database_max_pool_size; + } + } else { + cinder_config { + 'database/max_pool_size': ensure => absent; + } + } + + if $database_max_overflow { + cinder_config { + 'database/max_overflow': value => $database_max_overflow; + } + } else { + cinder_config { + 'database/max_overflow': ensure => absent; + } + } + + if($database_connection_real =~ /mysql:\/\/\S+:\S+@\S+\/\S+/) { + require 'mysql::bindings' + require 'mysql::bindings::python' + } elsif($database_connection_real =~ /postgresql:\/\/\S+:\S+@\S+\/\S+/) { + + } elsif($database_connection_real =~ /sqlite:\/\//) { + + } else { + fail("Invalid db connection ${database_connection_real}") + } + + if $log_dir { + cinder_config { + 'DEFAULT/log_dir': value => $log_dir; + } + } else { + cinder_config { + 'DEFAULT/log_dir': ensure => absent; + } + } + + # SSL Options + if $use_ssl { + cinder_config { + 'DEFAULT/ssl_cert_file' : value => $cert_file; + 'DEFAULT/ssl_key_file' : value => $key_file; + } + if $ca_file { + cinder_config { 'DEFAULT/ssl_ca_file' : + value => $ca_file, + } + } else { + cinder_config { 'DEFAULT/ssl_ca_file' : + ensure => absent, + } + } + } else { + cinder_config { + 'DEFAULT/ssl_cert_file' : ensure => absent; + 'DEFAULT/ssl_key_file' : ensure => absent; + 'DEFAULT/ssl_ca_file' : ensure => absent; + } + } + + if $use_syslog { + cinder_config { + 'DEFAULT/use_syslog': value => true; + 'DEFAULT/syslog_log_facility': value => $log_facility; + } + } else { + cinder_config { + 'DEFAULT/use_syslog': value => false; + } + } + +} diff --git a/3rdparty/modules/cinder/manifests/keystone/auth.pp b/3rdparty/modules/cinder/manifests/keystone/auth.pp new file mode 100644 index 000000000..1621d1bdb --- /dev/null +++ b/3rdparty/modules/cinder/manifests/keystone/auth.pp @@ -0,0 +1,137 @@ +# == Class: cinder::keystone::auth +# +# Configures Cinder user, service and endpoint in Keystone. +# +# === Parameters +# +# [*password*] +# Password for Cinder user. Required. +# +# [*email*] +# Email for Cinder user. Optional. Defaults to 'cinder@localhost'. +# +# [*auth_name*] +# Username for Cinder service. Optional. Defaults to 'cinder'. +# +# [*auth_name_v2*] +# Username for Cinder v2 service. Optional. Defaults to 'cinder2'. +# +# [*configure_endpoint*] +# Should Cinder endpoint be configured? Optional. Defaults to 'true'. +# API v1 endpoint should be enabled in Icehouse for compatibility with Nova. +# +# [*configure_endpoint_v2*] +# Should Cinder v2 endpoint be configured? Optional. Defaults to 'true'. +# +# [*configure_user*] +# Should the service user be configured? Optional. Defaults to 'true'. +# +# [*configure_user_role*] +# Should the admin role be configured for the service user? +# Optional. Defaults to 'true'. +# +# [*service_type*] +# Type of service. Optional. Defaults to 'volume'. +# +# [*service_type_v2*] +# Type of API v2 service. Optional. Defaults to 'volume2'. +# +# [*public_address*] +# Public address for endpoint. Optional. Defaults to '127.0.0.1'. +# +# [*admin_address*] +# Admin address for endpoint. Optional. Defaults to '127.0.0.1'. +# +# [*internal_address*] +# Internal address for endpoint. Optional. Defaults to '127.0.0.1'. +# +# [*port*] +# Port for endpoint. Optional. Defaults to '8776'. +# +# [*volume_version*] +# Cinder API version. Optional. Defaults to 'v1'. +# +# [*region*] +# Region for endpoint. Optional. Defaults to 'RegionOne'. +# +# [*tenant*] +# Tenant for Cinder user. Optional. Defaults to 'services'. +# +# [*public_protocol*] +# Protocol for public endpoint. Optional. Defaults to 'http'. +# +# [*internal_protocol*] +# Protocol for internal endpoint. Optional. Defaults to 'http'. +# +# [*admin_protocol*] +# Protocol for admin endpoint. Optional. Defaults to 'http'. +# +class cinder::keystone::auth ( + $password, + $auth_name = 'cinder', + $auth_name_v2 = 'cinderv2', + $email = 'cinder@localhost', + $tenant = 'services', + $configure_endpoint = true, + $configure_endpoint_v2 = true, + $configure_user = true, + $configure_user_role = true, + $service_type = 'volume', + $service_type_v2 = 'volumev2', + $public_address = '127.0.0.1', + $admin_address = '127.0.0.1', + $internal_address = '127.0.0.1', + $port = '8776', + $volume_version = 'v1', + $region = 'RegionOne', + $public_protocol = 'http', + $admin_protocol = 'http', + $internal_protocol = 'http' +) { + + if $configure_user { + keystone_user { $auth_name: + ensure => present, + password => $password, + email => $email, + tenant => $tenant, + } + } + + if $configure_user_role { + Keystone_user_role["${auth_name}@${tenant}"] ~> Service <| name == 'cinder-api' |> + + keystone_user_role { "${auth_name}@${tenant}": + ensure => present, + roles => 'admin', + } + } + + keystone_service { $auth_name: + ensure => present, + type => $service_type, + description => 'Cinder Service', + } + keystone_service { $auth_name_v2: + ensure => present, + type => $service_type_v2, + description => 'Cinder Service v2', + } + + if $configure_endpoint { + keystone_endpoint { "${region}/${auth_name}": + ensure => present, + public_url => "${public_protocol}://${public_address}:${port}/${volume_version}/%(tenant_id)s", + admin_url => "${admin_protocol}://${admin_address}:${port}/${volume_version}/%(tenant_id)s", + internal_url => "${internal_protocol}://${internal_address}:${port}/${volume_version}/%(tenant_id)s", + } + } + if $configure_endpoint_v2 { + keystone_endpoint { "${region}/${auth_name_v2}": + ensure => present, + public_url => "${public_protocol}://${public_address}:${port}/v2/%(tenant_id)s", + admin_url => "${admin_protocol}://${admin_address}:${port}/v2/%(tenant_id)s", + internal_url => "${internal_protocol}://${internal_address}:${port}/v2/%(tenant_id)s", + } + } +} diff --git a/3rdparty/modules/cinder/manifests/logging.pp b/3rdparty/modules/cinder/manifests/logging.pp new file mode 100644 index 000000000..49fb612b4 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/logging.pp @@ -0,0 +1,208 @@ +# Class cinder::logging +# +# cinder extended logging configuration +# +# == parameters +# +# [*logging_context_format_string*] +# (optional) Format string to use for log messages with context. +# Defaults to undef. +# Example: '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s\ +# [%(request_id)s %(user_identity)s] %(instance)s%(message)s' +# +# [*logging_default_format_string*] +# (optional) Format string to use for log messages without context. +# Defaults to undef. +# Example: '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s\ +# [-] %(instance)s%(message)s' +# +# [*logging_debug_format_suffix*] +# (optional) Formatted data to append to log format when level is DEBUG. +# Defaults to undef. +# Example: '%(funcName)s %(pathname)s:%(lineno)d' +# +# [*logging_exception_prefix*] +# (optional) Prefix each line of exception output with this format. +# Defaults to undef. +# Example: '%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s' +# +# [*log_config_append*] +# The name of an additional logging configuration file. +# Defaults to undef. +# See https://docs.python.org/2/howto/logging.html +# +# [*default_log_levels*] +# (optional) Hash of logger (keys) and level (values) pairs. +# Defaults to undef. +# Example: +# { 'amqp' => 'WARN', 'amqplib' => 'WARN', 'boto' => 'WARN', +# 'qpid' => 'WARN', 'sqlalchemy' => 'WARN', 'suds' => 'INFO', +# 'iso8601' => 'WARN', +# 'requests.packages.urllib3.connectionpool' => 'WARN' } +# +# [*publish_errors*] +# (optional) Publish error events (boolean value). +# Defaults to undef (false if unconfigured). +# +# [*fatal_deprecations*] +# (optional) Make deprecations fatal (boolean value) +# Defaults to undef (false if unconfigured). +# +# [*instance_format*] +# (optional) If an instance is passed with the log message, format it +# like this (string value). +# Defaults to undef. +# Example: '[instance: %(uuid)s] ' +# +# [*instance_uuid_format*] +# (optional) If an instance UUID is passed with the log message, format +# it like this (string value). +# Defaults to undef. +# Example: instance_uuid_format='[instance: %(uuid)s] ' + +# [*log_date_format*] +# (optional) Format string for %%(asctime)s in log records. +# Defaults to undef. +# Example: 'Y-%m-%d %H:%M:%S' + +class cinder::logging( + $logging_context_format_string = undef, + $logging_default_format_string = undef, + $logging_debug_format_suffix = undef, + $logging_exception_prefix = undef, + $log_config_append = undef, + $default_log_levels = undef, + $publish_errors = undef, + $fatal_deprecations = undef, + $instance_format = undef, + $instance_uuid_format = undef, + $log_date_format = undef, +) { + + if $logging_context_format_string { + cinder_config { + 'DEFAULT/logging_context_format_string' : + value => $logging_context_format_string; + } + } + else { + cinder_config { + 'DEFAULT/logging_context_format_string' : ensure => absent; + } + } + + if $logging_default_format_string { + cinder_config { + 'DEFAULT/logging_default_format_string' : + value => $logging_default_format_string; + } + } + else { + cinder_config { + 'DEFAULT/logging_default_format_string' : ensure => absent; + } + } + + if $logging_debug_format_suffix { + cinder_config { + 'DEFAULT/logging_debug_format_suffix' : + value => $logging_debug_format_suffix; + } + } + else { + cinder_config { + 'DEFAULT/logging_debug_format_suffix' : ensure => absent; + } + } + + if $logging_exception_prefix { + cinder_config { + 'DEFAULT/logging_exception_prefix' : value => $logging_exception_prefix; + } + } + else { + cinder_config { + 'DEFAULT/logging_exception_prefix' : ensure => absent; + } + } + + if $log_config_append { + cinder_config { + 'DEFAULT/log_config_append' : value => $log_config_append; + } + } + else { + cinder_config { + 'DEFAULT/log_config_append' : ensure => absent; + } + } + + if $default_log_levels { + cinder_config { + 'DEFAULT/default_log_levels' : + value => join(sort(join_keys_to_values($default_log_levels, '=')), ','); + } + } + else { + cinder_config { + 'DEFAULT/default_log_levels' : ensure => absent; + } + } + + if $publish_errors { + cinder_config { + 'DEFAULT/publish_errors' : value => $publish_errors; + } + } + else { + cinder_config { + 'DEFAULT/publish_errors' : ensure => absent; + } + } + + if $fatal_deprecations { + cinder_config { + 'DEFAULT/fatal_deprecations' : value => $fatal_deprecations; + } + } + else { + cinder_config { + 'DEFAULT/fatal_deprecations' : ensure => absent; + } + } + + if $instance_format { + cinder_config { + 'DEFAULT/instance_format' : value => $instance_format; + } + } + else { + cinder_config { + 'DEFAULT/instance_format' : ensure => absent; + } + } + + if $instance_uuid_format { + cinder_config { + 'DEFAULT/instance_uuid_format' : value => $instance_uuid_format; + } + } + else { + cinder_config { + 'DEFAULT/instance_uuid_format' : ensure => absent; + } + } + + if $log_date_format { + cinder_config { + 'DEFAULT/log_date_format' : value => $log_date_format; + } + } + else { + cinder_config { + 'DEFAULT/log_date_format' : ensure => absent; + } + } + + +} diff --git a/3rdparty/modules/cinder/manifests/params.pp b/3rdparty/modules/cinder/manifests/params.pp new file mode 100644 index 000000000..465096348 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/params.pp @@ -0,0 +1,59 @@ +# +class cinder::params { + + $cinder_conf = '/etc/cinder/cinder.conf' + $cinder_paste_api_ini = '/etc/cinder/api-paste.ini' + + if $::osfamily == 'Debian' { + $package_name = 'cinder-common' + $client_package = 'python-cinderclient' + $api_package = 'cinder-api' + $api_service = 'cinder-api' + $backup_package = 'cinder-backup' + $backup_service = 'cinder-backup' + $scheduler_package = 'cinder-scheduler' + $scheduler_service = 'cinder-scheduler' + $volume_package = 'cinder-volume' + $volume_service = 'cinder-volume' + $db_sync_command = 'cinder-manage db sync' + $tgt_package_name = 'tgt' + $tgt_service_name = 'tgt' + $ceph_init_override = '/etc/init/cinder-volume.override' + $iscsi_helper = 'tgtadm' + $lio_package_name = 'targetcli' + + } elsif($::osfamily == 'RedHat') { + + $package_name = 'openstack-cinder' + $client_package = 'python-cinderclient' + $api_package = false + $api_service = 'openstack-cinder-api' + $backup_package = false + $backup_service = 'openstack-cinder-backup' + $scheduler_package = false + $scheduler_service = 'openstack-cinder-scheduler' + $volume_package = false + $volume_service = 'openstack-cinder-volume' + $db_sync_command = 'cinder-manage db sync' + $tgt_package_name = 'scsi-target-utils' + $tgt_service_name = 'tgtd' + $ceph_init_override = '/etc/sysconfig/openstack-cinder-volume' + $lio_package_name = 'targetcli' + + case $::operatingsystem { + 'RedHat', 'CentOS', 'Scientific': { + if $::operatingsystemmajrelease >= 7 { + $iscsi_helper = 'lioadm' + } else { + $iscsi_helper = 'tgtadm' + } + } + default: { + $iscsi_helper = 'lioadm' + } + } + + } else { + fail("unsuported osfamily ${::osfamily}, currently Debian and Redhat are the only supported platforms") + } +} diff --git a/3rdparty/modules/cinder/manifests/policy.pp b/3rdparty/modules/cinder/manifests/policy.pp new file mode 100644 index 000000000..322dd0daa --- /dev/null +++ b/3rdparty/modules/cinder/manifests/policy.pp @@ -0,0 +1,29 @@ +# == Class: cinder::policy +# +# Configure the cinder policies +# +# === Parameters +# +# [*policies*] +# (optional) Set of policies to configure for cinder +# Example : { 'cinder-context_is_admin' => {'context_is_admin' => 'true'}, 'cinder-default' => {'default' => 'rule:admin_or_owner'} } +# Defaults to empty hash. +# +# [*policy_path*] +# (optional) Path to the cinder policy.json file +# Defaults to /etc/cinder/policy.json +# +class cinder::policy ( + $policies = {}, + $policy_path = '/etc/cinder/policy.json', +) { + + validate_hash($policies) + + Openstacklib::Policy::Base { + file_path => $policy_path, + } + + create_resources('openstacklib::policy::base', $policies) + +} diff --git a/3rdparty/modules/cinder/manifests/qpid.pp b/3rdparty/modules/cinder/manifests/qpid.pp new file mode 100644 index 000000000..6b4d29852 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/qpid.pp @@ -0,0 +1,35 @@ +# +# class for installing qpid server for cinder +# +# +class cinder::qpid( + $enabled = true, + $user='guest', + $password='guest', + $file='/var/lib/qpidd/qpidd.sasldb', + $realm='OPENSTACK' +) { + + # only configure cinder after the queue is up + Class['qpid::server'] -> Package<| title == 'cinder' |> + + if ($enabled) { + $service_ensure = 'running' + + qpid_user { $user: + password => $password, + file => $file, + realm => $realm, + provider => 'saslpasswd2', + require => Class['qpid::server'], + } + + } else { + $service_ensure = 'stopped' + } + + class { 'qpid::server': + service_ensure => $service_ensure + } + +} diff --git a/3rdparty/modules/cinder/manifests/quota.pp b/3rdparty/modules/cinder/manifests/quota.pp new file mode 100644 index 000000000..4542d468f --- /dev/null +++ b/3rdparty/modules/cinder/manifests/quota.pp @@ -0,0 +1,34 @@ +# == Class: cinder::quota +# +# Setup and configure Cinder quotas. +# +# === Parameters +# +# [*quota_volumes*] +# (optional) Number of volumes allowed per project. Defaults to 10. +# +# [*quota_snapshots*] +# (optional) Number of volume snapshots allowed per project. Defaults to 10. +# +# [*quota_gigabytes*] +# (optional) Number of volume gigabytes (snapshots are also included) +# allowed per project. Defaults to 1000. +# +# [*quota_driver*] +# (optional) Default driver to use for quota checks. +# Defaults to 'cinder.quota.DbQuotaDriver'. +# +class cinder::quota ( + $quota_volumes = 10, + $quota_snapshots = 10, + $quota_gigabytes = 1000, + $quota_driver = 'cinder.quota.DbQuotaDriver' +) { + + cinder_config { + 'DEFAULT/quota_volumes': value => $quota_volumes; + 'DEFAULT/quota_snapshots': value => $quota_snapshots; + 'DEFAULT/quota_gigabytes': value => $quota_gigabytes; + 'DEFAULT/quota_driver': value => $quota_driver; + } +} diff --git a/3rdparty/modules/cinder/manifests/rabbitmq.pp b/3rdparty/modules/cinder/manifests/rabbitmq.pp new file mode 100644 index 000000000..1c69f3559 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/rabbitmq.pp @@ -0,0 +1,81 @@ +# == Class: cinder::rabbitmq +# +# Installs and manages rabbitmq server for cinder +# +# == 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' +# +# [*port*] +# (optional) The port to use when connecting to Rabbit +# Defaults to '5672' +# +# [*virtual_host*] +# (optional) The virtual host to use when connecting to Rabbit +# Defaults to '/' +# +# [*enabled*] +# (optional) Whether to enable the Rabbit service +# Defaults to false +# +# [*rabbitmq_class*] +# (optional) The rabbitmq puppet class to depend on, +# which is dependent on the puppet-rabbitmq version. +# Use the default for 1.x, use 'rabbitmq' for 3.x +# Defaults to 'rabbitmq::server' +# +class cinder::rabbitmq( + $userid = 'guest', + $password = 'guest', + $port = '5672', + $virtual_host = '/', + $enabled = true, + $rabbitmq_class = 'rabbitmq::server', +) { + + # only configure cinder after the queue is up + Class[$rabbitmq_class] -> Anchor<| title == 'cinder-start' |> + + if ($enabled) { + if $userid == 'guest' { + $delete_guest_user = false + } else { + $delete_guest_user = true + rabbitmq_user { $userid: + admin => true, + password => $password, + provider => 'rabbitmqctl', + require => Class[$rabbitmq_class], + } + # I need to figure out the appropriate permissions + rabbitmq_user_permissions { "${userid}@${virtual_host}": + configure_permission => '.*', + write_permission => '.*', + read_permission => '.*', + provider => 'rabbitmqctl', + }->Anchor<| title == 'cinder-start' |> + } + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + + class { $rabbitmq_class: + service_ensure => $service_ensure, + port => $port, + delete_guest_user => $delete_guest_user, + } + + if ($enabled) { + rabbitmq_vhost { $virtual_host: + provider => 'rabbitmqctl', + require => Class[$rabbitmq_class], + } + } +} diff --git a/3rdparty/modules/cinder/manifests/scheduler.pp b/3rdparty/modules/cinder/manifests/scheduler.pp new file mode 100644 index 000000000..26b1e5854 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/scheduler.pp @@ -0,0 +1,46 @@ +# +class cinder::scheduler ( + $scheduler_driver = false, + $package_ensure = 'present', + $enabled = true, + $manage_service = true +) { + + include cinder::params + + Cinder_config<||> ~> Service['cinder-scheduler'] + Cinder_api_paste_ini<||> ~> Service['cinder-scheduler'] + Exec<| title == 'cinder-manage db_sync' |> ~> Service['cinder-scheduler'] + + if $scheduler_driver { + cinder_config { + 'DEFAULT/scheduler_driver': value => $scheduler_driver; + } + } + + if $::cinder::params::scheduler_package { + Package['cinder-scheduler'] -> Cinder_config<||> + Package['cinder-scheduler'] -> Cinder_api_paste_ini<||> + Package['cinder-scheduler'] -> Service['cinder-scheduler'] + package { 'cinder-scheduler': + ensure => $package_ensure, + name => $::cinder::params::scheduler_package, + } + } + + if $manage_service { + if $enabled { + $ensure = 'running' + } else { + $ensure = 'stopped' + } + } + + service { 'cinder-scheduler': + ensure => $ensure, + name => $::cinder::params::scheduler_service, + enable => $enabled, + hasstatus => true, + require => Package['cinder'], + } +} diff --git a/3rdparty/modules/cinder/manifests/setup_test_volume.pp b/3rdparty/modules/cinder/manifests/setup_test_volume.pp new file mode 100644 index 000000000..e747e101b --- /dev/null +++ b/3rdparty/modules/cinder/manifests/setup_test_volume.pp @@ -0,0 +1,59 @@ +# == Class: cinder::setup_test_volume +# +# Setup a volume group on a loop device for test purposes. +# +# === Parameters +# +# [*volume_name*] +# Volume group name. Defaults to 'cinder-volumes'. +# +# [*size*] +# Volume group size. Defaults to '4G'. +# +# [*loopback_device*] +# Loop device name. Defaults to '/dev/loop2'. +# +# [*volume_path*] +# Volume image location. Defaults to '/var/lib/cinder'. +class cinder::setup_test_volume( + $volume_name = 'cinder-volumes', + $volume_path = '/var/lib/cinder', + $size = '4G', + $loopback_device = '/dev/loop2' +) { + + package { 'lvm2': + ensure => present, + } ~> + + file { $volume_path: + ensure => directory, + owner => 'cinder', + group => 'cinder', + require => Package['cinder'], + } ~> + + exec { "create_${volume_path}/${volume_name}": + command => "dd if=/dev/zero of=\"${volume_path}/${volume_name}\" bs=1 count=0 seek=${size}", + path => ['/bin','/usr/bin','/sbin','/usr/sbin'], + unless => "stat ${volume_path}/${volume_name}", + } ~> + + exec { "losetup ${loopback_device} ${volume_path}/${volume_name}": + path => ['/bin','/usr/bin','/sbin','/usr/sbin'], + refreshonly => true, + } ~> + + exec { "pvcreate ${loopback_device}": + path => ['/bin','/usr/bin','/sbin','/usr/sbin'], + unless => "pvdisplay | grep ${volume_name}", + refreshonly => true, + } ~> + + exec { "vgcreate ${volume_name} ${loopback_device}": + path => ['/bin','/usr/bin','/sbin','/usr/sbin'], + refreshonly => true, + } + +} + diff --git a/3rdparty/modules/cinder/manifests/type.pp b/3rdparty/modules/cinder/manifests/type.pp new file mode 100644 index 000000000..435f9b293 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/type.pp @@ -0,0 +1,81 @@ +# ==Define: cinder::type +# +# Creates cinder type and assigns backends. +# +# === Parameters +# +# [*os_password*] +# (required) The keystone tenant:username password. +# +# [*set_key*] +# (optional) Must be used with set_value. Accepts a single string be used +# as the key in type_set +# +# [*set_value*] +# (optional) Accepts list of strings or singular string. A list of values +# passed to type_set +# +# [*os_tenant_name*] +# (optional) The keystone tenant name. Defaults to 'admin'. +# +# [*os_username*] +# (optional) The keystone user name. Defaults to 'admin. +# +# [*os_auth_url*] +# (optional) The keystone auth url. Defaults to 'http://127.0.0.1:5000/v2.0/'. +# +# [*os_region_name*] +# (optional) The keystone region name. Default is unset. +# +# Author: Andrew Woodward + +define cinder::type ( + $os_password, + $set_key = undef, + $set_value = undef, + $os_tenant_name = 'admin', + $os_username = 'admin', + $os_auth_url = 'http://127.0.0.1:5000/v2.0/', + $os_region_name = undef, + ) { + + $volume_name = $name + +# TODO: (xarses) This should be moved to a ruby provider so that among other +# reasons, the credential discovery magic can occur like in neutron. + + $cinder_env = [ + "OS_TENANT_NAME=${os_tenant_name}", + "OS_USERNAME=${os_username}", + "OS_PASSWORD=${os_password}", + "OS_AUTH_URL=${os_auth_url}", + ] + + if $os_region_name { + $region_env = ["OS_REGION_NAME=${os_region_name}"] + } + else { + $region_env = [] + } + + exec {"cinder type-create ${volume_name}": + command => "cinder type-create ${volume_name}", + unless => "cinder type-list | grep -qP '\\b${volume_name}\\b'", + environment => concat($cinder_env, $region_env), + require => Package['python-cinderclient'], + path => ['/usr/bin', '/bin'], + } + + if ($set_value and $set_key) { + Exec["cinder type-create ${volume_name}"] -> + cinder::type_set { $set_value: + type => $volume_name, + key => $set_key, + os_password => $os_password, + os_tenant_name => $os_tenant_name, + os_username => $os_username, + os_auth_url => $os_auth_url, + os_region_name => $os_region_name, + } + } +} diff --git a/3rdparty/modules/cinder/manifests/type_set.pp b/3rdparty/modules/cinder/manifests/type_set.pp new file mode 100644 index 000000000..5b5745373 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/type_set.pp @@ -0,0 +1,65 @@ +# ==Define: cinder::type_set +# +# Assigns keys after the volume type is set. +# +# === Parameters +# +# [*os_password*] +# (required) The keystone tenant:username password. +# +# [*type*] +# (required) Accepts single name of type to set. +# +# [*key*] +# (required) the key name that we are setting the value for. +# +# [*os_tenant_name*] +# (optional) The keystone tenant name. Defaults to 'admin'. +# +# [*os_username*] +# (optional) The keystone user name. Defaults to 'admin. +# +# [*os_auth_url*] +# (optional) The keystone auth url. Defaults to 'http://127.0.0.1:5000/v2.0/'. +# +# [*os_region_name*] +# (optional) The keystone region name. Default is unset. +# +# Author: Andrew Woodward + + +define cinder::type_set ( + $type, + $key, + $os_password, + $os_tenant_name = 'admin', + $os_username = 'admin', + $os_auth_url = 'http://127.0.0.1:5000/v2.0/', + $os_region_name = undef, + ) { + +# TODO: (xarses) This should be moved to a ruby provider so that among other +# reasons, the credential discovery magic can occur like in neutron. + + $cinder_env = [ + "OS_TENANT_NAME=${os_tenant_name}", + "OS_USERNAME=${os_username}", + "OS_PASSWORD=${os_password}", + "OS_AUTH_URL=${os_auth_url}", + ] + + if $os_region_name { + $region_env = ["OS_REGION_NAME=${os_region_name}"] + } + else { + $region_env = [] + } + + exec {"cinder type-key ${type} set ${key}=${name}": + path => ['/usr/bin', '/bin'], + command => "cinder type-key ${type} set ${key}=${name}", + unless => "cinder extra-specs-list | grep -Eq '\\b${type}\\b.*\\b${key}\\b.*\\b${name}\\b'", + environment => concat($cinder_env, $region_env), + require => Package['python-cinderclient'] + } +} diff --git a/3rdparty/modules/cinder/manifests/vmware.pp b/3rdparty/modules/cinder/manifests/vmware.pp new file mode 100644 index 000000000..b254eaf2d --- /dev/null +++ b/3rdparty/modules/cinder/manifests/vmware.pp @@ -0,0 +1,53 @@ +# ==Define: cinder::vmware +# +# Creates vmdk specific disk file type & clone type. +# +# === Parameters +# +# [*os_password*] +# (required) The keystone tenant:username password. +# +# [*os_tenant_name*] +# (optional) The keystone tenant name. Defaults to 'admin'. +# +# [*os_username*] +# (optional) The keystone user name. Defaults to 'admin. +# +# [*os_auth_url*] +# (optional) The keystone auth url. Defaults to 'http://127.0.0.1:5000/v2.0/'. +# +class cinder::vmware ( + $os_password, + $os_tenant_name = 'admin', + $os_username = 'admin', + $os_auth_url = 'http://127.0.0.1:5000/v2.0/' + ) { + + Cinder::Type { + os_password => $os_password, + os_tenant_name => $os_tenant_name, + os_username => $os_username, + os_auth_url => $os_auth_url + } + + cinder::type {'vmware-thin': + set_value => 'thin', + set_key => 'vmware:vmdk_type' + } + cinder::type {'vmware-thick': + set_value => 'thick', + set_key => 'vmware:vmdk_type' + } + cinder::type {'vmware-eagerZeroedThick': + set_value => 'eagerZeroedThick', + set_key => 'vmware:vmdk_type' + } + cinder::type {'vmware-full': + set_value => 'full', + set_key => 'vmware:clone_type' + } + cinder::type {'vmware-linked': + set_value => 'linked', + set_key => 'vmware:clone_type' + } +} \ No newline at end of file diff --git a/3rdparty/modules/cinder/manifests/volume.pp b/3rdparty/modules/cinder/manifests/volume.pp new file mode 100644 index 000000000..6617991eb --- /dev/null +++ b/3rdparty/modules/cinder/manifests/volume.pp @@ -0,0 +1,40 @@ +# $volume_name_template = volume-%s +class cinder::volume ( + $package_ensure = 'present', + $enabled = true, + $manage_service = true +) { + + include cinder::params + + Cinder_config<||> ~> Service['cinder-volume'] + Cinder_api_paste_ini<||> ~> Service['cinder-volume'] + Exec<| title == 'cinder-manage db_sync' |> ~> Service['cinder-volume'] + + if $::cinder::params::volume_package { + Package['cinder-volume'] -> Cinder_config<||> + Package['cinder-volume'] -> Cinder_api_paste_ini<||> + Package['cinder'] -> Package['cinder-volume'] + Package['cinder-volume'] -> Service['cinder-volume'] + package { 'cinder-volume': + ensure => $package_ensure, + name => $::cinder::params::volume_package, + } + } + + if $manage_service { + if $enabled { + $ensure = 'running' + } else { + $ensure = 'stopped' + } + } + + service { 'cinder-volume': + ensure => $ensure, + name => $::cinder::params::volume_service, + enable => $enabled, + hasstatus => true, + require => Package['cinder'], + } +} diff --git a/3rdparty/modules/cinder/manifests/volume/emc_vnx.pp b/3rdparty/modules/cinder/manifests/volume/emc_vnx.pp new file mode 100644 index 000000000..5c50f176a --- /dev/null +++ b/3rdparty/modules/cinder/manifests/volume/emc_vnx.pp @@ -0,0 +1,50 @@ +# == Class: cinder::volume::emc_enx +# +# Configures Cinder volume EMC VNX driver. +# Parameters are particular to each volume driver. +# +# === Parameters +# +# [*san_ip*] +# (required) IP address of SAN controller. +# +# [*san_password*] +# (required) Password of SAN controller. +# +# [*san_login*] +# (optional) Login of SAN controller. +# Defaults to : 'admin' +# +# [*storage_vnx_pool_name*] +# (required) Storage pool name. +# +# [*default_timeout*] +# (optonal) Default timeout for CLI operations in minutes. +# Defaults to: '10' +# +# [*max_luns_per_storage_group*] +# (optonal) Default max number of LUNs in a storage group. +# Defaults to: '256' +# +class cinder::volume::emc_vnx( + $iscsi_ip_address, + $san_ip, + $san_password, + $storage_vnx_pool_name, + $default_timeout = '10', + $max_luns_per_storage_group = '256', + $package_ensure = 'present', + $san_login = 'admin', +) { + + cinder::backend::emc_vnx { 'DEFAULT': + default_timeout => $default_timeout, + iscsi_ip_address => $iscsi_ip_address, + max_luns_per_storage_group => $max_luns_per_storage_group, + package_ensure => $package_ensure, + san_ip => $san_ip, + san_login => $san_login, + san_password => $san_password, + storage_vnx_pool_name => $storage_vnx_pool_name, + } +} diff --git a/3rdparty/modules/cinder/manifests/volume/eqlx.pp b/3rdparty/modules/cinder/manifests/volume/eqlx.pp new file mode 100644 index 000000000..6c89ec6bd --- /dev/null +++ b/3rdparty/modules/cinder/manifests/volume/eqlx.pp @@ -0,0 +1,74 @@ +# == define: cinder::volume::eqlx +# +# Configure the Dell EqualLogic driver for cinder. +# +# === Parameters +# +# [*san_ip*] +# (required) The IP address of the Dell EqualLogic array. +# +# [*san_login*] +# (required) The account to use for issuing SSH commands. +# +# [*san_password*] +# (required) The password for the specified SSH account. +# +# [*san_thin_provision*] +# (optional) Whether or not to use thin provisioning for volumes. +# Defaults to true +# +# [*eqlx_group_name*] +# (optional) The CLI prompt message without '>'. +# Defaults to 'group-0' +# +# [*eqlx_pool*] +# (optional) The pool in which volumes will be created. +# Defaults to 'default' +# +# [*eqlx_use_chap*] +# (optional) Use CHAP authentification for targets? +# Defaults to false +# +# [*eqlx_chap_login*] +# (optional) An existing CHAP account name. +# Defaults to 'chapadmin' +# +# [*eqlx_chap_password*] +# (optional) The password for the specified CHAP account name. +# Defaults to '12345' +# +# [*eqlx_cli_timeout*] +# (optional) The timeout for the Group Manager cli command execution. +# Defaults to 30 seconds +# +# [*eqlx_cli_max_retries*] +# (optional) The maximum retry count for reconnection. +# Defaults to 5 +# +class cinder::volume::eqlx ( + $san_ip, + $san_login, + $san_password, + $san_thin_provision = true, + $eqlx_group_name = 'group-0', + $eqlx_pool = 'default', + $eqlx_use_chap = false, + $eqlx_chap_login = 'chapadmin', + $eqlx_chap_password = '12345', + $eqlx_cli_timeout = 30, + $eqlx_cli_max_retries = 5, +) { + cinder::backend::eqlx { 'DEFAULT': + san_ip => $san_ip, + san_login => $san_login, + san_password => $san_password, + san_thin_provision => $san_thin_provision, + eqlx_group_name => $eqlx_group_name, + eqlx_pool => $eqlx_pool, + eqlx_use_chap => $eqlx_use_chap, + eqlx_chap_login => $eqlx_chap_login, + eqlx_chap_password => $eqlx_chap_password, + eqlx_cli_timeout => $eqlx_cli_timeout, + eqlx_cli_max_retries => $eqlx_cli_max_retries, + } +} diff --git a/3rdparty/modules/cinder/manifests/volume/glusterfs.pp b/3rdparty/modules/cinder/manifests/volume/glusterfs.pp new file mode 100644 index 000000000..f5de750a6 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/volume/glusterfs.pp @@ -0,0 +1,48 @@ +# +# == Class: cinder::volume::glusterfs +# +# Configures Cinder to use GlusterFS as a volume driver +# +# === Parameters +# +# [*glusterfs_shares*] +# (required) An array of GlusterFS volume locations. +# Must be an array even if there is only one volume. +# +# [*glusterfs_disk_util*] +# Removed in Icehouse. +# +# [*glusterfs_sparsed_volumes*] +# (optional) Whether or not to use sparse (thin) volumes. +# Defaults to undef which uses the driver's default of "true". +# +# [*glusterfs_mount_point_base*] +# (optional) Where to mount the Gluster volumes. +# Defaults to undef which uses the driver's default of "$state_path/mnt". +# +# [*glusterfs_shares_config*] +# (optional) The config file to store the given $glusterfs_shares. +# Defaults to '/etc/cinder/shares.conf' +# +# === Examples +# +# class { 'cinder::volume::glusterfs': +# glusterfs_shares = ['192.168.1.1:/volumes'], +# } +# +class cinder::volume::glusterfs ( + $glusterfs_shares, + $glusterfs_disk_util = false, + $glusterfs_sparsed_volumes = undef, + $glusterfs_mount_point_base = undef, + $glusterfs_shares_config = '/etc/cinder/shares.conf' +) { + + cinder::backend::glusterfs { 'DEFAULT': + glusterfs_shares => $glusterfs_shares, + glusterfs_disk_util => $glusterfs_disk_util, + glusterfs_sparsed_volumes => $glusterfs_sparsed_volumes, + glusterfs_mount_point_base => $glusterfs_mount_point_base, + glusterfs_shares_config => $glusterfs_shares_config, + } +} diff --git a/3rdparty/modules/cinder/manifests/volume/hp3par_iscsi.pp b/3rdparty/modules/cinder/manifests/volume/hp3par_iscsi.pp new file mode 100644 index 000000000..7f622848e --- /dev/null +++ b/3rdparty/modules/cinder/manifests/volume/hp3par_iscsi.pp @@ -0,0 +1,73 @@ +# == Class: cinder::volume::hp3par +# +# Configures Cinder volume HP 3par driver. +# Parameters are particular to each volume driver. +# +# === Parameters +# +# [*volume_driver*] +# (optional) Setup cinder-volume to use HP 3par volume driver. +# Defaults to 'cinder.volume.drivers.san.hp.hp_3par_iscsi.HP3PARISCSIDriver' +# +# [*san_ip*] +# (required) IP address of HP 3par service processor. +# +# [*san_login*] +# (required) Username for HP 3par account. +# +# [*san_password*] +# (required) Password for HP 3par account. +# +# [*hp3par_api_url*] +# (required) url for api access to 3par - expample https://10.x.x.x:8080/api/v1 +# +# [*hp3par_username*] +# (required) Username for HP3par admin user +# +# [*hp3par_password*] +# (required) Password for hp3par_username +# +# [*hp3par_iscsi_ips*] +# (required) iscsi ip addresses for the HP 3par array +# +# [*hp3par_iscsi_chap_enabled*] +# (required) setting to false by default +# +# [*hp3par_snap_cpg*] +# (optional) set to hp3par_cfg by default in the cinder driver +# +# [*hp3par_snapshot_retention*] +# (required) setting to 48 hours as default expiration - ensures snapshot cannot be deleted prior to expiration +# +# [*hp3par_snapshot_expiration*] +# (required) setting to 72 hours as default (must be larger than retention) + +class cinder::volume::hp3par_iscsi( + $hp3par_api_url, + $hp3par_username, + $hp3par_password, + $san_ip, + $san_login, + $san_password, + $volume_driver = 'cinder.volume.drivers.san.hp.hp_3par_iscsi.HP3PARISCSIDriver', + $hp3par_iscsi_ips, + $hp3par_iscsi_chap_enabled = false, + $hp3par_snap_cpg = OpenstackCPG, + $hp3par_snapshot_retention = 48, + $hp3par_snapshot_expiration = 72, +) { + + cinder::backend::hp3par_iscsi { 'DEFAULT': + volume_driver => $volume_driver, + hp3par_username => $hp3par_username, + hp3par_password => $hp3par_password, + san_ip => $san_ip, + san_login => $san_login, + san_password => $san_password, + hp3par_iscsi_ips => $hp3par_iscsi_ips, + hp3par_api_url => $hp3par_api_url, + hp3par_snap_cpg => $hp3par_snap_cpg, + hp3par_snapshot_retention => $hp3par_snapshot_retention, + hp3par_snapshot_expiration => $hp3par_snapshot_expiration, + } +} diff --git a/3rdparty/modules/cinder/manifests/volume/iscsi.pp b/3rdparty/modules/cinder/manifests/volume/iscsi.pp new file mode 100644 index 000000000..e9eb4dad4 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/volume/iscsi.pp @@ -0,0 +1,17 @@ +# +class cinder::volume::iscsi ( + $iscsi_ip_address, + $volume_driver = 'cinder.volume.drivers.lvm.LVMISCSIDriver', + $volume_group = 'cinder-volumes', + $iscsi_helper = $::cinder::params::iscsi_helper, +) { + + include cinder::params + + cinder::backend::iscsi { 'DEFAULT': + iscsi_ip_address => $iscsi_ip_address, + volume_driver => $volume_driver, + volume_group => $volume_group, + iscsi_helper => $iscsi_helper + } +} diff --git a/3rdparty/modules/cinder/manifests/volume/netapp.pp b/3rdparty/modules/cinder/manifests/volume/netapp.pp new file mode 100644 index 000000000..1db840c3b --- /dev/null +++ b/3rdparty/modules/cinder/manifests/volume/netapp.pp @@ -0,0 +1,210 @@ +# == Class: cinder::volume::netapp +# +# Configures Cinder to use the NetApp unified volume driver +# +# === Parameters +# +# [*netapp_login*] +# (required) Administrative user account name used to access the storage +# system. +# +# [*netapp_password*] +# (required) Password for the administrative user account specified in the +# netapp_login parameter. +# +# [*netapp_server_hostname*] +# (required) The hostname (or IP address) for the storage system. +# +# [*netapp_server_port*] +# (optional) The TCP port to use for communication with ONTAPI on the +# storage system. Traditionally, port 80 is used for HTTP and port 443 is +# used for HTTPS; however, this value should be changed if an alternate +# port has been configured on the storage system. +# Defaults to 80 +# +# [*netapp_size_multiplier*] +# (optional) The quantity to be multiplied by the requested volume size to +# ensure enough space is available on the virtual storage server (Vserver) to +# fulfill the volume creation request. +# Defaults to 1.2 +# +# [*netapp_storage_family*] +# (optional) The storage family type used on the storage system; valid values +# are ontap_7mode for using Data ONTAP operating in 7-Mode or ontap_cluster +# for using clustered Data ONTAP. +# Defaults to ontap_cluster +# +# [*netapp_storage_protocol*] +# (optional) The storage protocol to be used on the data path with the storage +# system; valid values are iscsi or nfs. +# Defaults to nfs +# +# [*netapp_transport_type*] +# (optional) The transport protocol used when communicating with ONTAPI on the +# storage system. Valid values are http or https. +# Defaults to http +# +# [*netapp_vfiler*] +# (optional) The vFiler unit on which provisioning of block storage volumes +# will be done. This parameter is only used by the driver when connecting to +# an instance with a storage family of Data ONTAP operating in 7-Mode and the +# storage protocol selected is iSCSI. Only use this parameter when utilizing +# the MultiStore feature on the NetApp storage system. +# Defaults to '' +# +# [*netapp_volume_list*] +# (optional) This parameter is only utilized when the storage protocol is +# configured to use iSCSI. This parameter is used to restrict provisioning to +# the specified controller volumes. Specify the value of this parameter to be +# a comma separated list of NetApp controller volume names to be used for +# provisioning. +# Defaults to '' +# +# [*netapp_vserver*] +# (optional) This parameter specifies the virtual storage server (Vserver) +# name on the storage cluster on which provisioning of block storage volumes +# should occur. If using the NFS storage protocol, this parameter is mandatory +# for storage service catalog support (utilized by Cinder volume type +# extra_specs support). If this parameter is specified, the exports belonging +# to the Vserver will only be used for provisioning in the future. Block +# storage volumes on exports not belonging to the Vserver specified by +# this parameter will continue to function normally. +# Defaults to '' +# +# [*expiry_thres_minutes*] +# (optional) This parameter specifies the threshold for last access time for +# images in the NFS image cache. When a cache cleaning cycle begins, images +# in the cache that have not been accessed in the last M minutes, where M is +# the value of this parameter, will be deleted from the cache to create free +# space on the NFS share. +# Defaults to 720 +# +# [*thres_avl_size_perc_start*] +# (optional) If the percentage of available space for an NFS share has +# dropped below the value specified by this parameter, the NFS image cache +# will be cleaned. +# Defaults to 20 +# +# [*thres_avl_size_perc_stop*] +# (optional) When the percentage of available space on an NFS share has reached the +# percentage specified by this parameter, the driver will stop clearing files +# from the NFS image cache that have not been accessed in the last M +# 'minutes, where M is the value of the expiry_thres_minutes parameter. +# Defaults to 60 +# +# [*nfs_shares*] +# (optional) Array of NFS exports in the form of host:/share; will be written into +# file specified in nfs_shares_config +# Defaults to undef +# +# [*nfs_shares_config*] +# (optional) File with the list of available NFS shares +# Defaults to '/etc/cinder/shares.conf' +# +# [*nfs_mount_options*] +# (optional) Mount options passed to the nfs client. See section +# of the nfs man page for details. +# Defaults to undef +# +# [*netapp_copyoffload_tool_path*] +# (optional) This option specifies the path of the NetApp Copy Offload tool +# binary. Ensure that the binary has execute permissions set which allow the +# effective user of the cinder-volume process to execute the file. +# Defaults to '' +# +# [*netapp_controller_ips*] +# (optional) This option is only utilized when the storage family is +# configured to eseries. This option is used to restrict provisioning to the +# specified controllers. Specify the value of this option to be a comma +# separated list of controller hostnames or IP addresses to be used for +# provisioning. +# Defaults to '' +# +# [*netapp_sa_password*] +# (optional) Password for the NetApp E-Series storage array. +# Defaults to '' +# +# [*netapp_storage_pools*] +# (optional) This option is used to restrict provisioning to the specified +# storage pools. Only dynamic disk pools are currently supported. Specify the +# value of this option to be a comma separated list of disk pool names to be +# used for provisioning. +# Defaults to '' +# +# [*netapp_webservice_path*] +# (optional) This option is used to specify the path to the E-Series proxy +# application on a proxy server. The value is combined with the value of the +# netapp_transport_type, netapp_server_hostname, and netapp_server_port +# options to create the URL used by the driver to connect to the proxy +# application. +# Defaults to '/devmgr/v2' +# +# === Examples +# +# class { 'cinder::volume::netapp': +# netapp_login => 'clusterAdmin', +# netapp_password => 'password', +# netapp_server_hostname => 'netapp.mycorp.com', +# netapp_server_port => '443', +# netapp_transport_type => 'https', +# netapp_vserver => 'openstack-vserver', +# } +# +# === Authors +# +# Bob Callaway +# +# === Copyright +# +# Copyright 2013 NetApp, Inc. +# +class cinder::volume::netapp ( + $netapp_login, + $netapp_password, + $netapp_server_hostname, + $netapp_server_port = '80', + $netapp_size_multiplier = '1.2', + $netapp_storage_family = 'ontap_cluster', + $netapp_storage_protocol = 'nfs', + $netapp_transport_type = 'http', + $netapp_vfiler = '', + $netapp_volume_list = '', + $netapp_vserver = '', + $expiry_thres_minutes = '720', + $thres_avl_size_perc_start = '20', + $thres_avl_size_perc_stop = '60', + $nfs_shares = undef, + $nfs_shares_config = '/etc/cinder/shares.conf', + $netapp_copyoffload_tool_path = '', + $netapp_controller_ips = '', + $netapp_sa_password = '', + $netapp_storage_pools = '', + $netapp_webservice_path = '/devmgr/v2', + $nfs_mount_options = undef, +) { + + cinder::backend::netapp { 'DEFAULT': + netapp_login => $netapp_login, + netapp_password => $netapp_password, + netapp_server_hostname => $netapp_server_hostname, + netapp_server_port => $netapp_server_port, + netapp_size_multiplier => $netapp_size_multiplier, + netapp_storage_family => $netapp_storage_family, + netapp_storage_protocol => $netapp_storage_protocol, + netapp_transport_type => $netapp_transport_type, + netapp_vfiler => $netapp_vfiler, + netapp_volume_list => $netapp_volume_list, + netapp_vserver => $netapp_vserver, + expiry_thres_minutes => $expiry_thres_minutes, + thres_avl_size_perc_start => $thres_avl_size_perc_start, + thres_avl_size_perc_stop => $thres_avl_size_perc_stop, + nfs_shares => $nfs_shares, + nfs_shares_config => $nfs_shares_config, + netapp_copyoffload_tool_path => $netapp_copyoffload_tool_path, + netapp_controller_ips => $netapp_controller_ips, + netapp_sa_password => $netapp_sa_password, + netapp_storage_pools => $netapp_storage_pools, + netapp_webservice_path => $netapp_webservice_path, + nfs_mount_options => $nfs_mount_options, + } +} diff --git a/3rdparty/modules/cinder/manifests/volume/nexenta.pp b/3rdparty/modules/cinder/manifests/volume/nexenta.pp new file mode 100644 index 000000000..6b653d8b8 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/volume/nexenta.pp @@ -0,0 +1,52 @@ +# == Class: cinder::volume::nexenta +# +# Setups Cinder with Nexenta volume driver. +# +# === Parameters +# +# [*nexenta_user*] +# (required) User name to connect to Nexenta SA. +# +# [*nexenta_password*] +# (required) Password to connect to Nexenta SA. +# +# [*nexenta_host*] +# (required) IP address of Nexenta SA. +# +# [*nexenta_volume*] +# (optional) Pool on SA that will hold all volumes. Defaults to 'cinder'. +# +# [*nexenta_target_prefix*] +# (optional) IQN prefix for iSCSI targets. Defaults to 'iqn:'. +# +# [*nexenta_target_group_prefix*] +# (optional) Prefix for iSCSI target groups on SA. Defaults to 'cinder/'. +# +# [*nexenta_blocksize*] +# (optional) Block size for volumes. Defaults to '8k'. +# +# [*nexenta_sparse*] +# (optional) Flag to create sparse volumes. Defaults to true. +# +class cinder::volume::nexenta ( + $nexenta_user, + $nexenta_password, + $nexenta_host, + $nexenta_volume = 'cinder', + $nexenta_target_prefix = 'iqn:', + $nexenta_target_group_prefix = 'cinder/', + $nexenta_blocksize = '8k', + $nexenta_sparse = true +) { + + cinder::backend::nexenta { 'DEFAULT': + nexenta_user => $nexenta_user, + nexenta_password => $nexenta_password, + nexenta_host => $nexenta_host, + nexenta_volume => $nexenta_volume, + nexenta_target_prefix => $nexenta_target_prefix, + nexenta_target_group_prefix => $nexenta_target_group_prefix, + nexenta_blocksize => $nexenta_blocksize, + nexenta_sparse => $nexenta_sparse, + } +} diff --git a/3rdparty/modules/cinder/manifests/volume/nfs.pp b/3rdparty/modules/cinder/manifests/volume/nfs.pp new file mode 100644 index 000000000..53edc2d57 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/volume/nfs.pp @@ -0,0 +1,23 @@ +# +class cinder::volume::nfs ( + $nfs_servers = [], + $nfs_mount_options = undef, + $nfs_disk_util = undef, + $nfs_sparsed_volumes = undef, + $nfs_mount_point_base = undef, + $nfs_shares_config = '/etc/cinder/shares.conf', + $nfs_used_ratio = '0.95', + $nfs_oversub_ratio = '1.0', +) { + + cinder::backend::nfs { 'DEFAULT': + nfs_servers => $nfs_servers, + nfs_mount_options => $nfs_mount_options, + nfs_disk_util => $nfs_disk_util, + nfs_sparsed_volumes => $nfs_sparsed_volumes, + nfs_mount_point_base => $nfs_mount_point_base, + nfs_shares_config => $nfs_shares_config, + nfs_used_ratio => $nfs_used_ratio, + nfs_oversub_ratio => $nfs_oversub_ratio, + } +} diff --git a/3rdparty/modules/cinder/manifests/volume/quobyte.pp b/3rdparty/modules/cinder/manifests/volume/quobyte.pp new file mode 100644 index 000000000..9f045a6c3 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/volume/quobyte.pp @@ -0,0 +1,55 @@ +# +# == Class: cinder::volume::quobyte +# +# Configures Cinder to use Quobyte USP as a volume driver +# +# === Parameters +# +# [*quobyte_volume_url*] +# (required) The URL of the Quobyte volume to use. +# Not an array as a Quobyte driver instance supports exactly one volume +# at a time - but you can load the driver more than once. +# Example: quobyte://quobyte.cluster.example.com/volume-name +# +# [*quobyte_client_cfg*] +# (optional) Path to a Quobyte client configuration file. +# This is needed if client certificate authentication is enabled on the +# Quobyte cluster. The config file includes the certificate and key. +# +# [*quobyte_qcow2_volumes*] +# (optional) Boolean if volumes should be created as qcow2 volumes. +# Defaults to True. qcow2 volumes allow snapshots, at the cost of a small +# performance penalty. If False, raw volumes will be used. +# +# [*quobyte_sparsed_volumes*] +# (optional) Boolean if raw volumes should be created as sparse files. +# Defaults to True. Non-sparse volumes may have a very small performance +# benefit, but take a long time to create. +# +# [*quobyte_mount_point_base*] +# (optional) Path where the driver should create mountpoints. +# Defaults to a subdirectory "mnt" under the Cinder state directory. +# +# === Examples +# +# class { 'cinder::volume::quobyte': +# quobyte_volume_url => 'quobyte://quobyte.cluster.example.com/volume-name', +# } +# +class cinder::volume::quobyte ( + $quobyte_volume_url, + $quobyte_client_cfg = undef, + $quobyte_qcow2_volumes = undef, + $quobyte_sparsed_volumes = undef, + $quobyte_mount_point_base = undef, +) { + + cinder::backend::quobyte { 'DEFAULT': + quobyte_volume_url => $quobyte_volume_url, + quobyte_client_cfg => $quobyte_client_cfg, + quobyte_qcow2_volumes => $quobyte_qcow2_volumes, + quobyte_sparsed_volumes => $quobyte_sparsed_volumes, + quobyte_mount_point_base => $quobyte_mount_point_base, + } + +} diff --git a/3rdparty/modules/cinder/manifests/volume/rbd.pp b/3rdparty/modules/cinder/manifests/volume/rbd.pp new file mode 100644 index 000000000..2a3e2248f --- /dev/null +++ b/3rdparty/modules/cinder/manifests/volume/rbd.pp @@ -0,0 +1,64 @@ +# == Class: cinder::volume::rbd +# +# Setup Cinder to use the RBD driver. +# +# === Parameters +# +# [*rbd_pool*] +# (required) Specifies the pool name for the block device driver. +# +# [*rbd_user*] +# (required) A required parameter to configure OS init scripts and cephx. +# +# [*rbd_ceph_conf*] +# (optional) Path to the ceph configuration file to use +# Defaults to '/etc/ceph/ceph.conf' +# +# [*rbd_flatten_volume_from_snapshot*] +# (optional) Enable flatten volumes created from snapshots. +# Defaults to false +# +# [*rbd_secret_uuid*] +# (optional) A required parameter to use cephx. +# Defaults to false +# +# [*volume_tmp_dir*] +# (optional) Location to store temporary image files if the volume +# driver does not write them directly to the volume +# Defaults to false +# +# [*rbd_max_clone_depth*] +# (optional) Maximum number of nested clones that can be taken of a +# volume before enforcing a flatten prior to next clone. +# A value of zero disables cloning +# Defaults to '5' +# +# [*glance_api_version*] +# (optional) DEPRECATED: Use cinder::glance Class instead. +# Glance API version. (Defaults to '2') +# Setting this parameter cause a duplicate resource declaration +# with cinder::glance +# +class cinder::volume::rbd ( + $rbd_pool, + $rbd_user, + $rbd_ceph_conf = '/etc/ceph/ceph.conf', + $rbd_flatten_volume_from_snapshot = false, + $rbd_secret_uuid = false, + $volume_tmp_dir = false, + $rbd_max_clone_depth = '5', + # DEPRECATED PARAMETERS + $glance_api_version = undef, +) { + + cinder::backend::rbd { 'DEFAULT': + rbd_pool => $rbd_pool, + rbd_user => $rbd_user, + rbd_ceph_conf => $rbd_ceph_conf, + rbd_flatten_volume_from_snapshot => $rbd_flatten_volume_from_snapshot, + rbd_secret_uuid => $rbd_secret_uuid, + volume_tmp_dir => $volume_tmp_dir, + rbd_max_clone_depth => $rbd_max_clone_depth, + glance_api_version => $glance_api_version, + } +} diff --git a/3rdparty/modules/cinder/manifests/volume/san.pp b/3rdparty/modules/cinder/manifests/volume/san.pp new file mode 100644 index 000000000..a787cd948 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/volume/san.pp @@ -0,0 +1,74 @@ +# == Class: cinder::volume::san +# +# Configures Cinder volume SAN driver. +# Parameters are particular to each volume driver. +# +# === Parameters +# +# [*volume_driver*] +# (required) Setup cinder-volume to use volume driver. +# +# [*san_thin_provision*] +# (optional) Use thin provisioning for SAN volumes? Defaults to true. +# +# [*san_ip*] +# (optional) IP address of SAN controller. +# +# [*san_login*] +# (optional) Username for SAN controller. Defaults to 'admin'. +# +# [*san_password*] +# (optional) Password for SAN controller. +# +# [*san_private_key*] +# (optional) Filename of private key to use for SSH authentication. +# +# [*san_clustername*] +# (optional) Cluster name to use for creating volumes. +# +# [*san_ssh_port*] +# (optional) SSH port to use with SAN. Defaults to 22. +# +# [*san_is_local*] +# (optional) Execute commands locally instead of over SSH +# use if the volume service is running on the SAN device. +# +# [*ssh_conn_timeout*] +# (optional) SSH connection timeout in seconds. Defaults to 30. +# +# [*ssh_min_pool_conn*] +# (optional) Minimum ssh connections in the pool. +# +# [*ssh_min_pool_conn*] +# (optional) Maximum ssh connections in the pool. +# +class cinder::volume::san ( + $volume_driver, + $san_thin_provision = true, + $san_ip = undef, + $san_login = 'admin', + $san_password = undef, + $san_private_key = undef, + $san_clustername = undef, + $san_ssh_port = 22, + $san_is_local = false, + $ssh_conn_timeout = 30, + $ssh_min_pool_conn = 1, + $ssh_max_pool_conn = 5 +) { + + cinder::backend::san { 'DEFAULT': + volume_driver => $volume_driver, + san_thin_provision => $san_thin_provision, + san_ip => $san_ip, + san_login => $san_login, + san_password => $san_password, + san_private_key => $san_private_key, + san_clustername => $san_clustername, + san_ssh_port => $san_ssh_port, + san_is_local => $san_is_local, + ssh_conn_timeout => $ssh_conn_timeout, + ssh_min_pool_conn => $ssh_min_pool_conn, + ssh_max_pool_conn => $ssh_max_pool_conn, + } +} diff --git a/3rdparty/modules/cinder/manifests/volume/solidfire.pp b/3rdparty/modules/cinder/manifests/volume/solidfire.pp new file mode 100644 index 000000000..4b2d8ef34 --- /dev/null +++ b/3rdparty/modules/cinder/manifests/volume/solidfire.pp @@ -0,0 +1,58 @@ +# == Class: cinder::volume::solidfire +# +# Configures Cinder volume SolidFire driver. +# Parameters are particular to each volume driver. +# +# === Parameters +# +# [*volume_driver*] +# (optional) Setup cinder-volume to use SolidFire volume driver. +# Defaults to 'cinder.volume.drivers.solidfire.SolidFireDriver' +# +# [*san_ip*] +# (required) IP address of SolidFire clusters MVIP. +# +# [*san_login*] +# (required) Username for SolidFire admin account. +# +# [*san_password*] +# (required) Password for SolidFire admin account. +# +# [*sf_emulate_512*] +# (optional) Use 512 byte emulation for volumes. +# Defaults to True +# +# [*sf_allow_tenant_qos*] +# (optional) Allow tenants to specify QoS via volume metadata. +# Defaults to False +# +# [*sf_account_prefix*] +# (optional) Prefix to use when creating tenant accounts on SolidFire Cluster. +# Defaults to None, so account name is simply the tenant-uuid +# +# [*sf_api_port*] +# (optional) Port ID to use to connect to SolidFire API. +# Defaults to 443 +# +class cinder::volume::solidfire( + $san_ip, + $san_login, + $san_password, + $volume_driver = 'cinder.volume.drivers.solidfire.SolidFireDriver', + $sf_emulate_512 = true, + $sf_allow_tenant_qos = false, + $sf_account_prefix = '', + $sf_api_port = '443' +) { + + cinder::backend::solidfire { 'DEFAULT': + san_ip => $san_ip, + san_login => $san_login, + san_password => $san_password, + volume_driver => $volume_driver, + sf_emulate_512 => $sf_emulate_512, + sf_allow_tenant_qos => $sf_allow_tenant_qos, + sf_account_prefix => $sf_account_prefix, + sf_api_port => $sf_api_port, + } +} diff --git a/3rdparty/modules/cinder/manifests/volume/vmdk.pp b/3rdparty/modules/cinder/manifests/volume/vmdk.pp new file mode 100644 index 000000000..f9a6b10cf --- /dev/null +++ b/3rdparty/modules/cinder/manifests/volume/vmdk.pp @@ -0,0 +1,72 @@ +# == define: cinder::volume::vmdk +# +# Configure the VMware VMDK driver for cinder. +# +# === Parameters +# +# [*host_ip*] +# The IP address of the VMware vCenter server. +# +# [*host_username*] +# The username for connection to VMware vCenter server. +# +# [*host_password*] +# The password for connection to VMware vCenter server. +# +# [*api_retry_count*] +# (optional) The number of times we retry on failures, +# e.g., socket error, etc. +# Defaults to 10. +# +# [*max_object_retrieval*] +# (optional) The maximum number of ObjectContent data objects that should +# be returned in a single result. A positive value will cause +# the operation to suspend the retrieval when the count of +# objects reaches the specified maximum. The server may still +# limit the count to something less than the configured value. +# Any remaining objects may be retrieved with additional requests. +# Defaults to 100. +# +# [*task_poll_interval*] +# (optional) The interval in seconds used for polling of remote tasks. +# Defaults to 5. +# +# [*image_transfer_timeout_secs*] +# (optional) The timeout in seconds for VMDK volume transfer between Cinder and Glance. +# Defaults to 7200. +# +# [*wsdl_location*] +# (optional) VIM Service WSDL Location e.g +# http:///vimService.wsdl. Optional over-ride to +# default location for bug work-arounds. +# Defaults to None. +# +# [*volume_folder*] +# (optional) The name for the folder in the VC datacenter that will contain cinder volumes. +# Defaults to 'cinder-volumes'. +# + +class cinder::volume::vmdk( + $host_ip, + $host_username, + $host_password, + $volume_folder = 'cinder-volumes', + $api_retry_count = 10, + $max_object_retrieval = 100, + $task_poll_interval = 5, + $image_transfer_timeout_secs = 7200, + $wsdl_location = undef +) { + + cinder::backend::vmdk { 'DEFAULT': + host_ip => $host_ip, + host_username => $host_username, + host_password => $host_password, + volume_folder => $volume_folder, + api_retry_count => $api_retry_count, + max_object_retrieval => $max_object_retrieval, + task_poll_interval => $task_poll_interval, + image_transfer_timeout_secs => $image_transfer_timeout_secs, + wsdl_location => $wsdl_location, + } +} diff --git a/3rdparty/modules/cinder/metadata.json b/3rdparty/modules/cinder/metadata.json new file mode 100644 index 000000000..3e7293b88 --- /dev/null +++ b/3rdparty/modules/cinder/metadata.json @@ -0,0 +1,57 @@ +{ + "name": "stackforge-cinder", + "version": "5.1.0", + "author": "Puppet Labs and OpenStack Contributors", + "summary": "Puppet module for OpenStack Cinder", + "license": "Apache-2.0", + "source": "git://github.com/openstack/puppet-cinder.git", + "project_page": "https://launchpad.net/puppet-cinder", + "issues_url": "https://bugs.launchpad.net/puppet-cinder", + "dependencies": [ + {"name":"dprince/qpid","version_requirement":">=1.0.0 <2.0.0"}, + {"name":"puppetlabs/inifile","version_requirement":">=1.0.0 <2.0.0"}, + {"name":"stackforge/keystone","version_requirement":">=5.0.0 <6.0.0"}, + {"name":"puppetlabs/rabbitmq","version_requirement":">=2.0.2 <4.0.0"}, + {"name":"puppetlabs/stdlib","version_requirement":">=4.0.0 <5.0.0"}, + {"name":"stackforge/openstacklib","version_requirement":">=5.0.0 <6.0.0"} + ], + "requirements": [ + { + "name": "pe", + "version_requirement": "3.x" + }, + { + "name": "puppet", + "version_requirement": "3.x" + } + ], + "operatingsystem_support": [ + { + "operatingsystem": "Debian", + "operatingsystemrelease": [ + "7" + ] + }, + { + "operatingsystem": "Fedora", + "operatingsystemrelease": [ + "20" + ] + }, + { + "operatingsystem": "RedHat", + "operatingsystemrelease": [ + "6.5", + "7" + ] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": [ + "12.04", + "14.04" + ] + } + ], + "description": "Installs and configures OpenStack Cinder (Block Storage)." +} diff --git a/3rdparty/modules/cinder/spec/classes/cinder_api_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_api_spec.rb new file mode 100644 index 000000000..173386ee6 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_api_spec.rb @@ -0,0 +1,226 @@ +require 'spec_helper' + +describe 'cinder::api' do + + let :req_params do + {:keystone_password => 'foo'} + end + let :facts do + {:osfamily => 'Debian', + :processorcount => 8 } + end + + describe 'with only required params' do + let :params do + req_params + end + + it { should contain_service('cinder-api').with( + 'hasstatus' => true, + 'ensure' => 'running' + )} + + it 'should configure cinder api correctly' do + should contain_cinder_config('DEFAULT/auth_strategy').with( + :value => 'keystone' + ) + should contain_cinder_config('DEFAULT/osapi_volume_listen').with( + :value => '0.0.0.0' + ) + should contain_cinder_config('DEFAULT/osapi_volume_workers').with( + :value => '8' + ) + should contain_cinder_config('DEFAULT/default_volume_type').with( + :ensure => 'absent' + ) + should contain_cinder_api_paste_ini('filter:authtoken/service_protocol').with( + :value => 'http' + ) + should contain_cinder_api_paste_ini('filter:authtoken/service_host').with( + :value => 'localhost' + ) + should contain_cinder_api_paste_ini('filter:authtoken/service_port').with( + :value => '5000' + ) + should contain_cinder_api_paste_ini('filter:authtoken/auth_protocol').with( + :value => 'http' + ) + should contain_cinder_api_paste_ini('filter:authtoken/auth_host').with( + :value => 'localhost' + ) + should contain_cinder_api_paste_ini('filter:authtoken/auth_port').with( + :value => '35357' + ) + should contain_cinder_api_paste_ini('filter:authtoken/auth_admin_prefix').with( + :ensure => 'absent' + ) + should contain_cinder_api_paste_ini('filter:authtoken/admin_tenant_name').with( + :value => 'services' + ) + should contain_cinder_api_paste_ini('filter:authtoken/admin_user').with( + :value => 'cinder' + ) + should contain_cinder_api_paste_ini('filter:authtoken/admin_password').with( + :value => 'foo', + :secret => true + ) + + should contain_cinder_api_paste_ini('filter:authtoken/auth_uri').with( + :value => 'http://localhost:5000/' + ) + + should_not contain_cinder_config('DEFAULT/os_region_name') + end + end + + describe 'with a custom region for nova' do + let :params do + req_params.merge({'os_region_name' => 'MyRegion'}) + end + it 'should configure the region for nova' do + should contain_cinder_config('DEFAULT/os_region_name').with( + :value => 'MyRegion' + ) + end + end + + describe 'with a default volume type' do + let :params do + req_params.merge({'default_volume_type' => 'foo'}) + end + it 'should configure the default volume type for cinder' do + should contain_cinder_config('DEFAULT/default_volume_type').with( + :value => 'foo' + ) + end + end + + describe 'with custom auth_uri' do + let :params do + req_params.merge({'keystone_auth_uri' => 'http://foo.bar:8080/v2.0/'}) + end + it 'should configure cinder auth_uri correctly' do + should contain_cinder_api_paste_ini('filter:authtoken/auth_uri').with( + :value => 'http://foo.bar:8080/v2.0/' + ) + end + end + + describe 'with only required params' do + let :params do + req_params.merge({'bind_host' => '192.168.1.3'}) + end + it 'should configure cinder api correctly' do + should contain_cinder_config('DEFAULT/osapi_volume_listen').with( + :value => '192.168.1.3' + ) + end + end + + [ '/keystone', '/keystone/admin', '' ].each do |keystone_auth_admin_prefix| + describe "with keystone_auth_admin_prefix containing incorrect value #{keystone_auth_admin_prefix}" do + let :params do + { + :keystone_auth_admin_prefix => keystone_auth_admin_prefix, + :keystone_password => 'dummy' + } + end + + it { should contain_cinder_api_paste_ini('filter:authtoken/auth_admin_prefix').with( + :value => keystone_auth_admin_prefix + )} + end + end + + [ + '/keystone/', + 'keystone/', + 'keystone', + '/keystone/admin/', + 'keystone/admin/', + 'keystone/admin' + ].each do |keystone_auth_admin_prefix| + describe "with keystone_auth_admin_prefix containing incorrect value #{keystone_auth_admin_prefix}" do + let :params do + { + :keystone_auth_admin_prefix => keystone_auth_admin_prefix, + :keystone_password => 'dummy' + } + end + + it { expect { should contain_cinder_api_paste_ini('filter:authtoken/auth_admin_prefix') }.to \ + raise_error(Puppet::Error, /validate_re\(\): "#{keystone_auth_admin_prefix}" does not match/) } + end + end + + describe 'with enabled false' do + let :params do + req_params.merge({'enabled' => false}) + end + it 'should stop the service' do + should contain_service('cinder-api').with_ensure('stopped') + end + it 'should contain db_sync exec' do + should_not contain_exec('cinder-manage db_sync') + end + end + + describe 'with manage_service false' do + let :params do + req_params.merge({'manage_service' => false}) + end + it 'should not change the state of the service' do + should contain_service('cinder-api').without_ensure + end + end + + describe 'with ratelimits' do + let :params do + req_params.merge({ :ratelimits => '(GET, "*", .*, 100, MINUTE);(POST, "*", .*, 200, MINUTE)' }) + end + + it { should contain_cinder_api_paste_ini('filter:ratelimit/limits').with( + :value => '(GET, "*", .*, 100, MINUTE);(POST, "*", .*, 200, MINUTE)' + )} + end + + describe 'while validating the service with default command' do + let :params do + req_params.merge({ + :validate => true, + }) + end + it { should contain_exec('execute cinder-api validation').with( + :path => '/usr/bin:/bin:/usr/sbin:/sbin', + :provider => 'shell', + :tries => '10', + :try_sleep => '2', + :command => 'cinder --os-auth-url http://localhost:5000/ --os-tenant-name services --os-username cinder --os-password foo list', + )} + + it { should contain_anchor('create cinder-api anchor').with( + :require => 'Exec[execute cinder-api validation]', + )} + end + + describe 'while validating the service with custom command' do + let :params do + req_params.merge({ + :validate => true, + :validation_options => { 'cinder-api' => { 'command' => 'my-script' } } + }) + end + it { should contain_exec('execute cinder-api validation').with( + :path => '/usr/bin:/bin:/usr/sbin:/sbin', + :provider => 'shell', + :tries => '10', + :try_sleep => '2', + :command => 'my-script', + )} + + it { should contain_anchor('create cinder-api anchor').with( + :require => 'Exec[execute cinder-api validation]', + )} + end + +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_backends_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_backends_spec.rb new file mode 100644 index 000000000..de990d028 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_backends_spec.rb @@ -0,0 +1,83 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Unit tests for cinder::backends class +# + +require 'spec_helper' + +describe 'cinder::backends' do + + let :default_params do + {} + end + + let :params do + {} + end + + shared_examples_for 'cinder backends' do + + let :p do + default_params.merge(params) + end + + context 'configure cinder with default parameters' do + before :each do + params.merge!( + :enabled_backends => ['lowcost', 'regular', 'premium'], + :default_volume_type => false + ) + end + + it 'configures cinder.conf with default params' do + should contain_cinder_config('DEFAULT/enabled_backends').with_value(p[:enabled_backends].join(',')) + end + end + + context 'configure cinder with a default volume type' do + before :each do + params.merge!( + :enabled_backends => ['foo', 'bar'], + :default_volume_type => 'regular' + ) + end + + it 'should fail to configure default volume type' do + expect { subject }.to raise_error(Puppet::Error, /The default_volume_type parameter is deprecated in this class, you should declare it in cinder::api./) + end + end + + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'cinder backends' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'cinder backends' + end + +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_backup_ceph_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_backup_ceph_spec.rb new file mode 100644 index 000000000..8c3a55218 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_backup_ceph_spec.rb @@ -0,0 +1,89 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Unit tests for cinder::ceph class +# + +require 'spec_helper' + +describe 'cinder::backup::ceph' do + + let :default_params do + { :backup_ceph_conf => '/etc/ceph/ceph.conf', + :backup_ceph_user => 'cinder', + :backup_ceph_chunk_size => '134217728', + :backup_ceph_pool => 'backups', + :backup_ceph_stripe_unit => '0', + :backup_ceph_stripe_count => '0' } + end + + let :params do + {} + end + + shared_examples_for 'cinder backup with ceph' do + let :p do + default_params.merge(params) + end + + it 'configures cinder.conf' do + should contain_cinder_config('DEFAULT/backup_driver').with_value('cinder.backup.drivers.ceph') + should contain_cinder_config('DEFAULT/backup_ceph_conf').with_value(p[:backup_ceph_conf]) + should contain_cinder_config('DEFAULT/backup_ceph_user').with_value(p[:backup_ceph_user]) + should contain_cinder_config('DEFAULT/backup_ceph_chunk_size').with_value(p[:backup_ceph_chunk_size]) + should contain_cinder_config('DEFAULT/backup_ceph_pool').with_value(p[:backup_ceph_pool]) + should contain_cinder_config('DEFAULT/backup_ceph_stripe_unit').with_value(p[:backup_ceph_stripe_unit]) + should contain_cinder_config('DEFAULT/backup_ceph_stripe_count').with_value(p[:backup_ceph_stripe_count]) + end + + context 'when overriding default parameters' do + before :each do + params.merge!(:backup_ceph_conf => '/tmp/ceph.conf') + params.merge!(:backup_ceph_user => 'toto') + params.merge!(:backup_ceph_chunk_size => '123') + params.merge!(:backup_ceph_pool => 'foo') + params.merge!(:backup_ceph_stripe_unit => '56') + params.merge!(:backup_ceph_stripe_count => '67') + end + it 'should replace default parameters with new values' do + should contain_cinder_config('DEFAULT/backup_ceph_conf').with_value(p[:backup_ceph_conf]) + should contain_cinder_config('DEFAULT/backup_ceph_user').with_value(p[:backup_ceph_user]) + should contain_cinder_config('DEFAULT/backup_ceph_chunk_size').with_value(p[:backup_ceph_chunk_size]) + should contain_cinder_config('DEFAULT/backup_ceph_pool').with_value(p[:backup_ceph_pool]) + should contain_cinder_config('DEFAULT/backup_ceph_stripe_unit').with_value(p[:backup_ceph_stripe_unit]) + should contain_cinder_config('DEFAULT/backup_ceph_stripe_count').with_value(p[:backup_ceph_stripe_count]) + end + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'cinder backup with ceph' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'cinder backup with ceph' + end + +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_backup_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_backup_spec.rb new file mode 100644 index 000000000..0f632ccb3 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_backup_spec.rb @@ -0,0 +1,101 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Unit tests for cinder::backup class +# + +require 'spec_helper' + +describe 'cinder::backup' do + + let :default_params do + { :enable => true, + :backup_topic => 'cinder-backup', + :backup_manager => 'cinder.backup.manager.BackupManager', + :backup_api_class => 'cinder.backup.api.API', + :backup_name_template => 'backup-%s' } + end + + let :params do + {} + end + + shared_examples_for 'cinder backup' do + let :p do + default_params.merge(params) + end + + it { should contain_class('cinder::params') } + + it 'installs cinder backup package' do + if platform_params.has_key?(:backup_package) + should contain_package('cinder-backup').with( + :name => platform_params[:backup_package], + :ensure => 'present' + ) + should contain_package('cinder-backup').with_before(/Cinder_config\[.+\]/) + should contain_package('cinder-backup').with_before(/Service\[cinder-backup\]/) + end + end + + it 'ensure cinder backup service is running' do + should contain_service('cinder-backup').with('hasstatus' => true) + end + + it 'configures cinder.conf' do + should contain_cinder_config('DEFAULT/backup_topic').with_value(p[:backup_topic]) + should contain_cinder_config('DEFAULT/backup_manager').with_value(p[:backup_manager]) + should contain_cinder_config('DEFAULT/backup_api_class').with_value(p[:backup_api_class]) + should contain_cinder_config('DEFAULT/backup_name_template').with_value(p[:backup_name_template]) + end + + context 'when overriding backup_name_template' do + before :each do + params.merge!(:backup_name_template => 'foo-bar-%s') + end + it 'should replace default parameter with new value' do + should contain_cinder_config('DEFAULT/backup_name_template').with_value(p[:backup_name_template]) + end + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { :backup_package => 'cinder-backup', + :backup_service => 'cinder-backup' } + end + + it_configures 'cinder backup' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :backup_service => 'cinder-backup' } + end + + it_configures 'cinder backup' + end + +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_backup_swift_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_backup_swift_spec.rb new file mode 100644 index 000000000..dae1bd61d --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_backup_swift_spec.rb @@ -0,0 +1,85 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Unit tests for cinder::backup::swift class +# + +require 'spec_helper' + +describe 'cinder::backup::swift' do + + let :default_params do + { :backup_swift_url => 'http://localhost:8080/v1/AUTH_', + :backup_swift_container => 'volumes_backup', + :backup_swift_object_size => '52428800', + :backup_swift_retry_attempts => '3', + :backup_swift_retry_backoff => '2' } + end + + let :params do + {} + end + + shared_examples_for 'cinder backup with swift' do + let :p do + default_params.merge(params) + end + + it 'configures cinder.conf' do + should contain_cinder_config('DEFAULT/backup_driver').with_value('cinder.backup.drivers.swift') + should contain_cinder_config('DEFAULT/backup_swift_url').with_value(p[:backup_swift_url]) + should contain_cinder_config('DEFAULT/backup_swift_container').with_value(p[:backup_swift_container]) + should contain_cinder_config('DEFAULT/backup_swift_object_size').with_value(p[:backup_swift_object_size]) + should contain_cinder_config('DEFAULT/backup_swift_retry_attempts').with_value(p[:backup_swift_retry_attempts]) + should contain_cinder_config('DEFAULT/backup_swift_retry_backoff').with_value(p[:backup_swift_retry_backoff]) + end + + context 'when overriding default parameters' do + before :each do + params.merge!(:backup_swift_url => 'https://controller2:8080/v1/AUTH_') + params.merge!(:backup_swift_container => 'toto') + params.merge!(:backup_swift_object_size => '123') + params.merge!(:backup_swift_retry_attempts => '99') + params.merge!(:backup_swift_retry_backoff => '56') + end + it 'should replace default parameters with new values' do + should contain_cinder_config('DEFAULT/backup_swift_url').with_value(p[:backup_swift_url]) + should contain_cinder_config('DEFAULT/backup_swift_container').with_value(p[:backup_swift_container]) + should contain_cinder_config('DEFAULT/backup_swift_object_size').with_value(p[:backup_swift_object_size]) + should contain_cinder_config('DEFAULT/backup_swift_retry_attempts').with_value(p[:backup_swift_retry_attempts]) + should contain_cinder_config('DEFAULT/backup_swift_retry_backoff').with_value(p[:backup_swift_retry_backoff]) + end + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'cinder backup with swift' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'cinder backup with swift' + end + +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_ceilometer_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_ceilometer_spec.rb new file mode 100644 index 000000000..e1b52a10d --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_ceilometer_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +describe 'cinder::ceilometer' do + + describe 'with default parameters' do + it 'contains default values' do + should contain_cinder_config('DEFAULT/notification_driver').with( + :value => 'cinder.openstack.common.notifier.rpc_notifier') + end + end +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_client_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_client_spec.rb new file mode 100644 index 000000000..77b51ced8 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_client_spec.rb @@ -0,0 +1,14 @@ +require 'spec_helper' + +describe 'cinder::client' do + it { should contain_package('python-cinderclient').with_ensure('present') } + let :facts do + {:osfamily => 'Debian'} + end + context 'with params' do + let :params do + {:package_ensure => 'latest'} + end + it { should contain_package('python-cinderclient').with_ensure('latest') } + end +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_db_mysql_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_db_mysql_spec.rb new file mode 100644 index 000000000..3d85cdddb --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_db_mysql_spec.rb @@ -0,0 +1,58 @@ +require 'spec_helper' + +describe 'cinder::db::mysql' do + + let :req_params do + {:password => 'pw', + } + end + + let :facts do + {:osfamily => 'Debian'} + end + + let :pre_condition do + 'include mysql::server' + end + + describe 'with only required params' do + let :params do + req_params + end + it { should contain_openstacklib__db__mysql('cinder').with( + :user => 'cinder', + :password_hash => '*D821809F681A40A6E379B50D0463EFAE20BDD122', + :host => '127.0.0.1', + :charset => 'utf8', + :collate => 'utf8_general_ci', + ) } + end + describe "overriding allowed_hosts param to array" do + let :params do + { + :password => 'cinderpass', + :allowed_hosts => ['127.0.0.1','%'] + } + end + + end + describe "overriding allowed_hosts param to string" do + let :params do + { + :password => 'cinderpass2', + :allowed_hosts => '192.168.1.1' + } + end + + end + + describe "overriding allowed_hosts param equals to host param " do + let :params do + { + :password => 'cinderpass2', + :allowed_hosts => '127.0.0.1' + } + end + + end +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_db_postgresql_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_db_postgresql_spec.rb new file mode 100644 index 000000000..93296ae1d --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_db_postgresql_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' + +describe 'cinder::db::postgresql' do + + let :req_params do + {:password => 'pw'} + end + + let :facts do + { + :postgres_default_version => '8.4', + :osfamily => 'RedHat', + } + end + + describe 'with only required params' do + let :params do + req_params + end + it { should contain_postgresql__db('cinder').with( + :user => 'cinder', + :password => 'pw' + ) } + end + +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_db_sync_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_db_sync_spec.rb new file mode 100644 index 000000000..906d4391a --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_db_sync_spec.rb @@ -0,0 +1,16 @@ +require 'spec_helper' + +describe 'cinder::db::sync' do + + let :facts do + {:osfamily => 'Debian'} + end + it { should contain_exec('cinder-manage db_sync').with( + :command => 'cinder-manage db sync', + :path => '/usr/bin', + :user => 'cinder', + :refreshonly => true, + :logoutput => 'on_failure' + ) } + +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_glance_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_glance_spec.rb new file mode 100644 index 000000000..64bf89a52 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_glance_spec.rb @@ -0,0 +1,82 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Unit tests for cinder::glance class +# + +require 'spec_helper' + +describe 'cinder::glance' do + + let :default_params do + { :glance_api_version => '2', + :glance_num_retries => '0', + :glance_api_insecure => false, + :glance_api_ssl_compression => false } + end + + let :params do + {} + end + + shared_examples_for 'cinder with glance' do + let :p do + default_params.merge(params) + end + + it 'configures cinder.conf with default params' do + should contain_cinder_config('DEFAULT/glance_api_version').with_value(p[:glance_api_version]) + should contain_cinder_config('DEFAULT/glance_num_retries').with_value(p[:glance_num_retries]) + should contain_cinder_config('DEFAULT/glance_api_insecure').with_value(p[:glance_api_insecure]) + end + + context 'configure cinder with one glance server' do + before :each do + params.merge!(:glance_api_servers => '10.0.0.1:9292') + end + it 'should configure one glance server' do + should contain_cinder_config('DEFAULT/glance_api_servers').with_value(p[:glance_api_servers]) + end + end + + context 'configure cinder with two glance servers' do + before :each do + params.merge!(:glance_api_servers => ['10.0.0.1:9292','10.0.0.2:9292']) + end + it 'should configure two glance servers' do + should contain_cinder_config('DEFAULT/glance_api_servers').with_value(p[:glance_api_servers].join(',')) + end + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'cinder with glance' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'cinder with glance' + end + +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_keystone_auth_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_keystone_auth_spec.rb new file mode 100644 index 000000000..9c3690b7f --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_keystone_auth_spec.rb @@ -0,0 +1,135 @@ +require 'spec_helper' + +describe 'cinder::keystone::auth' do + + let :req_params do + {:password => 'pw'} + end + + describe 'with only required params' do + + let :params do + req_params + end + + it 'should contain auth info' do + + should contain_keystone_user('cinder').with( + :ensure => 'present', + :password => 'pw', + :email => 'cinder@localhost', + :tenant => 'services' + ) + should contain_keystone_user_role('cinder@services').with( + :ensure => 'present', + :roles => 'admin' + ) + should contain_keystone_service('cinder').with( + :ensure => 'present', + :type => 'volume', + :description => 'Cinder Service' + ) + should contain_keystone_service('cinderv2').with( + :ensure => 'present', + :type => 'volumev2', + :description => 'Cinder Service v2' + ) + + end + it { should contain_keystone_endpoint('RegionOne/cinder').with( + :ensure => 'present', + :public_url => 'http://127.0.0.1:8776/v1/%(tenant_id)s', + :admin_url => 'http://127.0.0.1:8776/v1/%(tenant_id)s', + :internal_url => 'http://127.0.0.1:8776/v1/%(tenant_id)s' + ) } + it { should contain_keystone_endpoint('RegionOne/cinderv2').with( + :ensure => 'present', + :public_url => 'http://127.0.0.1:8776/v2/%(tenant_id)s', + :admin_url => 'http://127.0.0.1:8776/v2/%(tenant_id)s', + :internal_url => 'http://127.0.0.1:8776/v2/%(tenant_id)s' + ) } + + end + + context 'when overriding endpoint params' do + let :params do + req_params.merge( + :public_address => '10.0.42.1', + :admin_address => '10.0.42.2', + :internal_address => '10.0.42.3', + :region => 'RegionThree', + :port => '4242', + :admin_protocol => 'https', + :internal_protocol => 'https', + :public_protocol => 'https', + :volume_version => 'v42' + ) + end + + it { should contain_keystone_endpoint('RegionThree/cinder').with( + :ensure => 'present', + :public_url => 'https://10.0.42.1:4242/v42/%(tenant_id)s', + :admin_url => 'https://10.0.42.2:4242/v42/%(tenant_id)s', + :internal_url => 'https://10.0.42.3:4242/v42/%(tenant_id)s' + )} + + it { should contain_keystone_endpoint('RegionThree/cinderv2').with( + :ensure => 'present', + :public_url => 'https://10.0.42.1:4242/v2/%(tenant_id)s', + :admin_url => 'https://10.0.42.2:4242/v2/%(tenant_id)s', + :internal_url => 'https://10.0.42.3:4242/v2/%(tenant_id)s' + )} + end + + + describe 'when endpoint should not be configured' do + let :params do + req_params.merge( + :configure_endpoint => false, + :configure_endpoint_v2 => false + ) + end + it { should_not contain_keystone_endpoint('RegionOne/cinder') } + it { should_not contain_keystone_endpoint('RegionOne/cinderv2') } + end + + describe 'when user should not be configured' do + let :params do + req_params.merge( + :configure_user => false + ) + end + + it { should_not contain_keystone_user('cinder') } + + it { should contain_keystone_user_role('cinder@services') } + + it { should contain_keystone_service('cinder').with( + :ensure => 'present', + :type => 'volume', + :description => 'Cinder Service' + ) } + + end + + describe 'when user and user role should not be configured' do + let :params do + req_params.merge( + :configure_user => false, + :configure_user_role => false + ) + end + + it { should_not contain_keystone_user('cinder') } + + it { should_not contain_keystone_user_role('cinder@services') } + + it { should contain_keystone_service('cinder').with( + :ensure => 'present', + :type => 'volume', + :description => 'Cinder Service' + ) } + + end + +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_logging_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_logging_spec.rb new file mode 100644 index 000000000..ca967e7c4 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_logging_spec.rb @@ -0,0 +1,107 @@ +require 'spec_helper' + +describe 'cinder::logging' do + + let :params do + { + } + end + + let :log_params do + { + :logging_context_format_string => '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s', + :logging_default_format_string => '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s', + :logging_debug_format_suffix => '%(funcName)s %(pathname)s:%(lineno)d', + :logging_exception_prefix => '%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s', + :log_config_append => '/etc/cinder/logging.conf', + :publish_errors => true, + :default_log_levels => { + 'amqp' => 'WARN', 'amqplib' => 'WARN', 'boto' => 'WARN', + 'qpid' => 'WARN', 'sqlalchemy' => 'WARN', 'suds' => 'INFO', + 'iso8601' => 'WARN', + 'requests.packages.urllib3.connectionpool' => 'WARN' }, + :fatal_deprecations => true, + :instance_format => '[instance: %(uuid)s] ', + :instance_uuid_format => '[instance: %(uuid)s] ', + :log_date_format => '%Y-%m-%d %H:%M:%S', + } + end + + shared_examples_for 'cinder-logging' do + + context 'with extended logging options' do + before { params.merge!( log_params ) } + it_configures 'logging params set' + end + + context 'without extended logging options' do + it_configures 'logging params unset' + end + + end + + shared_examples_for 'logging params set' do + it 'enables logging params' do + should contain_cinder_config('DEFAULT/logging_context_format_string').with_value( + '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s') + + should contain_cinder_config('DEFAULT/logging_default_format_string').with_value( + '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s') + + should contain_cinder_config('DEFAULT/logging_debug_format_suffix').with_value( + '%(funcName)s %(pathname)s:%(lineno)d') + + should contain_cinder_config('DEFAULT/logging_exception_prefix').with_value( + '%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s') + + should contain_cinder_config('DEFAULT/log_config_append').with_value( + '/etc/cinder/logging.conf') + should contain_cinder_config('DEFAULT/publish_errors').with_value( + true) + + should contain_cinder_config('DEFAULT/default_log_levels').with_value( + 'amqp=WARN,amqplib=WARN,boto=WARN,iso8601=WARN,qpid=WARN,requests.packages.urllib3.connectionpool=WARN,sqlalchemy=WARN,suds=INFO') + + should contain_cinder_config('DEFAULT/fatal_deprecations').with_value( + true) + + should contain_cinder_config('DEFAULT/instance_format').with_value( + '[instance: %(uuid)s] ') + + should contain_cinder_config('DEFAULT/instance_uuid_format').with_value( + '[instance: %(uuid)s] ') + + should contain_cinder_config('DEFAULT/log_date_format').with_value( + '%Y-%m-%d %H:%M:%S') + end + end + + + shared_examples_for 'logging params unset' do + [ :logging_context_format_string, :logging_default_format_string, + :logging_debug_format_suffix, :logging_exception_prefix, + :log_config_append, :publish_errors, + :default_log_levels, :fatal_deprecations, + :instance_format, :instance_uuid_format, + :log_date_format, ].each { |param| + it { should contain_cinder_config("DEFAULT/#{param}").with_ensure('absent') } + } + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'cinder-logging' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'cinder-logging' + end + +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_params_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_params_spec.rb new file mode 100644 index 000000000..306ce1811 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_params_spec.rb @@ -0,0 +1,12 @@ +require 'spec_helper' + +describe 'cinder::params' do + + let :facts do + {:osfamily => 'Debian'} + end + it 'should compile' do + subject + end + +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_policy_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_policy_spec.rb new file mode 100644 index 000000000..e9b6d46d2 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_policy_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +describe 'cinder::policy' do + + shared_examples_for 'cinder policies' do + let :params do + { + :policy_path => '/etc/cinder/policy.json', + :policies => { + 'context_is_admin' => { + 'key' => 'context_is_admin', + 'value' => 'foo:bar' + } + } + } + end + + it 'set up the policies' do + should contain_openstacklib__policy__base('context_is_admin').with({ + :key => 'context_is_admin', + :value => 'foo:bar' + }) + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'cinder policies' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'cinder policies' + end +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_qpid_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_qpid_spec.rb new file mode 100644 index 000000000..0ace32090 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_qpid_spec.rb @@ -0,0 +1,51 @@ +require 'spec_helper' + +describe 'cinder::qpid' do + + let :facts do + {:puppetversion => '2.7', + :osfamily => 'RedHat'} + end + + describe 'with defaults' do + + it 'should contain all of the default resources' do + + should contain_class('qpid::server').with( + :service_ensure => 'running', + :port => '5672' + ) + + end + + it 'should contain user' do + + should contain_qpid_user('guest').with( + :password => 'guest', + :file => '/var/lib/qpidd/qpidd.sasldb', + :realm => 'OPENSTACK', + :provider => 'saslpasswd2' + ) + + end + + end + + describe 'when disabled' do + let :params do + { + :enabled => false + } + end + + it 'should be disabled' do + + should_not contain_qpid_user('guest') + should contain_class('qpid::server').with( + :service_ensure => 'stopped' + ) + + end + end + +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_quota_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_quota_spec.rb new file mode 100644 index 000000000..ecbc2d97b --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_quota_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe 'cinder::quota' do + + describe 'with default parameters' do + it 'contains default values' do + should contain_cinder_config('DEFAULT/quota_volumes').with( + :value => 10) + should contain_cinder_config('DEFAULT/quota_snapshots').with( + :value => 10) + should contain_cinder_config('DEFAULT/quota_gigabytes').with( + :value => 1000) + should contain_cinder_config('DEFAULT/quota_driver').with( + :value => 'cinder.quota.DbQuotaDriver') + end + end + + describe 'with overridden parameters' do + let :params do + { :quota_volumes => 1000, + :quota_snapshots => 1000, + :quota_gigabytes => 100000 } + end + it 'contains overrided values' do + should contain_cinder_config('DEFAULT/quota_volumes').with( + :value => 1000) + should contain_cinder_config('DEFAULT/quota_snapshots').with( + :value => 1000) + should contain_cinder_config('DEFAULT/quota_gigabytes').with( + :value => 100000) + should contain_cinder_config('DEFAULT/quota_driver').with( + :value => 'cinder.quota.DbQuotaDriver') + end + end +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_rabbitmq_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_rabbitmq_spec.rb new file mode 100644 index 000000000..3fcfd7a0a --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_rabbitmq_spec.rb @@ -0,0 +1,81 @@ +require 'spec_helper' + +describe 'cinder::rabbitmq' do + + let :facts do + { :puppetversion => '2.7', + :osfamily => 'Debian', + } + end + + describe 'with defaults' do + + it 'should contain all of the default resources' do + + should contain_class('rabbitmq::server').with( + :service_ensure => 'running', + :port => '5672', + :delete_guest_user => false + ) + + should contain_rabbitmq_vhost('/').with( + :provider => 'rabbitmqctl' + ) + end + + end + + describe 'when a rabbitmq user is specified' do + + let :params do + { + :userid => 'dan', + :password => 'pass' + } + end + + it 'should contain user and permissions' do + + should contain_rabbitmq_user('dan').with( + :admin => true, + :password => 'pass', + :provider => 'rabbitmqctl' + ) + + should contain_rabbitmq_user_permissions('dan@/').with( + :configure_permission => '.*', + :write_permission => '.*', + :read_permission => '.*', + :provider => 'rabbitmqctl' + ) + + end + + end + + describe 'when disabled' do + let :params do + { + :userid => 'dan', + :password => 'pass', + :enabled => false + } + end + + it 'should be disabled' do + + should_not contain_rabbitmq_user('dan') + should_not contain_rabbitmq_user_permissions('dan@/') + should contain_class('rabbitmq::server').with( + :service_ensure => 'stopped', + :port => '5672', + :delete_guest_user => false + ) + + should_not contain_rabbitmq_vhost('/') + + end + end + + +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_scheduler_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_scheduler_spec.rb new file mode 100644 index 000000000..4ce066a09 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_scheduler_spec.rb @@ -0,0 +1,81 @@ +require 'spec_helper' + +describe 'cinder::scheduler' do + + describe 'on debian platforms' do + + let :facts do + { :osfamily => 'Debian' } + end + + describe 'with default parameters' do + + it { should contain_class('cinder::params') } + + it { should contain_package('cinder-scheduler').with( + :name => 'cinder-scheduler', + :ensure => 'present', + :before => 'Service[cinder-scheduler]' + ) } + + it { should contain_service('cinder-scheduler').with( + :name => 'cinder-scheduler', + :enable => true, + :ensure => 'running', + :require => 'Package[cinder]', + :hasstatus => true + ) } + end + + describe 'with parameters' do + + let :params do + { :scheduler_driver => 'cinder.scheduler.filter_scheduler.FilterScheduler', + :package_ensure => 'present' + } + end + + it { should contain_cinder_config('DEFAULT/scheduler_driver').with_value('cinder.scheduler.filter_scheduler.FilterScheduler') } + it { should contain_package('cinder-scheduler').with_ensure('present') } + end + + describe 'with manage_service false' do + let :params do + { 'manage_service' => false + } + end + it 'should not change the state of the service' do + should contain_service('cinder-scheduler').without_ensure + end + end + end + + + describe 'on rhel platforms' do + + let :facts do + { :osfamily => 'RedHat' } + end + + describe 'with default parameters' do + + it { should contain_class('cinder::params') } + + it { should contain_service('cinder-scheduler').with( + :name => 'openstack-cinder-scheduler', + :enable => true, + :ensure => 'running', + :require => 'Package[cinder]' + ) } + end + + describe 'with parameters' do + + let :params do + { :scheduler_driver => 'cinder.scheduler.filter_scheduler.FilterScheduler' } + end + + it { should contain_cinder_config('DEFAULT/scheduler_driver').with_value('cinder.scheduler.filter_scheduler.FilterScheduler') } + end + end +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_setup_test_volume_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_setup_test_volume_spec.rb new file mode 100644 index 000000000..678e196cf --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_setup_test_volume_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe 'cinder::setup_test_volume' do + + it { should contain_package('lvm2').with( + :ensure => 'present' + ) } + + it { should contain_file('/var/lib/cinder').with( + :ensure => 'directory', + :require => 'Package[cinder]' + ) } + + it 'should contain volume creation execs' do + should contain_exec('create_/var/lib/cinder/cinder-volumes').with( + :command => 'dd if=/dev/zero of="/var/lib/cinder/cinder-volumes" bs=1 count=0 seek=4G' + ) + should contain_exec('losetup /dev/loop2 /var/lib/cinder/cinder-volumes') + should contain_exec('pvcreate /dev/loop2') + should contain_exec('vgcreate cinder-volumes /dev/loop2') + end +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_spec.rb new file mode 100644 index 000000000..d7c68c755 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_spec.rb @@ -0,0 +1,382 @@ +require 'spec_helper' +describe 'cinder' do + let :req_params do + {:rabbit_password => 'guest', :database_connection => 'mysql://user:password@host/database'} + end + + let :facts do + {:osfamily => 'Debian'} + end + + describe 'with only required params' do + let :params do + req_params + end + + it { should contain_class('cinder::params') } + it { should contain_class('mysql::bindings::python') } + + it 'should contain default config' do + should contain_cinder_config('DEFAULT/rpc_backend').with( + :value => 'cinder.openstack.common.rpc.impl_kombu' + ) + should contain_cinder_config('DEFAULT/control_exchange').with( + :value => 'openstack' + ) + should contain_cinder_config('DEFAULT/rabbit_password').with( + :value => 'guest', + :secret => true + ) + should contain_cinder_config('DEFAULT/rabbit_host').with( + :value => '127.0.0.1' + ) + should contain_cinder_config('DEFAULT/rabbit_port').with( + :value => '5672' + ) + should contain_cinder_config('DEFAULT/rabbit_hosts').with( + :value => '127.0.0.1:5672' + ) + should contain_cinder_config('DEFAULT/rabbit_ha_queues').with( + :value => false + ) + should contain_cinder_config('DEFAULT/rabbit_virtual_host').with( + :value => '/' + ) + should contain_cinder_config('DEFAULT/rabbit_userid').with( + :value => 'guest' + ) + should contain_cinder_config('database/connection').with( + :value => 'mysql://user:password@host/database', + :secret => true + ) + should contain_cinder_config('database/idle_timeout').with( + :value => '3600' + ) + should contain_cinder_config('database/min_pool_size').with( + :value => '1' + ) + should contain_cinder_config('database/max_pool_size').with_ensure('absent') + should contain_cinder_config('database/max_retries').with( + :value => '10' + ) + should contain_cinder_config('database/retry_interval').with( + :value => '10' + ) + should contain_cinder_config('database/max_overflow').with_ensure('absent') + should contain_cinder_config('DEFAULT/verbose').with( + :value => false + ) + should contain_cinder_config('DEFAULT/debug').with( + :value => false + ) + should contain_cinder_config('DEFAULT/storage_availability_zone').with( + :value => 'nova' + ) + should contain_cinder_config('DEFAULT/default_availability_zone').with( + :value => 'nova' + ) + should contain_cinder_config('DEFAULT/api_paste_config').with( + :value => '/etc/cinder/api-paste.ini' + ) + should contain_cinder_config('DEFAULT/log_dir').with(:value => '/var/log/cinder') + end + + it { should contain_file('/etc/cinder/cinder.conf').with( + :owner => 'cinder', + :group => 'cinder', + :mode => '0600', + :require => 'Package[cinder]' + ) } + + it { should contain_file('/etc/cinder/api-paste.ini').with( + :owner => 'cinder', + :group => 'cinder', + :mode => '0600', + :require => 'Package[cinder]' + ) } + + end + describe 'with modified rabbit_hosts' do + let :params do + req_params.merge({'rabbit_hosts' => ['rabbit1:5672', 'rabbit2:5672']}) + end + + it 'should contain many' do + should contain_cinder_config('DEFAULT/rabbit_host').with( + :value => nil + ) + should contain_cinder_config('DEFAULT/rabbit_port').with( + :value => nil + ) + should contain_cinder_config('DEFAULT/rabbit_hosts').with( + :value => 'rabbit1:5672,rabbit2:5672' + ) + should contain_cinder_config('DEFAULT/rabbit_ha_queues').with( + :value => true + ) + end + end + + describe 'with a single rabbit_hosts entry' do + let :params do + req_params.merge({'rabbit_hosts' => ['rabbit1:5672']}) + end + + it 'should contain many' do + should contain_cinder_config('DEFAULT/rabbit_host').with( + :value => nil + ) + should contain_cinder_config('DEFAULT/rabbit_port').with( + :value => nil + ) + should contain_cinder_config('DEFAULT/rabbit_hosts').with( + :value => 'rabbit1:5672' + ) + should contain_cinder_config('DEFAULT/rabbit_ha_queues').with( + :value => true + ) + end + end + + describe 'with qpid rpc supplied' do + + let :params do + { + :database_connection => 'mysql://user:password@host/database', + :qpid_password => 'guest', + :rpc_backend => 'cinder.openstack.common.rpc.impl_qpid' + } + end + + it { should contain_cinder_config('database/connection').with_value('mysql://user:password@host/database') } + it { should contain_cinder_config('DEFAULT/rpc_backend').with_value('cinder.openstack.common.rpc.impl_qpid') } + it { should contain_cinder_config('DEFAULT/qpid_hostname').with_value('localhost') } + it { should contain_cinder_config('DEFAULT/qpid_port').with_value('5672') } + it { should contain_cinder_config('DEFAULT/qpid_username').with_value('guest') } + it { should contain_cinder_config('DEFAULT/qpid_password').with_value('guest').with_secret(true) } + it { should contain_cinder_config('DEFAULT/qpid_reconnect').with_value(true) } + it { should contain_cinder_config('DEFAULT/qpid_reconnect_timeout').with_value('0') } + it { should contain_cinder_config('DEFAULT/qpid_reconnect_limit').with_value('0') } + it { should contain_cinder_config('DEFAULT/qpid_reconnect_interval_min').with_value('0') } + it { should contain_cinder_config('DEFAULT/qpid_reconnect_interval_max').with_value('0') } + it { should contain_cinder_config('DEFAULT/qpid_reconnect_interval').with_value('0') } + it { should contain_cinder_config('DEFAULT/qpid_heartbeat').with_value('60') } + it { should contain_cinder_config('DEFAULT/qpid_protocol').with_value('tcp') } + it { should contain_cinder_config('DEFAULT/qpid_tcp_nodelay').with_value(true) } + end + + describe 'with qpid rpc and no qpid_sasl_mechanisms' do + let :params do + { + :database_connection => 'mysql://user:password@host/database', + :qpid_password => 'guest', + :rpc_backend => 'cinder.openstack.common.rpc.impl_qpid' + } + end + + it { should contain_cinder_config('DEFAULT/qpid_sasl_mechanisms').with_ensure('absent') } + end + + describe 'with qpid rpc and qpid_sasl_mechanisms string' do + let :params do + { + :database_connection => 'mysql://user:password@host/database', + :qpid_password => 'guest', + :qpid_sasl_mechanisms => 'PLAIN', + :rpc_backend => 'cinder.openstack.common.rpc.impl_qpid' + } + end + + it { should contain_cinder_config('DEFAULT/qpid_sasl_mechanisms').with_value('PLAIN') } + end + + describe 'with qpid rpc and qpid_sasl_mechanisms array' do + let :params do + { + :database_connection => 'mysql://user:password@host/database', + :qpid_password => 'guest', + :qpid_sasl_mechanisms => [ 'DIGEST-MD5', 'GSSAPI', 'PLAIN' ], + :rpc_backend => 'cinder.openstack.common.rpc.impl_qpid' + } + end + + it { should contain_cinder_config('DEFAULT/qpid_sasl_mechanisms').with_value('DIGEST-MD5 GSSAPI PLAIN') } + end + + describe 'with SSL enabled with kombu' do + let :params do + req_params.merge!({ + :rabbit_use_ssl => true, + :kombu_ssl_ca_certs => '/path/to/ssl/ca/certs', + :kombu_ssl_certfile => '/path/to/ssl/cert/file', + :kombu_ssl_keyfile => '/path/to/ssl/keyfile', + :kombu_ssl_version => 'TLSv1' + }) + end + + it do + should contain_cinder_config('DEFAULT/rabbit_use_ssl').with_value('true') + should contain_cinder_config('DEFAULT/kombu_ssl_ca_certs').with_value('/path/to/ssl/ca/certs') + should contain_cinder_config('DEFAULT/kombu_ssl_certfile').with_value('/path/to/ssl/cert/file') + should contain_cinder_config('DEFAULT/kombu_ssl_keyfile').with_value('/path/to/ssl/keyfile') + should contain_cinder_config('DEFAULT/kombu_ssl_version').with_value('TLSv1') + end + end + + describe 'with SSL enabled without kombu' do + let :params do + req_params.merge!({ + :rabbit_use_ssl => true, + }) + end + + it do + should contain_cinder_config('DEFAULT/rabbit_use_ssl').with_value('true') + should contain_cinder_config('DEFAULT/kombu_ssl_ca_certs').with_ensure('absent') + should contain_cinder_config('DEFAULT/kombu_ssl_certfile').with_ensure('absent') + should contain_cinder_config('DEFAULT/kombu_ssl_keyfile').with_ensure('absent') + should contain_cinder_config('DEFAULT/kombu_ssl_version').with_value('TLSv1') + end + end + + describe 'with SSL disabled' do + let :params do + req_params.merge!({ + :rabbit_use_ssl => false, + :kombu_ssl_ca_certs => 'undef', + :kombu_ssl_certfile => 'undef', + :kombu_ssl_keyfile => 'undef', + :kombu_ssl_version => 'TLSv1' + }) + end + + it do + should contain_cinder_config('DEFAULT/rabbit_use_ssl').with_value('false') + should contain_cinder_config('DEFAULT/kombu_ssl_ca_certs').with_ensure('absent') + should contain_cinder_config('DEFAULT/kombu_ssl_certfile').with_ensure('absent') + should contain_cinder_config('DEFAULT/kombu_ssl_keyfile').with_ensure('absent') + should contain_cinder_config('DEFAULT/kombu_ssl_version').with_ensure('absent') + end + end + + describe 'with syslog disabled' do + let :params do + req_params + end + + it { should contain_cinder_config('DEFAULT/use_syslog').with_value(false) } + end + + describe 'with syslog enabled' do + let :params do + req_params.merge({ + :use_syslog => 'true', + }) + end + + it { should contain_cinder_config('DEFAULT/use_syslog').with_value(true) } + it { should contain_cinder_config('DEFAULT/syslog_log_facility').with_value('LOG_USER') } + end + + describe 'with syslog enabled and custom settings' do + let :params do + req_params.merge({ + :use_syslog => 'true', + :log_facility => 'LOG_LOCAL0' + }) + end + + it { should contain_cinder_config('DEFAULT/use_syslog').with_value(true) } + it { should contain_cinder_config('DEFAULT/syslog_log_facility').with_value('LOG_LOCAL0') } + end + + describe 'with log_dir disabled' do + let(:params) { req_params.merge!({:log_dir => false}) } + it { should contain_cinder_config('DEFAULT/log_dir').with_ensure('absent') } + end + + describe 'with amqp_durable_queues disabled' do + let :params do + req_params + end + + it { should contain_cinder_config('DEFAULT/amqp_durable_queues').with_value(false) } + end + + describe 'with amqp_durable_queues enabled' do + let :params do + req_params.merge({ + :amqp_durable_queues => true, + }) + end + + it { should contain_cinder_config('DEFAULT/amqp_durable_queues').with_value(true) } + end + + describe 'with postgresql' do + let :params do + { + :database_connection => 'postgresql://user:drowssap@host/database', + :rabbit_password => 'guest', + } + end + + it { should contain_cinder_config('database/connection').with( + :value => 'postgresql://user:drowssap@host/database', + :secret => true + ) } + it { should_not contain_class('mysql::python') } + it { should_not contain_class('mysql::bindings') } + it { should_not contain_class('mysql::bindings::python') } + end + + describe 'with SSL socket options set' do + let :params do + { + :use_ssl => true, + :cert_file => '/path/to/cert', + :ca_file => '/path/to/ca', + :key_file => '/path/to/key', + :rabbit_password => 'guest', + } + end + + it { should contain_cinder_config('DEFAULT/ssl_ca_file').with_value('/path/to/ca') } + it { should contain_cinder_config('DEFAULT/ssl_cert_file').with_value('/path/to/cert') } + it { should contain_cinder_config('DEFAULT/ssl_key_file').with_value('/path/to/key') } + end + + describe 'with SSL socket options set to false' do + let :params do + { + :use_ssl => false, + :cert_file => false, + :ca_file => false, + :key_file => false, + :rabbit_password => 'guest', + } + end + + it { should contain_cinder_config('DEFAULT/ssl_ca_file').with_ensure('absent') } + it { should contain_cinder_config('DEFAULT/ssl_cert_file').with_ensure('absent') } + it { should contain_cinder_config('DEFAULT/ssl_key_file').with_ensure('absent') } + end + + describe 'with SSL socket options set wrongly configured' do + let :params do + { + :use_ssl => true, + :ca_file => '/path/to/ca', + :key_file => '/path/to/key', + :rabbit_password => 'guest', + } + end + + it 'should raise an error' do + expect { + should compile + }.to raise_error Puppet::Error, /The cert_file parameter is required when use_ssl is set to true/ + end + end + +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_vmware_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_vmware_spec.rb new file mode 100644 index 000000000..705613626 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_vmware_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe 'cinder::vmware' do + + let :params do + {:os_password => 'asdf', + :os_tenant_name => 'admin', + :os_username => 'admin', + :os_auth_url => 'http://127.127.127.1:5000/v2.0/'} + end + + describe 'with defaults' do + it 'should create vmware special types' do + should contain_cinder__type('vmware-thin').with( + :set_key => 'vmware:vmdk_type', + :set_value => 'thin') + + should contain_cinder__type('vmware-thick').with( + :set_key => 'vmware:vmdk_type', + :set_value => 'thick') + + should contain_cinder__type('vmware-eagerZeroedThick').with( + :set_key => 'vmware:vmdk_type', + :set_value => 'eagerZeroedThick') + + should contain_cinder__type('vmware-full').with( + :set_key => 'vmware:clone_type', + :set_value => 'full') + + should contain_cinder__type('vmware-linked').with( + :set_key => 'vmware:clone_type', + :set_value => 'linked') + end + end +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_volume_emc_vnx_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_volume_emc_vnx_spec.rb new file mode 100644 index 000000000..3372e1f57 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_volume_emc_vnx_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe 'cinder::volume::emc_vnx' do + let :req_params do + { + :san_ip => '127.0.0.2', + :san_login => 'emc', + :san_password => 'password', + :iscsi_ip_address => '127.0.0.3', + :storage_vnx_pool_name => 'emc-storage-pool' + } + end + + let :facts do + {:osfamily => 'Redhat' } + end + + let :params do + req_params + end + + describe 'emc vnx volume driver' do + it 'configure emc vnx volume driver' do + should contain_cinder_config('DEFAULT/volume_driver').with_value('cinder.volume.drivers.emc.emc_cli_iscsi.EMCCLIISCSIDriver') + should contain_cinder_config('DEFAULT/san_ip').with_value('127.0.0.2') + should contain_cinder_config('DEFAULT/san_login').with_value('emc') + should contain_cinder_config('DEFAULT/san_password').with_value('password') + should contain_cinder_config('DEFAULT/iscsi_ip_address').with_value('127.0.0.3') + should contain_cinder_config('DEFAULT/storage_vnx_pool_name').with_value('emc-storage-pool') + end + end +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_volume_eqlx_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_volume_eqlx_spec.rb new file mode 100644 index 000000000..0f1a0ab8c --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_volume_eqlx_spec.rb @@ -0,0 +1,35 @@ +require 'spec_helper' + +describe 'cinder::volume::eqlx' do + + let :params do { + :san_ip => '192.168.100.10', + :san_login => 'grpadmin', + :san_password => '12345', + :san_thin_provision => true, + :eqlx_group_name => 'group-a', + :eqlx_pool => 'apool', + :eqlx_use_chap => true, + :eqlx_chap_login => 'chapadm', + :eqlx_chap_password => '56789', + :eqlx_cli_timeout => 31, + :eqlx_cli_max_retries => 6, + } + end + + describe 'eqlx volume driver' do + it 'configures eqlx volume driver' do + should contain_cinder_config('DEFAULT/volume_driver').with_value('cinder.volume.drivers.eqlx.DellEQLSanISCSIDriver') + should contain_cinder_config('DEFAULT/volume_backend_name').with_value('DEFAULT') + + params.each_pair do |config,value| + should contain_cinder_config("DEFAULT/#{config}").with_value(value) + end + end + + it 'marks eqlx_chap_password as secret' do + should contain_cinder_config('DEFAULT/eqlx_chap_password').with_secret( true ) + end + + end +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_volume_glusterfs_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_volume_glusterfs_spec.rb new file mode 100644 index 000000000..950d0c411 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_volume_glusterfs_spec.rb @@ -0,0 +1,59 @@ +require 'spec_helper' + +describe 'cinder::volume::glusterfs' do + + shared_examples_for 'glusterfs volume driver' do + let :params do + { + :glusterfs_shares => ['10.10.10.10:/volumes', '10.10.10.11:/volumes'], + :glusterfs_shares_config => '/etc/cinder/other_shares.conf', + :glusterfs_sparsed_volumes => true, + :glusterfs_mount_point_base => '/cinder_mount_point', + } + end + + it 'configures glusterfs volume driver' do + should contain_cinder_config('DEFAULT/volume_driver').with_value( + 'cinder.volume.drivers.glusterfs.GlusterfsDriver') + should contain_cinder_config('DEFAULT/glusterfs_shares_config').with_value( + '/etc/cinder/other_shares.conf') + should contain_cinder_config('DEFAULT/glusterfs_sparsed_volumes').with_value( + true) + should contain_cinder_config('DEFAULT/glusterfs_mount_point_base').with_value( + '/cinder_mount_point') + should contain_file('/etc/cinder/other_shares.conf').with( + :content => "10.10.10.10:/volumes\n10.10.10.11:/volumes\n", + :require => 'Package[cinder]', + :notify => 'Service[cinder-volume]' + ) + end + + context "with an parameter which has been removed" do + before do + params.merge!({ + :glusterfs_disk_util => 'foo', + }) + end + it 'should fails' do + expect { subject }.to raise_error(Puppet::Error, /glusterfs_disk_util is removed in Icehouse./) + end + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'glusterfs volume driver' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'glusterfs volume driver' + end + +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_volume_hp3par_iscsi_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_volume_hp3par_iscsi_spec.rb new file mode 100644 index 000000000..64a44769d --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_volume_hp3par_iscsi_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe 'cinder::volume::hp3par_iscsi' do + let :req_params do + { + :hp3par_api_url => 'https://172.0.0.2:8080/api/v1', + :hp3par_username => '3paradm', + :hp3par_password => 'password', + :hp3par_iscsi_ips => '172.0.0.3', + :san_ip => '172.0.0.2', + :san_login => '3paradm', + :san_password => 'password', + } + end + + let :params do + req_params + end + + describe 'hp3par_iscsi volume driver' do + it 'configure hp3par_iscsi volume driver' do + should contain_cinder_config('DEFAULT/volume_driver').with_value('cinder.volume.drivers.san.hp.hp_3par_iscsi.HP3PARISCSIDriver') + should contain_cinder_config('DEFAULT/hp3par_api_url').with_value('https://172.0.0.2:8080/api/v1') + should contain_cinder_config('DEFAULT/hp3par_username').with_value('3paradm') + should contain_cinder_config('DEFAULT/hp3par_password').with_value('password') + should contain_cinder_config('DEFAULT/hp3par_iscsi_ips').with_value('172.0.0.3') + should contain_cinder_config('DEFAULT/san_ip').with_value('172.0.0.2') + should contain_cinder_config('DEFAULT/san_login').with_value('3paradm') + should contain_cinder_config('DEFAULT/san_password').with_value('password') + end + end +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_volume_iscsi_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_volume_iscsi_spec.rb new file mode 100644 index 000000000..5352badfc --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_volume_iscsi_spec.rb @@ -0,0 +1,85 @@ +require 'spec_helper' + +describe 'cinder::volume::iscsi' do + + let :req_params do + {:iscsi_ip_address => '127.0.0.2'} + end + + let :facts do + {:osfamily => 'Debian'} + end + + describe 'with default params' do + + let :params do + req_params + end + + it { should contain_cinder_config('DEFAULT/volume_driver').with( + :value => 'cinder.volume.drivers.lvm.LVMISCSIDriver')} + it { should contain_cinder_config('DEFAULT/iscsi_ip_address').with(:value => '127.0.0.2')} + it { should contain_cinder_config('DEFAULT/iscsi_helper').with(:value => 'tgtadm')} + it { should contain_cinder_config('DEFAULT/volume_group').with(:value => 'cinder-volumes')} + + end + + describe 'with iSER driver' do + let(:params) { req_params.merge( + :volume_driver => 'cinder.volume.drivers.lvm.LVMISERDriver')} + + it { should contain_cinder_config('DEFAULT/volume_driver').with( + :value => 'cinder.volume.drivers.lvm.LVMISERDriver')} + end + + describe 'with a unsupported iscsi helper' do + let(:params) { req_params.merge(:iscsi_helper => 'fooboozoo')} + + it 'should raise an error' do + expect { + should compile + }.to raise_error Puppet::Error, /Unsupported iscsi helper: fooboozoo/ + end + end + + describe 'with RedHat' do + + let :params do + req_params + end + + let :facts do + {:osfamily => 'RedHat', + :operatingsystem => 'RedHat', + :operatingsystemmajrelease => '6'} + end + + it { should contain_file_line('cinder include').with( + :line => 'include /etc/cinder/volumes/*', + :path => '/etc/tgt/targets.conf' + ) } + + end + + describe 'with lioadm' do + + let :params do { + :iscsi_ip_address => '127.0.0.2', + :iscsi_helper => 'lioadm' + } + end + + let :facts do + {:osfamily => 'RedHat'} + end + + it { should contain_package('targetcli').with_ensure('present')} + it { should contain_service('target').with( + :ensure => 'running', + :enable => 'true', + :require => 'Package[targetcli]' + ) } + + end + +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_volume_netapp_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_volume_netapp_spec.rb new file mode 100644 index 000000000..fda68ad36 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_volume_netapp_spec.rb @@ -0,0 +1,83 @@ +require 'spec_helper' + +describe 'cinder::volume::netapp' do + + let :params do + { + :netapp_login => 'netapp', + :netapp_password => 'password', + :netapp_server_hostname => '127.0.0.2', + } + end + + let :default_params do + { + :netapp_server_port => '80', + :netapp_size_multiplier => '1.2', + :netapp_storage_family => 'ontap_cluster', + :netapp_storage_protocol => 'nfs', + :netapp_transport_type => 'http', + :netapp_vfiler => '', + :netapp_volume_list => '', + :netapp_vserver => '', + :expiry_thres_minutes => '720', + :thres_avl_size_perc_start => '20', + :thres_avl_size_perc_stop => '60', + :nfs_shares_config => '/etc/cinder/shares.conf', + :netapp_copyoffload_tool_path => '', + :netapp_controller_ips => '', + :netapp_sa_password => '', + :netapp_storage_pools => '', + :nfs_mount_options => nil, + :netapp_webservice_path => '/devmgr/v2', + } + end + + + shared_examples_for 'netapp volume driver' do + let :params_hash do + default_params.merge(params) + end + + it 'configures netapp volume driver' do + should contain_cinder_config('DEFAULT/volume_driver').with_value( + 'cinder.volume.drivers.netapp.common.NetAppDriver') + params_hash.each_pair do |config,value| + should contain_cinder_config("DEFAULT/#{config}").with_value( value ) + end + end + + it 'marks netapp_password as secret' do + should contain_cinder_config('DEFAULT/netapp_password').with_secret( true ) + end + + it 'marks netapp_sa_password as secret' do + should contain_cinder_config('DEFAULT/netapp_sa_password').with_secret( true ) + end + end + + + context 'with default parameters' do + before do + params = {} + end + + it_configures 'netapp volume driver' + end + + context 'with provided parameters' do + it_configures 'netapp volume driver' + end + + context 'with NFS shares provided' do + let (:req_params) { params.merge!({ + :nfs_shares => ['10.0.0.1:/test1', '10.0.0.2:/test2'], + :nfs_shares_config => '/etc/cinder/shares.conf', + }) } + + it 'writes NFS shares to file' do + should contain_file("#{req_params[:nfs_shares_config]}") + .with_content("10.0.0.1:/test1\n10.0.0.2:/test2") + end + end +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_volume_nexenta_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_volume_nexenta_spec.rb new file mode 100644 index 000000000..258400fae --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_volume_nexenta_spec.rb @@ -0,0 +1,43 @@ +# author 'Aimon Bustardo ' +# license 'Apache License 2.0' +# description 'configures openstack cinder nexenta driver' +require 'spec_helper' + +describe 'cinder::volume::nexenta' do + + let :params do + { :nexenta_user => 'nexenta', + :nexenta_password => 'password', + :nexenta_host => '127.0.0.2' } + end + + let :default_params do + { :nexenta_volume => 'cinder', + :nexenta_target_prefix => 'iqn:', + :nexenta_target_group_prefix => 'cinder/', + :nexenta_blocksize => '8k', + :nexenta_sparse => true } + end + + let :facts do + { :osfamily => 'Debian' } + end + + + context 'with required params' do + let :params_hash do + default_params.merge(params) + end + + it 'configures nexenta volume driver' do + params_hash.each_pair do |config, value| + should contain_cinder_config("DEFAULT/#{config}").with_value(value) + end + end + + it 'marks nexenta_password as secret' do + should contain_cinder_config('DEFAULT/nexenta_password').with_secret( true ) + end + + end +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_volume_nfs_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_volume_nfs_spec.rb new file mode 100644 index 000000000..449153fcd --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_volume_nfs_spec.rb @@ -0,0 +1,43 @@ +require 'spec_helper' + +describe 'cinder::volume::nfs' do + + let :params do + { + :nfs_servers => ['10.10.10.10:/shares', '10.10.10.10:/shares2'], + :nfs_mount_options => 'vers=3', + :nfs_shares_config => '/etc/cinder/other_shares.conf', + :nfs_disk_util => 'du', + :nfs_sparsed_volumes => true, + :nfs_mount_point_base => '/cinder_mount_point', + :nfs_used_ratio => '0.95', + :nfs_oversub_ratio => '1.0', + } + end + + describe 'nfs volume driver' do + it 'configures nfs volume driver' do + should contain_cinder_config('DEFAULT/volume_driver').with_value( + 'cinder.volume.drivers.nfs.NfsDriver') + should contain_cinder_config('DEFAULT/nfs_shares_config').with_value( + '/etc/cinder/other_shares.conf') + should contain_cinder_config('DEFAULT/nfs_mount_options').with_value( + 'vers=3') + should contain_cinder_config('DEFAULT/nfs_sparsed_volumes').with_value( + true) + should contain_cinder_config('DEFAULT/nfs_mount_point_base').with_value( + '/cinder_mount_point') + should contain_cinder_config('DEFAULT/nfs_disk_util').with_value( + 'du') + should contain_cinder_config('DEFAULT/nfs_used_ratio').with_value( + '0.95') + should contain_cinder_config('DEFAULT/nfs_oversub_ratio').with_value( + '1.0') + should contain_file('/etc/cinder/other_shares.conf').with( + :content => "10.10.10.10:/shares\n10.10.10.10:/shares2", + :require => 'Package[cinder]', + :notify => 'Service[cinder-volume]' + ) + end + end +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_volume_quobyte_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_volume_quobyte_spec.rb new file mode 100644 index 000000000..58ab30871 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_volume_quobyte_spec.rb @@ -0,0 +1,43 @@ +require 'spec_helper' + +describe 'cinder::volume::quobyte' do + + shared_examples_for 'quobyte volume driver' do + let :params do + { + :quobyte_volume_url => 'quobyte://quobyte.cluster.example.com/volume-name', + :quobyte_qcow2_volumes => false, + :quobyte_sparsed_volumes => true, + } + end + + it 'configures quobyte volume driver' do + should contain_cinder_config('DEFAULT/volume_driver').with_value( + 'cinder.volume.drivers.quobyte.QuobyteDriver') + should contain_cinder_config('DEFAULT/quobyte_volume_url').with_value( + 'quobyte://quobyte.cluster.example.com/volume-name') + should contain_cinder_config('DEFAULT/quobyte_qcow2_volumes').with_value( + false) + should contain_cinder_config('DEFAULT/quobyte_sparsed_volumes').with_value( + true) + end + + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'quobyte volume driver' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'quobyte volume driver' + end + +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_volume_rbd_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_volume_rbd_spec.rb new file mode 100644 index 000000000..ec3a92677 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_volume_rbd_spec.rb @@ -0,0 +1,82 @@ +require 'spec_helper' + +describe 'cinder::volume::rbd' do + let :req_params do + { + :rbd_pool => 'volumes', + :glance_api_version => '2', + :rbd_user => 'test', + :rbd_secret_uuid => '0123456789', + :rbd_ceph_conf => '/foo/boo/zoo/ceph.conf', + :rbd_flatten_volume_from_snapshot => true, + :volume_tmp_dir => '/foo/tmp', + :rbd_max_clone_depth => '0' + } + end + + it { should contain_class('cinder::params') } + + let :params do + req_params + end + + let :facts do + {:osfamily => 'Debian'} + end + + describe 'rbd volume driver' do + it 'configure rbd volume driver' do + should contain_cinder_config('DEFAULT/volume_driver').with_value('cinder.volume.drivers.rbd.RBDDriver') + + should contain_cinder_config('DEFAULT/rbd_ceph_conf').with_value(req_params[:rbd_ceph_conf]) + should contain_cinder_config('DEFAULT/rbd_flatten_volume_from_snapshot').with_value(req_params[:rbd_flatten_volume_from_snapshot]) + should contain_cinder_config('DEFAULT/volume_tmp_dir').with_value(req_params[:volume_tmp_dir]) + should contain_cinder_config('DEFAULT/rbd_max_clone_depth').with_value(req_params[:rbd_max_clone_depth]) + should contain_cinder_config('DEFAULT/rbd_pool').with_value(req_params[:rbd_pool]) + should contain_cinder_config('DEFAULT/rbd_user').with_value(req_params[:rbd_user]) + should contain_cinder_config('DEFAULT/rbd_secret_uuid').with_value(req_params[:rbd_secret_uuid]) + should contain_file('/etc/init/cinder-volume.override').with(:ensure => 'present') + should contain_file_line('set initscript env').with( + :line => /env CEPH_ARGS=\"--id test\"/, + :path => '/etc/init/cinder-volume.override', + :notify => 'Service[cinder-volume]') + end + + context 'with rbd_secret_uuid disabled' do + let(:params) { req_params.merge!({:rbd_secret_uuid => false}) } + it { should contain_cinder_config('DEFAULT/rbd_secret_uuid').with_ensure('absent') } + end + + context 'with volume_tmp_dir disabled' do + let(:params) { req_params.merge!({:volume_tmp_dir => false}) } + it { should contain_cinder_config('DEFAULT/volume_tmp_dir').with_ensure('absent') } + end + + end + + + describe 'with RedHat' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :params do + req_params + end + + it 'should ensure that the cinder-volume sysconfig file is present' do + should contain_file('/etc/sysconfig/openstack-cinder-volume').with( + :ensure => 'present' + ) + end + + it 'should configure RedHat init override' do + should contain_file_line('set initscript env').with( + :line => /export CEPH_ARGS=\"--id test\"/, + :path => '/etc/sysconfig/openstack-cinder-volume', + :notify => 'Service[cinder-volume]') + end + end + +end + diff --git a/3rdparty/modules/cinder/spec/classes/cinder_volume_san_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_volume_san_spec.rb new file mode 100644 index 000000000..f843fd915 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_volume_san_spec.rb @@ -0,0 +1,44 @@ +require 'spec_helper' + +describe 'cinder::volume::san' do + + let :params do + { :volume_driver => 'cinder.volume.san.SolarisISCSIDriver', + :san_ip => '127.0.0.1', + :san_login => 'cluster_operator', + :san_password => '007', + :san_clustername => 'storage_cluster' } + end + + let :default_params do + { :san_thin_provision => true, + :san_login => 'admin', + :san_ssh_port => 22, + :san_is_local => false, + :ssh_conn_timeout => 30, + :ssh_min_pool_conn => 1, + :ssh_max_pool_conn => 5 } + end + + shared_examples_for 'a san volume driver' do + let :params_hash do + default_params.merge(params) + end + + it 'configures cinder volume driver' do + params_hash.each_pair do |config,value| + should contain_cinder_config("DEFAULT/#{config}").with_value( value ) + end + end + + it 'marks san_password as secret' do + should contain_cinder_config('DEFAULT/san_password').with_secret( true ) + end + + end + + + context 'with parameters' do + it_configures 'a san volume driver' + end +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_volume_solidfire_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_volume_solidfire_spec.rb new file mode 100644 index 000000000..d6d4e5fd7 --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_volume_solidfire_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' + +describe 'cinder::volume::solidfire' do + let :req_params do + { + :san_ip => '127.0.0.2', + :san_login => 'solidfire', + :san_password => 'password', + } + end + + let :params do + req_params + end + + describe 'solidfire volume driver' do + it 'configure solidfire volume driver' do + should contain_cinder_config('DEFAULT/volume_driver').with_value('cinder.volume.drivers.solidfire.SolidFireDriver') + should contain_cinder_config('DEFAULT/san_ip').with_value('127.0.0.2') + should contain_cinder_config('DEFAULT/san_login').with_value('solidfire') + should contain_cinder_config('DEFAULT/san_password').with_value('password') + end + + it 'marks san_password as secret' do + should contain_cinder_config('DEFAULT/san_password').with_secret( true ) + end + + end +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_volume_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_volume_spec.rb new file mode 100644 index 000000000..4b3cc14bd --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_volume_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' + +describe 'cinder::volume' do + + let :pre_condition do + 'class { "cinder": rabbit_password => "fpp", database_connection => "mysql://a:b@c/d" }' + end + + let :facts do + {:osfamily => 'Debian'} + end + + it { should contain_package('cinder-volume').with_ensure('present') } + it { should contain_service('cinder-volume').with( + 'hasstatus' => true + )} + + describe 'with manage_service false' do + let :params do + { 'manage_service' => false } + end + it 'should not change the state of the service' do + should contain_service('cinder-volume').without_ensure + end + end +end diff --git a/3rdparty/modules/cinder/spec/classes/cinder_volume_vmdk_spec.rb b/3rdparty/modules/cinder/spec/classes/cinder_volume_vmdk_spec.rb new file mode 100644 index 000000000..8aa364c3f --- /dev/null +++ b/3rdparty/modules/cinder/spec/classes/cinder_volume_vmdk_spec.rb @@ -0,0 +1,61 @@ +require 'spec_helper' + +describe 'cinder::volume::vmdk' do + + let :params do + { + :host_ip => '172.16.16.16', + :host_password => 'asdf', + :host_username => 'user' + } + end + + let :optional_params do + { + :volume_folder => 'cinder-volume-folder', + :api_retry_count => 5, + :max_object_retrieval => 200, + :task_poll_interval => 10, + :image_transfer_timeout_secs => 3600, + :wsdl_location => 'http://127.0.0.1:8080/vmware/SDK/wsdl/vim25/vimService.wsdl' + } + end + + it 'should configure vmdk driver in cinder.conf' do + should contain_cinder_config('DEFAULT/volume_driver').with_value('cinder.volume.drivers.vmware.vmdk.VMwareVcVmdkDriver') + should contain_cinder_config('DEFAULT/vmware_host_ip').with_value(params[:host_ip]) + should contain_cinder_config('DEFAULT/vmware_host_username').with_value(params[:host_username]) + should contain_cinder_config('DEFAULT/vmware_host_password').with_value(params[:host_password]) + should contain_cinder_config('DEFAULT/vmware_volume_folder').with_value('cinder-volumes') + should contain_cinder_config('DEFAULT/vmware_api_retry_count').with_value(10) + should contain_cinder_config('DEFAULT/vmware_max_object_retrieval').with_value(100) + should contain_cinder_config('DEFAULT/vmware_task_poll_interval').with_value(5) + should contain_cinder_config('DEFAULT/vmware_image_transfer_timeout_secs').with_value(7200) + should_not contain_cinder_config('DEFAULT/vmware_wsdl_location') + end + + it 'marks vmware_host_password as secret' do + should contain_cinder_config('DEFAULT/vmware_host_password').with_secret( true ) + end + + it 'installs vmdk python driver' do + should contain_package('python-suds').with( + :ensure => 'present' + ) + end + + context 'with optional parameters' do + before :each do + params.merge!(optional_params) + end + + it 'should configure vmdk driver in cinder.conf' do + should contain_cinder_config('DEFAULT/vmware_volume_folder').with_value(params[:volume_folder]) + should contain_cinder_config('DEFAULT/vmware_api_retry_count').with_value(params[:api_retry_count]) + should contain_cinder_config('DEFAULT/vmware_max_object_retrieval').with_value(params[:max_object_retrieval]) + should contain_cinder_config('DEFAULT/vmware_task_poll_interval').with_value(params[:task_poll_interval]) + should contain_cinder_config('DEFAULT/vmware_image_transfer_timeout_secs').with_value(params[:image_transfer_timeout_secs]) + should contain_cinder_config('DEFAULT/vmware_wsdl_location').with_value(params[:wsdl_location]) + end + end +end diff --git a/3rdparty/modules/cinder/spec/defines/cinder_backend_emc_vnx_spec.rb b/3rdparty/modules/cinder/spec/defines/cinder_backend_emc_vnx_spec.rb new file mode 100644 index 000000000..e5031bb67 --- /dev/null +++ b/3rdparty/modules/cinder/spec/defines/cinder_backend_emc_vnx_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe 'cinder::backend::emc_vnx' do + let (:title) { 'emc' } + + let :req_params do + { + :san_ip => '127.0.0.2', + :san_login => 'emc', + :san_password => 'password', + :iscsi_ip_address => '127.0.0.3', + :storage_vnx_pool_name => 'emc-storage-pool' + } + end + + let :facts do + {:osfamily => 'Redhat' } + end + + let :params do + req_params + end + + describe 'emc vnx volume driver' do + it 'configure emc vnx volume driver' do + should contain_cinder_config('emc/volume_driver').with_value('cinder.volume.drivers.emc.emc_cli_iscsi.EMCCLIISCSIDriver') + should contain_cinder_config('emc/san_ip').with_value('127.0.0.2') + should contain_cinder_config('emc/san_login').with_value('emc') + should contain_cinder_config('emc/san_password').with_value('password') + should contain_cinder_config('emc/iscsi_ip_address').with_value('127.0.0.3') + should contain_cinder_config('emc/storage_vnx_pool_name').with_value('emc-storage-pool') + end + end +end diff --git a/3rdparty/modules/cinder/spec/defines/cinder_backend_eqlx_spec.rb b/3rdparty/modules/cinder/spec/defines/cinder_backend_eqlx_spec.rb new file mode 100644 index 000000000..a6a287a9d --- /dev/null +++ b/3rdparty/modules/cinder/spec/defines/cinder_backend_eqlx_spec.rb @@ -0,0 +1,36 @@ +require 'spec_helper' + +describe 'cinder::backend::eqlx' do + let (:config_group_name) { 'eqlx-1' } + + let (:title) { config_group_name } + + let :params do + { + :san_ip => '192.168.100.10', + :san_login => 'grpadmin', + :san_password => '12345', + :volume_backend_name => 'Dell_EQLX', + :san_thin_provision => true, + :eqlx_group_name => 'group-a', + :eqlx_pool => 'apool', + :eqlx_use_chap => true, + :eqlx_chap_login => 'chapadm', + :eqlx_chap_password => '56789', + :eqlx_cli_timeout => 31, + :eqlx_cli_max_retries => 6, + } + end + + describe 'eqlx volume driver' do + it 'configure eqlx volume driver' do + should contain_cinder_config( + "#{config_group_name}/volume_driver").with_value( + 'cinder.volume.drivers.eqlx.DellEQLSanISCSIDriver') + params.each_pair do |config,value| + should contain_cinder_config( + "#{config_group_name}/#{config}").with_value(value) + end + end + end +end diff --git a/3rdparty/modules/cinder/spec/defines/cinder_backend_glusterfs_spec.rb b/3rdparty/modules/cinder/spec/defines/cinder_backend_glusterfs_spec.rb new file mode 100644 index 000000000..c0b4fa2ef --- /dev/null +++ b/3rdparty/modules/cinder/spec/defines/cinder_backend_glusterfs_spec.rb @@ -0,0 +1,61 @@ +require 'spec_helper' + +describe 'cinder::backend::glusterfs' do + + shared_examples_for 'glusterfs volume driver' do + let(:title) {'mygluster'} + + let :params do + { + :glusterfs_shares => ['10.10.10.10:/volumes', '10.10.10.11:/volumes'], + :glusterfs_shares_config => '/etc/cinder/other_shares.conf', + :glusterfs_sparsed_volumes => true, + :glusterfs_mount_point_base => '/cinder_mount_point', + } + end + + it 'configures glusterfs volume driver' do + should contain_cinder_config('mygluster/volume_driver').with_value( + 'cinder.volume.drivers.glusterfs.GlusterfsDriver') + should contain_cinder_config('mygluster/glusterfs_shares_config').with_value( + '/etc/cinder/other_shares.conf') + should contain_cinder_config('mygluster/glusterfs_sparsed_volumes').with_value( + true) + should contain_cinder_config('mygluster/glusterfs_mount_point_base').with_value( + '/cinder_mount_point') + should contain_file('/etc/cinder/other_shares.conf').with( + :content => "10.10.10.10:/volumes\n10.10.10.11:/volumes\n", + :require => 'Package[cinder]', + :notify => 'Service[cinder-volume]' + ) + end + + context "with an parameter which has been removed" do + before do + params.merge!({ + :glusterfs_disk_util => 'foo', + }) + end + it 'should fails' do + expect { subject }.to raise_error(Puppet::Error, /glusterfs_disk_util is removed in Icehouse./) + end + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'glusterfs volume driver' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'glusterfs volume driver' + end + +end diff --git a/3rdparty/modules/cinder/spec/defines/cinder_backend_hp3par_iscsi_spec.rb b/3rdparty/modules/cinder/spec/defines/cinder_backend_hp3par_iscsi_spec.rb new file mode 100644 index 000000000..dd2cb766e --- /dev/null +++ b/3rdparty/modules/cinder/spec/defines/cinder_backend_hp3par_iscsi_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe 'cinder::backend::hp3par_iscsi' do + let (:title) { 'hp3par_iscsi' } + + let :req_params do + { + :hp3par_api_url => 'https://172.0.0.2:8080/api/v1', + :hp3par_username => '3paradm', + :hp3par_password => 'password', + :hp3par_iscsi_ips => '172.0.0.3', + :san_ip => '172.0.0.2', + :san_login => '3paradm', + :san_password => 'password', + } + end + + let :params do + req_params + end + + describe 'hp3par_iscsi volume driver' do + it 'configure hp3par_iscsi volume driver' do + should contain_cinder_config('hp3par_iscsi/volume_driver').with_value('cinder.volume.drivers.san.hp.hp_3par_iscsi.HP3PARISCSIDriver') + should contain_cinder_config('hp3par_iscsi/hp3par_api_url').with_value('https://172.0.0.2:8080/api/v1') + should contain_cinder_config('hp3par_iscsi/hp3par_username').with_value('3paradm') + should contain_cinder_config('hp3par_iscsi/hp3par_password').with_value('password') + should contain_cinder_config('hp3par_iscsi/hp3par_iscsi_ips').with_value('172.0.0.3') + should contain_cinder_config('hp3par_iscsi/san_ip').with_value('172.0.0.2') + should contain_cinder_config('hp3par_iscsi/san_login').with_value('3paradm') + should contain_cinder_config('hp3par_iscsi/san_password').with_value('password') + end + end +end diff --git a/3rdparty/modules/cinder/spec/defines/cinder_backend_iscsi_spec.rb b/3rdparty/modules/cinder/spec/defines/cinder_backend_iscsi_spec.rb new file mode 100644 index 000000000..1006d7478 --- /dev/null +++ b/3rdparty/modules/cinder/spec/defines/cinder_backend_iscsi_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper' + +describe 'cinder::backend::iscsi' do + + let(:title) {'hippo'} + + let :req_params do { + :iscsi_ip_address => '127.0.0.2', + :iscsi_helper => 'tgtadm', + } + end + + let :facts do + {:osfamily => 'Debian'} + end + + let :params do + req_params + end + + describe 'with default params' do + + it 'should configure iscsi driver' do + should contain_cinder_config('hippo/volume_backend_name').with( + :value => 'hippo') + should contain_cinder_config('hippo/volume_driver').with( + :value => 'cinder.volume.drivers.lvm.LVMISCSIDriver') + should contain_cinder_config('hippo/iscsi_ip_address').with( + :value => '127.0.0.2') + should contain_cinder_config('hippo/iscsi_helper').with( + :value => 'tgtadm') + should contain_cinder_config('hippo/volume_group').with( + :value => 'cinder-volumes') + end + end + + describe 'with RedHat' do + + let :facts do + {:osfamily => 'RedHat'} + end + + it { should contain_file_line('cinder include').with( + :line => 'include /etc/cinder/volumes/*', + :path => '/etc/tgt/targets.conf' + ) } + + end + +end diff --git a/3rdparty/modules/cinder/spec/defines/cinder_backend_netapp_spec.rb b/3rdparty/modules/cinder/spec/defines/cinder_backend_netapp_spec.rb new file mode 100644 index 000000000..3f2ece54c --- /dev/null +++ b/3rdparty/modules/cinder/spec/defines/cinder_backend_netapp_spec.rb @@ -0,0 +1,115 @@ +require 'spec_helper' + +describe 'cinder::backend::netapp' do + + let(:title) {'hippo'} + + let :params do + { + :volume_backend_name => 'netapp-cdot-nfs', + :netapp_login => 'netapp', + :netapp_password => 'password', + :netapp_server_hostname => '127.0.0.2', + } + end + + let :default_params do + { + :netapp_server_port => '80', + :netapp_size_multiplier => '1.2', + :netapp_storage_family => 'ontap_cluster', + :netapp_storage_protocol => 'nfs', + :netapp_transport_type => 'http', + :netapp_vfiler => '', + :netapp_volume_list => '', + :netapp_vserver => '', + :expiry_thres_minutes => '720', + :thres_avl_size_perc_start => '20', + :thres_avl_size_perc_stop => '60', + :nfs_shares_config => '/etc/cinder/shares.conf', + :netapp_copyoffload_tool_path => '', + :netapp_controller_ips => '', + :netapp_sa_password => '', + :netapp_storage_pools => '', + :nfs_mount_options => nil, + :netapp_webservice_path => '/devmgr/v2', + } + end + + shared_examples_for 'netapp volume driver' do + let :params_hash do + default_params.merge(params) + end + + it 'configures netapp volume driver' do + should contain_cinder_config("#{params_hash[:volume_backend_name]}/volume_driver").with_value( + 'cinder.volume.drivers.netapp.common.NetAppDriver') + params_hash.each_pair do |config,value| + should contain_cinder_config("#{params_hash[:volume_backend_name]}/#{config}").with_value( value ) + end + end + + it 'marks netapp_password as secret' do + should contain_cinder_config("#{params_hash[:volume_backend_name]}/netapp_password").with_secret( true ) + end + + it 'marks netapp_sa_password as secret' do + should contain_cinder_config("#{params_hash[:volume_backend_name]}/netapp_sa_password").with_secret( true ) + end + end + + + context 'with default parameters' do + before do + params = {} + end + + it_configures 'netapp volume driver' + end + + context 'with provided parameters' do + it_configures 'netapp volume driver' + end + + context 'with netapp_storage_family eseries' do + let (:req_params) { params.merge!({ + :netapp_storage_family => 'eseries', + }) } + + it { should contain_cinder_config("#{req_params[:volume_backend_name]}/use_multipath_for_image_xfer").with_value('true') } + end + + context 'with NFS mount options' do + let (:req_params) { params.merge!({ + :nfs_mount_options => 'rw,proto=tcp,sec=sys', + }) } + + it { should contain_cinder_config("#{req_params[:volume_backend_name]}/nfs_mount_options").with_value('rw,proto=tcp,sec=sys') } + end + + context 'with NFS shares provided' do + let (:req_params) { params.merge!({ + :nfs_shares => ['10.0.0.1:/test1', '10.0.0.2:/test2'], + :nfs_shares_config => '/etc/cinder/shares.conf', + }) } + + it 'writes NFS shares to file' do + should contain_file("#{req_params[:nfs_shares_config]}") \ + .with_content("10.0.0.1:/test1\n10.0.0.2:/test2") + end + end + + context 'with invalid NFS shares provided' do + before do + params.merge!({ + :nfs_shares => "not an array", + :nfs_shares_config => '/etc/cinder/shares.conf', + }) + end + + it 'throw error' do + expect {subject}.to raise_error(Puppet::Error, /"not an array" is not an Array. It looks to be a String/) + end + end + +end diff --git a/3rdparty/modules/cinder/spec/defines/cinder_backend_nexenta_spec.rb b/3rdparty/modules/cinder/spec/defines/cinder_backend_nexenta_spec.rb new file mode 100644 index 000000000..2c26c5865 --- /dev/null +++ b/3rdparty/modules/cinder/spec/defines/cinder_backend_nexenta_spec.rb @@ -0,0 +1,39 @@ +# author 'Aimon Bustardo ' +# license 'Apache License 2.0' +# description 'configures openstack cinder nexenta driver' +require 'spec_helper' + +describe 'cinder::backend::nexenta' do + let (:title) { 'nexenta' } + + let :params do + { :nexenta_user => 'nexenta', + :nexenta_password => 'password', + :nexenta_host => '127.0.0.2' } + end + + let :default_params do + { :nexenta_volume => 'cinder', + :nexenta_target_prefix => 'iqn:', + :nexenta_target_group_prefix => 'cinder/', + :nexenta_blocksize => '8k', + :nexenta_sparse => true } + end + + let :facts do + { :osfamily => 'Debian' } + end + + + context 'with required params' do + let :params_hash do + default_params.merge(params) + end + + it 'configures nexenta volume driver' do + params_hash.each_pair do |config, value| + should contain_cinder_config("nexenta/#{config}").with_value(value) + end + end + end +end diff --git a/3rdparty/modules/cinder/spec/defines/cinder_backend_nfs_spec.rb b/3rdparty/modules/cinder/spec/defines/cinder_backend_nfs_spec.rb new file mode 100644 index 000000000..bc7906f6d --- /dev/null +++ b/3rdparty/modules/cinder/spec/defines/cinder_backend_nfs_spec.rb @@ -0,0 +1,48 @@ +require 'spec_helper' + +describe 'cinder::backend::nfs' do + + let(:title) {'hippo'} + + let :params do + { + :nfs_servers => ['10.10.10.10:/shares', '10.10.10.10:/shares2'], + :nfs_mount_options => 'vers=3', + :nfs_shares_config => '/etc/cinder/other_shares.conf', + :nfs_disk_util => 'du', + :nfs_sparsed_volumes => true, + :nfs_mount_point_base => '/cinder_mount_point', + :nfs_used_ratio => '0.7', + :nfs_oversub_ratio => '0.9' + } + end + + describe 'nfs volume driver' do + + it 'configures nfs volume driver' do + should contain_cinder_config('hippo/volume_backend_name').with( + :value => 'hippo') + should contain_cinder_config('hippo/volume_driver').with_value( + 'cinder.volume.drivers.nfs.NfsDriver') + should contain_cinder_config('hippo/nfs_shares_config').with_value( + '/etc/cinder/other_shares.conf') + should contain_cinder_config('hippo/nfs_mount_options').with_value( + 'vers=3') + should contain_cinder_config('hippo/nfs_sparsed_volumes').with_value( + true) + should contain_cinder_config('hippo/nfs_mount_point_base').with_value( + '/cinder_mount_point') + should contain_cinder_config('hippo/nfs_disk_util').with_value( + 'du') + should contain_cinder_config('hippo/nfs_used_ratio').with_value( + '0.7') + should contain_cinder_config('hippo/nfs_oversub_ratio').with_value( + '0.9') + should contain_file('/etc/cinder/other_shares.conf').with( + :content => "10.10.10.10:/shares\n10.10.10.10:/shares2", + :require => 'Package[cinder]', + :notify => 'Service[cinder-volume]' + ) + end + end +end diff --git a/3rdparty/modules/cinder/spec/defines/cinder_backend_quobyte_spec.rb b/3rdparty/modules/cinder/spec/defines/cinder_backend_quobyte_spec.rb new file mode 100644 index 000000000..a3499f2bc --- /dev/null +++ b/3rdparty/modules/cinder/spec/defines/cinder_backend_quobyte_spec.rb @@ -0,0 +1,45 @@ +require 'spec_helper' + +describe 'cinder::backend::quobyte' do + + shared_examples_for 'quobyte volume driver' do + let(:title) {'myquobyte'} + + let :params do + { + :quobyte_volume_url => 'quobyte://quobyte.cluster.example.com/volume-name', + :quobyte_qcow2_volumes => false, + :quobyte_sparsed_volumes => true, + } + end + + it 'configures quobyte volume driver' do + should contain_cinder_config('myquobyte/volume_driver').with_value( + 'cinder.volume.drivers.quobyte.QuobyteDriver') + should contain_cinder_config('myquobyte/quobyte_volume_url').with_value( + 'quobyte://quobyte.cluster.example.com/volume-name') + should contain_cinder_config('myquobyte/quobyte_qcow2_volumes').with_value( + false) + should contain_cinder_config('myquobyte/quobyte_sparsed_volumes').with_value( + true) + end + + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'quobyte volume driver' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'quobyte volume driver' + end + +end diff --git a/3rdparty/modules/cinder/spec/defines/cinder_backend_rbd_spec.rb b/3rdparty/modules/cinder/spec/defines/cinder_backend_rbd_spec.rb new file mode 100644 index 000000000..0636344c0 --- /dev/null +++ b/3rdparty/modules/cinder/spec/defines/cinder_backend_rbd_spec.rb @@ -0,0 +1,98 @@ +require 'spec_helper' + +describe 'cinder::backend::rbd' do + + let(:title) {'rbd-ssd'} + + let :req_params do + { + :volume_backend_name => 'rbd-ssd', + :rbd_pool => 'volumes', + :glance_api_version => '2', + :rbd_user => 'test', + :rbd_secret_uuid => '0123456789', + :rbd_ceph_conf => '/foo/boo/zoo/ceph.conf', + :rbd_flatten_volume_from_snapshot => true, + :volume_tmp_dir => '/foo/tmp', + :rbd_max_clone_depth => '0' + } + end + + it { should contain_class('cinder::params') } + + let :params do + req_params + end + + let :facts do + {:osfamily => 'Debian'} + end + + describe 'rbd backend volume driver' do + it 'configure rbd volume driver' do + should contain_cinder_config("#{req_params[:volume_backend_name]}/volume_backend_name").with_value(req_params[:volume_backend_name]) + should contain_cinder_config("#{req_params[:volume_backend_name]}/volume_driver").with_value('cinder.volume.drivers.rbd.RBDDriver') + should contain_cinder_config("#{req_params[:volume_backend_name]}/rbd_ceph_conf").with_value(req_params[:rbd_ceph_conf]) + should contain_cinder_config("#{req_params[:volume_backend_name]}/rbd_flatten_volume_from_snapshot").with_value(req_params[:rbd_flatten_volume_from_snapshot]) + should contain_cinder_config("#{req_params[:volume_backend_name]}/volume_tmp_dir").with_value(req_params[:volume_tmp_dir]) + should contain_cinder_config("#{req_params[:volume_backend_name]}/rbd_max_clone_depth").with_value(req_params[:rbd_max_clone_depth]) + should contain_cinder_config("#{req_params[:volume_backend_name]}/rbd_pool").with_value(req_params[:rbd_pool]) + should contain_cinder_config("#{req_params[:volume_backend_name]}/rbd_user").with_value(req_params[:rbd_user]) + should contain_cinder_config("#{req_params[:volume_backend_name]}/rbd_secret_uuid").with_value(req_params[:rbd_secret_uuid]) + should contain_file('/etc/init/cinder-volume.override').with(:ensure => 'present') + should contain_file_line('set initscript env').with( + :line => /env CEPH_ARGS=\"--id test\"/, + :path => '/etc/init/cinder-volume.override', + :notify => 'Service[cinder-volume]') + end + + context 'with rbd_secret_uuid disabled' do + let(:params) { req_params.merge!({:rbd_secret_uuid => false}) } + it { should contain_cinder_config("#{req_params[:volume_backend_name]}/rbd_secret_uuid").with_ensure('absent') } + end + + context 'with volume_tmp_dir disabled' do + let(:params) { req_params.merge!({:volume_tmp_dir => false}) } + it { should contain_cinder_config("#{req_params[:volume_backend_name]}/volume_tmp_dir").with_ensure('absent') } + end + + context 'with another RBD backend' do + let :pre_condition do + "cinder::backend::rbd { 'ceph2': + rbd_pool => 'volumes2', + rbd_user => 'test' + }" + end + it { should contain_cinder_config("#{req_params[:volume_backend_name]}/volume_driver").with_value('cinder.volume.drivers.rbd.RBDDriver') } + it { should contain_cinder_config("#{req_params[:volume_backend_name]}/rbd_pool").with_value(req_params[:rbd_pool]) } + it { should contain_cinder_config("#{req_params[:volume_backend_name]}/rbd_user").with_value(req_params[:rbd_user]) } + it { should contain_cinder_config("ceph2/volume_driver").with_value('cinder.volume.drivers.rbd.RBDDriver') } + it { should contain_cinder_config("ceph2/rbd_pool").with_value('volumes2') } + it { should contain_cinder_config("ceph2/rbd_user").with_value('test') } + end + end + + describe 'with RedHat' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :params do + req_params + end + + it 'should ensure that the cinder-volume sysconfig file is present' do + should contain_file('/etc/sysconfig/openstack-cinder-volume').with( + :ensure => 'present' + ) + end + + it 'should configure RedHat init override' do + should contain_file_line('set initscript env').with( + :line => /export CEPH_ARGS=\"--id test\"/, + :path => '/etc/sysconfig/openstack-cinder-volume', + :notify => 'Service[cinder-volume]') + end + end + +end diff --git a/3rdparty/modules/cinder/spec/defines/cinder_backend_san_spec.rb b/3rdparty/modules/cinder/spec/defines/cinder_backend_san_spec.rb new file mode 100644 index 000000000..ef647de29 --- /dev/null +++ b/3rdparty/modules/cinder/spec/defines/cinder_backend_san_spec.rb @@ -0,0 +1,40 @@ +require 'spec_helper' + +describe 'cinder::backend::san' do + let (:title) { 'mysan' } + + let :params do + { :volume_driver => 'cinder.volume.san.SolarisISCSIDriver', + :san_ip => '127.0.0.1', + :san_login => 'cluster_operator', + :san_password => '007', + :san_clustername => 'storage_cluster' } + end + + let :default_params do + { :san_thin_provision => true, + :san_login => 'admin', + :san_ssh_port => 22, + :san_is_local => false, + :ssh_conn_timeout => 30, + :ssh_min_pool_conn => 1, + :ssh_max_pool_conn => 5 } + end + + shared_examples_for 'a san volume driver' do + let :params_hash do + default_params.merge(params) + end + + it 'configures cinder volume driver' do + params_hash.each_pair do |config,value| + should contain_cinder_config("mysan/#{config}").with_value( value ) + end + end + end + + + context 'with parameters' do + it_configures 'a san volume driver' + end +end diff --git a/3rdparty/modules/cinder/spec/defines/cinder_backend_solidfire_spec.rb b/3rdparty/modules/cinder/spec/defines/cinder_backend_solidfire_spec.rb new file mode 100644 index 000000000..0b5a71226 --- /dev/null +++ b/3rdparty/modules/cinder/spec/defines/cinder_backend_solidfire_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' + +describe 'cinder::backend::solidfire' do + let (:title) { 'solidfire' } + + let :req_params do + { + :san_ip => '127.0.0.2', + :san_login => 'solidfire', + :san_password => 'password', + } + end + + let :params do + req_params + end + + describe 'solidfire volume driver' do + it 'configure solidfire volume driver' do + should contain_cinder_config('solidfire/volume_driver').with_value( + 'cinder.volume.drivers.solidfire.SolidFireDriver') + should contain_cinder_config('solidfire/san_ip').with_value( + '127.0.0.2') + should contain_cinder_config('solidfire/san_login').with_value( + 'solidfire') + should contain_cinder_config('solidfire/san_password').with_value( + 'password') + end + end +end diff --git a/3rdparty/modules/cinder/spec/defines/cinder_backend_vmdk_spec.rb b/3rdparty/modules/cinder/spec/defines/cinder_backend_vmdk_spec.rb new file mode 100644 index 000000000..85940acaa --- /dev/null +++ b/3rdparty/modules/cinder/spec/defines/cinder_backend_vmdk_spec.rb @@ -0,0 +1,59 @@ +require 'spec_helper' + +describe 'cinder::backend::vmdk' do + + let(:title) { 'hippo' } + + let :params do + { + :host_ip => '172.16.16.16', + :host_password => 'asdf', + :host_username => 'user' + } + end + + let :optional_params do + { + :volume_folder => 'cinder-volume-folder', + :api_retry_count => 5, + :max_object_retrieval => 200, + :task_poll_interval => 10, + :image_transfer_timeout_secs => 3600, + :wsdl_location => 'http://127.0.0.1:8080/vmware/SDK/wsdl/vim25/vimService.wsdl' + } + end + + it 'should configure vmdk driver in cinder.conf' do + should contain_cinder_config('hippo/volume_backend_name').with_value('hippo') + should contain_cinder_config('hippo/volume_driver').with_value('cinder.volume.drivers.vmware.vmdk.VMwareVcVmdkDriver') + should contain_cinder_config('hippo/vmware_host_ip').with_value(params[:host_ip]) + should contain_cinder_config('hippo/vmware_host_username').with_value(params[:host_username]) + should contain_cinder_config('hippo/vmware_host_password').with_value(params[:host_password]) + should contain_cinder_config('hippo/vmware_volume_folder').with_value('cinder-volumes') + should contain_cinder_config('hippo/vmware_api_retry_count').with_value(10) + should contain_cinder_config('hippo/vmware_max_object_retrieval').with_value(100) + should contain_cinder_config('hippo/vmware_task_poll_interval').with_value(5) + should contain_cinder_config('hippo/vmware_image_transfer_timeout_secs').with_value(7200) + should_not contain_cinder_config('hippo/vmware_wsdl_location') + end + + it 'installs suds python package' do + should contain_package('python-suds').with( + :ensure => 'present') + end + + context 'with optional parameters' do + before :each do + params.merge!(optional_params) + end + + it 'should configure vmdk driver in cinder.conf' do + should contain_cinder_config('hippo/vmware_volume_folder').with_value(params[:volume_folder]) + should contain_cinder_config('hippo/vmware_api_retry_count').with_value(params[:api_retry_count]) + should contain_cinder_config('hippo/vmware_max_object_retrieval').with_value(params[:max_object_retrieval]) + should contain_cinder_config('hippo/vmware_task_poll_interval').with_value(params[:task_poll_interval]) + should contain_cinder_config('hippo/vmware_image_transfer_timeout_secs').with_value(params[:image_transfer_timeout_secs]) + should contain_cinder_config('hippo/vmware_wsdl_location').with_value(params[:wsdl_location]) + end + end +end diff --git a/3rdparty/modules/cinder/spec/defines/cinder_type_set_spec.rb b/3rdparty/modules/cinder/spec/defines/cinder_type_set_spec.rb new file mode 100644 index 000000000..2faba85ea --- /dev/null +++ b/3rdparty/modules/cinder/spec/defines/cinder_type_set_spec.rb @@ -0,0 +1,30 @@ +#Author: Andrew Woodward + +require 'spec_helper' + +describe 'cinder::type_set' do + + let(:title) {'hippo'} + + let :params do { + :type => 'sith', + :key => 'monchichi', + :os_password => 'asdf', + :os_tenant_name => 'admin', + :os_username => 'admin', + :os_auth_url => 'http://127.127.127.1:5000/v2.0/', + } + end + + it 'should have its execs' do + should contain_exec('cinder type-key sith set monchichi=hippo').with( + :command => 'cinder type-key sith set monchichi=hippo', + :unless => "cinder extra-specs-list | grep -Eq '\\bsith\\b.*\\bmonchichi\\b.*\\bhippo\\b'", + :environment => [ + 'OS_TENANT_NAME=admin', + 'OS_USERNAME=admin', + 'OS_PASSWORD=asdf', + 'OS_AUTH_URL=http://127.127.127.1:5000/v2.0/'], + :require => 'Package[python-cinderclient]') + end +end diff --git a/3rdparty/modules/cinder/spec/defines/cinder_type_spec.rb b/3rdparty/modules/cinder/spec/defines/cinder_type_spec.rb new file mode 100644 index 000000000..4fa2ac981 --- /dev/null +++ b/3rdparty/modules/cinder/spec/defines/cinder_type_spec.rb @@ -0,0 +1,32 @@ +#Author: Andrew Woodward + +require 'spec_helper' + +describe 'cinder::type' do + + let(:title) {'hippo'} + + let :params do { + :set_value => ['name1','name2'], + :set_key => 'volume_backend_name', + :os_password => 'asdf', + :os_tenant_name => 'admin', + :os_username => 'admin', + :os_auth_url => 'http://127.127.127.1:5000/v2.0/', + } + end + + it 'should have its execs' do + should contain_exec('cinder type-create hippo').with( + :command => 'cinder type-create hippo', + :environment => [ + 'OS_TENANT_NAME=admin', + 'OS_USERNAME=admin', + 'OS_PASSWORD=asdf', + 'OS_AUTH_URL=http://127.127.127.1:5000/v2.0/'], + :unless => "cinder type-list | grep -qP '\\bhippo\\b'", + :require => 'Package[python-cinderclient]') + should contain_exec('cinder type-key hippo set volume_backend_name=name1') + should contain_exec('cinder type-key hippo set volume_backend_name=name2') + end +end diff --git a/3rdparty/modules/cinder/spec/shared_examples.rb b/3rdparty/modules/cinder/spec/shared_examples.rb new file mode 100644 index 000000000..d92156a36 --- /dev/null +++ b/3rdparty/modules/cinder/spec/shared_examples.rb @@ -0,0 +1,5 @@ +shared_examples_for "a Puppet::Error" do |description| + it "with message matching #{description.inspect}" do + expect { should have_class_count(1) }.to raise_error(Puppet::Error, description) + end +end diff --git a/3rdparty/modules/cinder/spec/spec_helper.rb b/3rdparty/modules/cinder/spec/spec_helper.rb new file mode 100644 index 000000000..53d4dd02d --- /dev/null +++ b/3rdparty/modules/cinder/spec/spec_helper.rb @@ -0,0 +1,7 @@ +require 'puppetlabs_spec_helper/module_spec_helper' +require 'shared_examples' + +RSpec.configure do |c| + c.alias_it_should_behave_like_to :it_configures, 'configures' + c.alias_it_should_behave_like_to :it_raises, 'raises' +end diff --git a/3rdparty/modules/glance/Gemfile b/3rdparty/modules/glance/Gemfile new file mode 100644 index 000000000..f3182fde2 --- /dev/null +++ b/3rdparty/modules/glance/Gemfile @@ -0,0 +1,19 @@ +source 'https://rubygems.org' + +group :development, :test do + gem 'puppetlabs_spec_helper', :require => false + gem 'puppet-lint', '~> 0.3.2' + gem 'rspec-puppet', '~> 1.0.1' + gem 'rake', '10.1.1' + gem 'rspec', '< 2.99' + gem 'json' + gem 'webmock' +end + +if puppetversion = ENV['PUPPET_GEM_VERSION'] + gem 'puppet', puppetversion, :require => false +else + gem 'puppet', :require => false +end + +# vim:ft=ruby diff --git a/3rdparty/modules/glance/LICENSE b/3rdparty/modules/glance/LICENSE new file mode 100644 index 000000000..8d968b6cb --- /dev/null +++ b/3rdparty/modules/glance/LICENSE @@ -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. diff --git a/3rdparty/modules/glance/README.md b/3rdparty/modules/glance/README.md new file mode 100644 index 000000000..1e4172674 --- /dev/null +++ b/3rdparty/modules/glance/README.md @@ -0,0 +1,240 @@ +glance +======= + +5.1.0 - 2014.2 - Juno + +#### Table of Contents + +1. [Overview - What is the glance module?](#overview) +2. [Module Description - What does the module do?](#module-description) +3. [Setup - The basics of getting started with glance](#setup) +4. [Implementation - An under-the-hood peek at what the module is doing](#implementation) +5. [Limitations - OS compatibility, etc.](#limitations) +6. [Development - Guide for contributing to the module](#development) +7. [Contributors - Those with commits](#contributors) +8. [Release Notes - Notes on the most recent updates to the module](#release-notes) + +Overview +-------- + +The glance module is a part of [Stackforge](https://github.com/stackfoge), an effort by the Openstack infrastructure team to provide continuous integration testing and code review for Openstack and Openstack community projects not part of the core software. The module its self is used to flexibly configure and manage the image service for Openstack. + +Module Description +------------------ + +The glance module is a thorough attempt to make Puppet capable of managing the entirety of glance. This includes manifests to provision such things as keystone endpoints, RPC configurations specific to glance, and database connections. Types are shipped as part of the glance module to assist in manipulation of configuration files. + +This module is tested in combination with other modules needed to build and leverage an entire Openstack software stack. These modules can be found, all pulled together in the [openstack module](https://github.com/stackfoge/puppet-openstack). + +Setup +----- + +**What the glance module affects** + +* glance, the image service for Openstack. + +### Installing glance + + example% puppet module install puppetlabs/glance + +### Beginning with glance + +To utilize the glance module's functionality you will need to declare multiple resources. The following is a modified excerpt from the [openstack module](https://github.com/stackfoge/puppet-openstack). This is not an exhaustive list of all the components needed, we recommend you consult and understand the [openstack module](https://github.com/stackforge/puppet-openstack) and the [core openstack](http://docs.openstack.org) documentation. + +**Define a glance node** + +```puppet +class { 'glance::api': + verbose => true, + keystone_tenant => 'services', + keystone_user => 'glance', + keystone_password => '12345', + sql_connection => 'mysql://glance:12345@127.0.0.1/glance', +} + +class { 'glance::registry': + verbose => true, + keystone_tenant => 'services', + keystone_user => 'glance', + keystone_password => '12345', + sql_connection => 'mysql://glance:12345@127.0.0.1/glance', +} + +class { 'glance::backend::file': } +``` + +**Setup postgres node glance** + +```puppet +class { 'glance::db::postgresql': + password => '12345', +} +``` + +**Setup mysql node for glance** + +```puppet +class { 'glance::db::mysql': + password => '12345', + allowed_hosts => '%', +} +``` + +**Setup up keystone endpoints for glance on keystone node** + +```puppet +class { 'glance::keystone::auth': + password => '12345' + email => 'glance@example.com', + public_address => '172.17.0.3', + admin_address => '172.17.0.3', + internal_address => '172.17.1.3', + region => 'example-west-1', +} +``` + +**Setup up notifications for multiple RabbitMQ nodes** + +```puppet +class { 'glance::notify::rabbitmq': + rabbit_password => 'pass', + rabbit_userid => 'guest', + rabbit_hosts => [ + 'localhost:5672', 'remotehost:5672' + ], + rabbit_use_ssl => false, +} +``` + +Implementation +-------------- + +### glance + +glance is a combination of Puppet manifest and ruby code to deliver configuration and extra functionality through types and providers. + +Limitations +------------ + +* Only supports configuring the file, swift and rbd storage backends. + +Development +----------- + +Developer documentation for the entire puppet-openstack project. + +* https://wiki.openstack.org/wiki/Puppet-openstack#Developer_documentation + +Contributors +------------ + +* https://github.com/stackforge/puppet-glance/graphs/contributors + +Release Notes +------------- + +**5.1.0** + +* Service Validation for Glance-API +* Switch to TLSv1 +* spec: pin rspec-puppet to 1.0.1 +* Makes kombu_ssl_* parameters optional when rabbit_use_ssl => true +* Allow overriding package ensure for glance-registry +* Move rbd related options into glance_store section +* Pin puppetlabs-concat to 1.2.1 in fixtures +* change default MySQL collate to utf8_general_ci +* Add openstack tag to glance packages +* Correctly munge glance_image is_public property +* Create a sync_db boolean for Glance +* Command parameter to sync the correct Database +* Fix catalog compilation when not configuring endpoint +* Add $notification_driver parameter to notify::rabbitmq +* Fix is_public munge +* Update .gitreview file for project rename + +**5.0.0** + +* Stable Juno release +* Added ceilometer::policy to control policy.json +* Fixed bug in glance_image type +* Added parameter os_region_name to glance::api +* Added support for vSphere datastore backend +* Updated the calls to the glance command-line utility +* Added parameter swift_store_large_object_size to glance::backend::swift +* Bumped stdlib dependency to >=4.0.0 +* Added parameter command_options to glance::cache::cleaner and glance::cache::pruner +* Added parameter package_ensure to glance::backend::rbd +* Added parameter manage_service to various classes +* Added parameters to control whether to configure users +* Migrated the glance::db::mysql class to use openstacklib::db::mysql and deprecated the mysql_module parameter +* Added parameter registery_client_protocol to glance::api +* Fixed ssl parameter requirements for kombu and rabbit + +**4.2.0** + +* Added ability to hide secret type parameters from logs + +**4.1.0** + +* Added multiple rabbit hosts support. +* Added image_cache_dir parameter. +* Deprecated old SQL parameters. +* Fixed the Glance add_image parser for new client. +* Fixed values in get_glance_image_attrs. +* Fixed 'could not find user glance' bug. +* Pinned major gems. + +**4.0.0** + +* Stable Icehouse release. +* Added glance::config to handle additional custom options. +* Added known_stores option for glance::api. +* Added copy-on-write cloning of images to volumes. +* Added support for puppetlabs-mysql 2.2 and greater. +* Added support for python-glanceclient v2 API update. +* Removed deprecated notifier_stratgy parameter. +* Deprecated show_image_direct_url in glance::rbd. + +**3.1.0** + +* Added availability to configure show_image_direct_url. +* Removed Keystone client warnings. +* Added support for https authentication endpoints. +* Enabled ssl configuration for glance-registry. +* Explicitly sets default notifier strategy. + +**3.0.0** + +* Major release for OpenStack Havana. +* Fixed bug to ensure keystone endpoint is set before service starts. +* Added Cinder backend to image storage. +* Fixed qpid_hostname bug. + +**2.2.0** + +* Added syslog support. +* Added support for iso disk format. +* Fixed bug to allow support for rdb options in glance-api.conf. +* Fixed bug for rabbitmq options in notify::rabbitmq. +* Removed non-implemented glance::scrubber class. +* Various lint and bug fixes. + +**2.1.0** + +* Added glance-cache-cleaner and glance-cache-pruner. +* Added ceph/rdb support. +* Added retry for glance provider to account for service startup time. +* Added support for both file and swift backends. +* Fixed allowed_hosts/database access bug. +* Fixed glance_image type example. +* Removed unnecessary mysql::server dependency. +* Removed --silent-upload option. +* Removed glance-manage version_control. +* Pinned rabbit and mysql module versions. +* Various lint and bug fixes. + +**2.0.0** + +* Upstream is now part of stackfoge. +* Added postgresql support. +* Various cleanups and bug fixes. diff --git a/3rdparty/modules/glance/Rakefile b/3rdparty/modules/glance/Rakefile new file mode 100644 index 000000000..4c2b2ed07 --- /dev/null +++ b/3rdparty/modules/glance/Rakefile @@ -0,0 +1,6 @@ +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' + +PuppetLint.configuration.fail_on_warnings = true +PuppetLint.configuration.send('disable_80chars') +PuppetLint.configuration.send('disable_class_parameter_defaults') diff --git a/3rdparty/modules/glance/checksums.json b/3rdparty/modules/glance/checksums.json new file mode 100644 index 000000000..ae1859a26 --- /dev/null +++ b/3rdparty/modules/glance/checksums.json @@ -0,0 +1,66 @@ +{ + "Gemfile": "4a83c46a2bb3896cf81852501819bb3a", + "LICENSE": "0e5ccf641e613489e66aa98271dbe798", + "README.md": "4c3db32c955c66826e6b87ab448ded5f", + "Rakefile": "2ca4ff31c946a19edd44348fbfdc2aab", + "ext/glance.rb": "d18e56aa4ec3c74d709927d74e413eb0", + "ext/glance.sh": "d4a51eea6741cadfcc699daf376e3528", + "lib/puppet/provider/glance.rb": "33d83e907b30e1e65d3f6b93c65b6fdd", + "lib/puppet/provider/glance_api_config/ini_setting.rb": "6f5af831ae0c2550c3c3f7b52b103e6d", + "lib/puppet/provider/glance_api_paste_ini/ini_setting.rb": "94023412cb02989c38e191d699b9b3b5", + "lib/puppet/provider/glance_cache_config/ini_setting.rb": "44b67f634c27a4e7eef7101e24a3d9d3", + "lib/puppet/provider/glance_image/glance.rb": "15c2dc366e8d8cc245cddfbfd99e39c4", + "lib/puppet/provider/glance_registry_config/ini_setting.rb": "a4b09634d752a27179a32726efda2005", + "lib/puppet/provider/glance_registry_paste_ini/ini_setting.rb": "c3992b977d0964f15e3f9bc59eab94d5", + "lib/puppet/type/glance_api_config.rb": "2dd6ba070ec6b8c29686c011d26b885b", + "lib/puppet/type/glance_api_paste_ini.rb": "a43114f08b8b2bf4471b24b8d13f88f5", + "lib/puppet/type/glance_cache_config.rb": "a6091df3dd2220de8b4e6b32581d2c63", + "lib/puppet/type/glance_image.rb": "837a74258eb6d9e1afb7b253b01e154c", + "lib/puppet/type/glance_registry_config.rb": "6ddb62b71bedf2002849ef723a5a97f4", + "lib/puppet/type/glance_registry_paste_ini.rb": "1be6eec04acbd2c915f6fd39a521e9dd", + "manifests/api.pp": "3d78b4559a16478f2b039d03917ccc65", + "manifests/backend/cinder.pp": "9ddd4d8e67a49b2f838df2f75199e422", + "manifests/backend/file.pp": "b896d14d0d88ec0e64980143f9347232", + "manifests/backend/rbd.pp": "e38edef0eb9d2a3b4a2c20649ee4bdce", + "manifests/backend/swift.pp": "3eeac1138bb2a3c116732705864ca02c", + "manifests/backend/vsphere.pp": "9eae12284e771630eb05d1d77f583212", + "manifests/cache/cleaner.pp": "f293a5378077c706df326cde2c6d626f", + "manifests/cache/pruner.pp": "9de8c064128734431ef882573a50ef8f", + "manifests/client.pp": "b17bb7d83c69e23a0578fcce5944e4eb", + "manifests/config.pp": "de257a14b405c666e621504b40838d17", + "manifests/db/mysql.pp": "86eeca033caa137bfa5f53813757f5b7", + "manifests/db/postgresql.pp": "cea3216111a730d89196ecdaec0f1be9", + "manifests/init.pp": "0c1ade8036598e54d25e123fa46b6ec6", + "manifests/keystone/auth.pp": "f96d9a28ef273c8fb873bf3bcefd28b7", + "manifests/notify/qpid.pp": "3ea1e110dca68e6c1ef65adc755da1fa", + "manifests/notify/rabbitmq.pp": "f00e1301610de2b335f486a408d3e302", + "manifests/params.pp": "ce7528c3b4dee6ee1d3b775e5de11da4", + "manifests/policy.pp": "4a65f721753fcdce3d280cd799894088", + "manifests/registry.pp": "0597c51797f790c47949bead929aa542", + "metadata.json": "8627384faaa47dfc73f32c559f39a4d3", + "spec/classes/glance_api_spec.rb": "ea2efa3e14aafd920073cafb2c41feaa", + "spec/classes/glance_backend_cinder_spec.rb": "5c8220b2463d535ef35c334a1b3a197b", + "spec/classes/glance_backend_file_spec.rb": "390fcabf9b18c7189087eda6836352f7", + "spec/classes/glance_backend_rbd_spec.rb": "60b6797a1ad8243e0e4c2789e0cda015", + "spec/classes/glance_backend_swift_spec.rb": "6ecd2b0aea2591e331349780334b2214", + "spec/classes/glance_backend_vsphere_spec.rb": "d75685d4afe54482db819ddb149b6aa8", + "spec/classes/glance_cache_cleaner_spec.rb": "f75b76e559d3f6b8c55b177165b25f4a", + "spec/classes/glance_cache_pruner_spec.rb": "c823c9a16b139b6b3c4b26b5b1e5c002", + "spec/classes/glance_client_spec.rb": "61f596440d481df9cbddef494b8833ad", + "spec/classes/glance_db_mysql_spec.rb": "e7f8868e4774aede8d0aa12038efe41f", + "spec/classes/glance_db_postgresql_spec.rb": "35d461fbdfbb39c3dbbce60cd36b4a2b", + "spec/classes/glance_keystone_auth_spec.rb": "9374aaf53ad3397c835aab046bcfe8bb", + "spec/classes/glance_notify_qpid_spec.rb": "35fbbae76a73e09621d324dca9144574", + "spec/classes/glance_notify_rabbitmq_spec.rb": "e38ec04e62b7ac8b1386b1e066a94e08", + "spec/classes/glance_policy_spec.rb": "69318ee870c92233a9b392e01e246e18", + "spec/classes/glance_registry_spec.rb": "54286c11709cc8276b7369cf47f3ab14", + "spec/classes/glance_spec.rb": "fc2ea9f357a6948835f5acfae6256f9f", + "spec/shared_examples.rb": "172c63c57efca8c741f297494ed9ef0f", + "spec/spec.opts": "a600ded995d948e393fbe2320ba8e51c", + "spec/spec_helper.rb": "1d9a0ed080a66070ae5b45738113e1a3", + "spec/unit/provider/glance_spec.rb": "26c8c1c63fdc8e04139529fa987c70e8", + "tests/api.pp": "1628c0a94db35bf37659412190600189", + "tests/init.pp": "0df45b7489688f7cfde9231466305ffe", + "tests/registry.pp": "af5a7e7f542d9ec04d6925d6b7107e11", + "tests/site.pp": "180f23cc1ba29ebf40e0466513306105" +} \ No newline at end of file diff --git a/3rdparty/modules/glance/ext/glance.rb b/3rdparty/modules/glance/ext/glance.rb new file mode 100644 index 000000000..6510397c0 --- /dev/null +++ b/3rdparty/modules/glance/ext/glance.rb @@ -0,0 +1,86 @@ +#!/usr/bin/env ruby +# +# test that we can upload and download files +# +require 'open3' +require 'fileutils' + +keystone_public = '127.0.0.1' +image_dir='/tmp/images' + +ENV['OS_USERNAME']='admin' +ENV['OS_TENANT_NAME']='admin' +ENV['OS_PASSWORD']='ChangeMe' +ENV['OS_AUTH_URL']='http://127.0.0.1:5000/v2.0/' +ENV['OS_REGION_NAME']='RegionOne' + +FileUtils.mkdir_p(image_dir) +Dir.chdir(image_dir) do |dir| + + kernel_id = nil + initrd_id = nil + + remote_image_url='http://smoser.brickies.net/ubuntu/ttylinux-uec/ttylinux-uec-amd64-12.1_2.6.35-22_1.tar.gz; tar -zxvf ttylinux-uec-amd64-12.1_2.6.35-22_1.tar.gz' + + wget_command = "wget #{remote_image_url}" + + Open3.popen3(wget_command) do |stdin, stdout, stderr| + puts "wget stdout: #{stdout.read}" + puts "wget stderr: #{stderr.read}" + end + + add_kernel='disk_format=aki container_format=aki < ttylinux-uec-amd64-12.1_2.6.35-22_1-vmlinuz' + kernel_name='tty-linux-kernel' + kernel_format='aki' + + add_kernel_command="glance add name='#{kernel_name}' disk_format='#{kernel_format}' container_format=#{kernel_format} < ttylinux-uec-amd64-12.1_2.6.35-22_1-vmlinuz" + + Open3.popen3(add_kernel_command) do |stdin, stdout, stderr| + stdout = stdout.read.split("\n") + stdout.each do |line| + if line =~ /Added new image with ID: (\w+)/ + kernel_id = $1 + end + end + puts stderr.read + puts stdout + end + + raise(Exception, 'Did not add kernel successfully') unless kernel_id + + initrd_id = nil + add_initrd_command="glance add name='tty-linux-ramdisk' disk_format=ari container_format=ari < ttylinux-uec-amd64-12.1_2.6.35-22_1-loader" + + Open3.popen3(add_initrd_command) do |stdin, stdout, stderr| + stdout = stdout.read.split("\n") + stdout.each do |line| + if line =~ /Added new image with ID: (\w+)/ + initrd_id = $1 + end + end + puts stderr.read + puts stdout + end + + raise(Exception, 'Did not add initrd successfully') unless initrd_id + + add_image_command="glance add name='tty-linux' disk_format=ami container_format=ami kernel_id=#{kernel_id} ramdisk_id=#{initrd_id} < ttylinux-uec-amd64-12.1_2.6.35-22_1.img" + + Open3.popen3(add_image_command) do |stdin, stdout, stderr| + stdout = stdout.read.split("\n") + stdout.each do |line| + if line =~ /Added new image with ID: (\w+)/ + kernel_id = $1 + end + end + puts stderr.read + puts stdout + end + + get_index='glance index' + + Open3.popen3(get_index) do |stdin, stdout, stderr| + puts stdout.read + puts stderr.read + end +end diff --git a/3rdparty/modules/glance/ext/glance.sh b/3rdparty/modules/glance/ext/glance.sh new file mode 100755 index 000000000..174749981 --- /dev/null +++ b/3rdparty/modules/glance/ext/glance.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# +# assumes that resonable credentials have been stored at +# /root/auth +source /root/auth +wget http://uec-images.ubuntu.com/releases/11.10/release/ubuntu-11.10-server-cloudimg-amd64-disk1.img +glance add name="Ubuntu 11.10 cloudimg amd64" is_public=true container_format=ovf disk_format=qcow2 < ubuntu-11.10-server-cloudimg-amd64-disk1.img +glance index diff --git a/3rdparty/modules/glance/lib/puppet/provider/glance.rb b/3rdparty/modules/glance/lib/puppet/provider/glance.rb new file mode 100644 index 000000000..ec4e1c08e --- /dev/null +++ b/3rdparty/modules/glance/lib/puppet/provider/glance.rb @@ -0,0 +1,188 @@ +# Since there's only one glance type for now, +# this probably could have all gone in the provider file. +# But maybe this is good long-term. +require 'puppet/util/inifile' +class Puppet::Provider::Glance < Puppet::Provider + + def self.glance_credentials + @glance_credentials ||= get_glance_credentials + end + + def self.get_glance_credentials + if glance_file and glance_file['keystone_authtoken'] and + glance_file['keystone_authtoken']['auth_host'] and + glance_file['keystone_authtoken']['auth_port'] and + glance_file['keystone_authtoken']['auth_protocol'] and + glance_file['keystone_authtoken']['admin_tenant_name'] and + glance_file['keystone_authtoken']['admin_user'] and + glance_file['keystone_authtoken']['admin_password'] and + glance_file['DEFAULT']['os_region_name'] + + g = {} + g['auth_host'] = glance_file['keystone_authtoken']['auth_host'].strip + g['auth_port'] = glance_file['keystone_authtoken']['auth_port'].strip + g['auth_protocol'] = glance_file['keystone_authtoken']['auth_protocol'].strip + g['admin_tenant_name'] = glance_file['keystone_authtoken']['admin_tenant_name'].strip + g['admin_user'] = glance_file['keystone_authtoken']['admin_user'].strip + g['admin_password'] = glance_file['keystone_authtoken']['admin_password'].strip + g['os_region_name'] = glance_file['DEFAULT']['os_region_name'].strip + + # auth_admin_prefix not required to be set. + g['auth_admin_prefix'] = (glance_file['keystone_authtoken']['auth_admin_prefix'] || '').strip + + return g + else + raise(Puppet::Error, 'File: /etc/glance/glance-api.conf does not contain all required sections.') + end + end + + def glance_credentials + self.class.glance_credentials + end + + def self.auth_endpoint + @auth_endpoint ||= get_auth_endpoint + end + + def self.get_auth_endpoint + g = glance_credentials + "#{g['auth_protocol']}://#{g['auth_host']}:#{g['auth_port']}#{g['auth_admin_prefix']}/v2.0/" + end + + def self.glance_file + return @glance_file if @glance_file + @glance_file = Puppet::Util::IniConfig::File.new + @glance_file.read('/etc/glance/glance-api.conf') + @glance_file + end + + def self.glance_hash + @glance_hash ||= build_glance_hash + end + + def self.reset + @glance_hash = nil + @glance_file = nil + @glance_credentials = nil + @auth_endpoint = nil + end + + def glance_hash + self.class.glance_hash + end + + def self.auth_glance(*args) + begin + g = glance_credentials + remove_warnings(glance('--os-tenant-name', g['admin_tenant_name'], '--os-username', g['admin_user'], '--os-password', g['admin_password'], '--os-region-name', g['os_region_name'], '--os-auth-url', auth_endpoint, args)) + rescue Exception => e + if (e.message =~ /\[Errno 111\] Connection refused/) or (e.message =~ /\(HTTP 400\)/) or (e.message =~ /HTTP Unable to establish connection/) + sleep 10 + remove_warnings(glance('--os-tenant-name', g['admin_tenant_name'], '--os-username', g['admin_user'], '--os-password', g['admin_password'], '--os-region-name', g['os_region_name'], '--os-auth-url', auth_endpoint, args)) + else + raise(e) + end + end + end + + def auth_glance(*args) + self.class.auth_glance(args) + end + + def self.auth_glance_stdin(*args) + begin + g = glance_credentials + command = "glance --os-tenant-name #{g['admin_tenant_name']} --os-username #{g['admin_user']} --os-password #{g['admin_password']} --os-region-name #{g['os_region_name']} --os-auth-url #{auth_endpoint} #{args.join(' ')}" + + # This is a horrible, horrible hack + # Redirect stderr to stdout in order to report errors + # Ignore good output + err = `#{command} 3>&1 1>/dev/null 2>&3` + if $? != 0 + raise(Puppet::Error, err) + end + end + end + + def auth_glance_stdin(*args) + self.class.auth_glance_stdin(args) + end + + private + def self.list_glance_images + ids = [] + (auth_glance('image-list').split("\n")[3..-2] || []).collect do |line| + ids << line.split('|')[1].strip() + end + return ids + end + + def self.get_glance_image_attr(id, attr) + (auth_glance('image-show', id).split("\n") || []).collect do |line| + if line =~ /^#{attr}:/ + return line.split(': ')[1..-1] + end + end + end + + def self.get_glance_image_attrs(id) + attrs = {} + (auth_glance('image-show', id).split("\n")[3..-2] || []).collect do |line| + attrs[line.split('|')[1].strip()] = line.split('|')[2].strip() + end + return attrs + end + + def parse_table(table) + # parse the table into an array of maps with a simplistic state machine + found_header = false + parsed_header = false + keys = nil + results = [] + table.split("\n").collect do |line| + # look for the header + if not found_header + if line =~ /^\+[-|+]+\+$/ + found_header = true + nil + end + # look for the key names in the table header + elsif not parsed_header + if line =~ /^(\|\s*[:alpha:]\s*)|$/ + keys = line.split('|').map(&:strip) + parsed_header = true + end + # parse the values in the rest of the table + elsif line =~ /^|.*|$/ + values = line.split('|').map(&:strip) + result = Hash[keys.zip values] + results << result + end + end + results + end + + # Remove warning from the output. This is a temporary hack until + # things will be refactored to use the REST API + def self.remove_warnings(results) + found_header = false + in_warning = false + results.split("\n").collect do |line| + unless found_header + if line =~ /^\+[-\+]+\+$/ # Matches upper and lower box borders + in_warning = false + found_header = true + line + elsif line =~ /^WARNING/ or line =~ /UserWarning/ or in_warning + # warnings can be multi line, we have to skip all of them + in_warning = true + nil + else + line + end + else + line + end + end.compact.join("\n") + end +end diff --git a/3rdparty/modules/glance/lib/puppet/provider/glance_api_config/ini_setting.rb b/3rdparty/modules/glance/lib/puppet/provider/glance_api_config/ini_setting.rb new file mode 100644 index 000000000..4323ae8cd --- /dev/null +++ b/3rdparty/modules/glance/lib/puppet/provider/glance_api_config/ini_setting.rb @@ -0,0 +1,27 @@ +Puppet::Type.type(:glance_api_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def self.file_path + '/etc/glance/glance-api.conf' + end + + # this needs to be removed. This has been replaced with the class method + def file_path + self.class.file_path + end + +end diff --git a/3rdparty/modules/glance/lib/puppet/provider/glance_api_paste_ini/ini_setting.rb b/3rdparty/modules/glance/lib/puppet/provider/glance_api_paste_ini/ini_setting.rb new file mode 100644 index 000000000..d624d64bc --- /dev/null +++ b/3rdparty/modules/glance/lib/puppet/provider/glance_api_paste_ini/ini_setting.rb @@ -0,0 +1,27 @@ +Puppet::Type.type(:glance_api_paste_ini).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def self.file_path + '/etc/glance/glance-api-paste.ini' + end + + # added for backwards compatibility with older versions of inifile + def file_path + self.class.file_path + end + +end diff --git a/3rdparty/modules/glance/lib/puppet/provider/glance_cache_config/ini_setting.rb b/3rdparty/modules/glance/lib/puppet/provider/glance_cache_config/ini_setting.rb new file mode 100644 index 000000000..579dfb469 --- /dev/null +++ b/3rdparty/modules/glance/lib/puppet/provider/glance_cache_config/ini_setting.rb @@ -0,0 +1,27 @@ +Puppet::Type.type(:glance_cache_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def self.file_path + '/etc/glance/glance-cache.conf' + end + + # added for backwards compatibility with older versions of inifile + def file_path + self.class.file_path + end + +end diff --git a/3rdparty/modules/glance/lib/puppet/provider/glance_image/glance.rb b/3rdparty/modules/glance/lib/puppet/provider/glance_image/glance.rb new file mode 100644 index 000000000..7be1ace9d --- /dev/null +++ b/3rdparty/modules/glance/lib/puppet/provider/glance_image/glance.rb @@ -0,0 +1,115 @@ +# Load the Glance provider library to help +require File.join(File.dirname(__FILE__), '..','..','..', 'puppet/provider/glance') + +Puppet::Type.type(:glance_image).provide( + :glance, + :parent => Puppet::Provider::Glance +) do + desc <<-EOT + Glance provider to manage glance_image type. + + Assumes that the glance-api service is on the same host and is working. + EOT + + commands :glance => 'glance' + + mk_resource_methods + + def self.instances + list_glance_images.collect do |image| + attrs = get_glance_image_attrs(image) + new( + :ensure => :present, + :name => attrs['name'], + :is_public => attrs['is_public'], + :container_format => attrs['container_format'], + :id => attrs['id'], + :disk_format => attrs['disk_format'] + ) + end + end + + def self.prefetch(resources) + images = instances + resources.keys.each do |name| + if provider = images.find{ |pkg| pkg.name == name } + resources[name].provider = provider + end + end + end + + def exists? + @property_hash[:ensure] == :present + end + + def create + if resource[:source] + # copy_from cannot handle file:// + if resource[:source] =~ /^\// # local file + location = "--file=#{resource[:source]}" + else + location = "--copy-from=#{resource[:source]}" + end + # location cannot handle file:// + # location does not import, so no sense in doing anything more than this + elsif resource[:location] + location = "--location=#{resource[:location]}" + else + raise(Puppet::Error, "Must specify either source or location") + end + results = auth_glance('image-create', "--name=#{resource[:name]}", "--is-public=#{resource[:is_public]}", "--container-format=#{resource[:container_format]}", "--disk-format=#{resource[:disk_format]}", location) + + id = nil + + # Check the old behavior of the python-glanceclient + if results =~ /Added new image with ID: (\S+)/ + id = $1 + else # the new behavior doesn't print the status, so parse the table + results_array = parse_table(results) + results_array.each do |result| + if result["Property"] == "id" + id = result["Value"] + end + end + end + + if id + @property_hash = { + :ensure => :present, + :name => resource[:name], + :is_public => resource[:is_public], + :container_format => resource[:container_format], + :disk_format => resource[:disk_format], + :id => id + } + else + fail("did not get expected message from image creation, got #{results}") + end + end + + def destroy + auth_glance('image-delete', id) + @property_hash[:ensure] = :absent + end + + def location=(value) + auth_glance('image-update', id, "--location=#{value}") + end + + def is_public=(value) + auth_glance('image-update', id, "--is-public=#{value}") + end + + def disk_format=(value) + auth_glance('image-update', id, "--disk-format=#{value}") + end + + def container_format=(value) + auth_glance('image-update', id, "--container-format=#{value}") + end + + def id=(id) + fail('id is read only') + end + +end diff --git a/3rdparty/modules/glance/lib/puppet/provider/glance_registry_config/ini_setting.rb b/3rdparty/modules/glance/lib/puppet/provider/glance_registry_config/ini_setting.rb new file mode 100644 index 000000000..5f843b5e9 --- /dev/null +++ b/3rdparty/modules/glance/lib/puppet/provider/glance_registry_config/ini_setting.rb @@ -0,0 +1,27 @@ +Puppet::Type.type(:glance_registry_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def self.file_path + '/etc/glance/glance-registry.conf' + end + + # added for backwards compatibility with older versions of inifile + def file_path + self.class.file_path + end + +end diff --git a/3rdparty/modules/glance/lib/puppet/provider/glance_registry_paste_ini/ini_setting.rb b/3rdparty/modules/glance/lib/puppet/provider/glance_registry_paste_ini/ini_setting.rb new file mode 100644 index 000000000..36cb7e12c --- /dev/null +++ b/3rdparty/modules/glance/lib/puppet/provider/glance_registry_paste_ini/ini_setting.rb @@ -0,0 +1,27 @@ +Puppet::Type.type(:glance_registry_paste_ini).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def self.file_path + '/etc/glance/glance-registry-paste.ini' + end + + # added for backwards compatibility with older versions of inifile + def file_path + self.class.file_path + end + +end diff --git a/3rdparty/modules/glance/lib/puppet/type/glance_api_config.rb b/3rdparty/modules/glance/lib/puppet/type/glance_api_config.rb new file mode 100644 index 000000000..80c7f6cc8 --- /dev/null +++ b/3rdparty/modules/glance/lib/puppet/type/glance_api_config.rb @@ -0,0 +1,43 @@ +Puppet::Type.newtype(:glance_api_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from glance-api.conf' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end + +end diff --git a/3rdparty/modules/glance/lib/puppet/type/glance_api_paste_ini.rb b/3rdparty/modules/glance/lib/puppet/type/glance_api_paste_ini.rb new file mode 100644 index 000000000..daf4cc498 --- /dev/null +++ b/3rdparty/modules/glance/lib/puppet/type/glance_api_paste_ini.rb @@ -0,0 +1,43 @@ +Puppet::Type.newtype(:glance_api_paste_ini) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from glance-api-paste.ini' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end + +end diff --git a/3rdparty/modules/glance/lib/puppet/type/glance_cache_config.rb b/3rdparty/modules/glance/lib/puppet/type/glance_cache_config.rb new file mode 100644 index 000000000..5f801fd7a --- /dev/null +++ b/3rdparty/modules/glance/lib/puppet/type/glance_cache_config.rb @@ -0,0 +1,43 @@ +Puppet::Type.newtype(:glance_cache_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from glance-cache.conf' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end + +end diff --git a/3rdparty/modules/glance/lib/puppet/type/glance_image.rb b/3rdparty/modules/glance/lib/puppet/type/glance_image.rb new file mode 100644 index 000000000..8ee348a9a --- /dev/null +++ b/3rdparty/modules/glance/lib/puppet/type/glance_image.rb @@ -0,0 +1,79 @@ +Puppet::Type.newtype(:glance_image) do + desc <<-EOT + This allows manifests to declare an image to be + stored in glance. + + glance_image { "Ubuntu 12.04 cloudimg amd64": + ensure => present, + name => "Ubuntu 12.04 cloudimg amd64" + is_public => yes, + container_format => ovf, + disk_format => 'qcow2', + source => 'http://uec-images.ubuntu.com/releases/precise/release/ubuntu-12.04-server-cloudimg-amd64-disk1.img' + } + + Known problems / limitations: + * All images are managed by the glance service. + This means that since users are unable to manage their own images via this type, + is_public is really of no use. You can probably hide images this way but that's all. + * As glance image names do not have to be unique, you must ensure that your glance + repository does not have any duplicate names prior to using this. + * Ensure this is run on the same server as the glance-api service. + + EOT + + ensurable + + newparam(:name, :namevar => true) do + desc 'The image name' + newvalues(/.*/) + end + + newproperty(:id) do + desc 'The unique id of the image' + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:location) do + desc "The permanent location of the image. Optional" + newvalues(/\S+/) + end + + newproperty(:is_public) do + desc "Whether the image is public or not. Default true" + newvalues(/(y|Y)es/, /(n|N)o/) + defaultto('Yes') + munge do |v| + if v =~ /^(y|Y)es$/ + 'True' + elsif v =~ /^(n|N)o$/ + 'False' + end + end + end + + newproperty(:container_format) do + desc "The format of the container" + newvalues(:ami, :ari, :aki, :bare, :ovf) + end + + newproperty(:disk_format) do + desc "The format of the disk" + newvalues(:ami, :ari, :aki, :vhd, :vmd, :raw, :qcow2, :vdi, :iso) + end + + newparam(:source) do + desc "The source of the image to import from" + newvalues(/\S+/) + end + + # Require the Glance service to be running + autorequire(:service) do + ['glance'] + end + +end + + diff --git a/3rdparty/modules/glance/lib/puppet/type/glance_registry_config.rb b/3rdparty/modules/glance/lib/puppet/type/glance_registry_config.rb new file mode 100644 index 000000000..3291be391 --- /dev/null +++ b/3rdparty/modules/glance/lib/puppet/type/glance_registry_config.rb @@ -0,0 +1,43 @@ +Puppet::Type.newtype(:glance_registry_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from glance-registry.conf' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end + +end diff --git a/3rdparty/modules/glance/lib/puppet/type/glance_registry_paste_ini.rb b/3rdparty/modules/glance/lib/puppet/type/glance_registry_paste_ini.rb new file mode 100644 index 000000000..1afeafd75 --- /dev/null +++ b/3rdparty/modules/glance/lib/puppet/type/glance_registry_paste_ini.rb @@ -0,0 +1,43 @@ +Puppet::Type.newtype(:glance_registry_paste_ini) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from glance-registry-paste.ini' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end + +end diff --git a/3rdparty/modules/glance/manifests/api.pp b/3rdparty/modules/glance/manifests/api.pp new file mode 100644 index 000000000..999a7199a --- /dev/null +++ b/3rdparty/modules/glance/manifests/api.pp @@ -0,0 +1,494 @@ +# == Class glance::api +# +# Configure API service in glance +# +# == Parameters +# +# [*keystone_password*] +# (required) Password used to authentication. +# +# [*verbose*] +# (optional) Rather to log the glance api service at verbose level. +# Default: false +# +# [*debug*] +# (optional) Rather to log the glance api service at debug level. +# Default: false +# +# [*bind_host*] +# (optional) The address of the host to bind to. +# Default: 0.0.0.0 +# +# [*bind_port*] +# (optional) The port the server should bind to. +# Default: 9292 +# +# [*backlog*] +# (optional) Backlog requests when creating socket +# Default: 4096 +# +# [*workers*] +# (optional) Number of Glance API worker processes to start +# Default: $::processorcount +# +# [*log_file*] +# (optional) The path of file used for logging +# If set to boolean false, it will not log to any file. +# Default: /var/log/glance/api.log +# +# [*log_dir*] +# (optional) directory to which glance logs are sent. +# If set to boolean false, it will not log to any directory. +# Defaults to '/var/log/glance' +# +# [*registry_host*] +# (optional) The address used to connect to the registry service. +# Default: 0.0.0.0 +# +# [*registry_port*] +# (optional) The port of the Glance registry service. +# Default: 9191 +# +# [*registry_client_protocol*] +# (optional) The protocol of the Glance registry service. +# Default: http +# +# [*auth_type*] +# (optional) Type is authorization being used. +# Defaults to 'keystone' +# +# [* auth_host*] +# (optional) Host running auth service. +# Defaults to '127.0.0.1'. +# +# [*auth_url*] +# (optional) Authentication URL. +# Defaults to 'http://localhost:5000/v2.0'. +# +# [* auth_port*] +# (optional) Port to use for auth service on auth_host. +# Defaults to '35357'. +# +# [* auth_uri*] +# (optional) Complete public Identity API endpoint. +# Defaults to false. +# +# [*auth_admin_prefix*] +# (optional) Path part of the auth url. +# This allow admin auth URIs like http://auth_host:35357/keystone/admin. +# (where '/keystone/admin' is auth_admin_prefix) +# Defaults to false for empty. If defined, should be a string with a leading '/' and no trailing '/'. +# +# [* auth_protocol*] +# (optional) Protocol to use for auth. +# Defaults to 'http'. +# +# [*pipeline*] +# (optional) Partial name of a pipeline in your paste configuration file with the +# service name removed. +# Defaults to 'keystone+cachemanagement'. +# +# [*keystone_tenant*] +# (optional) Tenant to authenticate to. +# Defaults to services. +# +# [*keystone_user*] +# (optional) User to authenticate as with keystone. +# Defaults to 'glance'. +# +# [*manage_service*] +# (optional) If Puppet should manage service startup / shutdown. +# Defaults to true. +# +# [*enabled*] +# (optional) Whether to enable services. +# Defaults to true. +# +# [*sql_idle_timeout*] +# (optional) Deprecated. Use database_idle_timeout instead +# Defaults to false +# +# [*sql_connection*] +# (optional) Deprecated. Use database_connection instead. +# Defaults to false +# +# [*database_connection*] +# (optional) Connection url to connect to nova database. +# Defaults to 'sqlite:///var/lib/glance/glance.sqlite' +# +# [*database_idle_timeout*] +# (optional) Timeout before idle db connections are reaped. +# Defaults to 3600 +# +# [*use_syslog*] +# (optional) Use syslog for logging. +# Defaults to false. +# +# [*log_facility*] +# (optional) Syslog facility to receive log lines. +# Defaults to 'LOG_USER'. +# +# [*show_image_direct_url*] +# (optional) Expose image location to trusted clients. +# Defaults to false. +# +# [*purge_config*] +# (optional) Whether to set only the specified config options +# in the api config. +# Defaults to false. +# +# [*cert_file*] +# (optinal) Certificate file to use when starting API server securely +# Defaults to false, not set +# +# [*key_file*] +# (optional) Private key file to use when starting API server securely +# Defaults to false, not set +# +# [*ca_file*] +# (optional) CA certificate file to use to verify connecting clients +# Defaults to false, not set +# +# [*mysql_module*] +# (optional) Deprecated. Does nothing. +# +# [*known_stores*] +# (optional)List of which store classes and store class locations are +# currently known to glance at startup. +# Defaults to false. +# Example: ['glance.store.filesystem.Store','glance.store.http.Store'] +# +# [*image_cache_dir*] +# (optional) Base directory that the Image Cache uses. +# Defaults to '/var/lib/glance/image-cache'. +# +# [*os_region_name*] +# (optional) Sets the keystone region to use. +# Defaults to 'RegionOne'. +# +# [*validate*] +# (optional) Whether to validate the service is working after any service refreshes +# Defaults to false +# +# [*validation_options*] +# (optional) Service validation options +# Should be a hash of options defined in openstacklib::service_validation +# If empty, defaults values are taken from openstacklib function. +# Default command list images. +# Require validate set at True. +# Example: +# glance::api::validation_options: +# glance-api: +# command: check_glance-api.py +# path: /usr/bin:/bin:/usr/sbin:/sbin +# provider: shell +# tries: 5 +# try_sleep: 10 +# Defaults to {} +# +class glance::api( + $keystone_password, + $verbose = false, + $debug = false, + $bind_host = '0.0.0.0', + $bind_port = '9292', + $backlog = '4096', + $workers = $::processorcount, + $log_file = '/var/log/glance/api.log', + $log_dir = '/var/log/glance', + $registry_host = '0.0.0.0', + $registry_port = '9191', + $registry_client_protocol = 'http', + $auth_type = 'keystone', + $auth_host = '127.0.0.1', + $auth_url = 'http://localhost:5000/v2.0', + $auth_port = '35357', + $auth_uri = false, + $auth_admin_prefix = false, + $auth_protocol = 'http', + $pipeline = 'keystone+cachemanagement', + $keystone_tenant = 'services', + $keystone_user = 'glance', + $manage_service = true, + $enabled = true, + $use_syslog = false, + $log_facility = 'LOG_USER', + $show_image_direct_url = false, + $purge_config = false, + $cert_file = false, + $key_file = false, + $ca_file = false, + $known_stores = false, + $database_connection = 'sqlite:///var/lib/glance/glance.sqlite', + $database_idle_timeout = 3600, + $image_cache_dir = '/var/lib/glance/image-cache', + $os_region_name = 'RegionOne', + $validate = false, + $validation_options = {}, + # DEPRECATED PARAMETERS + $mysql_module = undef, + $sql_idle_timeout = false, + $sql_connection = false, +) inherits glance { + + include glance::policy + require keystone::python + + if $mysql_module { + warning('The mysql_module parameter is deprecated. The latest 2.x mysql module will be used.') + } + + if ( $glance::params::api_package_name != $glance::params::registry_package_name ) { + ensure_packages([$glance::params::api_package_name], + { + tag => ['openstack'], + } + ) + } + + Package[$glance::params::api_package_name] -> File['/etc/glance/'] + Package[$glance::params::api_package_name] -> Class['glance::policy'] + Package[$glance::params::api_package_name] -> Glance_api_config<||> + Package[$glance::params::api_package_name] -> Glance_cache_config<||> + + # adding all of this stuff b/c it devstack says glance-api uses the + # db now + Glance_api_config<||> ~> Exec<| title == 'glance-manage db_sync' |> + Glance_cache_config<||> ~> Exec<| title == 'glance-manage db_sync' |> + Exec<| title == 'glance-manage db_sync' |> ~> Service['glance-api'] + Glance_api_config<||> ~> Service['glance-api'] + Glance_cache_config<||> ~> Service['glance-api'] + Class['glance::policy'] ~> Service['glance-api'] + Service['glance-api'] ~> Glance_image<||> + + File { + ensure => present, + owner => 'glance', + group => 'glance', + mode => '0640', + notify => Service['glance-api'], + require => Class['glance'] + } + + if $sql_connection { + warning('The sql_connection parameter is deprecated, use database_connection instead.') + $database_connection_real = $sql_connection + } else { + $database_connection_real = $database_connection + } + + if $sql_idle_timeout { + warning('The sql_idle_timeout parameter is deprecated, use database_idle_timeout instead.') + $database_idle_timeout_real = $sql_idle_timeout + } else { + $database_idle_timeout_real = $database_idle_timeout + } + + if $database_connection_real { + if($database_connection_real =~ /mysql:\/\/\S+:\S+@\S+\/\S+/) { + require 'mysql::bindings' + require 'mysql::bindings::python' + } elsif($database_connection_real =~ /postgresql:\/\/\S+:\S+@\S+\/\S+/) { + + } elsif($database_connection_real =~ /sqlite:\/\//) { + + } else { + fail("Invalid db connection ${database_connection_real}") + } + glance_api_config { + 'database/connection': value => $database_connection_real, secret => true; + 'database/idle_timeout': value => $database_idle_timeout_real; + } + } + + # basic service config + glance_api_config { + 'DEFAULT/verbose': value => $verbose; + 'DEFAULT/debug': value => $debug; + 'DEFAULT/bind_host': value => $bind_host; + 'DEFAULT/bind_port': value => $bind_port; + 'DEFAULT/backlog': value => $backlog; + 'DEFAULT/workers': value => $workers; + 'DEFAULT/show_image_direct_url': value => $show_image_direct_url; + 'DEFAULT/image_cache_dir': value => $image_cache_dir; + 'DEFAULT/os_region_name': value => $os_region_name; + } + + # known_stores config + if $known_stores { + glance_api_config { + 'glance_store/stores': value => join($known_stores, ','); + } + } else { + glance_api_config { + 'glance_store/stores': ensure => absent; + } + } + + glance_cache_config { + 'DEFAULT/verbose': value => $verbose; + 'DEFAULT/debug': value => $debug; + 'DEFAULT/os_region_name': value => $os_region_name; + } + + # configure api service to connect registry service + glance_api_config { + 'DEFAULT/registry_host': value => $registry_host; + 'DEFAULT/registry_port': value => $registry_port; + 'DEFAULT/registry_client_protocol': value => $registry_client_protocol; + } + + glance_cache_config { + 'DEFAULT/registry_host': value => $registry_host; + 'DEFAULT/registry_port': value => $registry_port; + } + + if $auth_uri { + glance_api_config { 'keystone_authtoken/auth_uri': value => $auth_uri; } + } else { + glance_api_config { 'keystone_authtoken/auth_uri': value => "${auth_protocol}://${auth_host}:5000/"; } + } + + # auth config + glance_api_config { + 'keystone_authtoken/auth_host': value => $auth_host; + 'keystone_authtoken/auth_port': value => $auth_port; + 'keystone_authtoken/auth_protocol': value => $auth_protocol; + } + + if $auth_admin_prefix { + validate_re($auth_admin_prefix, '^(/.+[^/])?$') + glance_api_config { + 'keystone_authtoken/auth_admin_prefix': value => $auth_admin_prefix; + } + } else { + glance_api_config { + 'keystone_authtoken/auth_admin_prefix': ensure => absent; + } + } + + # Set the pipeline, it is allowed to be blank + if $pipeline != '' { + validate_re($pipeline, '^(\w+([+]\w+)*)*$') + glance_api_config { + 'paste_deploy/flavor': + ensure => present, + value => $pipeline, + } + } else { + glance_api_config { 'paste_deploy/flavor': ensure => absent } + } + + # keystone config + if $auth_type == 'keystone' { + glance_api_config { + 'keystone_authtoken/admin_tenant_name': value => $keystone_tenant; + 'keystone_authtoken/admin_user' : value => $keystone_user; + 'keystone_authtoken/admin_password' : value => $keystone_password, secret => true; + } + glance_cache_config { + 'DEFAULT/auth_url' : value => $auth_url; + 'DEFAULT/admin_tenant_name': value => $keystone_tenant; + 'DEFAULT/admin_user' : value => $keystone_user; + 'DEFAULT/admin_password' : value => $keystone_password, secret => true; + } + } + + # SSL Options + if $cert_file { + glance_api_config { + 'DEFAULT/cert_file' : value => $cert_file; + } + } else { + glance_api_config { + 'DEFAULT/cert_file': ensure => absent; + } + } + if $key_file { + glance_api_config { + 'DEFAULT/key_file' : value => $key_file; + } + } else { + glance_api_config { + 'DEFAULT/key_file': ensure => absent; + } + } + if $ca_file { + glance_api_config { + 'DEFAULT/ca_file' : value => $ca_file; + } + } else { + glance_api_config { + 'DEFAULT/ca_file': ensure => absent; + } + } + + # Logging + if $log_file { + glance_api_config { + 'DEFAULT/log_file': value => $log_file; + } + } else { + glance_api_config { + 'DEFAULT/log_file': ensure => absent; + } + } + + if $log_dir { + glance_api_config { + 'DEFAULT/log_dir': value => $log_dir; + } + } else { + glance_api_config { + 'DEFAULT/log_dir': ensure => absent; + } + } + + # Syslog + if $use_syslog { + glance_api_config { + 'DEFAULT/use_syslog' : value => true; + 'DEFAULT/syslog_log_facility' : value => $log_facility; + } + } else { + glance_api_config { + 'DEFAULT/use_syslog': value => false; + } + } + + resources { 'glance_api_config': + purge => $purge_config, + } + + file { ['/etc/glance/glance-api.conf', + '/etc/glance/glance-api-paste.ini', + '/etc/glance/glance-cache.conf']: + } + + if $manage_service { + if $enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + } + + service { 'glance-api': + ensure => $service_ensure, + name => $::glance::params::api_service_name, + enable => $enabled, + hasstatus => true, + hasrestart => true, + } + + if $validate { + $defaults = { + 'glance-api' => { + 'command' => "glance --os-auth-url ${auth_url} --os-tenant-name ${keystone_tenant} --os-username ${keystone_user} --os-password ${keystone_password} image-list", + } + } + $validation_options_hash = merge ($defaults, $validation_options) + create_resources('openstacklib::service_validation', $validation_options_hash, {'subscribe' => 'Service[glance-api]'}) + } + +} diff --git a/3rdparty/modules/glance/manifests/backend/cinder.pp b/3rdparty/modules/glance/manifests/backend/cinder.pp new file mode 100644 index 000000000..75507d7f5 --- /dev/null +++ b/3rdparty/modules/glance/manifests/backend/cinder.pp @@ -0,0 +1,99 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Class: glance::backend::cinder +# +# Setup Glance to backend images into Cinder +# +# === Parameters +# +# [*cinder_catalog_info*] +# (optional) Info to match when looking for cinder in the service catalog. +# Format is : separated values of the form: +# :: (string value) +# Defaults to 'volume:cinder:publicURL' +# +# [*cinder_endpoint_template*] +# (optional) Override service catalog lookup with template for cinder endpoint. +# Should be a valid URL. Example: 'http://localhost:8776/v1/%(project_id)s' +# Defaults to 'undef' +# +# [*os_region_name*] +# (optional) The os_region_name parameter is deprecated and has no effect. +# Use glance::api::os_region_name instead. +# Defaults to 'undef' +# +# [*cinder_ca_certificates_file*] +# (optional) Location of ca certicate file to use for cinder client requests. +# Should be a valid ca certicate file +# Defaults to undef +# +# [*cinder_http_retries*] +# (optional) Number of cinderclient retries on failed http calls. +# Should be a valid integer +# Defaults to '3' +# +# [*cinder_api_insecure*] +# (optional) Allow to perform insecure SSL requests to cinder. +# Should be a valid boolean value +# Defaults to false +# + +class glance::backend::cinder( + $os_region_name = undef, + $cinder_ca_certificates_file = undef, + $cinder_api_insecure = false, + $cinder_catalog_info = 'volume:cinder:publicURL', + $cinder_endpoint_template = undef, + $cinder_http_retries = '3' + +) { + + if $os_region_name { + notice('The os_region_name parameter is deprecated and has no effect. Use glance::api::os_region_name instead.') + } + + glance_api_config { + 'DEFAULT/cinder_api_insecure': value => $cinder_api_insecure; + 'DEFAULT/cinder_catalog_info': value => $cinder_catalog_info; + 'DEFAULT/cinder_http_retries': value => $cinder_http_retries; + 'glance_store/default_store': value => 'cinder'; + } + + glance_cache_config { + 'DEFAULT/cinder_api_insecure': value => $cinder_api_insecure; + 'DEFAULT/cinder_catalog_info': value => $cinder_catalog_info; + 'DEFAULT/cinder_http_retries': value => $cinder_http_retries; + } + + if $cinder_endpoint_template { + glance_api_config { 'DEFAULT/cinder_endpoint_template': value => $cinder_endpoint_template; } + glance_cache_config { 'DEFAULT/cinder_endpoint_template': value => $cinder_endpoint_template; } + } else { + glance_api_config { 'DEFAULT/cinder_endpoint_template': ensure => absent; } + glance_cache_config { 'DEFAULT/cinder_endpoint_template': ensure => absent; } + } + + if $cinder_ca_certificates_file { + glance_api_config { 'DEFAULT/cinder_ca_certificates_file': value => $cinder_ca_certificates_file; } + glance_cache_config { 'DEFAULT/cinder_ca_certificates_file': value => $cinder_ca_certificates_file; } + } else { + glance_api_config { 'DEFAULT/cinder_ca_certificates_file': ensure => absent; } + glance_cache_config { 'DEFAULT/cinder_ca_certificates_file': ensure => absent; } + } + +} diff --git a/3rdparty/modules/glance/manifests/backend/file.pp b/3rdparty/modules/glance/manifests/backend/file.pp new file mode 100644 index 000000000..0eb2dcd2b --- /dev/null +++ b/3rdparty/modules/glance/manifests/backend/file.pp @@ -0,0 +1,19 @@ +# +# used to configure file backends for glance +# +# $filesystem_store_datadir - Location where dist images are stored when +# default_store == file. +# Optional. Default: /var/lib/glance/images/ +class glance::backend::file( + $filesystem_store_datadir = '/var/lib/glance/images/' +) inherits glance::api { + + glance_api_config { + 'glance_store/default_store': value => 'file'; + 'glance_store/filesystem_store_datadir': value => $filesystem_store_datadir; + } + + glance_cache_config { + 'glance_store/filesystem_store_datadir': value => $filesystem_store_datadir; + } +} diff --git a/3rdparty/modules/glance/manifests/backend/rbd.pp b/3rdparty/modules/glance/manifests/backend/rbd.pp new file mode 100644 index 000000000..e38dad0f7 --- /dev/null +++ b/3rdparty/modules/glance/manifests/backend/rbd.pp @@ -0,0 +1,49 @@ +# +# configures the storage backend for glance +# as a rbd instance +# +# $rbd_store_user - Optional. +# +# $rbd_store_pool - Optional. Default:'images' +# +# $rbd_store_ceph_conf - Optional. Default:'/etc/ceph/ceph.conf' +# +# $rbd_store_chunk_size - Optional. Default:'8' +# +# $show_image_direct_url - Optional. Enables direct COW from glance to rbd +# DEPRECATED, use show_image_direct_url in glance::api +# +# [*package_ensure*] +# (optional) Desired ensure state of packages. +# accepts latest or specific versions. +# Defaults to present. +# + +class glance::backend::rbd( + $rbd_store_user = undef, + $rbd_store_ceph_conf = '/etc/ceph/ceph.conf', + $rbd_store_pool = 'images', + $rbd_store_chunk_size = '8', + $show_image_direct_url = undef, + $package_ensure = 'present', +) { + include glance::params + + if $show_image_direct_url { + notice('parameter show_image_direct_url is deprecated, use parameter in glance::api') + } + + glance_api_config { + 'glance_store/default_store': value => 'rbd'; + 'glance_store/rbd_store_ceph_conf': value => $rbd_store_ceph_conf; + 'glance_store/rbd_store_user': value => $rbd_store_user; + 'glance_store/rbd_store_pool': value => $rbd_store_pool; + 'glance_store/rbd_store_chunk_size': value => $rbd_store_chunk_size; + } + + package { 'python-ceph': + ensure => $package_ensure, + name => $::glance::params::pyceph_package_name, + } + +} diff --git a/3rdparty/modules/glance/manifests/backend/swift.pp b/3rdparty/modules/glance/manifests/backend/swift.pp new file mode 100644 index 000000000..4ce897dc1 --- /dev/null +++ b/3rdparty/modules/glance/manifests/backend/swift.pp @@ -0,0 +1,53 @@ +# +# configures the storage backend for glance +# as a swift instance +# +# $swift_store_user - Required. +# +# $swift_store_key - Required. +# +# $swift_store_auth_address - Optional. Default: '127.0.0.1:5000/v2.0/' +# +# $swift_store_container - Optional. Default: 'glance' +# +# $swift_store_auth_version - Optional. Default: '2' +# +# $swift_store_create_container_on_put - Optional. Default: 'False' +# +# $swift_store_large_object_size - Optional. Default: '5120' +class glance::backend::swift( + $swift_store_user, + $swift_store_key, + $swift_store_auth_address = '127.0.0.1:5000/v2.0/', + $swift_store_container = 'glance', + $swift_store_auth_version = '2', + $swift_store_large_object_size = '5120', + $swift_store_create_container_on_put = false +) { + + glance_api_config { + 'glance_store/default_store': value => 'swift'; + 'glance_store/swift_store_user': value => $swift_store_user; + 'glance_store/swift_store_key': value => $swift_store_key; + 'glance_store/swift_store_auth_address': value => $swift_store_auth_address; + 'DEFAULT/swift_store_container': value => $swift_store_container; + 'DEFAULT/swift_store_auth_version': value => $swift_store_auth_version; + 'DEFAULT/swift_store_create_container_on_put': + value => $swift_store_create_container_on_put; + 'DEFAULT/swift_store_large_object_size': + value => $swift_store_large_object_size; + } + + glance_cache_config { + 'glance_store/swift_store_user': value => $swift_store_user; + 'glance_store/swift_store_key': value => $swift_store_key; + 'glance_store/swift_store_auth_address': value => $swift_store_auth_address; + 'DEFAULT/swift_store_container': value => $swift_store_container; + 'DEFAULT/swift_store_auth_version': value => $swift_store_auth_version; + 'DEFAULT/swift_store_create_container_on_put': + value => $swift_store_create_container_on_put; + 'DEFAULT/swift_store_large_object_size': + value => $swift_store_large_object_size; + } + +} diff --git a/3rdparty/modules/glance/manifests/backend/vsphere.pp b/3rdparty/modules/glance/manifests/backend/vsphere.pp new file mode 100644 index 000000000..133b0986e --- /dev/null +++ b/3rdparty/modules/glance/manifests/backend/vsphere.pp @@ -0,0 +1,83 @@ +# +# Copyright (C) 2014 Mirantis +# +# Author: Steapn Rogov +# +# 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: glance::backend::vsphere +# +# Setup Glance to backend images into VMWare vCenter/ESXi +# +# === Parameters +# +# [*vcenter_api_insecure*] +# (optional) Allow to perform insecure SSL requests to vCenter/ESXi. +# Should be a valid string boolean value +# Defaults to 'False' +# +# [*vcenter_host*] +# (required) vCenter/ESXi Server target system. +# Should be a valid an IP address or a DNS name. +# +# [*vcenter_user*] +# (required) Username for authenticating with vCenter/ESXi server. +# +# [*vcenter_password*] +# (required) Password for authenticating with vCenter/ESXi server. +# +# [*vcenter_datacenter*] +# (required) Inventory path to a datacenter. +# If you want to use ESXi host as datastore,it should be "ha-datacenter". +# +# [*vcenter_datastore*] +# (required) Datastore associated with the datacenter. +# +# [*vcenter_image_dir*] +# (required) The name of the directory where the glance images will be stored +# in the VMware datastore. +# +# [*vcenter_task_poll_interval*] +# (optional) The interval used for polling remote tasks invoked on +# vCenter/ESXi server. +# Defaults to '5' +# +# [*vcenter_api_retry_count*] +# (optional) Number of times VMware ESX/VC server API must be retried upon +# connection related issues. +# Defaults to '10' +# +class glance::backend::vsphere( + $vcenter_host, + $vcenter_user, + $vcenter_password, + $vcenter_datacenter, + $vcenter_datastore, + $vcenter_image_dir, + $vcenter_api_insecure = 'False', + $vcenter_task_poll_interval = '5', + $vcenter_api_retry_count = '10', +) { + glance_api_config { + 'DEFAULT/default_store': value => 'vsphere'; + 'DEFAULT/vmware_api_insecure': value => $vcenter_api_insecure; + 'DEFAULT/vmware_server_host': value => $vcenter_host; + 'DEFAULT/vmware_server_username': value => $vcenter_user; + 'DEFAULT/vmware_server_password': value => $vcenter_password; + 'DEFAULT/vmware_datastore_name': value => $vcenter_datastore; + 'DEFAULT/vmware_store_image_dir': value => $vcenter_image_dir; + 'DEFAULT/vmware_task_poll_interval': value => $vcenter_task_poll_interval; + 'DEFAULT/vmware_api_retry_count': value => $vcenter_api_retry_count; + 'DEFAULT/vmware_datacenter_path': value => $vcenter_datacenter; + } +} diff --git a/3rdparty/modules/glance/manifests/cache/cleaner.pp b/3rdparty/modules/glance/manifests/cache/cleaner.pp new file mode 100644 index 000000000..f05258db2 --- /dev/null +++ b/3rdparty/modules/glance/manifests/cache/cleaner.pp @@ -0,0 +1,49 @@ +# == Class: glance::cache::cleaner +# +# Installs a cron job to run glance-cache-cleaner. +# +# === Parameters +# +# [*minute*] +# (optional) Defaults to '1'. +# +# [*hour*] +# (optional) Defaults to '0'. +# +# [*monthday*] +# (optional) Defaults to '*'. +# +# [*month*] +# (optional) Defaults to '*'. +# +# [*weekday*] +# (optional) Defaults to '*'. +# +# [*command_options*] +# command options to add to the cronjob +# (eg. point to config file, or redirect output) +# (optional) Defaults to ''. +# +class glance::cache::cleaner ( + $minute = 1, + $hour = 0, + $monthday = '*', + $month = '*', + $weekday = '*', + $command_options = '', +) { + + include glance::params + + cron { 'glance-cache-cleaner': + command => "${glance::params::cache_cleaner_command} ${command_options}", + environment => 'PATH=/bin:/usr/bin:/usr/sbin', + user => 'glance', + minute => $minute, + hour => $hour, + monthday => $monthday, + month => $month, + weekday => $weekday, + require => Package[$::glance::params::api_package_name], + } +} diff --git a/3rdparty/modules/glance/manifests/cache/pruner.pp b/3rdparty/modules/glance/manifests/cache/pruner.pp new file mode 100644 index 000000000..96e135fb2 --- /dev/null +++ b/3rdparty/modules/glance/manifests/cache/pruner.pp @@ -0,0 +1,50 @@ +# == Class: glance::cache::pruner +# +# Installs a cron job to run glance-cache-pruner. +# +# === Parameters +# +# [*minute*] +# (optional) Defaults to '*/30'. +# +# [*hour*] +# (optional) Defaults to '*'. +# +# [*monthday*] +# (optional) Defaults to '*'. +# +# [*month*] +# (optional) Defaults to '*'. +# +# [*weekday*] +# (optional) Defaults to '*'. +# +# [*command_options*] +# command options to add to the cronjob +# (eg. point to config file, or redirect output) +# (optional) Defaults to ''. +# +class glance::cache::pruner ( + $minute = '*/30', + $hour = '*', + $monthday = '*', + $month = '*', + $weekday = '*', + $command_options = '', +) { + + include glance::params + + cron { 'glance-cache-pruner': + command => "${glance::params::cache_pruner_command} ${command_options}", + environment => 'PATH=/bin:/usr/bin:/usr/sbin', + user => 'glance', + minute => $minute, + hour => $hour, + monthday => $monthday, + month => $month, + weekday => $weekday, + require => Package[$::glance::params::api_package_name], + + } +} diff --git a/3rdparty/modules/glance/manifests/client.pp b/3rdparty/modules/glance/manifests/client.pp new file mode 100644 index 000000000..c2ae06011 --- /dev/null +++ b/3rdparty/modules/glance/manifests/client.pp @@ -0,0 +1,19 @@ +# +# Installs the glance python library. +# +# == parameters +# * ensure - ensure state for pachage. +# +class glance::client ( + $ensure = 'present' +) { + + include glance::params + + package { 'python-glanceclient': + ensure => $ensure, + name => $::glance::params::client_package_name, + tag => ['openstack'], + } + +} diff --git a/3rdparty/modules/glance/manifests/config.pp b/3rdparty/modules/glance/manifests/config.pp new file mode 100644 index 000000000..d9c6a4371 --- /dev/null +++ b/3rdparty/modules/glance/manifests/config.pp @@ -0,0 +1,56 @@ +# == Class: glance::config +# +# This class is used to manage arbitrary glance configurations. +# +# === Parameters +# +# [*xxx_config*] +# (optional) Allow configuration of arbitrary glance configurations. +# The value is an hash of glance_config resources. Example: +# { 'DEFAULT/foo' => { value => 'fooValue'}, +# 'DEFAULT/bar' => { value => 'barValue'} +# } +# In yaml format, Example: +# glance_config: +# DEFAULT/foo: +# value: fooValue +# DEFAULT/bar: +# value: barValue +# +# [**api_config**] +# (optional) Allow configuration of glance-api.conf configurations. +# +# [**api_paste_ini_config**] +# (optional) Allow configuration of glance-api-paste.ini configurations. +# +# [**registry_config**] +# (optional) Allow configuration of glance-registry.conf configurations. +# +# [**registry_paste_ini_config**] +# (optional) Allow configuration of glance-registry-paste.ini configurations. +# +# [**cache_config**] +# (optional) Allow configuration of glance-cache.conf configurations. +# +# NOTE: The configuration MUST NOT be already handled by this module +# or Puppet catalog compilation will fail with duplicate resources. +# +class glance::config ( + $api_config = {}, + $api_paste_ini_config = {}, + $registry_config = {}, + $registry_paste_ini_config = {}, + $cache_config = {}, +) { + validate_hash($api_config) + validate_hash($api_paste_ini_config) + validate_hash($registry_config) + validate_hash($registry_paste_ini_config) + validate_hash($cache_config) + + create_resources('glance_api_config', $api_config) + create_resources('glance_api_paste_ini', $api_paste_ini_config) + create_resources('glance_registry_config', $registry_config) + create_resources('glance_registry_paste_ini', $registry_paste_ini_config) + create_resources('glance_cache_config', $cache_config) +} diff --git a/3rdparty/modules/glance/manifests/db/mysql.pp b/3rdparty/modules/glance/manifests/db/mysql.pp new file mode 100644 index 000000000..341fc42a3 --- /dev/null +++ b/3rdparty/modules/glance/manifests/db/mysql.pp @@ -0,0 +1,62 @@ +# The glance::db::mysql class creates a MySQL database for glance. +# It must be used on the MySQL server +# +# == Parameters +# +# [*password*] +# password to connect to the database. Mandatory. +# +# [*dbname*] +# name of the database. Optional. Defaults to glance. +# +# [*user*] +# user to connect to the database. Optional. Defaults to glance. +# +# [*host*] +# the default source host user is allowed to connect from. +# Optional. Defaults to 'localhost' +# +# [*allowed_hosts*] +# other hosts the user is allowd to connect from. +# Optional. Defaults to undef. +# +# [*charset*] +# the database charset. Optional. Defaults to 'utf8' +# +# [*collate*] +# the database collation. Optional. Defaults to 'utf8_general_ci' +# +# [*mysql_module*] +# (optional) Deprecated. Does nothing. +# +class glance::db::mysql( + $password, + $dbname = 'glance', + $user = 'glance', + $host = '127.0.0.1', + $allowed_hosts = undef, + $charset = 'utf8', + $collate = 'utf8_general_ci', + $cluster_id = 'localzone', + $mysql_module = undef, +) { + + if $mysql_module { + warning('The mysql_module parameter is deprecated. The latest 2.x mysql module will be used.') + } + + validate_string($password) + + ::openstacklib::db::mysql { 'glance': + user => $user, + password_hash => mysql_password($password), + dbname => $dbname, + host => $host, + charset => $charset, + collate => $collate, + allowed_hosts => $allowed_hosts, + } + + ::Openstacklib::Db::Mysql['glance'] ~> Exec<| title == 'glance-manage db_sync' |> + +} diff --git a/3rdparty/modules/glance/manifests/db/postgresql.pp b/3rdparty/modules/glance/manifests/db/postgresql.pp new file mode 100644 index 000000000..a1eb54c63 --- /dev/null +++ b/3rdparty/modules/glance/manifests/db/postgresql.pp @@ -0,0 +1,21 @@ +# +# Class that configures postgresql for glance +# +# Requires the Puppetlabs postgresql module. +class glance::db::postgresql( + $password, + $dbname = 'glance', + $user = 'glance' +) { + + require postgresql::python + + Postgresql::Db[$dbname] ~> Exec<| title == 'glance-manage db_sync' |> + Package['python-psycopg2'] -> Exec<| title == 'glance-manage db_sync' |> + + postgresql::db { $dbname: + user => $user, + password => $password, + } + +} diff --git a/3rdparty/modules/glance/manifests/init.pp b/3rdparty/modules/glance/manifests/init.pp new file mode 100644 index 000000000..4ca809b76 --- /dev/null +++ b/3rdparty/modules/glance/manifests/init.pp @@ -0,0 +1,27 @@ +# +# base glacne config. +# +# == parameters +# * package_ensure - ensure state for package. +# +class glance( + $package_ensure = 'present' +) { + + include glance::params + + file { '/etc/glance/': + ensure => directory, + owner => 'glance', + group => 'root', + mode => '0770', + } + + if ( $glance::params::api_package_name == $glance::params::registry_package_name ) { + package { $glance::params::api_package_name : + ensure => $package_ensure, + name => $::glance::params::package_name, + tag => ['openstack'], + } + } +} diff --git a/3rdparty/modules/glance/manifests/keystone/auth.pp b/3rdparty/modules/glance/manifests/keystone/auth.pp new file mode 100644 index 000000000..8caf194b6 --- /dev/null +++ b/3rdparty/modules/glance/manifests/keystone/auth.pp @@ -0,0 +1,87 @@ +# +# Sets up glance users, service and endpoint +# +# == Parameters: +# +# $auth_name :: identifier used for all keystone objects related to glance. +# Optional. Defaults to glance. +# $password :: password for glance user. Optional. Defaults to glance_password. +# $configure_user :: Whether to configure a service user. Optional. Defaults to true. +# $configure_user_role :: Whether to configure the admin role for the service user. +# Optional. Defaults to true. +# $service_name :: name of the service. Optional. Defaults to value of auth_name. +# $service_type :: type of service to create. Optional. Defaults to image. +# $public_address :: Public address for endpoint. Optional. Defaults to 127.0.0.1. +# $admin_address :: Admin address for endpoint. Optional. Defaults to 127.0.0.1. +# $inernal_address :: Internal address for endpoint. Optional. Defaults to 127.0.0.1. +# $port :: Port for endpoint. Needs to match glance api service port. Optional. +# Defaults to 9292. +# $region :: Region where endpoint is set. +# $public_protocol :: Protocol for public endpoint. Optional. Defaults to http. +# $admin_protocol :: Protocol for admin endpoint. Optional. Defaults to http. +# $internal_protocol :: Protocol for internal endpoint. Optional. Defaults to http. +# +class glance::keystone::auth( + $password, + $email = 'glance@localhost', + $auth_name = 'glance', + $configure_endpoint = true, + $configure_user = true, + $configure_user_role = true, + $service_name = undef, + $service_type = 'image', + $public_address = '127.0.0.1', + $admin_address = '127.0.0.1', + $internal_address = '127.0.0.1', + $port = '9292', + $region = 'RegionOne', + $tenant = 'services', + $public_protocol = 'http', + $admin_protocol = 'http', + $internal_protocol = 'http' +) { + + if $service_name == undef { + $real_service_name = $auth_name + } else { + $real_service_name = $service_name + } + + if $configure_endpoint { + Keystone_endpoint["${region}/${real_service_name}"] ~> Service <| name == 'glance-api' |> + } + + if $configure_user { + keystone_user { $auth_name: + ensure => present, + password => $password, + email => $email, + tenant => $tenant, + } + } + + if $configure_user_role { + Keystone_user_role["${auth_name}@${tenant}"] ~> Service <| name == 'glance-registry' |> + Keystone_user_role["${auth_name}@${tenant}"] ~> Service <| name == 'glance-api' |> + + keystone_user_role { "${auth_name}@${tenant}": + ensure => present, + roles => 'admin', + } + } + + keystone_service { $real_service_name: + ensure => present, + type => $service_type, + description => 'Openstack Image Service', + } + + if $configure_endpoint { + keystone_endpoint { "${region}/${real_service_name}": + ensure => present, + public_url => "${public_protocol}://${public_address}:${port}", + admin_url => "${admin_protocol}://${admin_address}:${port}", + internal_url => "${internal_protocol}://${internal_address}:${port}", + } + } +} diff --git a/3rdparty/modules/glance/manifests/notify/qpid.pp b/3rdparty/modules/glance/manifests/notify/qpid.pp new file mode 100644 index 000000000..af1ab7814 --- /dev/null +++ b/3rdparty/modules/glance/manifests/notify/qpid.pp @@ -0,0 +1,21 @@ +# +# used to configure qpid notifications for glance +# +class glance::notify::qpid( + $qpid_password, + $qpid_username = 'guest', + $qpid_hostname = 'localhost', + $qpid_port = '5672', + $qpid_protocol = 'tcp' +) inherits glance::api { + + glance_api_config { + 'DEFAULT/notifier_driver': value => 'qpid'; + 'DEFAULT/qpid_hostname': value => $qpid_hostname; + 'DEFAULT/qpid_port': value => $qpid_port; + 'DEFAULT/qpid_protocol': value => $qpid_protocol; + 'DEFAULT/qpid_username': value => $qpid_username; + 'DEFAULT/qpid_password': value => $qpid_password, secret => true; + } + +} diff --git a/3rdparty/modules/glance/manifests/notify/rabbitmq.pp b/3rdparty/modules/glance/manifests/notify/rabbitmq.pp new file mode 100644 index 000000000..bc68804ce --- /dev/null +++ b/3rdparty/modules/glance/manifests/notify/rabbitmq.pp @@ -0,0 +1,123 @@ +# +# used to configure rabbitmq notifications for glance +# +# [*rabbit_password*] +# password to connect to the rabbit_server. +# [*rabbit_userid*] +# user to connect to the rabbit server. Optional. Defaults to 'guest' +# [*rabbit_host*] +# ip or hostname of the rabbit server. Optional. Defaults to 'localhost' +# [*rabbit_port*] +# port of the rabbit server. Optional. Defaults to 5672. +# [*rabbit_virtual_host*] +# virtual_host to use. Optional. Defaults to '/' +# [*rabbit_use_ssl*] +# (optional) Connect over SSL for RabbitMQ +# Defaults to false +# [*kombu_ssl_ca_certs*] +# (optional) SSL certification authority file (valid only if SSL enabled). +# Defaults to undef +# [*kombu_ssl_certfile*] +# (optional) SSL cert file (valid only if SSL enabled). +# Defaults to undef +# [*kombu_ssl_keyfile*] +# (optional) SSL key file (valid only if SSL enabled). +# Defaults to undef +# [*kombu_ssl_version*] +# (optional) SSL version to use (valid only if SSL enabled). +# Valid values are TLSv1, SSLv23 and SSLv3. SSLv2 may be +# available on some distributions. +# Defaults to 'TLSv1' +# [*rabbit_notification_exchange*] +# Defaults to 'glance' +# [*rabbit_notification_topic*] +# Defaults to 'notifications' +# [*rabbit_durable_queues*] +# Defaults to false +# +# [*notification_driver*] +# Notification driver to use. Defaults to 'messaging'. + +class glance::notify::rabbitmq( + $rabbit_password, + $rabbit_userid = 'guest', + $rabbit_host = 'localhost', + $rabbit_port = '5672', + $rabbit_hosts = false, + $rabbit_virtual_host = '/', + $rabbit_use_ssl = false, + $kombu_ssl_ca_certs = undef, + $kombu_ssl_certfile = undef, + $kombu_ssl_keyfile = undef, + $kombu_ssl_version = 'TLSv1', + $rabbit_notification_exchange = 'glance', + $rabbit_notification_topic = 'notifications', + $rabbit_durable_queues = false, + $amqp_durable_queues = false, + $notification_driver = 'messaging', +) { + + if $rabbit_durable_queues { + warning('The rabbit_durable_queues parameter is deprecated, use amqp_durable_queues.') + $amqp_durable_queues_real = $rabbit_durable_queues + } else { + $amqp_durable_queues_real = $amqp_durable_queues + } + + if $rabbit_hosts { + glance_api_config { + 'DEFAULT/rabbit_hosts': value => join($rabbit_hosts, ','); + 'DEFAULT/rabbit_ha_queues': value => true + } + } else { + glance_api_config { + 'DEFAULT/rabbit_host': value => $rabbit_host; + 'DEFAULT/rabbit_port': value => $rabbit_port; + 'DEFAULT/rabbit_hosts': value => "${rabbit_host}:${rabbit_port}"; + 'DEFAULT/rabbit_ha_queues': value => false + } + } + + glance_api_config { + 'DEFAULT/notification_driver': value => $notification_driver; + 'DEFAULT/rabbit_virtual_host': value => $rabbit_virtual_host; + 'DEFAULT/rabbit_password': value => $rabbit_password, secret => true; + 'DEFAULT/rabbit_userid': value => $rabbit_userid; + 'DEFAULT/rabbit_notification_exchange': value => $rabbit_notification_exchange; + 'DEFAULT/rabbit_notification_topic': value => $rabbit_notification_topic; + 'DEFAULT/rabbit_use_ssl': value => $rabbit_use_ssl; + 'DEFAULT/amqp_durable_queues': value => $amqp_durable_queues_real; + } + + if $rabbit_use_ssl { + glance_api_config { 'DEFAULT/kombu_ssl_version': value => $kombu_ssl_version } + + if $kombu_ssl_ca_certs { + glance_api_config { 'DEFAULT/kombu_ssl_ca_certs': value => $kombu_ssl_ca_certs } + } else { + glance_api_config { 'DEFAULT/kombu_ssl_ca_certs': ensure => absent} + } + + if $kombu_ssl_certfile { + glance_api_config { 'DEFAULT/kombu_ssl_certfile': value => $kombu_ssl_certfile } + } else { + glance_api_config { 'DEFAULT/kombu_ssl_certfile': ensure => absent} + } + + if $kombu_ssl_keyfile { + glance_api_config { 'DEFAULT/kombu_ssl_keyfile': value => $kombu_ssl_keyfile } + } else { + glance_api_config { 'DEFAULT/kombu_ssl_keyfile': ensure => absent} + } + } else { + glance_api_config { + 'DEFAULT/kombu_ssl_version': ensure => absent; + 'DEFAULT/kombu_ssl_ca_certs': ensure => absent; + 'DEFAULT/kombu_ssl_certfile': ensure => absent; + 'DEFAULT/kombu_ssl_keyfile': ensure => absent; + } + if ($kombu_ssl_keyfile or $kombu_ssl_certfile or $kombu_ssl_ca_certs) { + notice('Configuration of certificates with $rabbit_use_ssl == false is a useless config') + } + } +} diff --git a/3rdparty/modules/glance/manifests/params.pp b/3rdparty/modules/glance/manifests/params.pp new file mode 100644 index 000000000..61df5b8db --- /dev/null +++ b/3rdparty/modules/glance/manifests/params.pp @@ -0,0 +1,31 @@ +# these parameters need to be accessed from several locations and +# should be considered to be constant +class glance::params { + + $client_package_name = 'python-glanceclient' + $pyceph_package_name = 'python-ceph' + + $cache_cleaner_command = 'glance-cache-cleaner' + $cache_pruner_command = 'glance-cache-pruner' + + case $::osfamily { + 'RedHat': { + $api_package_name = 'openstack-glance' + $registry_package_name = 'openstack-glance' + $api_service_name = 'openstack-glance-api' + $registry_service_name = 'openstack-glance-registry' + $db_sync_command = 'glance-manage --config-file=/etc/glance/glance-registry.conf db_sync' + } + 'Debian': { + $api_package_name = 'glance-api' + $registry_package_name = 'glance-registry' + $api_service_name = 'glance-api' + $registry_service_name = 'glance-registry' + $db_sync_command = 'glance-manage --config-file=/etc/glance/glance-registry.conf db_sync' + } + default: { + fail("Unsupported osfamily: ${::osfamily} operatingsystem: ${::operatingsystem}, module ${module_name} only support osfamily RedHat and Debian") + } + } + +} diff --git a/3rdparty/modules/glance/manifests/policy.pp b/3rdparty/modules/glance/manifests/policy.pp new file mode 100644 index 000000000..bf1d8e45d --- /dev/null +++ b/3rdparty/modules/glance/manifests/policy.pp @@ -0,0 +1,39 @@ +# == Class: glance::policy +# +# Configure the glance policies +# +# === Parameters +# +# [*policies*] +# (optional) Set of policies to configure for glance +# Example : +# { +# 'glance-context_is_admin' => { +# 'key' => 'context_is_admin', +# 'value' => 'true' +# }, +# 'glance-default' => { +# 'key' => 'default', +# 'value' => 'rule:admin_or_owner' +# } +# } +# Defaults to empty hash. +# +# [*policy_path*] +# (optional) Path to the glance policy.json file +# Defaults to /etc/glance/policy.json +# +class glance::policy ( + $policies = {}, + $policy_path = '/etc/glance/policy.json', +) { + + validate_hash($policies) + + Openstacklib::Policy::Base { + file_path => $policy_path, + } + + create_resources('openstacklib::policy::base', $policies) + +} diff --git a/3rdparty/modules/glance/manifests/registry.pp b/3rdparty/modules/glance/manifests/registry.pp new file mode 100644 index 000000000..5d792fc6b --- /dev/null +++ b/3rdparty/modules/glance/manifests/registry.pp @@ -0,0 +1,373 @@ +# == Class: glance::registry +# +# Installs and configures glance-registry +# +# === Parameters +# +# [*keystone_password*] +# (required) The keystone password for administrative user +# +# [*package_ensure*] +# (optional) Ensure state for package. Defaults to 'present'. On RedHat +# platforms this setting is ignored and the setting from the glance class is +# used because there is only one glance package. +# +# [*verbose*] +# (optional) Enable verbose logs (true|false). Defaults to false. +# +# [*debug*] +# (optional) Enable debug logs (true|false). Defaults to false. +# +# [*bind_host*] +# (optional) The address of the host to bind to. Defaults to '0.0.0.0'. +# +# [*bind_port*] +# (optional) The port the server should bind to. Defaults to '9191'. +# +# [*log_file*] +# (optional) Log file for glance-registry. +# If set to boolean false, it will not log to any file. +# Defaults to '/var/log/glance/registry.log'. +# +# [*log_dir*] +# (optional) directory to which glance logs are sent. +# If set to boolean false, it will not log to any directory. +# Defaults to '/var/log/glance' +# +# [*sql_idle_timeout*] +# (optional) Deprecated. Use database_idle_timeout instead +# Defaults to false +# +# [*sql_connection*] +# (optional) Deprecated. Use database_connection instead. +# Defaults to false +# +# [*database_connection*] +# (optional) Connection url to connect to nova database. +# Defaults to 'sqlite:///var/lib/glance/glance.sqlite' +# +# [*database_idle_timeout*] +# (optional) Timeout before idle db connections are reaped. +# Defaults to 3600 +# +# [*auth_type*] +# (optional) Authentication type. Defaults to 'keystone'. +# +# [*auth_host*] +# (optional) Address of the admin authentication endpoint. +# Defaults to '127.0.0.1'. +# +# [*auth_port*] +# (optional) Port of the admin authentication endpoint. Defaults to '35357'. +# +# [*auth_admin_prefix*] +# (optional) path part of the auth url. +# This allow admin auth URIs like http://auth_host:35357/keystone/admin. +# (where '/keystone/admin' is auth_admin_prefix) +# Defaults to false for empty. If defined, should be a string with a leading '/' and no trailing '/'. +# +# [*auth_protocol*] +# (optional) Protocol to communicate with the admin authentication endpoint. +# Defaults to 'http'. Should be 'http' or 'https'. +# +# [*auth_uri*] +# (optional) Complete public Identity API endpoint. +# +# [*keystone_tenant*] +# (optional) administrative tenant name to connect to keystone. +# Defaults to 'services'. +# +# [*keystone_user*] +# (optional) administrative user name to connect to keystone. +# Defaults to 'glance'. +# +# [*use_syslog*] +# (optional) Use syslog for logging. +# Defaults to false. +# +# [*log_facility*] +# (optional) Syslog facility to receive log lines. +# Defaults to LOG_USER. +# +# [*manage_service*] +# (optional) If Puppet should manage service startup / shutdown. +# Defaults to true. +# +# [*enabled*] +# (optional) Should the service be enabled. +# Defaults to true. +# +# [*purge_config*] +# (optional) Whether to create only the specified config values in +# the glance registry config file. +# Defaults to false. +# +# [*cert_file*] +# (optinal) Certificate file to use when starting registry server securely +# Defaults to false, not set +# +# [*key_file*] +# (optional) Private key file to use when starting registry server securely +# Defaults to false, not set +# +# [*ca_file*] +# (optional) CA certificate file to use to verify connecting clients +# Defaults to false, not set +# +# [*sync_db*] +# (Optional) Run db sync on the node. +# Defaults to true +# +# [*mysql_module*] +# (optional) Deprecated. Does nothing. +# +class glance::registry( + $keystone_password, + $package_ensure = 'present', + $verbose = false, + $debug = false, + $bind_host = '0.0.0.0', + $bind_port = '9191', + $log_file = '/var/log/glance/registry.log', + $log_dir = '/var/log/glance', + $database_connection = 'sqlite:///var/lib/glance/glance.sqlite', + $database_idle_timeout = 3600, + $auth_type = 'keystone', + $auth_host = '127.0.0.1', + $auth_port = '35357', + $auth_admin_prefix = false, + $auth_uri = false, + $auth_protocol = 'http', + $keystone_tenant = 'services', + $keystone_user = 'glance', + $pipeline = 'keystone', + $use_syslog = false, + $log_facility = 'LOG_USER', + $manage_service = true, + $enabled = true, + $purge_config = false, + $cert_file = false, + $key_file = false, + $ca_file = false, + $sync_db = true, + # DEPRECATED PARAMETERS + $mysql_module = undef, + $sql_idle_timeout = false, + $sql_connection = false, +) inherits glance { + + require keystone::python + + if $mysql_module { + warning('The mysql_module parameter is deprecated. The latest 2.x mysql module will be used.') + } + + if ( $glance::params::api_package_name != $glance::params::registry_package_name ) { + ensure_packages( [$glance::params::registry_package_name], + { + ensure => $package_ensure, + tag => ['openstack'], + } + ) + } + + Package[$glance::params::registry_package_name] -> File['/etc/glance/'] + Package[$glance::params::registry_package_name] -> Glance_registry_config<||> + + Glance_registry_config<||> ~> Exec<| title == 'glance-manage db_sync' |> + Glance_registry_config<||> ~> Service['glance-registry'] + + File { + ensure => present, + owner => 'glance', + group => 'glance', + mode => '0640', + notify => Service['glance-registry'], + require => Class['glance'] + } + + if $sql_connection { + warning('The sql_connection parameter is deprecated, use database_connection instead.') + $database_connection_real = $sql_connection + } else { + $database_connection_real = $database_connection + } + + if $sql_idle_timeout { + warning('The sql_idle_timeout parameter is deprecated, use database_idle_timeout instead.') + $database_idle_timeout_real = $sql_idle_timeout + } else { + $database_idle_timeout_real = $database_idle_timeout + } + + if $database_connection_real { + if($database_connection_real =~ /mysql:\/\/\S+:\S+@\S+\/\S+/) { + require 'mysql::bindings' + require 'mysql::bindings::python' + } elsif($database_connection_real =~ /postgresql:\/\/\S+:\S+@\S+\/\S+/) { + + } elsif($database_connection_real =~ /sqlite:\/\//) { + + } else { + fail("Invalid db connection ${database_connection_real}") + } + glance_registry_config { + 'database/connection': value => $database_connection_real, secret => true; + 'database/idle_timeout': value => $database_idle_timeout_real; + } + } + + glance_registry_config { + 'DEFAULT/verbose': value => $verbose; + 'DEFAULT/debug': value => $debug; + 'DEFAULT/bind_host': value => $bind_host; + 'DEFAULT/bind_port': value => $bind_port; + } + + if $auth_uri { + glance_registry_config { 'keystone_authtoken/auth_uri': value => $auth_uri; } + } else { + glance_registry_config { 'keystone_authtoken/auth_uri': value => "${auth_protocol}://${auth_host}:5000/"; } + } + + # auth config + glance_registry_config { + 'keystone_authtoken/auth_host': value => $auth_host; + 'keystone_authtoken/auth_port': value => $auth_port; + 'keystone_authtoken/auth_protocol': value => $auth_protocol; + } + + if $auth_admin_prefix { + validate_re($auth_admin_prefix, '^(/.+[^/])?$') + glance_registry_config { + 'keystone_authtoken/auth_admin_prefix': value => $auth_admin_prefix; + } + } else { + glance_registry_config { + 'keystone_authtoken/auth_admin_prefix': ensure => absent; + } + } + + # Set the pipeline, it is allowed to be blank + if $pipeline != '' { + validate_re($pipeline, '^(\w+([+]\w+)*)*$') + glance_registry_config { + 'paste_deploy/flavor': + ensure => present, + value => $pipeline, + } + } else { + glance_registry_config { 'paste_deploy/flavor': ensure => absent } + } + + # keystone config + if $auth_type == 'keystone' { + glance_registry_config { + 'keystone_authtoken/admin_tenant_name': value => $keystone_tenant; + 'keystone_authtoken/admin_user' : value => $keystone_user; + 'keystone_authtoken/admin_password' : value => $keystone_password, secret => true; + } + } + + # SSL Options + if $cert_file { + glance_registry_config { + 'DEFAULT/cert_file' : value => $cert_file; + } + } else { + glance_registry_config { + 'DEFAULT/cert_file': ensure => absent; + } + } + if $key_file { + glance_registry_config { + 'DEFAULT/key_file' : value => $key_file; + } + } else { + glance_registry_config { + 'DEFAULT/key_file': ensure => absent; + } + } + if $ca_file { + glance_registry_config { + 'DEFAULT/ca_file' : value => $ca_file; + } + } else { + glance_registry_config { + 'DEFAULT/ca_file': ensure => absent; + } + } + + # Logging + if $log_file { + glance_registry_config { + 'DEFAULT/log_file': value => $log_file; + } + } else { + glance_registry_config { + 'DEFAULT/log_file': ensure => absent; + } + } + + if $log_dir { + glance_registry_config { + 'DEFAULT/log_dir': value => $log_dir; + } + } else { + glance_registry_config { + 'DEFAULT/log_dir': ensure => absent; + } + } + + # Syslog + if $use_syslog { + glance_registry_config { + 'DEFAULT/use_syslog': value => true; + 'DEFAULT/syslog_log_facility': value => $log_facility; + } + } else { + glance_registry_config { + 'DEFAULT/use_syslog': value => false; + } + } + + resources { 'glance_registry_config': + purge => $purge_config + } + + file { ['/etc/glance/glance-registry.conf', + '/etc/glance/glance-registry-paste.ini']: + } + + + if $manage_service { + if $enabled { + if $sync_db { + Exec['glance-manage db_sync'] ~> Service['glance-registry'] + + exec { 'glance-manage db_sync': + command => $::glance::params::db_sync_command, + path => '/usr/bin', + user => 'glance', + refreshonly => true, + logoutput => on_failure, + subscribe => [Package[$glance::params::registry_package_name], File['/etc/glance/glance-registry.conf']], + } + } + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + } + + service { 'glance-registry': + ensure => $service_ensure, + name => $::glance::params::registry_service_name, + enable => $enabled, + hasstatus => true, + hasrestart => true, + subscribe => File['/etc/glance/glance-registry.conf'], + require => Class['glance'] + } + +} diff --git a/3rdparty/modules/glance/metadata.json b/3rdparty/modules/glance/metadata.json new file mode 100644 index 000000000..153f4659a --- /dev/null +++ b/3rdparty/modules/glance/metadata.json @@ -0,0 +1,55 @@ +{ + "name": "stackforge-glance", + "version": "5.1.0", + "author": "Puppet Labs and OpenStack Contributors", + "summary": "Puppet module for OpenStack Glance", + "license": "Apache License 2.0", + "source": "git://github.com/openstack/puppet-glance.git", + "project_page": "https://launchpad.net/puppet-glance", + "issues_url": "https://bugs.launchpad.net/puppet-glance", + "dependencies": [ + {"name":"puppetlabs/inifile","version_requirement":">=1.0.0 <2.0.0"}, + {"name":"stackforge/keystone","version_requirement":">=5.0.0 <6.0.0"}, + {"name":"puppetlabs/stdlib","version_requirement":">=4.0.0 <5.0.0"}, + {"name":"stackforge/openstacklib","version_requirement":">=5.0.0 <6.0.0"} + ], + "requirements": [ + { + "name": "pe", + "version_requirement": "3.x" + }, + { + "name": "puppet", + "version_requirement": "3.x" + } + ], + "operatingsystem_support": [ + { + "operatingsystem": "Debian", + "operatingsystemrelease": [ + "7" + ] + }, + { + "operatingsystem": "Fedora", + "operatingsystemrelease": [ + "20" + ] + }, + { + "operatingsystem": "RedHat", + "operatingsystemrelease": [ + "6.5", + "7" + ] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": [ + "12.04", + "14.04" + ] + } + ], + "description": "Installs and configures OpenStack Glance (Image Service)." +} diff --git a/3rdparty/modules/glance/spec/classes/glance_api_spec.rb b/3rdparty/modules/glance/spec/classes/glance_api_spec.rb new file mode 100644 index 000000000..ffb265505 --- /dev/null +++ b/3rdparty/modules/glance/spec/classes/glance_api_spec.rb @@ -0,0 +1,429 @@ +require 'spec_helper' + +describe 'glance::api' do + + let :facts do + { + :osfamily => 'Debian', + :processorcount => '7', + } + end + + let :default_params do + { + :verbose => false, + :debug => false, + :bind_host => '0.0.0.0', + :bind_port => '9292', + :registry_host => '0.0.0.0', + :registry_port => '9191', + :registry_client_protocol => 'http', + :log_file => '/var/log/glance/api.log', + :log_dir => '/var/log/glance', + :auth_type => 'keystone', + :enabled => true, + :manage_service => true, + :backlog => '4096', + :workers => '7', + :auth_host => '127.0.0.1', + :auth_port => '35357', + :auth_protocol => 'http', + :auth_uri => 'http://127.0.0.1:5000/', + :keystone_tenant => 'services', + :keystone_user => 'glance', + :keystone_password => 'ChangeMe', + :database_idle_timeout => '3600', + :database_connection => 'sqlite:///var/lib/glance/glance.sqlite', + :show_image_direct_url => false, + :purge_config => false, + :known_stores => false, + :image_cache_dir => '/var/lib/glance/image-cache', + :os_region_name => 'RegionOne', + } + end + + [{:keystone_password => 'ChangeMe'}, + { + :verbose => true, + :debug => true, + :bind_host => '127.0.0.1', + :bind_port => '9222', + :registry_host => '127.0.0.1', + :registry_port => '9111', + :registry_client_protocol => 'https', + :auth_type => 'not_keystone', + :enabled => false, + :backlog => '4095', + :workers => '5', + :auth_host => '127.0.0.2', + :auth_port => '35358', + :auth_protocol => 'https', + :auth_uri => 'https://127.0.0.2:5000/v2.0/', + :keystone_tenant => 'admin2', + :keystone_user => 'admin2', + :keystone_password => 'ChangeMe2', + :database_idle_timeout => '36002', + :database_connection => 'mysql:///var:lib@glance/glance', + :show_image_direct_url => true, + :image_cache_dir => '/tmp/glance', + :os_region_name => 'RegionOne2', + } + ].each do |param_set| + + describe "when #{param_set == {:keystone_password => 'ChangeMe'} ? "using default" : "specifying"} class parameters" do + + let :param_hash do + default_params.merge(param_set) + end + + let :params do + param_set + end + + it { should contain_class 'glance' } + it { should contain_class 'glance::policy' } + + it { should contain_service('glance-api').with( + 'ensure' => (param_hash[:manage_service] && param_hash[:enabled]) ? 'running': 'stopped', + 'enable' => param_hash[:enabled], + 'hasstatus' => true, + 'hasrestart' => true + ) } + + it { should_not contain_exec('validate_nova_api') } + + it 'should lay down default api config' do + [ + 'verbose', + 'debug', + 'bind_host', + 'bind_port', + 'registry_host', + 'registry_port', + 'registry_client_protocol', + 'show_image_direct_url', + 'os_region_name', + ].each do |config| + should contain_glance_api_config("DEFAULT/#{config}").with_value(param_hash[config.intern]) + end + end + + it 'should lay down default cache config' do + [ + 'verbose', + 'debug', + 'registry_host', + 'registry_port', + 'os_region_name', + ].each do |config| + should contain_glance_cache_config("DEFAULT/#{config}").with_value(param_hash[config.intern]) + end + end + + it 'should config db' do + should contain_glance_api_config('database/connection').with_value(param_hash[:database_connection]) + should contain_glance_api_config('database/connection').with_value(param_hash[:database_connection]).with_secret(true) + should contain_glance_api_config('database/idle_timeout').with_value(param_hash[:database_idle_timeout]) + end + + it 'should have no ssl options' do + should contain_glance_api_config('DEFAULT/ca_file').with_ensure('absent') + should contain_glance_api_config('DEFAULT/cert_file').with_ensure('absent') + should contain_glance_api_config('DEFAULT/key_file').with_ensure('absent') + end + + it 'should lay down default auth config' do + [ + 'auth_host', + 'auth_port', + 'auth_protocol' + ].each do |config| + should contain_glance_api_config("keystone_authtoken/#{config}").with_value(param_hash[config.intern]) + end + end + it { should contain_glance_api_config('keystone_authtoken/auth_admin_prefix').with_ensure('absent') } + + it 'should configure itself for keystone if that is the auth_type' do + if params[:auth_type] == 'keystone' + should contain('paste_deploy/flavor').with_value('keystone+cachemanagement') + + ['admin_tenant_name', 'admin_user', 'admin_password'].each do |config| + should contain_glance_api_config("keystone_authtoken/#{config}").with_value(param_hash[config.intern]) + end + should contain_glance_api_config('keystone_authtoken/admin_password').with_value(param_hash[:keystone_password]).with_secret(true) + + ['admin_tenant_name', 'admin_user', 'admin_password'].each do |config| + should contain_glance_cache_config("keystone_authtoken/#{config}").with_value(param_hash[config.intern]) + end + should contain_glance_cache_config('keystone_authtoken/admin_password').with_value(param_hash[:keystone_password]).with_secret(true) + end + end + end + + end + + describe 'with disabled service managing' do + let :params do + { + :keystone_password => 'ChangeMe', + :manage_service => false, + :enabled => false, + } + end + + it { should contain_service('glance-api').with( + 'ensure' => nil, + 'enable' => false, + 'hasstatus' => true, + 'hasrestart' => true + ) } + end + + describe 'with overridden pipeline' do + let :params do + { + :keystone_password => 'ChangeMe', + :pipeline => 'keystone', + } + end + + it { should contain_glance_api_config('paste_deploy/flavor').with_value('keystone') } + end + + describe 'with blank pipeline' do + let :params do + { + :keystone_password => 'ChangeMe', + :pipeline => '', + } + end + + it { should contain_glance_api_config('paste_deploy/flavor').with_ensure('absent') } + end + + [ + 'keystone/', + 'keystone+', + '+keystone', + 'keystone+cachemanagement+', + '+' + ].each do |pipeline| + describe "with pipeline incorrect value #{pipeline}" do + let :params do + { + :keystone_password => 'ChangeMe', + :pipeline => pipeline + } + end + + it { expect { should contain_glance_api_config('filter:paste_deploy/flavor') }.to\ + raise_error(Puppet::Error, /validate_re\(\): .* does not match/) } + end + end + + describe 'with overriden auth_admin_prefix' do + let :params do + { + :keystone_password => 'ChangeMe', + :auth_admin_prefix => '/keystone/main' + } + end + + it { should contain_glance_api_config('keystone_authtoken/auth_admin_prefix').with_value('/keystone/main') } + end + + [ + '/keystone/', + 'keystone/', + 'keystone', + '/keystone/admin/', + 'keystone/admin/', + 'keystone/admin' + ].each do |auth_admin_prefix| + describe "with auth_admin_prefix_containing incorrect value #{auth_admin_prefix}" do + let :params do + { + :keystone_password => 'ChangeMe', + :auth_admin_prefix => auth_admin_prefix + } + end + + it { expect { should contain_glance_api_config('filter:authtoken/auth_admin_prefix') }.to\ + raise_error(Puppet::Error, /validate_re\(\): "#{auth_admin_prefix}" does not match/) } + end + end + + describe 'with syslog disabled by default' do + let :params do + default_params + end + + it { should contain_glance_api_config('DEFAULT/use_syslog').with_value(false) } + it { should_not contain_glance_api_config('DEFAULT/syslog_log_facility') } + end + + describe 'with syslog enabled' do + let :params do + default_params.merge({ + :use_syslog => 'true', + }) + end + + it { should contain_glance_api_config('DEFAULT/use_syslog').with_value(true) } + it { should contain_glance_api_config('DEFAULT/syslog_log_facility').with_value('LOG_USER') } + end + + describe 'with syslog enabled and custom settings' do + let :params do + default_params.merge({ + :use_syslog => 'true', + :log_facility => 'LOG_LOCAL0' + }) + end + + it { should contain_glance_api_config('DEFAULT/use_syslog').with_value(true) } + it { should contain_glance_api_config('DEFAULT/syslog_log_facility').with_value('LOG_LOCAL0') } + end + + describe 'with log_file enabled by default' do + let(:params) { default_params } + + it { should contain_glance_api_config('DEFAULT/log_file').with_value(default_params[:log_file]) } + + context 'with log_file disabled' do + let(:params) { default_params.merge!({ :log_file => false }) } + it { should contain_glance_api_config('DEFAULT/log_file').with_ensure('absent') } + end + end + + describe 'with log_dir enabled by default' do + let(:params) { default_params } + + it { should contain_glance_api_config('DEFAULT/log_dir').with_value(default_params[:log_dir]) } + + context 'with log_dir disabled' do + let(:params) { default_params.merge!({ :log_dir => false }) } + it { should contain_glance_api_config('DEFAULT/log_dir').with_ensure('absent') } + end + end + + describe 'with ssl options' do + let :params do + default_params.merge({ + :ca_file => '/tmp/ca_file', + :cert_file => '/tmp/cert_file', + :key_file => '/tmp/key_file' + }) + end + + context 'with ssl options' do + it { should contain_glance_api_config('DEFAULT/ca_file').with_value('/tmp/ca_file') } + it { should contain_glance_api_config('DEFAULT/cert_file').with_value('/tmp/cert_file') } + it { should contain_glance_api_config('DEFAULT/key_file').with_value('/tmp/key_file') } + end + end + describe 'with known_stores by default' do + let :params do + default_params + end + + it { should_not contain_glance_api_config('glance_store/stores').with_value('false') } + end + + describe 'with known_stores override' do + let :params do + default_params.merge({ + :known_stores => ['glance.store.filesystem.Store','glance.store.http.Store'], + }) + end + + it { should contain_glance_api_config('glance_store/stores').with_value("glance.store.filesystem.Store,glance.store.http.Store") } + end + + describe 'with deprecated sql parameters' do + let :params do + default_params.merge({ + :sql_connection => 'mysql://user:pass@db/db', + :sql_idle_timeout => '30' + }) + end + + it 'configures database' do + should contain_glance_api_config('database/connection').with_value('mysql://user:pass@db/db') + should contain_glance_api_config('database/idle_timeout').with_value('30') + end + end + + describe 'while validating the service with default command' do + let :params do + default_params.merge({ + :validate => true, + }) + end + it { should contain_exec('execute glance-api validation').with( + :path => '/usr/bin:/bin:/usr/sbin:/sbin', + :provider => 'shell', + :tries => '10', + :try_sleep => '2', + :command => 'glance --os-auth-url http://localhost:5000/v2.0 --os-tenant-name services --os-username glance --os-password ChangeMe image-list', + )} + + it { should contain_anchor('create glance-api anchor').with( + :require => 'Exec[execute glance-api validation]', + )} + end + + describe 'while validating the service with custom command' do + let :params do + default_params.merge({ + :validate => true, + :validation_options => { 'glance-api' => { 'command' => 'my-script' } } + }) + end + it { should contain_exec('execute glance-api validation').with( + :path => '/usr/bin:/bin:/usr/sbin:/sbin', + :provider => 'shell', + :tries => '10', + :try_sleep => '2', + :command => 'my-script', + )} + + it { should contain_anchor('create glance-api anchor').with( + :require => 'Exec[execute glance-api validation]', + )} + end + + describe 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + let(:params) { default_params } + + it { should contain_package('glance-api').with( + :tag => ['openstack'], + )} + end + + describe 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + let(:params) { default_params } + + it { should contain_package('openstack-glance').with( + :tag => ['openstack'], + )} + end + + describe 'on unknown platforms' do + let :facts do + { :osfamily => 'unknown' } + end + let(:params) { default_params } + + it 'should fails to configure glance-api' do + expect { subject }.to raise_error(Puppet::Error, /module glance only support osfamily RedHat and Debian/) + end + end + +end diff --git a/3rdparty/modules/glance/spec/classes/glance_backend_cinder_spec.rb b/3rdparty/modules/glance/spec/classes/glance_backend_cinder_spec.rb new file mode 100644 index 000000000..bc4b43c21 --- /dev/null +++ b/3rdparty/modules/glance/spec/classes/glance_backend_cinder_spec.rb @@ -0,0 +1,94 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Unit tests for glance::backend::cinder class +# + +require 'spec_helper' + +describe 'glance::backend::cinder' do + + let :pre_condition do + 'class { "glance::api": keystone_password => "pass" }' + end + + shared_examples_for 'glance with cinder backend' do + + context 'when default parameters' do + + it 'configures glance-api.conf' do + should contain_glance_api_config('glance_store/default_store').with_value('cinder') + should contain_glance_api_config('DEFAULT/cinder_api_insecure').with_value(false) + should contain_glance_api_config('DEFAULT/cinder_catalog_info').with_value('volume:cinder:publicURL') + should contain_glance_api_config('DEFAULT/cinder_http_retries').with_value('3') + should contain_glance_api_config('DEFAULT/cinder_ca_certificates_file').with(:ensure => 'absent') + should contain_glance_api_config('DEFAULT/cinder_endpoint_template').with(:ensure => 'absent') + end + it 'configures glance-cache.conf' do + should contain_glance_cache_config('DEFAULT/cinder_api_insecure').with_value(false) + should contain_glance_cache_config('DEFAULT/cinder_catalog_info').with_value('volume:cinder:publicURL') + should contain_glance_cache_config('DEFAULT/cinder_http_retries').with_value('3') + should contain_glance_cache_config('DEFAULT/cinder_ca_certificates_file').with(:ensure => 'absent') + should contain_glance_cache_config('DEFAULT/cinder_endpoint_template').with(:ensure => 'absent') + end + end + + context 'when overriding parameters' do + let :params do + { + :cinder_api_insecure => true, + :cinder_ca_certificates_file => '/etc/ssh/ca.crt', + :cinder_catalog_info => 'volume:cinder:internalURL', + :cinder_endpoint_template => 'http://srv-foo:8776/v1/%(project_id)s', + :cinder_http_retries => '10', + } + end + it 'configures glance-api.conf' do + should contain_glance_api_config('glance_store/default_store').with_value('cinder') + should contain_glance_api_config('DEFAULT/cinder_api_insecure').with_value(true) + should contain_glance_api_config('DEFAULT/cinder_ca_certificates_file').with_value('/etc/ssh/ca.crt') + should contain_glance_api_config('DEFAULT/cinder_catalog_info').with_value('volume:cinder:internalURL') + should contain_glance_api_config('DEFAULT/cinder_endpoint_template').with_value('http://srv-foo:8776/v1/%(project_id)s') + should contain_glance_api_config('DEFAULT/cinder_http_retries').with_value('10') + end + it 'configures glance-cache.conf' do + should contain_glance_cache_config('DEFAULT/cinder_api_insecure').with_value(true) + should contain_glance_cache_config('DEFAULT/cinder_ca_certificates_file').with_value('/etc/ssh/ca.crt') + should contain_glance_cache_config('DEFAULT/cinder_catalog_info').with_value('volume:cinder:internalURL') + should contain_glance_cache_config('DEFAULT/cinder_endpoint_template').with_value('http://srv-foo:8776/v1/%(project_id)s') + should contain_glance_cache_config('DEFAULT/cinder_http_retries').with_value('10') + end + end + + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'glance with cinder backend' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'glance with cinder backend' + end +end diff --git a/3rdparty/modules/glance/spec/classes/glance_backend_file_spec.rb b/3rdparty/modules/glance/spec/classes/glance_backend_file_spec.rb new file mode 100644 index 000000000..5a3b5c4e0 --- /dev/null +++ b/3rdparty/modules/glance/spec/classes/glance_backend_file_spec.rb @@ -0,0 +1,34 @@ +require 'spec_helper' + +describe 'glance::backend::file' do + let :facts do + { :osfamily => 'Debian' } + end + + let :pre_condition do + 'class { "glance::api": keystone_password => "pass" }' + end + + it 'configures glance-api.conf' do + should contain_glance_api_config('glance_store/default_store').with_value('file') + should contain_glance_api_config('glance_store/filesystem_store_datadir').with_value('/var/lib/glance/images/') + end + + it 'configures glance-cache.conf' do + should contain_glance_cache_config('glance_store/filesystem_store_datadir').with_value('/var/lib/glance/images/') + end + + describe 'when overriding datadir' do + let :params do + {:filesystem_store_datadir => '/tmp/'} + end + + it 'configures glance-api.conf' do + should contain_glance_api_config('glance_store/filesystem_store_datadir').with_value('/tmp/') + end + + it 'configures glance-cache.conf' do + should contain_glance_cache_config('glance_store/filesystem_store_datadir').with_value('/tmp/') + end + end +end diff --git a/3rdparty/modules/glance/spec/classes/glance_backend_rbd_spec.rb b/3rdparty/modules/glance/spec/classes/glance_backend_rbd_spec.rb new file mode 100644 index 000000000..b843ac641 --- /dev/null +++ b/3rdparty/modules/glance/spec/classes/glance_backend_rbd_spec.rb @@ -0,0 +1,46 @@ +require 'spec_helper' + +describe 'glance::backend::rbd' do + let :facts do + { + :osfamily => 'Debian' + } + end + + describe 'when defaults with rbd_store_user' do + let :params do + { + :rbd_store_user => 'glance', + } + end + + it { should contain_glance_api_config('glance_store/default_store').with_value('rbd') } + it { should contain_glance_api_config('glance_store/rbd_store_pool').with_value('images') } + it { should contain_glance_api_config('glance_store/rbd_store_ceph_conf').with_value('/etc/ceph/ceph.conf') } + it { should contain_glance_api_config('glance_store/rbd_store_chunk_size').with_value('8') } + + + it { should contain_package('python-ceph').with( + :name => 'python-ceph', + :ensure => 'present' + ) + } + end + + describe 'when passing params' do + let :params do + { + :rbd_store_user => 'user', + :rbd_store_chunk_size => '2', + :package_ensure => 'latest', + } + end + it { should contain_glance_api_config('glance_store/rbd_store_user').with_value('user') } + it { should contain_glance_api_config('glance_store/rbd_store_chunk_size').with_value('2') } + it { should contain_package('python-ceph').with( + :name => 'python-ceph', + :ensure => 'latest' + ) + } + end +end diff --git a/3rdparty/modules/glance/spec/classes/glance_backend_swift_spec.rb b/3rdparty/modules/glance/spec/classes/glance_backend_swift_spec.rb new file mode 100644 index 000000000..ddd946c9b --- /dev/null +++ b/3rdparty/modules/glance/spec/classes/glance_backend_swift_spec.rb @@ -0,0 +1,74 @@ +require 'spec_helper' + +describe 'glance::backend::swift' do + let :facts do + { + :osfamily => 'Debian' + } + end + + let :params do + { + :swift_store_user => 'user', + :swift_store_key => 'key', + } + end + + let :pre_condition do + 'class { "glance::api": keystone_password => "pass" }' + end + + describe 'when default parameters' do + + it 'configures glance-api.conf' do + should contain_glance_api_config('glance_store/default_store').with_value('swift') + should contain_glance_api_config('glance_store/swift_store_key').with_value('key') + should contain_glance_api_config('glance_store/swift_store_user').with_value('user') + should contain_glance_api_config('DEFAULT/swift_store_auth_version').with_value('2') + should contain_glance_api_config('DEFAULT/swift_store_large_object_size').with_value('5120') + should contain_glance_api_config('glance_store/swift_store_auth_address').with_value('127.0.0.1:5000/v2.0/') + should contain_glance_api_config('DEFAULT/swift_store_container').with_value('glance') + should contain_glance_api_config('DEFAULT/swift_store_create_container_on_put').with_value(false) + end + + it 'configures glance-cache.conf' do + should contain_glance_cache_config('glance_store/swift_store_key').with_value('key') + should contain_glance_cache_config('glance_store/swift_store_user').with_value('user') + should contain_glance_cache_config('DEFAULT/swift_store_auth_version').with_value('2') + should contain_glance_cache_config('DEFAULT/swift_store_large_object_size').with_value('5120') + should contain_glance_cache_config('glance_store/swift_store_auth_address').with_value('127.0.0.1:5000/v2.0/') + should contain_glance_cache_config('DEFAULT/swift_store_container').with_value('glance') + should contain_glance_cache_config('DEFAULT/swift_store_create_container_on_put').with_value(false) + end + end + + describe 'when overriding parameters' do + let :params do + { + :swift_store_user => 'user', + :swift_store_key => 'key', + :swift_store_auth_version => '1', + :swift_store_large_object_size => '100', + :swift_store_auth_address => '127.0.0.2:8080/v1.0/', + :swift_store_container => 'swift', + :swift_store_create_container_on_put => true + } + end + + it 'configures glance-api.conf' do + should contain_glance_api_config('DEFAULT/swift_store_container').with_value('swift') + should contain_glance_api_config('DEFAULT/swift_store_create_container_on_put').with_value(true) + should contain_glance_api_config('DEFAULT/swift_store_auth_version').with_value('1') + should contain_glance_api_config('DEFAULT/swift_store_large_object_size').with_value('100') + should contain_glance_api_config('glance_store/swift_store_auth_address').with_value('127.0.0.2:8080/v1.0/') + end + + it 'configures glance-cache.conf' do + should contain_glance_cache_config('DEFAULT/swift_store_container').with_value('swift') + should contain_glance_cache_config('DEFAULT/swift_store_create_container_on_put').with_value(true) + should contain_glance_cache_config('DEFAULT/swift_store_auth_version').with_value('1') + should contain_glance_cache_config('DEFAULT/swift_store_large_object_size').with_value('100') + should contain_glance_cache_config('glance_store/swift_store_auth_address').with_value('127.0.0.2:8080/v1.0/') + end + end +end diff --git a/3rdparty/modules/glance/spec/classes/glance_backend_vsphere_spec.rb b/3rdparty/modules/glance/spec/classes/glance_backend_vsphere_spec.rb new file mode 100644 index 000000000..1b1f5465c --- /dev/null +++ b/3rdparty/modules/glance/spec/classes/glance_backend_vsphere_spec.rb @@ -0,0 +1,94 @@ +# +# Copyright (C) 2014 Mirantis +# +# Author: Steapn Rogov +# +# 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 glance::backend::vsphere class +# + +require 'spec_helper' + +describe 'glance::backend::vsphere' do + + let :pre_condition do + 'class { "glance::api": keystone_password => "pass" }' + end + + shared_examples_for 'glance with vsphere backend' do + + context 'when default parameters' do + let :params do + { + :vcenter_host => '10.0.0.1', + :vcenter_user => 'root', + :vcenter_password => '123456', + :vcenter_datacenter => 'Datacenter', + :vcenter_datastore => 'Datastore', + :vcenter_image_dir => '/openstack_glance', + } + end + it 'configures glance-api.conf' do + should contain_glance_api_config('DEFAULT/default_store').with_value('vsphere') + should contain_glance_api_config('DEFAULT/vmware_api_insecure').with_value('False') + should contain_glance_api_config('DEFAULT/vmware_server_host').with_value('10.0.0.1') + should contain_glance_api_config('DEFAULT/vmware_server_username').with_value('root') + should contain_glance_api_config('DEFAULT/vmware_server_password').with_value('123456') + should contain_glance_api_config('DEFAULT/vmware_datastore_name').with_value('Datastore') + should contain_glance_api_config('DEFAULT/vmware_store_image_dir').with_value('/openstack_glance') + should contain_glance_api_config('DEFAULT/vmware_task_poll_interval').with_value('5') + should contain_glance_api_config('DEFAULT/vmware_api_retry_count').with_value('10') + should contain_glance_api_config('DEFAULT/vmware_datacenter_path').with_value('Datacenter') + end + end + + context 'when overriding parameters' do + let :params do + { + :vcenter_host => '10.0.0.1', + :vcenter_user => 'root', + :vcenter_password => '123456', + :vcenter_datacenter => 'Datacenter', + :vcenter_datastore => 'Datastore', + :vcenter_image_dir => '/openstack_glance', + :vcenter_api_insecure => 'True', + :vcenter_task_poll_interval => '6', + :vcenter_api_retry_count => '11', + } + end + it 'configures glance-api.conf' do + should contain_glance_api_config('DEFAULT/vmware_api_insecure').with_value('True') + should contain_glance_api_config('DEFAULT/vmware_task_poll_interval').with_value('6') + should contain_glance_api_config('DEFAULT/vmware_api_retry_count').with_value('11') + end + end + + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'glance with vsphere backend' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'glance with vsphere backend' + end +end diff --git a/3rdparty/modules/glance/spec/classes/glance_cache_cleaner_spec.rb b/3rdparty/modules/glance/spec/classes/glance_cache_cleaner_spec.rb new file mode 100644 index 000000000..a5bb314c9 --- /dev/null +++ b/3rdparty/modules/glance/spec/classes/glance_cache_cleaner_spec.rb @@ -0,0 +1,65 @@ +require 'spec_helper' + +describe 'glance::cache::cleaner' do + + shared_examples_for 'glance cache cleaner' do + + context 'when default parameters' do + + it 'configures a cron' do + should contain_cron('glance-cache-cleaner').with( + :command => 'glance-cache-cleaner ', + :environment => 'PATH=/bin:/usr/bin:/usr/sbin', + :user => 'glance', + :minute => 1, + :hour => 0, + :monthday => '*', + :month => '*', + :weekday => '*' + ) + end + end + + context 'when overriding parameters' do + let :params do + { + :minute => 59, + :hour => 23, + :monthday => '1', + :month => '2', + :weekday => '3', + :command_options => '--config-dir /etc/glance/', + } + end + it 'configures a cron' do + should contain_cron('glance-cache-cleaner').with( + :command => 'glance-cache-cleaner --config-dir /etc/glance/', + :environment => 'PATH=/bin:/usr/bin:/usr/sbin', + :user => 'glance', + :minute => 59, + :hour => 23, + :monthday => '1', + :month => '2', + :weekday => '3' + ) + end + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + include_examples 'glance cache cleaner' + it { should contain_cron('glance-cache-cleaner').with(:require => 'Package[glance-api]')} + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + include_examples 'glance cache cleaner' + it { should contain_cron('glance-cache-cleaner').with(:require => 'Package[openstack-glance]')} + end + +end diff --git a/3rdparty/modules/glance/spec/classes/glance_cache_pruner_spec.rb b/3rdparty/modules/glance/spec/classes/glance_cache_pruner_spec.rb new file mode 100644 index 000000000..87bb46ca7 --- /dev/null +++ b/3rdparty/modules/glance/spec/classes/glance_cache_pruner_spec.rb @@ -0,0 +1,65 @@ +require 'spec_helper' + +describe 'glance::cache::pruner' do + + shared_examples_for 'glance cache pruner' do + + context 'when default parameters' do + + it 'configures a cron' do + should contain_cron('glance-cache-pruner').with( + :command => 'glance-cache-pruner ', + :environment => 'PATH=/bin:/usr/bin:/usr/sbin', + :user => 'glance', + :minute => '*/30', + :hour => '*', + :monthday => '*', + :month => '*', + :weekday => '*' + ) + end + end + + context 'when overriding parameters' do + let :params do + { + :minute => 59, + :hour => 23, + :monthday => '1', + :month => '2', + :weekday => '3', + :command_options => '--config-dir /etc/glance/', + } + end + it 'configures a cron' do + should contain_cron('glance-cache-pruner').with( + :command => 'glance-cache-pruner --config-dir /etc/glance/', + :environment => 'PATH=/bin:/usr/bin:/usr/sbin', + :user => 'glance', + :minute => 59, + :hour => 23, + :monthday => '1', + :month => '2', + :weekday => '3' + ) + end + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + include_examples 'glance cache pruner' + it { should contain_cron('glance-cache-pruner').with(:require => 'Package[glance-api]')} + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + include_examples 'glance cache pruner' + it { should contain_cron('glance-cache-pruner').with(:require => 'Package[openstack-glance]')} + end + +end diff --git a/3rdparty/modules/glance/spec/classes/glance_client_spec.rb b/3rdparty/modules/glance/spec/classes/glance_client_spec.rb new file mode 100644 index 000000000..158b23fba --- /dev/null +++ b/3rdparty/modules/glance/spec/classes/glance_client_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +describe 'glance::client' do + + shared_examples 'glance client' do + it { should contain_class('glance::params') } + it { should contain_package('python-glanceclient').with( + :name => 'python-glanceclient', + :ensure => 'present', + :tag => ['openstack'], + ) + } + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + include_examples 'glance client' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + include_examples 'glance client' + end +end diff --git a/3rdparty/modules/glance/spec/classes/glance_db_mysql_spec.rb b/3rdparty/modules/glance/spec/classes/glance_db_mysql_spec.rb new file mode 100644 index 000000000..aaa23103f --- /dev/null +++ b/3rdparty/modules/glance/spec/classes/glance_db_mysql_spec.rb @@ -0,0 +1,79 @@ +require 'spec_helper' + +describe 'glance::db::mysql' do + let :facts do + { + :osfamily => 'Debian' + } + end + + let :pre_condition do + 'include mysql::server' + end + + describe "with default params" do + let :params do + { + :password => 'glancepass1', + } + end + + it { should contain_openstacklib__db__mysql('glance').with( + :password_hash => '*41C910F70EB213CF4CB7B2F561B4995503C0A87B', + :charset => 'utf8', + :collate => 'utf8_general_ci', + )} + + end + + describe "overriding default params" do + let :params do + { + :password => 'glancepass2', + :dbname => 'glancedb2', + :charset => 'utf8', + } + end + + it { should contain_openstacklib__db__mysql('glance').with( + :password_hash => '*6F9A1CB9BD83EE06F3903BDFF9F4188764E694CA', + :dbname => 'glancedb2', + :charset => 'utf8' + )} + + end + + describe "overriding allowed_hosts param to array" do + let :params do + { + :password => 'glancepass2', + :dbname => 'glancedb2', + :allowed_hosts => ['127.0.0.1','%'] + } + end + + end + + describe "overriding allowed_hosts param to string" do + let :params do + { + :password => 'glancepass2', + :dbname => 'glancedb2', + :allowed_hosts => '192.168.1.1' + } + end + + end + + describe "overriding allowed_hosts param equals to host param " do + let :params do + { + :password => 'glancepass2', + :dbname => 'glancedb2', + :allowed_hosts => '127.0.0.1' + } + end + + end + +end diff --git a/3rdparty/modules/glance/spec/classes/glance_db_postgresql_spec.rb b/3rdparty/modules/glance/spec/classes/glance_db_postgresql_spec.rb new file mode 100644 index 000000000..dcb2b0126 --- /dev/null +++ b/3rdparty/modules/glance/spec/classes/glance_db_postgresql_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' + +describe 'glance::db::postgresql' do + + let :req_params do + {:password => 'pw'} + end + + let :facts do + { + :postgres_default_version => '8.4', + :osfamily => 'RedHat', + } + end + + describe 'with only required params' do + let :params do + req_params + end + it { should contain_postgresql__db('glance').with( + :user => 'glance', + :password => 'pw' + ) } + end + +end diff --git a/3rdparty/modules/glance/spec/classes/glance_keystone_auth_spec.rb b/3rdparty/modules/glance/spec/classes/glance_keystone_auth_spec.rb new file mode 100644 index 000000000..4a01edf2e --- /dev/null +++ b/3rdparty/modules/glance/spec/classes/glance_keystone_auth_spec.rb @@ -0,0 +1,175 @@ +require 'spec_helper' + +describe 'glance::keystone::auth' do + + describe 'with defaults' do + + let :params do + {:password => 'pass'} + end + + it { should contain_keystone_user('glance').with( + :ensure => 'present', + :password => 'pass' + )} + + it { should contain_keystone_user_role('glance@services').with( + :ensure => 'present', + :roles => 'admin' + ) } + + it { should contain_keystone_service('glance').with( + :ensure => 'present', + :type => 'image', + :description => 'Openstack Image Service' + ) } + + it { should contain_keystone_endpoint('RegionOne/glance').with( + :ensure => 'present', + :public_url => 'http://127.0.0.1:9292', + :admin_url => 'http://127.0.0.1:9292', + :internal_url => 'http://127.0.0.1:9292' + )} + + end + + describe 'when auth_type, password, and service_type are overridden' do + + let :params do + { + :auth_name => 'glancey', + :password => 'password', + :service_type => 'imagey' + } + end + + it { should contain_keystone_user('glancey').with( + :ensure => 'present', + :password => 'password' + )} + + it { should contain_keystone_user_role('glancey@services').with( + :ensure => 'present', + :roles => 'admin' + ) } + + it { should contain_keystone_service('glancey').with( + :ensure => 'present', + :type => 'imagey', + :description => 'Openstack Image Service' + ) } + + end + + describe 'when address, region, port and protocoll are overridden' do + + let :params do + { + :password => 'pass', + :public_address => '10.0.0.1', + :admin_address => '10.0.0.2', + :internal_address => '10.0.0.3', + :port => '9393', + :region => 'RegionTwo', + :public_protocol => 'https', + :admin_protocol => 'https', + :internal_protocol => 'https' + } + end + + it { should contain_keystone_endpoint('RegionTwo/glance').with( + :ensure => 'present', + :public_url => 'https://10.0.0.1:9393', + :admin_url => 'https://10.0.0.2:9393', + :internal_url => 'https://10.0.0.3:9393' + )} + + end + + describe 'when endpoint is not set' do + + let :params do + { + :configure_endpoint => false, + :password => 'pass', + } + end + + it { should_not contain_keystone_endpoint('RegionOne/glance') } + end + + describe 'when disabling user configuration' do + let :params do + { + :configure_user => false, + :password => 'pass', + } + end + + it { should_not contain_keystone_user('glance') } + + it { should contain_keystone_user_role('glance@services') } + + it { should contain_keystone_service('glance').with( + :ensure => 'present', + :type => 'image', + :description => 'Openstack Image Service' + ) } + end + + describe 'when disabling user and user role configuration' do + let :params do + { + :configure_user => false, + :configure_user_role => false, + :password => 'pass', + } + end + + it { should_not contain_keystone_user('glance') } + + it { should_not contain_keystone_user_role('glance@services') } + + it { should contain_keystone_service('glance').with( + :ensure => 'present', + :type => 'image', + :description => 'Openstack Image Service' + ) } + end + + describe 'when configuring glance-api and the keystone endpoint' do + let :pre_condition do + "class { 'glance::api': keystone_password => 'test' }" + end + + let :facts do + { :osfamily => 'Debian' } + end + + let :params do + { + :password => 'test', + :configure_endpoint => true + } + end + + it { should contain_keystone_endpoint('RegionOne/glance').with_notify('Service[glance-api]') } + end + + describe 'when overriding service name' do + + let :params do + { + :service_name => 'glance_service', + :password => 'pass' + } + end + + it { should contain_keystone_user('glance') } + it { should contain_keystone_user_role('glance@services') } + it { should contain_keystone_service('glance_service') } + it { should contain_keystone_endpoint('RegionOne/glance_service') } + + end + +end diff --git a/3rdparty/modules/glance/spec/classes/glance_notify_qpid_spec.rb b/3rdparty/modules/glance/spec/classes/glance_notify_qpid_spec.rb new file mode 100644 index 000000000..f6c615835 --- /dev/null +++ b/3rdparty/modules/glance/spec/classes/glance_notify_qpid_spec.rb @@ -0,0 +1,57 @@ +require 'spec_helper' +describe 'glance::notify::qpid' do + let :facts do + { + :osfamily => 'Debian' + } + end + + let :pre_condition do + 'class { "glance::api": keystone_password => "pass" }' + end + + describe 'when default params and qpid_password' do + let :params do + {:qpid_password => 'pass'} + end + + it { should contain_glance_api_config('DEFAULT/notifier_driver').with_value('qpid') } + it { should contain_glance_api_config('DEFAULT/qpid_username').with_value('guest') } + it { should contain_glance_api_config('DEFAULT/qpid_password').with_value('pass') } + it { should contain_glance_api_config('DEFAULT/qpid_password').with_value(params[:qpid_password]).with_secret(true) } + it { should contain_glance_api_config('DEFAULT/qpid_hostname').with_value('localhost') } + it { should contain_glance_api_config('DEFAULT/qpid_port').with_value('5672') } + it { should contain_glance_api_config('DEFAULT/qpid_protocol').with_value('tcp') } + end + + describe 'when passing params' do + let :params do + { + :qpid_password => 'pass2', + :qpid_username => 'guest2', + :qpid_hostname => 'localhost2', + :qpid_port => '5673' + } + end + it { should contain_glance_api_config('DEFAULT/qpid_username').with_value('guest2') } + it { should contain_glance_api_config('DEFAULT/qpid_hostname').with_value('localhost2') } + it { should contain_glance_api_config('DEFAULT/qpid_port').with_value('5673') } + it { should contain_glance_api_config('DEFAULT/qpid_protocol').with_value('tcp') } + end + + describe 'when configuring with ssl' do + let :params do + { + :qpid_password => 'pass3', + :qpid_username => 'guest3', + :qpid_hostname => 'localhost3', + :qpid_port => '5671', + :qpid_protocol => 'ssl' + } + end + it { should contain_glance_api_config('DEFAULT/qpid_username').with_value('guest3') } + it { should contain_glance_api_config('DEFAULT/qpid_hostname').with_value('localhost3') } + it { should contain_glance_api_config('DEFAULT/qpid_port').with_value('5671') } + it { should contain_glance_api_config('DEFAULT/qpid_protocol').with_value('ssl') } + end +end diff --git a/3rdparty/modules/glance/spec/classes/glance_notify_rabbitmq_spec.rb b/3rdparty/modules/glance/spec/classes/glance_notify_rabbitmq_spec.rb new file mode 100644 index 000000000..1b750828f --- /dev/null +++ b/3rdparty/modules/glance/spec/classes/glance_notify_rabbitmq_spec.rb @@ -0,0 +1,134 @@ +require 'spec_helper' +describe 'glance::notify::rabbitmq' do + let :facts do + { + :osfamily => 'Debian' + } + end + + let :pre_condition do + 'class { "glance::api": keystone_password => "pass" }' + end + + describe 'when defaults with rabbit pass specified' do + let :params do + {:rabbit_password => 'pass'} + end + it { should contain_glance_api_config('DEFAULT/notification_driver').with_value('messaging') } + it { should contain_glance_api_config('DEFAULT/rabbit_password').with_value('pass') } + it { should contain_glance_api_config('DEFAULT/rabbit_password').with_value(params[:rabbit_password]).with_secret(true) } + it { should contain_glance_api_config('DEFAULT/rabbit_userid').with_value('guest') } + it { should contain_glance_api_config('DEFAULT/rabbit_host').with_value('localhost') } + it { should contain_glance_api_config('DEFAULT/rabbit_port').with_value('5672') } + it { should contain_glance_api_config('DEFAULT/rabbit_hosts').with_value('localhost:5672') } + it { should contain_glance_api_config('DEFAULT/rabbit_ha_queues').with_value('false') } + it { should contain_glance_api_config('DEFAULT/amqp_durable_queues').with_value('false') } + it { should contain_glance_api_config('DEFAULT/rabbit_virtual_host').with_value('/') } + it { should contain_glance_api_config('DEFAULT/rabbit_notification_exchange').with_value('glance') } + it { should contain_glance_api_config('DEFAULT/rabbit_notification_topic').with_value('notifications') } + end + + describe 'when passing params and use ssl' do + let :params do + { + :rabbit_password => 'pass', + :rabbit_userid => 'guest2', + :rabbit_host => 'localhost2', + :rabbit_port => '5673', + :rabbit_use_ssl => true, + :rabbit_durable_queues => true, + } + it { should contain_glance_api_config('DEFAULT/rabbit_userid').with_value('guest2') } + it { should contain_glance_api_config('DEFAULT/rabbit_host').with_value('localhost2') } + it { should contain_glance_api_config('DEFAULT/rabbit_port').with_value('5673') } + it { should contain_glance_api_config('DEFAULT/rabbit_use_ssl').with_value('true') } + it { should contain_glance_api_config('DEFAULT/kombu_ssl_ca_certs').with_ensure('absent') } + it { should contain_glance_api_config('DEFAULT/kombu_ssl_certfile').with_ensure('absent') } + it { should contain_glance_api_config('DEFAULT/kombu_ssl_keyfile').with_ensure('absent') } + it { should contain_glance_api_config('DEFAULT/kombu_ssl_version').with_value('TLSv1') } + it { should contain_glance_api_config('DEFAULT/rabbit_durable_queues').with_value('true') } + end + end + + describe 'with rabbit ssl cert parameters' do + let :params do + { + :rabbit_password => 'pass', + :rabbit_use_ssl => 'true', + :kombu_ssl_ca_certs => '/etc/ca.cert', + :kombu_ssl_certfile => '/etc/certfile', + :kombu_ssl_keyfile => '/etc/key', + :kombu_ssl_version => 'TLSv1', + } + end + it { should contain_glance_api_config('DEFAULT/rabbit_use_ssl').with_value(true) } + it { should contain_glance_api_config('DEFAULT/kombu_ssl_ca_certs').with_value('/etc/ca.cert') } + it { should contain_glance_api_config('DEFAULT/kombu_ssl_certfile').with_value('/etc/certfile') } + it { should contain_glance_api_config('DEFAULT/kombu_ssl_keyfile').with_value('/etc/key') } + it { should contain_glance_api_config('DEFAULT/kombu_ssl_version').with_value('TLSv1') } + end + + describe 'with rabbit ssl disabled' do + let :params do + { + :rabbit_password => 'pass', + :rabbit_use_ssl => false, + :kombu_ssl_ca_certs => 'undef', + :kombu_ssl_certfile => 'undef', + :kombu_ssl_keyfile => 'undef', + :kombu_ssl_version => 'TLSv1', + } + end + + it { should contain_glance_api_config('DEFAULT/rabbit_use_ssl').with_value('false') } + it { should contain_glance_api_config('DEFAULT/kombu_ssl_ca_certs').with_ensure('absent') } + it { should contain_glance_api_config('DEFAULT/kombu_ssl_certfile').with_ensure('absent') } + it { should contain_glance_api_config('DEFAULT/kombu_ssl_keyfile').with_ensure('absent') } + it { should contain_glance_api_config('DEFAULT/kombu_ssl_version').with_ensure('absent') } + end + + describe 'when passing params for single rabbit host' do + let :params do + { + :rabbit_password => 'pass', + :rabbit_userid => 'guest2', + :rabbit_host => 'localhost2', + :rabbit_port => '5673', + :rabbit_use_ssl => true, + :rabbit_durable_queues => true, + } + end + it { should contain_glance_api_config('DEFAULT/rabbit_userid').with_value('guest2') } + it { should contain_glance_api_config('DEFAULT/rabbit_host').with_value('localhost2') } + it { should contain_glance_api_config('DEFAULT/rabbit_port').with_value('5673') } + it { should contain_glance_api_config('DEFAULT/rabbit_hosts').with_value('localhost2:5673') } + it { should contain_glance_api_config('DEFAULT/rabbit_use_ssl').with_value('true') } + it { should contain_glance_api_config('DEFAULT/amqp_durable_queues').with_value('true') } + end + + describe 'when passing params for multiple rabbit hosts' do + let :params do + { + :rabbit_password => 'pass', + :rabbit_userid => 'guest3', + :rabbit_hosts => ['nonlocalhost3:5673', 'nonlocalhost4:5673'] + } + end + it { should contain_glance_api_config('DEFAULT/rabbit_userid').with_value('guest3') } + it { should contain_glance_api_config('DEFAULT/rabbit_hosts').with_value( + 'nonlocalhost3:5673,nonlocalhost4:5673') } + it { should contain_glance_api_config('DEFAULT/rabbit_ha_queues').with_value('true') } + it { should_not contain_glance_api_config('DEFAULT/rabbit_port') } + it { should_not contain_glance_api_config('DEFAULT/rabbit_host') } + end + + describe 'when using deprecated params' do + let :params do + { + :rabbit_durable_queues => true, + :rabbit_password => 'pass' + } + end + it { should contain_glance_api_config('DEFAULT/amqp_durable_queues').with_value('true') } + end +end diff --git a/3rdparty/modules/glance/spec/classes/glance_policy_spec.rb b/3rdparty/modules/glance/spec/classes/glance_policy_spec.rb new file mode 100644 index 000000000..38ce0faac --- /dev/null +++ b/3rdparty/modules/glance/spec/classes/glance_policy_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +describe 'glance::policy' do + + shared_examples_for 'glance policies' do + let :params do + { + :policy_path => '/etc/glance/policy.json', + :policies => { + 'context_is_admin' => { + 'key' => 'context_is_admin', + 'value' => 'foo:bar' + } + } + } + end + + it 'set up the policies' do + should contain_openstacklib__policy__base('context_is_admin').with({ + :key => 'context_is_admin', + :value => 'foo:bar' + }) + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'glance policies' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'glance policies' + end +end diff --git a/3rdparty/modules/glance/spec/classes/glance_registry_spec.rb b/3rdparty/modules/glance/spec/classes/glance_registry_spec.rb new file mode 100644 index 000000000..8431d696b --- /dev/null +++ b/3rdparty/modules/glance/spec/classes/glance_registry_spec.rb @@ -0,0 +1,356 @@ + +describe 'glance::registry' do + + let :facts do + { + :osfamily => 'Debian' + } + end + + let :default_params do + { + :verbose => false, + :debug => false, + :bind_host => '0.0.0.0', + :bind_port => '9191', + :log_file => '/var/log/glance/registry.log', + :log_dir => '/var/log/glance', + :database_connection => 'sqlite:///var/lib/glance/glance.sqlite', + :database_idle_timeout => '3600', + :enabled => true, + :manage_service => true, + :auth_type => 'keystone', + :auth_host => '127.0.0.1', + :auth_port => '35357', + :auth_protocol => 'http', + :auth_uri => 'http://127.0.0.1:5000/', + :keystone_tenant => 'services', + :keystone_user => 'glance', + :keystone_password => 'ChangeMe', + :purge_config => false, + :sync_db => true, + } + end + + [ + {:keystone_password => 'ChangeMe'}, + { + :verbose => true, + :debug => true, + :bind_host => '127.0.0.1', + :bind_port => '9111', + :database_connection => 'sqlite:///var/lib/glance.sqlite', + :database_idle_timeout => '360', + :enabled => false, + :auth_type => 'keystone', + :auth_host => '127.0.0.1', + :auth_port => '35357', + :auth_protocol => 'http', + :auth_uri => 'http://127.0.0.1:5000/', + :keystone_tenant => 'admin', + :keystone_user => 'admin', + :keystone_password => 'ChangeMe', + :sync_db => false, + } + ].each do |param_set| + + describe "when #{param_set == {:keystone_password => 'ChangeMe'} ? "using default" : "specifying"} class parameters" do + let :param_hash do + default_params.merge(param_set) + end + + let :params do + param_set + end + + it { should contain_class 'glance::registry' } + + it { should contain_service('glance-registry').with( + 'ensure' => (param_hash[:manage_service] && param_hash[:enabled]) ? 'running' : 'stopped', + 'enable' => param_hash[:enabled], + 'hasstatus' => true, + 'hasrestart' => true, + 'subscribe' => 'File[/etc/glance/glance-registry.conf]', + 'require' => 'Class[Glance]' + )} + + it 'should only sync the db if the service is enabled' do + + if param_hash[:enabled] + should contain_exec('glance-manage db_sync').with( + 'path' => '/usr/bin', + 'command' => 'glance-manage --config-file=/etc/glance/glance-registry.conf db_sync', + 'refreshonly' => true, + 'logoutput' => 'on_failure', + 'subscribe' => ['Package[glance-registry]', 'File[/etc/glance/glance-registry.conf]'], + 'notify' => 'Service[glance-registry]' + ) + end + end + it 'should not sync the db if sync_db is set to false' do + + if param_hash[:enabled] and !param_hash[:sync_db] + is_expected.not_to contain_exec('glance-manage db_sync') + end + end + it 'should configure itself' do + [ + 'verbose', + 'debug', + 'bind_port', + 'bind_host', + ].each do |config| + should contain_glance_registry_config("DEFAULT/#{config}").with_value(param_hash[config.intern]) + end + [ + 'database_connection', + 'database_idle_timeout', + ].each do |config| + should contain_glance_registry_config("database/#{config.gsub(/database_/,'')}").with_value(param_hash[config.intern]) + end + [ + 'auth_host', + 'auth_port', + 'auth_protocol' + ].each do |config| + should contain_glance_registry_config("keystone_authtoken/#{config}").with_value(param_hash[config.intern]) + end + should contain_glance_registry_config('keystone_authtoken/auth_admin_prefix').with_ensure('absent') + if param_hash[:auth_type] == 'keystone' + should contain_glance_registry_config("paste_deploy/flavor").with_value('keystone') + should contain_glance_registry_config("keystone_authtoken/admin_tenant_name").with_value(param_hash[:keystone_tenant]) + should contain_glance_registry_config("keystone_authtoken/admin_user").with_value(param_hash[:keystone_user]) + should contain_glance_registry_config("keystone_authtoken/admin_password").with_value(param_hash[:keystone_password]) + should contain_glance_registry_config("keystone_authtoken/admin_password").with_value(param_hash[:keystone_password]).with_secret(true) + end + end + end + end + + describe 'with disabled service managing' do + let :params do + { + :keystone_password => 'ChangeMe', + :manage_service => false, + :enabled => false, + } + end + + it { should contain_service('glance-registry').with( + 'ensure' => nil, + 'enable' => false, + 'hasstatus' => true, + 'hasrestart' => true, + 'subscribe' => 'File[/etc/glance/glance-registry.conf]', + 'require' => 'Class[Glance]' + )} + end + + describe 'with overridden pipeline' do + # At the time of writing there was only blank and keystone as options + # but there is no reason that there can't be more options in the future. + let :params do + { + :keystone_password => 'ChangeMe', + :pipeline => 'validoptionstring', + } + end + + it { should contain_glance_registry_config('paste_deploy/flavor').with_value('validoptionstring') } + end + + describe 'with blank pipeline' do + let :params do + { + :keystone_password => 'ChangeMe', + :pipeline => '', + } + end + + it { should contain_glance_registry_config('paste_deploy/flavor').with_ensure('absent') } + end + + [ + 'keystone/', + 'keystone+', + '+keystone', + 'keystone+cachemanagement+', + '+' + ].each do |pipeline| + describe "with pipeline incorrect value #{pipeline}" do + let :params do + { + :keystone_password => 'ChangeMe', + :auth_type => 'keystone', + :pipeline => pipeline + } + end + + it { expect { should contain_glance_registry_config('filter:paste_deploy/flavor') }.to\ + raise_error(Puppet::Error, /validate_re\(\): .* does not match/) } + end + end + + describe 'with overriden auth_admin_prefix' do + let :params do + { + :keystone_password => 'ChangeMe', + :auth_admin_prefix => '/keystone/main' + } + end + + it { should contain_glance_registry_config('keystone_authtoken/auth_admin_prefix').with_value('/keystone/main') } + end + + [ + '/keystone/', + 'keystone/', + 'keystone', + '/keystone/admin/', + 'keystone/admin/', + 'keystone/admin' + ].each do |auth_admin_prefix| + describe "with auth_admin_prefix_containing incorrect value #{auth_admin_prefix}" do + let :params do + { + :keystone_password => 'ChangeMe', + :auth_admin_prefix => auth_admin_prefix + } + end + + it { expect { should contain_glance_registry_config('filter:authtoken/auth_admin_prefix') }.to\ + raise_error(Puppet::Error, /validate_re\(\): "#{auth_admin_prefix}" does not match/) } + end + end + + describe 'with syslog disabled by default' do + let :params do + default_params + end + + it { should contain_glance_registry_config('DEFAULT/use_syslog').with_value(false) } + it { should_not contain_glance_registry_config('DEFAULT/syslog_log_facility') } + end + + describe 'with syslog enabled' do + let :params do + default_params.merge({ + :use_syslog => 'true', + }) + end + + it { should contain_glance_registry_config('DEFAULT/use_syslog').with_value(true) } + it { should contain_glance_registry_config('DEFAULT/syslog_log_facility').with_value('LOG_USER') } + end + + describe 'with syslog enabled and custom settings' do + let :params do + default_params.merge({ + :use_syslog => 'true', + :log_facility => 'LOG_LOCAL0' + }) + end + + it { should contain_glance_registry_config('DEFAULT/use_syslog').with_value(true) } + it { should contain_glance_registry_config('DEFAULT/syslog_log_facility').with_value('LOG_LOCAL0') } + end + + describe 'with log_file enabled by default' do + let(:params) { default_params } + + it { should contain_glance_registry_config('DEFAULT/log_file').with_value(default_params[:log_file]) } + + context 'with log_file disabled' do + let(:params) { default_params.merge!({ :log_file => false }) } + it { should contain_glance_registry_config('DEFAULT/log_file').with_ensure('absent') } + end + end + + describe 'with log_dir enabled by default' do + let(:params) { default_params } + + it { should contain_glance_registry_config('DEFAULT/log_dir').with_value(default_params[:log_dir]) } + + context 'with log_dir disabled' do + let(:params) { default_params.merge!({ :log_dir => false }) } + it { should contain_glance_registry_config('DEFAULT/log_dir').with_ensure('absent') } + end + end + + describe 'with no ssl options (default)' do + let(:params) { default_params } + + it { should contain_glance_registry_config('DEFAULT/ca_file').with_ensure('absent')} + it { should contain_glance_registry_config('DEFAULT/cert_file').with_ensure('absent')} + it { should contain_glance_registry_config('DEFAULT/key_file').with_ensure('absent')} + end + + describe 'with ssl options' do + let :params do + default_params.merge({ + :ca_file => '/tmp/ca_file', + :cert_file => '/tmp/cert_file', + :key_file => '/tmp/key_file' + }) + end + + context 'with ssl options' do + it { should contain_glance_registry_config('DEFAULT/ca_file').with_value('/tmp/ca_file') } + it { should contain_glance_registry_config('DEFAULT/cert_file').with_value('/tmp/cert_file') } + it { should contain_glance_registry_config('DEFAULT/key_file').with_value('/tmp/key_file') } + end + end + + describe 'with deprecated sql parameters' do + let :params do + default_params.merge({ + :sql_connection => 'mysql://user:pass@db/db', + :sql_idle_timeout => '30' + }) + end + + it 'configures database' do + should contain_glance_registry_config('database/connection').with_value('mysql://user:pass@db/db') + should contain_glance_registry_config('database/idle_timeout').with_value('30') + end + end + + describe 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + # We only test this on Debian platforms, since on RedHat there isn't a + # separate package for glance registry. + ['present', 'latest'].each do |package_ensure| + context "with package_ensure '#{package_ensure}'" do + let(:params) { default_params.merge({ :package_ensure => package_ensure }) } + it { should contain_package('glance-registry').with( + :ensure => package_ensure, + :tag => ['openstack'] + )} + end + end + end + + describe 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + let(:params) { default_params } + + it { should contain_package('openstack-glance')} + end + + describe 'on unknown platforms' do + let :facts do + { :osfamily => 'unknown' } + end + let(:params) { default_params } + + it 'should fails to configure glance-registry' do + expect { subject }.to raise_error(Puppet::Error, /module glance only support osfamily RedHat and Debian/) + end + end + +end diff --git a/3rdparty/modules/glance/spec/classes/glance_spec.rb b/3rdparty/modules/glance/spec/classes/glance_spec.rb new file mode 100644 index 000000000..43d6e70a3 --- /dev/null +++ b/3rdparty/modules/glance/spec/classes/glance_spec.rb @@ -0,0 +1,57 @@ +require 'spec_helper' + +describe 'glance' do + + let :facts do + { + :osfamily => 'Debian' + } + end + + let :default_params do + {} + end + + [ + {}, + {} + ].each do |param_set| + + describe "when #{param_set == {} ? "using default" : "specifying"} class parameters" do + + let :param_hash do + param_set == {} ? default_params : params + end + + let :params do param_set end + + it { should contain_file('/etc/glance/').with( + 'ensure' => 'directory', + 'owner' => 'glance', + 'mode' => '0770' + )} + + end + end + + describe 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + let(:params) { default_params } + + it { should_not contain_package('glance') } + end + + describe 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + let(:params) { default_params } + + it { should contain_package('openstack-glance').with( + :tag => ['openstack'], + )} + end + +end diff --git a/3rdparty/modules/glance/spec/shared_examples.rb b/3rdparty/modules/glance/spec/shared_examples.rb new file mode 100644 index 000000000..d92156a36 --- /dev/null +++ b/3rdparty/modules/glance/spec/shared_examples.rb @@ -0,0 +1,5 @@ +shared_examples_for "a Puppet::Error" do |description| + it "with message matching #{description.inspect}" do + expect { should have_class_count(1) }.to raise_error(Puppet::Error, description) + end +end diff --git a/3rdparty/modules/glance/spec/spec.opts b/3rdparty/modules/glance/spec/spec.opts new file mode 100644 index 000000000..91cd6427e --- /dev/null +++ b/3rdparty/modules/glance/spec/spec.opts @@ -0,0 +1,6 @@ +--format +s +--colour +--loadby +mtime +--backtrace diff --git a/3rdparty/modules/glance/spec/spec_helper.rb b/3rdparty/modules/glance/spec/spec_helper.rb new file mode 100644 index 000000000..076e2bb39 --- /dev/null +++ b/3rdparty/modules/glance/spec/spec_helper.rb @@ -0,0 +1,7 @@ +require 'puppetlabs_spec_helper/module_spec_helper' +require 'shared_examples' + +RSpec.configure do |c| + c.alias_it_should_behave_like_to :it_configures, 'configures' + c.alias_it_should_behave_like_to :it_raises, 'raises' +end diff --git a/3rdparty/modules/glance/spec/unit/provider/glance_spec.rb b/3rdparty/modules/glance/spec/unit/provider/glance_spec.rb new file mode 100644 index 000000000..14d418b97 --- /dev/null +++ b/3rdparty/modules/glance/spec/unit/provider/glance_spec.rb @@ -0,0 +1,65 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/glance' +require 'tempfile' + + +klass = Puppet::Provider::Glance + +describe Puppet::Provider::Glance do + + after :each do + klass.reset + end + + describe 'when retrieving the auth credentials' do + + it 'should fail if the glance config file does not have the expected contents' do + mock = {} + Puppet::Util::IniConfig::File.expects(:new).returns(mock) + mock.expects(:read).with('/etc/glance/glance-api.conf') + expect do + klass.glance_credentials + end.to raise_error(Puppet::Error, /does not contain all required sections/) + end + + describe 'when testing glance connection retries' do + + ['[Errno 111] Connection refused', '(HTTP 400)', 'HTTP Unable to establish connection'].reverse.each do |valid_message| + it "should retry when glance is not ready with error #{valid_message}" do + mock = {'keystone_authtoken' => + { + 'auth_host' => '127.0.0.1', + 'auth_port' => '35357', + 'auth_protocol' => 'http', + 'admin_tenant_name' => 'foo', + 'admin_user' => 'user', + 'admin_password' => 'pass' + }, + 'DEFAULT' => + { + 'os_region_name' => 'SomeRegion', + } + } + Puppet::Util::IniConfig::File.expects(:new).returns(mock) + mock.expects(:read).with('/etc/glance/glance-api.conf') + klass.expects(:sleep).with(10).returns(nil) + klass.expects(:glance).twice.with( + '--os-tenant-name', + 'foo', + '--os-username', + 'user', + '--os-password', + 'pass', + '--os-region-name', + 'SomeRegion', + '--os-auth-url', + 'http://127.0.0.1:35357/v2.0/', + ['test_retries'] + ).raises(Exception, valid_message).then.returns('') + klass.auth_glance('test_retries') + end + end + end + end +end diff --git a/3rdparty/modules/glance/tests/api.pp b/3rdparty/modules/glance/tests/api.pp new file mode 100644 index 000000000..7b4931916 --- /dev/null +++ b/3rdparty/modules/glance/tests/api.pp @@ -0,0 +1,4 @@ +class { 'glance::api': + debug => true, + verbose => true, +} diff --git a/3rdparty/modules/glance/tests/init.pp b/3rdparty/modules/glance/tests/init.pp new file mode 100644 index 000000000..57cf401a1 --- /dev/null +++ b/3rdparty/modules/glance/tests/init.pp @@ -0,0 +1 @@ +class { 'glance': } diff --git a/3rdparty/modules/glance/tests/registry.pp b/3rdparty/modules/glance/tests/registry.pp new file mode 100644 index 000000000..8635cb267 --- /dev/null +++ b/3rdparty/modules/glance/tests/registry.pp @@ -0,0 +1,4 @@ +class { 'glance::registry': + debug => true, + verbose => true, +} diff --git a/3rdparty/modules/glance/tests/site.pp b/3rdparty/modules/glance/tests/site.pp new file mode 100644 index 000000000..2859b72d7 --- /dev/null +++ b/3rdparty/modules/glance/tests/site.pp @@ -0,0 +1,57 @@ + +# uses the keystone packages +# to ensure that we use the latest precise packages +Exec { logoutput => 'on_failure' } + +node glance_keystone_mysql { + class { 'mysql::server': } + class { 'keystone': + verbose => true, + debug => true, + catalog_type => 'sql', + admin_token => 'admin_token', + } + class { 'keystone::db::mysql': + password => 'keystone', + } + class { 'keystone::roles::admin': + email => 'test@puppetlabs.com', + password => 'ChangeMe', + } + class { 'glance::api': + verbose => true, + debug => true, + auth_type => 'keystone', + keystone_tenant => 'services', + keystone_user => 'glance', + keystone_password => 'glance_password', + sql_connection => 'mysql://glance:glance@127.0.0.1/glance', + } + class { 'glance::backend::file': } + + class { 'glance::db::mysql': + password => 'glance', + dbname => 'glance', + user => 'glance', + host => '127.0.0.1', + # allowed_hosts = undef, + # $cluster_id = 'localzone' + } + + class { 'glance::registry': + verbose => true, + debug => true, + auth_type => 'keystone', + keystone_tenant => 'services', + keystone_user => 'glance', + keystone_password => 'glance_password', + sql_connection => 'mysql://glance:glance@127.0.0.1/glance', + } + class { 'glance::keystone::auth': + password => 'glance_pass', + } +} + +node default { + fail("could not find a matching node entry for ${clientcert}") +} diff --git a/3rdparty/modules/horizon/Gemfile b/3rdparty/modules/horizon/Gemfile new file mode 100644 index 000000000..f3182fde2 --- /dev/null +++ b/3rdparty/modules/horizon/Gemfile @@ -0,0 +1,19 @@ +source 'https://rubygems.org' + +group :development, :test do + gem 'puppetlabs_spec_helper', :require => false + gem 'puppet-lint', '~> 0.3.2' + gem 'rspec-puppet', '~> 1.0.1' + gem 'rake', '10.1.1' + gem 'rspec', '< 2.99' + gem 'json' + gem 'webmock' +end + +if puppetversion = ENV['PUPPET_GEM_VERSION'] + gem 'puppet', puppetversion, :require => false +else + gem 'puppet', :require => false +end + +# vim:ft=ruby diff --git a/3rdparty/modules/horizon/LICENSE b/3rdparty/modules/horizon/LICENSE new file mode 100644 index 000000000..8961ce8a6 --- /dev/null +++ b/3rdparty/modules/horizon/LICENSE @@ -0,0 +1,15 @@ +Copyright (C) 2012 Puppet Labs Inc + +Puppet Labs can be contacted at: info@puppetlabs.com + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/3rdparty/modules/horizon/README.md b/3rdparty/modules/horizon/README.md new file mode 100644 index 000000000..b1e5a1a6b --- /dev/null +++ b/3rdparty/modules/horizon/README.md @@ -0,0 +1,173 @@ +horizon +======= + +5.1.0 - 2014.2 - Juno + +#### Table of Contents + +1. [Overview - What is the horizon module?](#overview) +2. [Module Description - What does the module do?](#module-description) +3. [Setup - The basics of getting started with horizon](#setup) +4. [Implementation - An under-the-hood peek at what the module is doing](#implementation) +5. [Limitations - OS compatibility, etc.](#limitations) +6. [Development - Guide for contributing to the module](#development) +7. [Contributors - Those with commits](#contributors) +8. [Release Notes - Notes on the most recent updates to the module](#release-notes) + +Overview +-------- + +The horizon module is a part of [Stackforge](https://github.com/stackforge), an effort by the Openstack infrastructure team to provide continuous integration testing and code review for Openstack and Openstack community projects not part of the core software. The module its self is used to flexibly configure and manage the dashboard service for Openstack. + +Module Description +------------------ + +The horizon module is a thorough attempt to make Puppet capable of managing the entirety of horizon. Horizon is a fairly classic django application, which results in a fairly simply Puppet module. + +This module is tested in combination with other modules needed to build and leverage an entire Openstack software stack. These modules can be found, all pulled together in the [openstack module](https://github.com/stackforge/puppet-openstack). + +Setup +----- + +**What the horizon module affects** + +* horizon, the dashboard service for Openstack. + +### Installing horizon + + example% puppet module install puppetlabs/horizon + +### Beginning with horizon + +To utilize the horizon module's functionality you will need to declare multiple resources but you'll find that doing so is much less complicated than the other OpenStack component modules. The following is a modified excerpt from the [openstack module](https://github.com/stackforge/puppet-openstack). We recommend you consult and understand the [openstack module](https://github.com/stackforge/puppet-openstack) and the [core openstack](http://docs.openstack.org) documentation. + +**Define a horizon dashboard** + +```puppet +class { 'memcached': + listen_ip => '127.0.0.1', + tcp_port => '11211', + udp_port => '11211', +} + +class { '::horizon': + cache_server_ip => '127.0.0.1', + cache_server_port => '11211', + secret_key => '12345', + swift => false, + django_debug => 'True', + api_result_limit => '2000', +} +``` + +Implementation +-------------- + +### horizon + +Horizon is a simple module using the combination of a package, template, and the file_line type. Most all the configuration lives inside the included local_settings template and the file_line type is for selectively inserting needed lines into configuration files that aren't explicitly managed by the horizon module. + +Limitations +------------ + +* Only supports Apache using mod_wsgi. + +Development +----------- + +Developer documentation for the entire puppet-openstack project. + +* https://wiki.openstack.org/wiki/Puppet-openstack#Developer_documentation + +Contributors +------------ + +* https://github.com/stackforge/puppet-horizon/graphs/contributors + +Release Notes +------------- + +**5.1.0** + +* spec: pin rspec-puppet to 1.0.1 +* Sort policy files in local_settings.py +* Pin puppetlabs-concat to 1.2.1 in fixtures +* Add support for the configuration of OPENSTACK_CINDER_FEATURES +* Update .gitreview file for project rename + +**5.0.0** + +* Stable Juno release +* Fixed the default value of compress_offline parameter +* Always manages local_settings.py +* Added parameters to configure policy files in horizon class +* Fixed Apache config file default +* Added parameter django_session_engine to horizon class +* Stops setting wsgi_socket_prefix since the apache module takes care of it +* Adds workaround for puppet's handling of undef for setting the vhost bind address +* Changes cache_server_ip in horizon class to accept arrays +* Switched the default log level to INFO from DEBUG +* Fixed the default MSSQL port in security group rules + +**4.2.0** + +* Added parameters to configure ALLOWED_HOSTS in settings_local.y and + ServerAlias in apache, no longer requiring these values to be the fqdn +* Fixed removal of vhost conf file +* Added support for secure cookies + +**4.1.0** + +* Added option to set temporary upload directory for images. +* Ensure ssl wsgi_process_group is the same as wsgi_daemon_process. +* Pined major gems. + +**4.0.0** + +* Stable Icehouse release. +* Added support to pass extra parameters to vhost. +* Added support to ensure online cache is present and can be refreshed. +* Added support to configure OPENSTACK_HYPERVISOR_FEATURES settings, AVAILABLE_REGIONS, OPENSTACK_NEUTRON_NETWORK. +* Added support to disable configuration of Apache. +* Fixed log ownership and WSGIProcess* settings for Red Hat releases. +* Fixed overriding of policy files in local settings. +* Fixed SSL bugs. +* Improved WSGI configuration. + +**3.1.0** + +* Added option parameterize OPENSTACK_NEUTRON_NETWORK settings. + +**3.0.1** + +* Adds COMPRESS_OFFLINE option to local_settings to fix broken Ubuntu installation. + +**3.0.0** + +* Major release for OpenStack Havana. +* Updated user and group for Debian family OSes. +* Updated policy files for RedHat family OSes. +* Enabled SSL support with cert/key. +* Improved default logging configuration. +* Fixed bug to set LOGOUT_URL properly. +* Introduced new parameters: keystone_url, help_url, endpoint type. +* Fixed user/group regression for Debian. +* Changed keystone_default_role to _member_. + +**2.2.0** + +* Fixed apache 0.9.0 incompatability. +* Various lint fixes. + +**2.1.0** + +* Updated local_settings.py. +* Pinned Apache module version. +* Various lint fixes. + +**2.0.0** + +* Upstream is now part of stackforge. +* httpd config now managed on every platform. +* Provides option to enable Horizon's display of block device mount points. + diff --git a/3rdparty/modules/horizon/Rakefile b/3rdparty/modules/horizon/Rakefile new file mode 100644 index 000000000..4c2b2ed07 --- /dev/null +++ b/3rdparty/modules/horizon/Rakefile @@ -0,0 +1,6 @@ +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' + +PuppetLint.configuration.fail_on_warnings = true +PuppetLint.configuration.send('disable_80chars') +PuppetLint.configuration.send('disable_class_parameter_defaults') diff --git a/3rdparty/modules/horizon/checksums.json b/3rdparty/modules/horizon/checksums.json new file mode 100644 index 000000000..18f6eec35 --- /dev/null +++ b/3rdparty/modules/horizon/checksums.json @@ -0,0 +1,18 @@ +{ + "Gemfile": "4a83c46a2bb3896cf81852501819bb3a", + "LICENSE": "b3f8a01d8699078d82e8c3c992307517", + "README.md": "b12af771a92375eedf4d97c200ed6b5d", + "Rakefile": "2ca4ff31c946a19edd44348fbfdc2aab", + "lib/puppet/parser/functions/os_any2array.rb": "f002c4a7168b4446719fcd4d0083320e", + "manifests/init.pp": "de3d0966e872dbdf3c8cf09bf2e94cdf", + "manifests/params.pp": "c8a5fce51b20821b302183989cf95998", + "manifests/wsgi/apache.pp": "73228f34e9fea5332be55aeae7b8f6d9", + "metadata.json": "aaa8584040320591b680902b318bc94b", + "spec/classes/horizon_init_spec.rb": "81184b7e164f345f4a1582f81133164b", + "spec/classes/horizon_wsgi_apache_spec.rb": "992a461cb5e320c1dfeb7aaeab00db7c", + "spec/fixtures/override_local_settings.py.erb": "22aa66d649d89eaa8152e818b4a3dd88", + "spec/shared_examples.rb": "80bbd2763ab2702dc310473f3ee8cb18", + "spec/spec_helper.rb": "41d71ed92d01bb23d52397572e9b24bb", + "spec/unit/puppet/parser/functions/os_any2array_spec.rb": "25b3520e2acc469573c402f630d49968", + "templates/local_settings.py.erb": "7261a1eeee412ca79f977eeeb3c92031" +} \ No newline at end of file diff --git a/3rdparty/modules/horizon/lib/puppet/parser/functions/os_any2array.rb b/3rdparty/modules/horizon/lib/puppet/parser/functions/os_any2array.rb new file mode 100644 index 000000000..a3877a0bd --- /dev/null +++ b/3rdparty/modules/horizon/lib/puppet/parser/functions/os_any2array.rb @@ -0,0 +1,34 @@ +# +# os_any2array.rb +# +# TODO: Remove this function when puppetlabs-stdlib 4.0.0 is in wider use + +module Puppet::Parser::Functions + newfunction(:os_any2array, :type => :rvalue, :doc => <<-EOS +This converts any object to an array containing that object. Empty argument +lists are converted to an empty array. Arrays are left untouched. Hashes are +converted to arrays of alternating keys and values. + EOS + ) do |arguments| + + if arguments.empty? + return [] + end + + if arguments.length == 1 + if arguments[0].kind_of?(Array) + return arguments[0] + elsif arguments[0].kind_of?(Hash) + result = [] + arguments[0].each do |key, value| + result << key << value + end + return result + end + end + + return arguments + end +end + +# vim: set ts=2 sw=2 et : diff --git a/3rdparty/modules/horizon/manifests/init.pp b/3rdparty/modules/horizon/manifests/init.pp new file mode 100644 index 000000000..f025acd66 --- /dev/null +++ b/3rdparty/modules/horizon/manifests/init.pp @@ -0,0 +1,360 @@ +# == Class: horizon +# +# Installs Horizon dashboard with Apache +# +# === Parameters +# +# [*secret_key*] +# (required) Secret key. This is used by Django to provide cryptographic +# signing, and should be set to a unique, unpredictable value. +# +# [*fqdn*] +# (optional) DEPRECATED, use allowed_hosts and server_aliases instead. +# FQDN(s) used to access Horizon. This is used by Django for +# security reasons. Can be set to * in environments where security is +# deemed unimportant. Also used for Server Aliases in web configs. +# Defaults to ::fqdn +# +# [*servername*] +# (optional) FQDN used for the Server Name directives +# Defaults to ::fqdn. +# +# [*allowed_hosts*] +# (optional) List of hosts which will be set as value of ALLOWED_HOSTS +# parameter in settings_local.py. This is used by Django for +# security reasons. Can be set to * in environments where security is +# deemed unimportant. +# Defaults to ::fqdn. +# +# [*server_aliases*] +# (optional) List of names which should be defined as ServerAlias directives +# in vhost.conf. +# Defaults to ::fqdn. +# +# [*package_ensure*] +# (optional) Package ensure state. Defaults to 'present'. +# +# [*cache_server_ip*] +# (optional) Memcached IP address. Can be a string, or an array. +# Defaults to '127.0.0.1'. +# +# [*cache_server_port*] +# (optional) Memcached port. Defaults to '11211'. +# +# [*swift*] +# (optional) Enable Swift interface extension. Defaults to false. +# +# [*horizon_app_links*] +# (optional) Array of arrays that can be used to add call-out links +# to the dashboard for other apps. There is no specific requirement +# for these apps to be for monitoring, that's just the defacto purpose. +# Each app is defined in two parts, the display name, and +# the URIDefaults to false. Defaults to false. (no app links) +# +# [*keystone_url*] +# (optional) Full url of keystone public endpoint. (Defaults to 'http://127.0.0.1:5000/v2.0') +# Use this parameter in favor of keystone_host, keystone_port and keystone_scheme. +# +# [*keystone_scheme*] +# (optional) DEPRECATED: Use keystone_url instead. +# Scheme of the Keystone service. (Defaults to 'http') +# Setting this parameter overrides keystone_url parameter. +# +# [*keystone_host*] +# (optional) DEPRECATED: Use keystone_url instead. +# IP address of the Keystone service. (Defaults to '127.0.0.1') +# Setting this parameter overrides keystone_url parameter. +# +# [*keystone_port*] +# (optional) DEPRECATED: Use keystone_url instead. +# Port of the Keystone service. (Defaults to 5000) +# Setting this parameter overrides keystone_url parameter. +# +# [*keystone_default_role*] +# (optional) Default Keystone role for new users. Defaults to '_member_'. +# +# [*django_debug*] +# (optional) Enable or disable Django debugging. Defaults to 'False'. +# +# [*openstack_endpoint_type*] +# (optional) endpoint type to use for the endpoints in the Keystone +# service catalog. Defaults to 'undef'. +# +# [*secondary_endpoint_type*] +# (optional) secondary endpoint type to use for the endpoints in the +# Keystone service catalog. Defaults to 'undef'. +# +# [*available_regions*] +# (optional) List of available regions. Value should be a list of tuple: +# [ ['urlOne', 'RegionOne'], ['urlTwo', 'RegionTwo'] ] +# Defaults to undef. +# +# [*api_result_limit*] +# (optional) Maximum number of Swift containers/objects to display +# on a single page. Defaults to 1000. +# +# [*log_level*] +# (optional) Log level. Defaults to 'INFO'. WARNING: Setting this to +# DEBUG will let plaintext passwords be logged in the Horizon log file. +# +# [*local_settings_template*] +# (optional) Location of template to use for local_settings.py generation. +# Defaults to 'horizon/local_settings.py.erb'. +# +# [*help_url*] +# (optional) Location where the documentation should point. +# Defaults to 'http://docs.openstack.org'. +# +# [*compress_offline*] +# (optional) Boolean to enable offline compress of assets. +# Defaults to True +# +# [*hypervisor_options*] +# (optional) A hash of parameters to enable features specific to +# Hypervisors. These include: +# 'can_set_mount_point': Boolean to enable or disable mount point setting +# Defaults to 'True'. +# 'can_set_password': Boolean to enable or disable VM password setting. +# Works only with Xen Hypervisor. +# Defaults to 'False'. +# +# [*cinder_options*] +# (optional) A hash of parameters to enable features specific to +# Cinder. These include: +# 'enable_backup': Boolean to enable or disable Cinders's backup feature. +# Defaults to False. +# +# [*neutron_options*] +# (optional) A hash of parameters to enable features specific to +# Neutron. These include: +# 'enable_lb': Boolean to enable or disable Neutron's LBaaS feature. +# Defaults to False. +# 'enable_firewall': Boolean to enable or disable Neutron's FWaaS feature. +# Defaults to False. +# 'enable_quotas': Boolean to enable or disable Neutron quotas. +# Defaults to True. +# 'enable_security_group': Boolean to enable or disable Neutron +# security groups. Defaults to True. +# 'enable_vpn': Boolean to enable or disable Neutron's VPNaaS feature. +# Defaults to False. +# 'profile_support': A string indiciating which plugin-specific +# profiles to enable. Defaults to 'None', other options include +# 'cisco'. +# +# [*configure_apache*] +# (optional) Configure Apache for Horizon. (Defaults to true) +# +# [*bind_address*] +# (optional) Bind address in Apache for Horizon. (Defaults to undef) +# +# [*listen_ssl*] +# (optional) Enable SSL support in Apache. (Defaults to false) +# +# [*ssl_redirect*] +# (optional) Whether to redirect http to https +# Defaults to True +# +# [*horizon_cert*] +# (required with listen_ssl) Certificate to use for SSL support. +# +# [*horizon_key*] +# (required with listen_ssl) Private key to use for SSL support. +# +# [*horizon_ca*] +# (required with listen_ssl) CA certificate to use for SSL support. +# +# [*vhost_extra_params*] +# (optionnal) extra parameter to pass to the apache::vhost class +# Defaults to undef +# +# [*file_upload_temp_dir*] +# (optional) Location to use for temporary storage of images uploaded +# You must ensure that the path leading to the directory is created +# already, only the last level directory is created by this manifest. +# Specify an absolute pathname. +# Defaults to /tmp +# +# [*secure_cookies*] +# (optional) Enables security settings for cookies. Useful when using +# https on public sites. See: http://docs.openstack.org/developer/horizon/topics/deployment.html#secure-site-recommendations +# Defaults to false +# +# [*django_session_engine*] +# (optional) Selects the session engine for Django to use. +# Defaults to undefined - will not add entry to local settings. +# +# === Deprecation notes +# +# If any value is provided for keystone_scheme, keystone_host, or +# keystone_port parameters; keystone_url will be completely ignored. Also +# can_set_mount_point is deprecated. +# +# === Examples +# +# class { 'horizon': +# secret_key => 's3cr3t', +# keystone_url => 'https://10.0.0.10:5000/v2.0', +# available_regions => [ +# ['http://region-1.example.com:5000/v2.0', 'Region-1'], +# ['http://region-2.example.com:5000/v2.0', 'Region-2'] +# ] +# } +# +class horizon( + $secret_key, + $fqdn = undef, + $package_ensure = 'present', + $cache_server_ip = '127.0.0.1', + $cache_server_port = '11211', + $swift = false, + $horizon_app_links = false, + $keystone_url = 'http://127.0.0.1:5000/v2.0', + $keystone_default_role = '_member_', + $django_debug = 'False', + $openstack_endpoint_type = undef, + $secondary_endpoint_type = undef, + $available_regions = undef, + $api_result_limit = 1000, + $log_level = 'INFO', + $help_url = 'http://docs.openstack.org', + $local_settings_template = 'horizon/local_settings.py.erb', + $configure_apache = true, + $bind_address = undef, + $servername = $::fqdn, + $server_aliases = $::fqdn, + $allowed_hosts = $::fqdn, + $listen_ssl = false, + $ssl_redirect = true, + $horizon_cert = undef, + $horizon_key = undef, + $horizon_ca = undef, + $compress_offline = true, + $hypervisor_options = {}, + $cinder_options = {}, + $neutron_options = {}, + $file_upload_temp_dir = '/tmp', + $policy_files_path = undef, + $policy_files = undef, + # DEPRECATED PARAMETERS + $can_set_mount_point = undef, + $keystone_host = undef, + $keystone_port = undef, + $keystone_scheme = undef, + $vhost_extra_params = undef, + $secure_cookies = false, + $django_session_engine = undef, +) { + + include ::horizon::params + + if $swift { + warning('swift parameter is deprecated and has no effect.') + } + + if $keystone_scheme { + warning('The keystone_scheme parameter is deprecated, use keystone_url instead.') + } + + if $keystone_host { + warning('The keystone_host parameter is deprecated, use keystone_url instead.') + } + + if $keystone_port { + warning('The keystone_port parameter is deprecated, use keystone_url instead.') + } + + # Default options for the OPENSTACK_HYPERVISOR_FEATURES section. These will + # be merged with user-provided options when the local_settings.py.erb + # template is interpolated. Also deprecates can_set_mount_point. + if $can_set_mount_point { + warning('The can_set_mount_point parameter is deprecated, use hypervisor_options instead.') + $hypervisor_defaults = { + 'can_set_mount_point' => $can_set_mount_point, + 'can_set_password' => false + } + } else { + $hypervisor_defaults = { + 'can_set_mount_point' => true, + 'can_set_password' => false + } + } + + if $fqdn { + warning('Parameter fqdn is deprecated. Please use parameter allowed_hosts for setting ALLOWED_HOSTS in settings_local.py and parameter server_aliases for setting ServerAlias directives in vhost.conf.') + $final_allowed_hosts = $fqdn + $final_server_aliases = $fqdn + } else { + $final_allowed_hosts = $allowed_hosts + $final_server_aliases = $server_aliases + } + + # Default options for the OPENSTACK_CINDER_FEATURES section. These will + # be merged with user-provided options when the local_settings.py.erb + # template is interpolated. + $cinder_defaults = { + 'enable_backup' => false, + } + + # Default options for the OPENSTACK_NEUTRON_NETWORK section. These will + # be merged with user-provided options when the local_settings.py.erb + # template is interpolated. + $neutron_defaults = { + 'enable_lb' => false, + 'enable_firewall' => false, + 'enable_quotas' => true, + 'enable_security_group' => true, + 'enable_vpn' => false, + 'profile_support' => 'None' + } + + Service <| title == 'memcached' |> -> Class['horizon'] + + package { 'horizon': + ensure => $package_ensure, + name => $::horizon::params::package_name, + } + + file { $::horizon::params::config_file: + content => template($local_settings_template), + mode => '0644', + require => Package['horizon'], + } + + package { 'python-lesscpy': + ensure => $package_ensure, + } + + exec { 'refresh_horizon_django_cache': + command => "${::horizon::params::manage_py} compress", + refreshonly => true, + require => [Package['python-lesscpy'], Package['horizon']], + } + + if $compress_offline { + File[$::horizon::params::config_file] ~> Exec['refresh_horizon_django_cache'] + } + + if $configure_apache { + class { 'horizon::wsgi::apache': + bind_address => $bind_address, + servername => $servername, + server_aliases => $final_server_aliases, + listen_ssl => $listen_ssl, + ssl_redirect => $ssl_redirect, + horizon_cert => $horizon_cert, + horizon_key => $horizon_key, + horizon_ca => $horizon_ca, + extra_params => $vhost_extra_params, + } + } + + if ! ($file_upload_temp_dir in ['/tmp','/var/tmp']) { + file { $file_upload_temp_dir : + ensure => directory, + owner => $::horizon::params::wsgi_user, + group => $::horizon::params::wsgi_group, + mode => '0755' + } + } + +} diff --git a/3rdparty/modules/horizon/manifests/params.pp b/3rdparty/modules/horizon/manifests/params.pp new file mode 100644 index 000000000..29aad33a6 --- /dev/null +++ b/3rdparty/modules/horizon/manifests/params.pp @@ -0,0 +1,47 @@ +# these parameters need to be accessed from several locations and +# should be considered to be constant +class horizon::params { + + $logdir = '/var/log/horizon' + $django_wsgi = '/usr/share/openstack-dashboard/openstack_dashboard/wsgi/django.wsgi' + $manage_py = '/usr/share/openstack-dashboard/manage.py' + + case $::osfamily { + 'RedHat': { + $http_service = 'httpd' + $http_modwsgi = 'mod_wsgi' + $package_name = 'openstack-dashboard' + $config_file = '/etc/openstack-dashboard/local_settings' + $httpd_config_file = '/etc/httpd/conf.d/openstack-dashboard.conf' + $httpd_listen_config_file = '/etc/httpd/conf/httpd.conf' + $root_url = '/dashboard' + $apache_user = 'apache' + $apache_group = 'apache' + $wsgi_user = 'dashboard' + $wsgi_group = 'dashboard' + } + 'Debian': { + $http_service = 'apache2' + $config_file = '/etc/openstack-dashboard/local_settings.py' + $httpd_listen_config_file = '/etc/apache2/ports.conf' + $root_url = '/horizon' + $apache_user = 'www-data' + $apache_group = 'www-data' + $wsgi_user = 'horizon' + $wsgi_group = 'horizon' + case $::operatingsystem { + 'Debian': { + $package_name = 'openstack-dashboard-apache' + $httpd_config_file = '/etc/apache2/sites-available/openstack-dashboard.conf' + } + default: { + $package_name = 'openstack-dashboard' + $httpd_config_file = '/etc/apache2/conf-available/openstack-dashboard.conf' + } + } + } + default: { + fail("Unsupported osfamily: ${::osfamily} operatingsystem: ${::operatingsystem}, module ${module_name} only support osfamily RedHat and Debian") + } + } +} diff --git a/3rdparty/modules/horizon/manifests/wsgi/apache.pp b/3rdparty/modules/horizon/manifests/wsgi/apache.pp new file mode 100644 index 000000000..4087f1959 --- /dev/null +++ b/3rdparty/modules/horizon/manifests/wsgi/apache.pp @@ -0,0 +1,199 @@ +# == Class: horizon::wsgi::apache +# +# Configures Apache WSGI for Horizon. +# +# === Parameters +# +# [*bind_address*] +# (optional) Bind address in Apache for Horizon. (Defaults to '0.0.0.0') +# +# [*server_aliases*] +# (optional) List of names which should be defined as ServerAlias directives +# in vhost.conf. +# Defaults to ::fqdn. +# +# [*listen_ssl*] +# (optional) Enable SSL support in Apache. (Defaults to false) +# +# [*horizon_cert*] +# (required with listen_ssl) Certificate to use for SSL support. +# +# [*horizon_key*] +# (required with listen_ssl) Private key to use for SSL support. +# +# [*horizon_ca*] +# (required with listen_ssl) CA certificate to use for SSL support. +# +# [*wsgi_processes*] +# (optional) Number of Horizon processes to spawn +# Defaults to '3' +# +# [*wsgi_threads*] +# (optional) Number of thread to run in a Horizon process +# Defaults to '10' +# +# [*priority*] +# (optional) The apache vhost priority. +# Defaults to '15'. To set Horizon as the primary vhost, change to '10'. +# +# [*extra_params*] +# (optional) A hash of extra paramaters for apache::wsgi class. +# Defaults to {} +class horizon::wsgi::apache ( + $bind_address = undef, + $fqdn = undef, + $servername = $::fqdn, + $server_aliases = $::fqdn, + $listen_ssl = false, + $ssl_redirect = true, + $horizon_cert = undef, + $horizon_key = undef, + $horizon_ca = undef, + $wsgi_processes = '3', + $wsgi_threads = '10', + $priority = '15', + $vhost_conf_name = 'horizon_vhost', + $vhost_ssl_conf_name = 'horizon_ssl_vhost', + $extra_params = {}, +) { + + include ::horizon::params + include ::apache + + if $fqdn { + warning('Parameter fqdn is deprecated. Please use parameter server_aliases for setting ServerAlias directives in vhost.conf.') + $final_server_aliases = $fqdn + } else { + $final_server_aliases = $server_aliases + } + + include ::apache::mod::wsgi + + # We already use apache::vhost to generate our own + # configuration file, let's clean the configuration + # embedded within the package + file { $::horizon::params::httpd_config_file: + ensure => present, + content => "# +# This file has been cleaned by Puppet. +# +# OpenStack Horizon configuration has been moved to: +# - ${priority}-${vhost_conf_name}.conf +# - ${priority}-${vhost_ssl_conf_name}.conf +#", + require => Package[$::horizon::params::package_name] + } + + + if $listen_ssl { + include ::apache::mod::ssl + $ensure_ssl_vhost = 'present' + + if $horizon_ca == undef { + fail('The horizon_ca parameter is required when listen_ssl is true') + } + + if $horizon_cert == undef { + fail('The horizon_cert parameter is required when listen_ssl is true') + } + + if $horizon_key == undef { + fail('The horizon_key parameter is required when listen_ssl is true') + } + + if $ssl_redirect { + $redirect_match = '(.*)' + $redirect_url = "https://${servername}" + } + + } else { + $ensure_ssl_vhost = 'absent' + $redirect_match = '^/$' + $redirect_url = $::horizon::params::root_url + } + + Package['horizon'] -> Package[$::horizon::params::http_service] + File[$::horizon::params::config_file] ~> Service[$::horizon::params::http_service] + + $unix_user = $::osfamily ? { + 'RedHat' => $::horizon::params::apache_user, + default => $::horizon::params::wsgi_user + } + $unix_group = $::osfamily ? { + 'RedHat' => $::horizon::params::apache_group, + default => $::horizon::params::wsgi_group, + } + + file { $::horizon::params::logdir: + ensure => directory, + owner => $unix_user, + group => $unix_group, + before => Service[$::horizon::params::http_service], + mode => '0751', + require => Package['horizon'] + } + + file { "${::horizon::params::logdir}/horizon.log": + ensure => file, + owner => $unix_user, + group => $unix_group, + before => Service[$::horizon::params::http_service], + mode => '0640', + require => [ File[$::horizon::params::logdir], Package['horizon'] ], + } + + $default_vhost_conf_no_ip = { + servername => $servername, + serveraliases => os_any2array($final_server_aliases), + docroot => '/var/www/', + access_log_file => 'horizon_access.log', + error_log_file => 'horizon_error.log', + priority => $priority, + aliases => [ + { alias => '/static', path => '/usr/share/openstack-dashboard/static' } + ], + port => 80, + ssl_cert => $horizon_cert, + ssl_key => $horizon_key, + ssl_ca => $horizon_ca, + wsgi_script_aliases => hash([$::horizon::params::root_url, $::horizon::params::django_wsgi]), + wsgi_daemon_process => $::horizon::params::wsgi_group, + wsgi_daemon_process_options => { + processes => $wsgi_processes, + threads => $wsgi_threads, + user => $unix_user, + group => $unix_group, + }, + wsgi_import_script => $::horizon::params::django_wsgi, + wsgi_process_group => $::horizon::params::wsgi_group, + redirectmatch_status => 'permanent', + } + + # Only add the 'ip' element to the $default_vhost_conf hash if it was explicitly + # specified in the instantiation of the class. This is because ip => undef gets + # changed to ip => '' via the Puppet function API when ensure_resource is called. + # See https://bugs.launchpad.net/puppet-horizon/+bug/1371345 + if $bind_address { + $default_vhost_conf = merge($default_vhost_conf_no_ip, { ip => $bind_address }) + } else { + $default_vhost_conf = $default_vhost_conf_no_ip + } + + ensure_resource('apache::vhost', $vhost_conf_name, merge ($default_vhost_conf, $extra_params, { + redirectmatch_regexp => $redirect_match, + redirectmatch_dest => $redirect_url, + })) + ensure_resource('apache::vhost', $vhost_ssl_conf_name, merge ($default_vhost_conf, $extra_params, { + access_log_file => 'horizon_ssl_access.log', + error_log_file => 'horizon_ssl_error.log', + priority => $priority, + ssl => true, + port => 443, + ensure => $ensure_ssl_vhost, + wsgi_daemon_process => 'horizon-ssl', + wsgi_process_group => 'horizon-ssl', + redirectmatch_regexp => '^/$', + redirectmatch_dest => $::horizon::params::root_url, + })) + +} diff --git a/3rdparty/modules/horizon/metadata.json b/3rdparty/modules/horizon/metadata.json new file mode 100644 index 000000000..554366d28 --- /dev/null +++ b/3rdparty/modules/horizon/metadata.json @@ -0,0 +1,54 @@ +{ + "name": "stackforge-horizon", + "version": "5.1.0", + "author": "Puppet Labs and OpenStack Contributors", + "summary": "Puppet module for OpenStack Horizon", + "license": "Apache-2.0", + "source": "git://github.com/openstack/puppet-horizon.git", + "project_page": "https://launchpad.net/puppet-horizon", + "issues_url": "https://bugs.launchpad.net/puppet-horizon", + "dependencies": [ + {"name":"puppetlabs/apache","version_requirement":">=1.2.0 <2.0.0"}, + {"name":"puppetlabs/stdlib","version_requirement":">=4.0.0 <5.0.0"}, + {"name":"saz/memcached","version_requirement":">=2.0.2 <3.0.0"} + ], + "requirements": [ + { + "name": "pe", + "version_requirement": "3.x" + }, + { + "name": "puppet", + "version_requirement": "3.x" + } + ], + "operatingsystem_support": [ + { + "operatingsystem": "Debian", + "operatingsystemrelease": [ + "7" + ] + }, + { + "operatingsystem": "Fedora", + "operatingsystemrelease": [ + "20" + ] + }, + { + "operatingsystem": "RedHat", + "operatingsystemrelease": [ + "6.5", + "7" + ] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": [ + "12.04", + "14.04" + ] + } + ], + "description": "Installs and configures OpenStack Horizon (Dashboard)." +} diff --git a/3rdparty/modules/horizon/spec/classes/horizon_init_spec.rb b/3rdparty/modules/horizon/spec/classes/horizon_init_spec.rb new file mode 100644 index 000000000..93d08a5af --- /dev/null +++ b/3rdparty/modules/horizon/spec/classes/horizon_init_spec.rb @@ -0,0 +1,332 @@ +require 'spec_helper' + +describe 'horizon' do + + let :params do + { 'secret_key' => 'elj1IWiLoWHgcyYxFVLj7cM5rGOOxWl0', + 'fqdn' => '*' } + end + + let :pre_condition do + 'include apache' + end + + let :fixtures_path do + File.expand_path(File.join(__FILE__, '..', '..', 'fixtures')) + end + + let :facts do + { :concat_basedir => '/var/lib/puppet/concat', + :fqdn => 'some.host.tld' + } + end + + shared_examples 'horizon' do + + context 'with default parameters' do + it { + should contain_package('python-lesscpy').with_ensure('present') + should contain_package('horizon').with_ensure('present') + } + it { should contain_exec('refresh_horizon_django_cache').with({ + :command => '/usr/share/openstack-dashboard/manage.py compress', + :refreshonly => true, + })} + it { should contain_file(platforms_params[:config_file]).that_notifies('Exec[refresh_horizon_django_cache]') } + + it 'configures apache' do + should contain_class('horizon::wsgi::apache').with({ + :servername => 'some.host.tld', + :listen_ssl => false, + :servername => 'some.host.tld', + :extra_params => {}, + }) + end + + it 'generates local_settings.py' do + verify_contents(subject, platforms_params[:config_file], [ + 'DEBUG = False', + "ALLOWED_HOSTS = ['*', ]", + "SECRET_KEY = 'elj1IWiLoWHgcyYxFVLj7cM5rGOOxWl0'", + 'OPENSTACK_KEYSTONE_URL = "http://127.0.0.1:5000/v2.0"', + 'OPENSTACK_KEYSTONE_DEFAULT_ROLE = "_member_"', + " 'can_set_mount_point': True,", + " 'can_set_password': False,", + " 'enable_lb': False,", + " 'enable_firewall': False,", + " 'enable_quotas': True,", + " 'enable_security_group': True,", + " 'enable_vpn': False,", + 'API_RESULT_LIMIT = 1000', + "LOGIN_URL = '#{platforms_params[:root_url]}/auth/login/'", + "LOGOUT_URL = '#{platforms_params[:root_url]}/auth/logout/'", + "LOGIN_REDIRECT_URL = '#{platforms_params[:root_url]}'", + 'COMPRESS_OFFLINE = True', + "FILE_UPLOAD_TEMP_DIR = '/tmp'" + ]) + + # From internals of verify_contents, get the contents to check for absence of a line + content = subject.resource('file', platforms_params[:config_file]).send(:parameters)[:content] + + # With default options, should _not_ have a line to configure SESSION_ENGINE + content.should_not match(/^SESSION_ENGINE/) + end + + it { should_not contain_file(params[:file_upload_temp_dir]) } + end + + context 'with overridden parameters' do + before do + params.merge!({ + :cache_server_ip => '10.0.0.1', + :django_session_engine => 'django.contrib.sessions.backends.cache', + :keystone_default_role => 'SwiftOperator', + :keystone_url => 'https://keystone.example.com:4682', + :openstack_endpoint_type => 'internalURL', + :secondary_endpoint_type => 'ANY-VALUE', + :django_debug => true, + :api_result_limit => 4682, + :compress_offline => false, + :hypervisor_options => {'can_set_mount_point' => false, 'can_set_password' => true }, + :cinder_options => {'enable_backup' => true }, + :neutron_options => {'enable_lb' => true, 'enable_firewall' => true, 'enable_quotas' => false, 'enable_security_group' => false, 'enable_vpn' => true, 'profile_support' => 'cisco' }, + :file_upload_temp_dir => '/var/spool/horizon', + :secure_cookies => true + }) + end + + it 'generates local_settings.py' do + verify_contents(subject, platforms_params[:config_file], [ + 'DEBUG = True', + "ALLOWED_HOSTS = ['*', ]", + 'CSRF_COOKIE_SECURE = True', + 'SESSION_COOKIE_SECURE = True', + "SECRET_KEY = 'elj1IWiLoWHgcyYxFVLj7cM5rGOOxWl0'", + " 'LOCATION': '10.0.0.1:11211',", + 'SESSION_ENGINE = "django.contrib.sessions.backends.cache"', + 'OPENSTACK_KEYSTONE_URL = "https://keystone.example.com:4682"', + 'OPENSTACK_KEYSTONE_DEFAULT_ROLE = "SwiftOperator"', + " 'can_set_mount_point': False,", + " 'can_set_password': True,", + " 'enable_backup': True,", + " 'enable_lb': True,", + " 'enable_firewall': True,", + " 'enable_quotas': False,", + " 'enable_security_group': False,", + " 'enable_vpn': True,", + " 'profile_support': 'cisco',", + 'OPENSTACK_ENDPOINT_TYPE = "internalURL"', + 'SECONDARY_ENDPOINT_TYPE = "ANY-VALUE"', + 'API_RESULT_LIMIT = 4682', + 'COMPRESS_OFFLINE = False', + "FILE_UPLOAD_TEMP_DIR = '/var/spool/horizon'" + ]) + end + + it { should_not contain_file(platforms_params[:config_file]).that_notifies('Exec[refresh_horizon_django_cache]') } + + it { should contain_file(params[:file_upload_temp_dir]) } + end + + context 'with overridden parameters and cache_server_ip array' do + before do + params.merge!({ + :cache_server_ip => ['10.0.0.1','10.0.0.2'], + }) + end + + it 'generates local_settings.py' do + verify_contents(subject, platforms_params[:config_file], [ + " 'LOCATION': [ '10.0.0.1:11211','10.0.0.2:11211', ],", + ]) + end + + it { should contain_exec('refresh_horizon_django_cache') } + end + + context 'with deprecated parameters' do + before do + params.merge!({ + :keystone_host => 'keystone.example.com', + :keystone_port => 4682, + :keystone_scheme => 'https', + :can_set_mount_point => true, + }) + end + + it 'generates local_settings.py' do + verify_contents(subject, platforms_params[:config_file], [ + 'OPENSTACK_KEYSTONE_URL = "https://keystone.example.com:4682/v2.0"', + " 'can_set_mount_point': True," + ]) + end + end + + context 'with vhost_extra_params' do + before do + params.merge!({ + :vhost_extra_params => { 'add_listen' => false }, + }) + end + + it 'configures apache' do + should contain_class('horizon::wsgi::apache').with({ + :extra_params => { 'add_listen' => false }, + }) + end + end + + + context 'with ssl enabled' do + before do + params.merge!({ + :listen_ssl => true, + :servername => 'some.host.tld', + :horizon_cert => '/etc/pki/tls/certs/httpd.crt', + :horizon_key => '/etc/pki/tls/private/httpd.key', + :horizon_ca => '/etc/pki/tls/certs/ca.crt', + }) + end + + it 'configures apache' do + should contain_class('horizon::wsgi::apache').with({ + :bind_address => nil, + :listen_ssl => true, + :horizon_cert => '/etc/pki/tls/certs/httpd.crt', + :horizon_key => '/etc/pki/tls/private/httpd.key', + :horizon_ca => '/etc/pki/tls/certs/ca.crt', + }) + end + end + + context 'without apache' do + before do + params.merge!({ :configure_apache => false }) + end + + it 'does not configure apache' do + should_not contain_class('horizon::wsgi::apache') + end + end + + context 'with available_regions parameter' do + before do + params.merge!({ + :available_regions => [ + ['http://region-1.example.com:5000/v2.0', 'Region-1'], + ['http://region-2.example.com:5000/v2.0', 'Region-2'] + ] + }) + end + + it 'AVAILABLE_REGIONS is configured' do + verify_contents(subject, platforms_params[:config_file], [ + "AVAILABLE_REGIONS = [", + " ('http://region-1.example.com:5000/v2.0', 'Region-1'),", + " ('http://region-2.example.com:5000/v2.0', 'Region-2'),", + "]" + ]) + end + end + + context 'with policy parameters' do + before do + params.merge!({ + :policy_files_path => '/opt/openstack-dashboard', + :policy_files => { + 'compute' => 'nova_policy.json', + 'identity' => 'keystone_policy.json', + 'network' => 'neutron_policy.json', + } + }) + end + + it 'POLICY_FILES_PATH and POLICY_FILES are configured' do + verify_contents(subject, platforms_params[:config_file], [ + "POLICY_FILES_PATH = '/opt/openstack-dashboard'", + "POLICY_FILES = {", + " 'compute': 'nova_policy.json',", + " 'identity': 'keystone_policy.json',", + " 'network': 'neutron_policy.json',", + "} # POLICY_FILES" + ]) + end + end + + context 'with overriding local_settings_template' do + before do + params.merge!({ + :django_debug => 'True', + :help_url => 'https://docs.openstack.org', + :local_settings_template => fixtures_path + '/override_local_settings.py.erb' + }) + end + + it 'uses the custom local_settings.py template' do + verify_contents(subject, platforms_params[:config_file], [ + '# Custom local_settings.py', + 'DEBUG = True', + "HORIZON_CONFIG = {", + " 'dashboards': ('project', 'admin', 'settings',),", + " 'default_dashboard': 'project',", + " 'user_home': 'openstack_dashboard.views.get_user_home',", + " 'ajax_queue_limit': 10,", + " 'auto_fade_alerts': {", + " 'delay': 3000,", + " 'fade_duration': 1500,", + " 'types': ['alert-success', 'alert-info']", + " },", + " 'help_url': \"https://docs.openstack.org\",", + " 'exceptions': {'recoverable': exceptions.RECOVERABLE,", + " 'not_found': exceptions.NOT_FOUND,", + " 'unauthorized': exceptions.UNAUTHORIZED},", + "}", + ]) + end + end + + context 'with /var/tmp as upload temp dir' do + before do + params.merge!({ + :file_upload_temp_dir => '/var/tmp' + }) + end + + it { should_not contain_file(params[:file_upload_temp_dir]) } + end + end + + context 'on RedHat platforms' do + before do + facts.merge!({ + :osfamily => 'RedHat', + :operatingsystemrelease => '6.0' + }) + end + + let :platforms_params do + { :config_file => '/etc/openstack-dashboard/local_settings', + :package_name => 'openstack-dashboard', + :root_url => '/dashboard' } + end + + it_behaves_like 'horizon' + end + + context 'on Debian platforms' do + before do + facts.merge!({ + :osfamily => 'Debian', + :operatingsystemrelease => '6.0' + }) + end + + let :platforms_params do + { :config_file => '/etc/openstack-dashboard/local_settings.py', + :package_name => 'openstack-dashboard-apache', + :root_url => '/horizon' } + end + + it_behaves_like 'horizon' + end +end diff --git a/3rdparty/modules/horizon/spec/classes/horizon_wsgi_apache_spec.rb b/3rdparty/modules/horizon/spec/classes/horizon_wsgi_apache_spec.rb new file mode 100644 index 000000000..7a7b9ef15 --- /dev/null +++ b/3rdparty/modules/horizon/spec/classes/horizon_wsgi_apache_spec.rb @@ -0,0 +1,230 @@ +require 'spec_helper' + +describe 'horizon::wsgi::apache' do + + let :params do + { :fqdn => '*', + :servername => 'some.host.tld', + :wsgi_processes => '3', + :wsgi_threads => '10', + } + end + + let :pre_condition do + "include apache\n" + + "class { 'horizon': secret_key => 's3cr3t', configure_apache => false }" + end + + let :fixtures_path do + File.expand_path(File.join(__FILE__, '..', '..', 'fixtures')) + end + + let :facts do + { :concat_basedir => '/var/lib/puppet/concat', + :fqdn => 'some.host.tld' + } + end + + shared_examples 'apache for horizon' do + + context 'with default parameters' do + it 'configures apache' do + should contain_class('horizon::params') + should contain_class('apache') + should contain_class('apache::mod::wsgi') + should contain_service('httpd').with_name(platforms_params[:http_service]) + should contain_file(platforms_params[:httpd_config_file]) + should contain_package('horizon').with_ensure('present') + should contain_apache__vhost('horizon_vhost').with( + 'servername' => 'some.host.tld', + 'access_log_file' => 'horizon_access.log', + 'error_log_file' => 'horizon_error.log', + 'priority' => '15', + 'serveraliases' => '*', + 'docroot' => '/var/www/', + 'ssl' => 'false', + 'redirectmatch_status' => 'permanent', + 'redirectmatch_regexp' => '^/$', + 'redirectmatch_dest' => platforms_params[:root_url], + 'wsgi_script_aliases' => { platforms_params[:root_url] => '/usr/share/openstack-dashboard/openstack_dashboard/wsgi/django.wsgi' }, + 'wsgi_process_group' => platforms_params[:wsgi_group], + 'wsgi_daemon_process' => platforms_params[:wsgi_group], + 'wsgi_daemon_process_options' => { 'processes' => params[:wsgi_processes], 'threads' => params[:wsgi_threads], 'user' => platforms_params[:unix_user], 'group' => platforms_params[:unix_group] } + ) + end + end + + context 'with overriden parameters' do + before do + params.merge!({ + :priority => '10', + }) + end + + it 'configures apache' do + should contain_class('horizon::params') + should contain_class('apache') + should contain_class('apache::mod::wsgi') + should contain_service('httpd').with_name(platforms_params[:http_service]) + should contain_file(platforms_params[:httpd_config_file]) + should contain_package('horizon').with_ensure('present') + should contain_apache__vhost('horizon_vhost').with( + 'servername' => 'some.host.tld', + 'access_log_file' => 'horizon_access.log', + 'error_log_file' => 'horizon_error.log', + 'priority' => params[:priority], + 'serveraliases' => '*', + 'docroot' => '/var/www/', + 'ssl' => 'false', + 'redirectmatch_status' => 'permanent', + 'redirectmatch_regexp' => '^/$', + 'redirectmatch_dest' => platforms_params[:root_url], + 'wsgi_script_aliases' => { platforms_params[:root_url] => '/usr/share/openstack-dashboard/openstack_dashboard/wsgi/django.wsgi' }, + 'wsgi_process_group' => platforms_params[:wsgi_group], + 'wsgi_daemon_process' => platforms_params[:wsgi_group], + 'wsgi_daemon_process_options' => { 'processes' => params[:wsgi_processes], 'threads' => params[:wsgi_threads], 'user' => platforms_params[:unix_user], 'group' => platforms_params[:unix_group] } + ) + end + end + + context 'with ssl enabled' do + before do + params.merge!({ + :listen_ssl => true, + :ssl_redirect => true, + :horizon_cert => '/etc/pki/tls/certs/httpd.crt', + :horizon_key => '/etc/pki/tls/private/httpd.key', + :horizon_ca => '/etc/pki/tls/certs/ca.crt', + }) + end + + context 'with required parameters' do + it 'configures apache for SSL' do + should contain_class('apache::mod::ssl') + end + it { should contain_apache__vhost('horizon_ssl_vhost').with( + 'servername' => 'some.host.tld', + 'access_log_file' => 'horizon_ssl_access.log', + 'error_log_file' => 'horizon_ssl_error.log', + 'priority' => '15', + 'serveraliases' => '*', + 'docroot' => '/var/www/', + 'ssl' => 'true', + 'ssl_cert' => '/etc/pki/tls/certs/httpd.crt', + 'ssl_key' => '/etc/pki/tls/private/httpd.key', + 'ssl_ca' => '/etc/pki/tls/certs/ca.crt', + 'redirectmatch_status' => 'permanent', + 'redirectmatch_regexp' => '^/$', + 'redirectmatch_dest' => platforms_params[:root_url], + 'wsgi_process_group' => 'horizon-ssl', + 'wsgi_daemon_process' => 'horizon-ssl', + 'wsgi_script_aliases' => { platforms_params[:root_url] => '/usr/share/openstack-dashboard/openstack_dashboard/wsgi/django.wsgi' } + )} + + it { should contain_apache__vhost('horizon_vhost').with( + 'servername' => 'some.host.tld', + 'access_log_file' => 'horizon_access.log', + 'error_log_file' => 'horizon_error.log', + 'priority' => '15', + 'serveraliases' => '*', + 'docroot' => '/var/www/', + 'ssl' => 'false', + 'redirectmatch_status' => 'permanent', + 'redirectmatch_regexp' => '(.*)', + 'redirectmatch_dest' => 'https://some.host.tld', + 'wsgi_process_group' => platforms_params[:wsgi_group], + 'wsgi_daemon_process' => platforms_params[:wsgi_group], + 'wsgi_script_aliases' => { platforms_params[:root_url] => '/usr/share/openstack-dashboard/openstack_dashboard/wsgi/django.wsgi' } + )} + end + + context 'without required parameters' do + + context 'without horizon_ca parameter' do + before { params.delete(:horizon_ca) } + it_raises 'a Puppet::Error', /The horizon_ca parameter is required when listen_ssl is true/ + end + + context 'without horizon_cert parameter' do + before { params.delete(:horizon_cert) } + it_raises 'a Puppet::Error', /The horizon_cert parameter is required when listen_ssl is true/ + end + + context 'without horizon_key parameter' do + before { params.delete(:horizon_key) } + it_raises 'a Puppet::Error', /The horizon_key parameter is required when listen_ssl is true/ + end + end + + context 'with extra parameters' do + before do + params.merge!({ + :extra_params => { + 'add_listen' => false, + 'docroot' => '/tmp' + }, + }) + end + + it 'configures apache' do + should contain_apache__vhost('horizon_vhost').with( + 'add_listen' => false, + 'docroot' => '/tmp' + ) + end + + end + + + end + end + + context 'on RedHat platforms' do + before do + facts.merge!({ + :osfamily => 'RedHat', + :operatingsystemrelease => '6.0' + }) + end + + let :platforms_params do + { :http_service => 'httpd', + :httpd_config_file => '/etc/httpd/conf.d/openstack-dashboard.conf', + :root_url => '/dashboard', + :apache_user => 'apache', + :apache_group => 'apache', + :wsgi_user => 'dashboard', + :wsgi_group => 'dashboard', + :unix_user => 'apache', + :unix_group => 'apache' } + end + + it_behaves_like 'apache for horizon' + it { + should contain_class('apache::mod::wsgi').with(:wsgi_socket_prefix => '/var/run/wsgi') + } + end + + context 'on Debian platforms' do + before do + facts.merge!({ + :osfamily => 'Debian', + :operatingsystemrelease => '6.0' + }) + end + + let :platforms_params do + { :http_service => 'apache2', + :httpd_config_file => '/etc/apache2/conf-available/openstack-dashboard.conf', + :root_url => '/horizon', + :apache_user => 'www-data', + :apache_group => 'www-data', + :wsgi_user => 'horizon', + :wsgi_group => 'horizon', + :unix_user => 'horizon', + :unix_group => 'horizon' } + end + + it_behaves_like 'apache for horizon' + end +end diff --git a/3rdparty/modules/horizon/spec/fixtures/override_local_settings.py.erb b/3rdparty/modules/horizon/spec/fixtures/override_local_settings.py.erb new file mode 100644 index 000000000..42639652a --- /dev/null +++ b/3rdparty/modules/horizon/spec/fixtures/override_local_settings.py.erb @@ -0,0 +1,18 @@ +# Custom local_settings.py +DEBUG = <%= @django_debug %> + +HORIZON_CONFIG = { + 'dashboards': ('project', 'admin', 'settings',), + 'default_dashboard': 'project', + 'user_home': 'openstack_dashboard.views.get_user_home', + 'ajax_queue_limit': 10, + 'auto_fade_alerts': { + 'delay': 3000, + 'fade_duration': 1500, + 'types': ['alert-success', 'alert-info'] + }, + 'help_url': "<%= @help_url %>", + 'exceptions': {'recoverable': exceptions.RECOVERABLE, + 'not_found': exceptions.NOT_FOUND, + 'unauthorized': exceptions.UNAUTHORIZED}, +} diff --git a/3rdparty/modules/horizon/spec/shared_examples.rb b/3rdparty/modules/horizon/spec/shared_examples.rb new file mode 100644 index 000000000..51e11c0ba --- /dev/null +++ b/3rdparty/modules/horizon/spec/shared_examples.rb @@ -0,0 +1,5 @@ +shared_examples_for "a Puppet::Error" do |description| + it "with message matching #{description.inspect}" do + expect { subject }.to raise_error(Puppet::Error, description) + end +end diff --git a/3rdparty/modules/horizon/spec/spec_helper.rb b/3rdparty/modules/horizon/spec/spec_helper.rb new file mode 100644 index 000000000..53d4dd02d --- /dev/null +++ b/3rdparty/modules/horizon/spec/spec_helper.rb @@ -0,0 +1,7 @@ +require 'puppetlabs_spec_helper/module_spec_helper' +require 'shared_examples' + +RSpec.configure do |c| + c.alias_it_should_behave_like_to :it_configures, 'configures' + c.alias_it_should_behave_like_to :it_raises, 'raises' +end diff --git a/3rdparty/modules/horizon/spec/unit/puppet/parser/functions/os_any2array_spec.rb b/3rdparty/modules/horizon/spec/unit/puppet/parser/functions/os_any2array_spec.rb new file mode 100644 index 000000000..dd5bbe2c3 --- /dev/null +++ b/3rdparty/modules/horizon/spec/unit/puppet/parser/functions/os_any2array_spec.rb @@ -0,0 +1,55 @@ +#! /usr/bin/env ruby -S rspec +require 'spec_helper' + +describe "the os_any2array function" do + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it "should exist" do + Puppet::Parser::Functions.function("os_any2array").should == "function_os_any2array" + end + + it "should return an empty array if there is less than 1 argument" do + result = scope.function_os_any2array([]) + result.should(eq([])) + end + + it "should convert boolean true to [ true ] " do + result = scope.function_os_any2array([true]) + result.should(eq([true])) + end + + it "should convert one object to [object]" do + result = scope.function_os_any2array(['one']) + result.should(eq(['one'])) + end + + it "should convert multiple objects to [objects]" do + result = scope.function_os_any2array(['one', 'two']) + result.should(eq(['one', 'two'])) + end + + it "should return empty array it was called with" do + result = scope.function_os_any2array([[]]) + result.should(eq([])) + end + + it "should return one-member array it was called with" do + result = scope.function_os_any2array([['string']]) + result.should(eq(['string'])) + end + + it "should return multi-member array it was called with" do + result = scope.function_os_any2array([['one', 'two']]) + result.should(eq(['one', 'two'])) + end + + it "should return members of a hash it was called with" do + result = scope.function_os_any2array([{ 'key' => 'value' }]) + result.should(eq(['key', 'value'])) + end + + it "should return an empty array if it was called with an empty hash" do + result = scope.function_os_any2array([{ }]) + result.should(eq([])) + end +end diff --git a/3rdparty/modules/horizon/templates/local_settings.py.erb b/3rdparty/modules/horizon/templates/local_settings.py.erb new file mode 100644 index 000000000..eca40cb90 --- /dev/null +++ b/3rdparty/modules/horizon/templates/local_settings.py.erb @@ -0,0 +1,577 @@ +import os + +from django.utils.translation import ugettext_lazy as _ + +from openstack_dashboard import exceptions + +DEBUG = <%= @django_debug.to_s.capitalize %> +TEMPLATE_DEBUG = DEBUG + +# Required for Django 1.5. +# If horizon is running in production (DEBUG is False), set this +# with the list of host/domain names that the application can serve. +# For more information see: +# https://docs.djangoproject.com/en/dev/ref/settings/#allowed-hosts +#ALLOWED_HOSTS = ['horizon.example.com', ] +<% if @final_allowed_hosts.kind_of?(Array) %> +ALLOWED_HOSTS = ['<%= @final_allowed_hosts.join("', '") %>', ] +<% else %> +ALLOWED_HOSTS = ['<%= @final_allowed_hosts %>', ] +<% end %> + +# Set SSL proxy settings: +# For Django 1.4+ pass this header from the proxy after terminating the SSL, +# and don't forget to strip it from the client's request. +# For more information see: +# https://docs.djangoproject.com/en/1.4/ref/settings/#secure-proxy-ssl-header +# SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTOCOL', 'https') + +# If Horizon is being served through SSL, then uncomment the following two +# settings to better secure the cookies from security exploits +<% if @secure_cookies %> +CSRF_COOKIE_SECURE = True +SESSION_COOKIE_SECURE = True +<% else %> +#CSRF_COOKIE_SECURE = True +#SESSION_COOKIE_SECURE = True +<% end %> + +# Overrides for OpenStack API versions. Use this setting to force the +# OpenStack dashboard to use a specfic API version for a given service API. +# NOTE: The version should be formatted as it appears in the URL for the +# service API. For example, The identity service APIs have inconsistent +# use of the decimal point, so valid options would be "2.0" or "3". +# OPENSTACK_API_VERSIONS = { +# "identity": 3 +# } + +# Set this to True if running on multi-domain model. When this is enabled, it +# will require user to enter the Domain name in addition to username for login. +# OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = False + +# Overrides the default domain used when running on single-domain model +# with Keystone V3. All entities will be created in the default domain. +# OPENSTACK_KEYSTONE_DEFAULT_DOMAIN = 'Default' + +# Set Console type: +# valid options would be "AUTO", "VNC" or "SPICE" +# CONSOLE_TYPE = "AUTO" + +# Default OpenStack Dashboard configuration. +HORIZON_CONFIG = { + 'dashboards': ('project', 'admin', 'settings',), + 'default_dashboard': 'project', + 'user_home': 'openstack_dashboard.views.get_user_home', + 'ajax_queue_limit': 10, + 'auto_fade_alerts': { + 'delay': 3000, + 'fade_duration': 1500, + 'types': ['alert-success', 'alert-info'] + }, + 'help_url': "<%= @help_url %>", + 'exceptions': {'recoverable': exceptions.RECOVERABLE, + 'not_found': exceptions.NOT_FOUND, + 'unauthorized': exceptions.UNAUTHORIZED}, +} + +# Specify a regular expression to validate user passwords. +# HORIZON_CONFIG["password_validator"] = { +# "regex": '.*', +# "help_text": _("Your password does not meet the requirements.") +# } + +# Disable simplified floating IP address management for deployments with +# multiple floating IP pools or complex network requirements. +# HORIZON_CONFIG["simple_ip_management"] = False + +# Turn off browser autocompletion for the login form if so desired. +# HORIZON_CONFIG["password_autocomplete"] = "off" + +LOCAL_PATH = os.path.dirname(os.path.abspath(__file__)) + +# Set custom secret key: +# You can either set it to a specific value or you can let horizion generate a +# default secret key that is unique on this machine, e.i. regardless of the +# amount of Python WSGI workers (if used behind Apache+mod_wsgi): However, there +# may be situations where you would want to set this explicitly, e.g. when +# multiple dashboard instances are distributed on different machines (usually +# behind a load-balancer). Either you have to make sure that a session gets all +# requests routed to the same dashboard instance or you set the same SECRET_KEY +# for all of them. +# from horizon.utils import secret_key +# SECRET_KEY = secret_key.generate_or_read_from_file(os.path.join(LOCAL_PATH, '.secret_key_store')) +SECRET_KEY = '<%= @secret_key %>' + +# We recommend you use memcached for development; otherwise after every reload +# of the django development server, you will have to login again. To use +# memcached set CACHES to something like +# CACHES = { +# 'default': { +# 'BACKEND' : 'django.core.cache.backends.memcached.MemcachedCache', +# 'LOCATION' : '127.0.0.1:11211', +# } +#} + +CACHES = { + 'default': { + <% if @cache_server_ip %> +# 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache' + 'BACKEND': 'django.core.cache.backends.memcached.MemcachedCache', + <% if @cache_server_ip.kind_of?(Array) %> + <% split = ":" + @cache_server_port + "','" %> + 'LOCATION': [ <% @cache_server_ip.each do |ip| -%>'<%= ip -%>:<%= @cache_server_port -%>',<% end -%> ], + <% else %> + 'LOCATION': '<%= @cache_server_ip %>:<%= @cache_server_port %>', + <% end %> + <% else %> + 'BACKEND': 'django.core.cache.backends.locmem.LocMemCache' + <% end %> + } +} + +<% if @django_session_engine %> +SESSION_ENGINE = "<%= @django_session_engine %>" +<% end %> + +# Send email to the console by default +EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend' +# Or send them to /dev/null +#EMAIL_BACKEND = 'django.core.mail.backends.dummy.EmailBackend' + +# Configure these for your outgoing email host +# EMAIL_HOST = 'smtp.my-company.com' +# EMAIL_PORT = 25 +# EMAIL_HOST_USER = 'djangomail' +# EMAIL_HOST_PASSWORD = 'top-secret!' + +# For multiple regions uncomment this configuration, and add (endpoint, title). +<% if @available_regions.kind_of?(Array) %> +AVAILABLE_REGIONS = [ +<% @available_regions.each do |r| -%> + ('<%= r[0] -%>', '<%= r[1] -%>'), +<% end -%> +] +<% end -%> + +<% +if (!@keystone_scheme.nil?) || (!@keystone_host.nil?) || (!@keystone_port.nil?) + @keystone_scheme ||= "http" + @keystone_host ||= "127.0.0.1" + @keystone_port ||= "5000" + @keystone_url = "#{@keystone_scheme}://#{@keystone_host}:#{@keystone_port}/v2.0" +end +-%> +OPENSTACK_KEYSTONE_URL = "<%= @keystone_url %>" +OPENSTACK_KEYSTONE_DEFAULT_ROLE = "<%= @keystone_default_role %>" + +# Disable SSL certificate checks (useful for self-signed certificates): +# OPENSTACK_SSL_NO_VERIFY = True + +# The CA certificate to use to verify SSL connections +# OPENSTACK_SSL_CACERT = '/path/to/cacert.pem' + +# The OPENSTACK_KEYSTONE_BACKEND settings can be used to identify the +# capabilities of the auth backend for Keystone. +# If Keystone has been configured to use LDAP as the auth backend then set +# can_edit_user to False and name to 'ldap'. +# +# TODO(tres): Remove these once Keystone has an API to identify auth backend. +OPENSTACK_KEYSTONE_BACKEND = { + 'name': 'native', + 'can_edit_user': True, + 'can_edit_group': True, + 'can_edit_project': True, + 'can_edit_domain': True, + 'can_edit_role': True +} + +# The OPENSTACK_HYPERVISOR_FEATURES settings can be used to enable optional +# services provided by hypervisors. +OPENSTACK_HYPERVISOR_FEATURES = { + <%- @hypervisor_options = @hypervisor_defaults.merge(@hypervisor_options) -%> + 'can_set_mount_point': <%= @hypervisor_options['can_set_mount_point'].to_s.capitalize %>, + 'can_set_password': <%= @hypervisor_options['can_set_password'].to_s.capitalize %>, +} + +# The OPENSTACK_CINDER_FEATURES settings can be used to enable optional +# # services provided by cinder that is not exposed by its extension API. +OPENSTACK_CINDER_FEATURES = { + <%- @cinder_options = @cinder_defaults.merge(@cinder_options) -%> + 'enable_backup': <%= @cinder_options['enable_backup'].to_s.capitalize %>, +} + +# The OPENSTACK_NEUTRON_NETWORK settings can be used to enable optional +# services provided by neutron. Options currenly available are load +# balancer service, security groups, quotas, VPN service. +OPENSTACK_NEUTRON_NETWORK = { + <%- @neutron_options = @neutron_defaults.merge(@neutron_options) -%> + 'enable_lb': <%= @neutron_options['enable_lb'].to_s.capitalize %>, + 'enable_firewall': <%= @neutron_options['enable_firewall'].to_s.capitalize %>, + 'enable_quotas': <%= @neutron_options['enable_quotas'].to_s.capitalize %>, + 'enable_security_group': <%= @neutron_options['enable_security_group'].to_s.capitalize %>, + 'enable_vpn': <%= @neutron_options['enable_vpn'].to_s.capitalize %>, + # The profile_support option is used to detect if an externa lrouter can be + # configured via the dashboard. When using specific plugins the + # profile_support can be turned on if needed. + <%- if @neutron_options['profile_support'] != 'None' -%> + 'profile_support': '<%= @neutron_options['profile_support'] %>', + <%- end -%> + #'profile_support': 'cisco', +} + +# The OPENSTACK_IMAGE_BACKEND settings can be used to customize features +# in the OpenStack Dashboard related to the Image service, such as the list +# of supported image formats. +# OPENSTACK_IMAGE_BACKEND = { +# 'image_formats': [ +# ('', ''), +# ('aki', _('AKI - Amazon Kernel Image')), +# ('ami', _('AMI - Amazon Machine Image')), +# ('ari', _('ARI - Amazon Ramdisk Image')), +# ('iso', _('ISO - Optical Disk Image')), +# ('qcow2', _('QCOW2 - QEMU Emulator')), +# ('raw', _('Raw')), +# ('vdi', _('VDI')), +# ('vhd', _('VHD')), +# ('vmdk', _('VMDK')) +# ] +# } + +# OPENSTACK_ENDPOINT_TYPE specifies the endpoint type to use for the endpoints +# in the Keystone service catalog. Use this setting when Horizon is running +# external to the OpenStack environment. The default is 'publicURL'. +#OPENSTACK_ENDPOINT_TYPE = "publicURL" +<% if @openstack_endpoint_type %> +OPENSTACK_ENDPOINT_TYPE = "<%= @openstack_endpoint_type %>" +<% end %> + +# SECONDARY_ENDPOINT_TYPE specifies the fallback endpoint type to use in the +# case that OPENSTACK_ENDPOINT_TYPE is not present in the endpoints +# in the Keystone service catalog. Use this setting when Horizon is running +# external to the OpenStack environment. The default is None. This +# value should differ from OPENSTACK_ENDPOINT_TYPE if used. +#SECONDARY_ENDPOINT_TYPE = "publicURL" +<% if @secondary_endpoint_type %> +SECONDARY_ENDPOINT_TYPE = "<%= @secondary_endpoint_type %>" +<% end %> + +# The number of objects (Swift containers/objects or images) to display +# on a single page before providing a paging element (a "more" link) +# to paginate results. +API_RESULT_LIMIT = <%= @api_result_limit %> +API_RESULT_PAGE_SIZE = 20 + +# The timezone of the server. This should correspond with the timezone +# of your entire OpenStack installation, and hopefully be in UTC. +TIME_ZONE = "UTC" + +# If you have external monitoring links, eg: +<% if @horizon_app_links %> +EXTERNAL_MONITORING = <%= @horizon_app_links %> +<% end %> + +# When launching an instance, the menu of available flavors is +# sorted by RAM usage, ascending. Provide a callback method here +# (and/or a flag for reverse sort) for the sorted() method if you'd +# like a different behaviour. For more info, see +# http://docs.python.org/2/library/functions.html#sorted +# CREATE_INSTANCE_FLAVOR_SORT = { +# 'key': my_awesome_callback_method, +# 'reverse': False, +# } + +# The Horizon Policy Enforcement engine uses these values to load per service +# policy rule files. The content of these files should match the files the +# OpenStack services are using to determine role based access control in the +# target installation. + +# Path to directory containing policy.json files +<% if !(@policy_files_path.nil?) %> +POLICY_FILES_PATH = '<%= @policy_files_path %>' +<% elsif @osfamily == 'RedHat' %> +POLICY_FILES_PATH = '/etc/openstack-dashboard' +<% else %> +#POLICY_FILES_PATH = os.path.join(ROOT_PATH, "conf") +<% end -%> + +# Map of local copy of service policy files +<% if @policy_files.kind_of?(Hash) %> +POLICY_FILES = { +<% @policy_files.sort.each do |service_name,filename| -%> + '<%= service_name -%>': '<%= filename -%>', +<% end -%> +} # POLICY_FILES +<% else -%> +#POLICY_FILES = { +# 'identity': 'keystone_policy.json', +# 'compute': 'nova_policy.json' +#} +<% end -%> + +# Trove user and database extension support. By default support for +# creating users and databases on database instances is turned on. +# To disable these extensions set the permission here to something +# unusable such as ["!"]. +# TROVE_ADD_USER_PERMS = [] +# TROVE_ADD_DATABASE_PERMS = [] + +LOGGING = { + 'version': 1, + # When set to True this will disable all logging except + # for loggers specified in this configuration dictionary. Note that + # if nothing is specified here and disable_existing_loggers is True, + # django.db.backends will still log unless it is disabled explicitly. + 'disable_existing_loggers': False, + 'formatters': { + 'verbose': { + 'format': '%(asctime)s %(process)d %(levelname)s %(name)s ' + '%(message)s' + }, + }, + 'handlers': { + 'null': { + 'level': 'DEBUG', + 'class': 'django.utils.log.NullHandler', + }, + 'console': { + # Set the level to "DEBUG" for verbose output logging. + 'level': 'INFO', + 'class': 'logging.StreamHandler', + }, + 'file': { + 'level': '<%= @log_level %>', + 'class': 'logging.FileHandler', + 'filename': '<%= scope.lookupvar("horizon::params::logdir") %>/horizon.log', + 'formatter': 'verbose', + }, + }, + 'loggers': { + # Logging from django.db.backends is VERY verbose, send to null + # by default. + 'django.db.backends': { + 'handlers': ['null'], + 'propagate': False, + }, + 'requests': { + 'handlers': ['null'], + 'propagate': False, + }, + 'horizon': { + # 'handlers': ['console'], + 'handlers': ['file'], + # 'level': 'DEBUG', + 'level': '<%= @log_level %>', + 'propagate': False, + }, + 'openstack_dashboard': { + # 'handlers': ['console'], + 'handlers': ['file'], + # 'level': 'DEBUG', + 'level': '<%= @log_level %>', + 'propagate': False, + }, + 'novaclient': { + # 'handlers': ['console'], + 'handlers': ['file'], + # 'level': 'DEBUG', + 'level': '<%= @log_level %>', + 'propagate': False, + }, + 'cinderclient': { + # 'handlers': ['console'], + 'handlers': ['file'], + # 'level': 'DEBUG', + 'level': '<%= @log_level %>', + 'propagate': False, + }, + 'keystoneclient': { + # 'handlers': ['console'], + 'handlers': ['file'], + # 'level': 'DEBUG', + 'level': '<%= @log_level %>', + 'propagate': False, + }, + 'glanceclient': { + # 'handlers': ['console'], + 'handlers': ['file'], + # 'level': 'DEBUG', + 'level': '<%= @log_level %>', + 'propagate': False, + }, + 'neutronclient': { + # 'handlers': ['console'], + 'handlers': ['file'], + # 'level': 'DEBUG', + 'level': '<%= @log_level %>', + 'propagate': False, + }, + 'heatclient': { + # 'handlers': ['console'], + 'handlers': ['file'], + # 'level': 'DEBUG', + 'level': '<%= @log_level %>', + 'propagate': False, + }, + 'ceilometerclient': { + # 'handlers': ['console'], + 'handlers': ['file'], + # 'level': 'DEBUG', + 'level': '<%= @log_level %>', + 'propagate': False, + }, + 'troveclient': { + # 'handlers': ['console'], + 'handlers': ['file'], + # 'level': 'DEBUG', + 'level': '<%= @log_level %>', + 'propagate': False, + }, + 'swiftclient': { + # 'handlers': ['console'], + 'handlers': ['file'], + # 'level': 'DEBUG', + 'level': '<%= @log_level %>', + 'propagate': False, + }, + 'openstack_auth': { + # 'handlers': ['console'], + 'handlers': ['file'], + # 'level': 'DEBUG', + 'level': '<%= @log_level %>', + 'propagate': False, + }, + 'nose.plugins.manager': { + # 'handlers': ['console'], + 'handlers': ['file'], + # 'level': 'DEBUG', + 'level': '<%= @log_level %>', + 'propagate': False, + }, + 'django': { + # 'handlers': ['console'], + 'handlers': ['file'], + # 'level': 'DEBUG', + 'level': '<%= @log_level %>', + 'propagate': False, + }, + } +} + +SECURITY_GROUP_RULES = { + 'all_tcp': { + 'name': 'ALL TCP', + 'ip_protocol': 'tcp', + 'from_port': '1', + 'to_port': '65535', + }, + 'all_udp': { + 'name': 'ALL UDP', + 'ip_protocol': 'udp', + 'from_port': '1', + 'to_port': '65535', + }, + 'all_icmp': { + 'name': 'ALL ICMP', + 'ip_protocol': 'icmp', + 'from_port': '-1', + 'to_port': '-1', + }, + 'ssh': { + 'name': 'SSH', + 'ip_protocol': 'tcp', + 'from_port': '22', + 'to_port': '22', + }, + 'smtp': { + 'name': 'SMTP', + 'ip_protocol': 'tcp', + 'from_port': '25', + 'to_port': '25', + }, + 'dns': { + 'name': 'DNS', + 'ip_protocol': 'tcp', + 'from_port': '53', + 'to_port': '53', + }, + 'http': { + 'name': 'HTTP', + 'ip_protocol': 'tcp', + 'from_port': '80', + 'to_port': '80', + }, + 'pop3': { + 'name': 'POP3', + 'ip_protocol': 'tcp', + 'from_port': '110', + 'to_port': '110', + }, + 'imap': { + 'name': 'IMAP', + 'ip_protocol': 'tcp', + 'from_port': '143', + 'to_port': '143', + }, + 'ldap': { + 'name': 'LDAP', + 'ip_protocol': 'tcp', + 'from_port': '389', + 'to_port': '389', + }, + 'https': { + 'name': 'HTTPS', + 'ip_protocol': 'tcp', + 'from_port': '443', + 'to_port': '443', + }, + 'smtps': { + 'name': 'SMTPS', + 'ip_protocol': 'tcp', + 'from_port': '465', + 'to_port': '465', + }, + 'imaps': { + 'name': 'IMAPS', + 'ip_protocol': 'tcp', + 'from_port': '993', + 'to_port': '993', + }, + 'pop3s': { + 'name': 'POP3S', + 'ip_protocol': 'tcp', + 'from_port': '995', + 'to_port': '995', + }, + 'ms_sql': { + 'name': 'MS SQL', + 'ip_protocol': 'tcp', + 'from_port': '1433', + 'to_port': '1433', + }, + 'mysql': { + 'name': 'MYSQL', + 'ip_protocol': 'tcp', + 'from_port': '3306', + 'to_port': '3306', + }, + 'rdp': { + 'name': 'RDP', + 'ip_protocol': 'tcp', + 'from_port': '3389', + 'to_port': '3389', + }, +} + +LOGIN_URL = '<%= scope.lookupvar("horizon::params::root_url") %>/auth/login/' +LOGOUT_URL = '<%= scope.lookupvar("horizon::params::root_url") %>/auth/logout/' +LOGIN_REDIRECT_URL = '<%= scope.lookupvar("horizon::params::root_url") %>' + +# The Ubuntu package includes pre-compressed JS and compiled CSS to allow +# offline compression by default. To enable online compression, install +# the python-lesscpy package and disable the following option. +COMPRESS_OFFLINE = <%= @compress_offline.to_s.capitalize %> + +# For Glance image upload, Horizon uses the file upload support from Django +# so we add this option to change the directory where uploaded files are temporarily +# stored until they are loaded into Glance. +FILE_UPLOAD_TEMP_DIR = '<%= @file_upload_temp_dir %>' diff --git a/3rdparty/modules/keystone/Gemfile b/3rdparty/modules/keystone/Gemfile new file mode 100644 index 000000000..e757d38fa --- /dev/null +++ b/3rdparty/modules/keystone/Gemfile @@ -0,0 +1,17 @@ +source 'https://rubygems.org' + +group :development, :test do + gem 'puppetlabs_spec_helper', :require => false + gem 'puppet-lint', '~> 0.3.2' + gem 'metadata-json-lint' + gem 'rspec-puppet', '~> 1.0.1' + gem 'rake', '10.1.1' +end + +if puppetversion = ENV['PUPPET_GEM_VERSION'] + gem 'puppet', puppetversion, :require => false +else + gem 'puppet', :require => false +end + +# vim:ft=ruby diff --git a/3rdparty/modules/keystone/LICENSE b/3rdparty/modules/keystone/LICENSE new file mode 100644 index 000000000..0bc44c17d --- /dev/null +++ b/3rdparty/modules/keystone/LICENSE @@ -0,0 +1,17 @@ +Puppet Labs Keystone Module - Puppet module for managing Keystone + +Copyright (C) 2012 Puppet Labs Inc + +Puppet Labs can be contacted at: info@puppetlabs.com + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/3rdparty/modules/keystone/README.md b/3rdparty/modules/keystone/README.md new file mode 100644 index 000000000..2f5b15553 --- /dev/null +++ b/3rdparty/modules/keystone/README.md @@ -0,0 +1,307 @@ +keystone +======= + +5.1.0 - 2014.2 - Juno + +#### Table of Contents + +1. [Overview - What is the keystone module?](#overview) +2. [Module Description - What does the module do?](#module-description) +3. [Setup - The basics of getting started with keystone](#setup) +4. [Implementation - An under-the-hood peek at what the module is doing](#implementation) +5. [Limitations - OS compatibility, etc.](#limitations) +6. [Development - Guide for contributing to the module](#development) +7. [Contributors - Those with commits](#contributors) +8. [Release Notes - Notes on the most recent updates to the module](#release-notes) + +Overview +-------- + +The keystone module is a part of [Stackforge](https://github.com/stackfoge), an effort by the Openstack infrastructure team to provide continuous integration testing and code review for Openstack and Openstack community projects not part of the core software. The module its self is used to flexibly configure and manage the identify service for Openstack. + +Module Description +------------------ + +The keystone module is a thorough attempt to make Puppet capable of managing the entirety of keystone. This includes manifests to provision region specific endpoint and database connections. Types are shipped as part of the keystone module to assist in manipulation of configuration files. + +This module is tested in combination with other modules needed to build and leverage an entire Openstack software stack. These modules can be found, all pulled together in the [openstack module](https://github.com/stackfoge/puppet-openstack). + +Setup +----- + +**What the keystone module affects** + +* keystone, the identify service for Openstack. + +### Installing keystone + + example% puppet module install puppetlabs/keystone + +### Beginning with keystone + +To utilize the keystone module's functionality you will need to declare multiple resources. The following is a modified excerpt from the [openstack module](https://github.com/stackfoge/puppet-openstack). This is not an exhaustive list of all the components needed, we recommend you consult and understand the [openstack module](https://github.com/stackforge/puppet-openstack) and the [core openstack](http://docs.openstack.org) documentation. + +**Define a keystone node** + +```puppet +class { 'keystone': + verbose => True, + catalog_type => 'sql', + admin_token => 'random_uuid', + sql_connection => 'mysql://keystone_admin:super_secret_db_password@openstack-controller.example.com/keystone', +} + +# Adds the admin credential to keystone. +class { 'keystone::roles::admin': + email => 'admin@example.com', + password => 'super_secret', +} + +# Installs the service user endpoint. +class { 'keystone::endpoint': + public_address => '10.16.0.101', + admin_address => '10.16.1.101', + internal_address => '10.16.2.101', + region => 'example-1', +} +``` + +**Leveraging the Native Types** + +Keystone ships with a collection of native types that can be used to interact with the data stored in keystone. The following, related to user management could live throughout your Puppet code base. They even support puppet's ability to introspect the current environment much the same as `puppet resource user`, `puppet resouce keystone_tenant` will print out all the currently stored tenants and their parameters. + +```puppet +keystone_tenant { 'openstack': + ensure => present, + enabled => True, +} +keystone_user { 'openstack': + ensure => present, + enabled => True, +} +keystone_role { 'admin': + ensure => present, +} +keystone_user_role { 'admin@openstack': + roles => ['admin', 'superawesomedude'], + ensure => present +} +``` + +These two will seldom be used outside openstack related classes, like nova or cinder. These are modified examples form Class['nova::keystone::auth']. + +```puppet +# Setup the nova keystone service +keystone_service { 'nova': + ensure => present, + type => 'compute', + description => 'Openstack Compute Service', +} + +# Setup nova keystone endpoint +keystone_endpoint { 'example-1-west/nova': + ensure => present, + public_url => "http://127.0.0.1:8774/v2/%(tenant_id)s", + admin_url => "http://127.0.0.1:8774/v2/%(tenant_id)s", + internal_url => "http://127.0.0.1:8774/v2/%(tenant_id)s", +} +``` + +**Setting up a database for keystone** + +A keystone database can be configured separately from the keystone services. + +If one needs to actually install a fresh database they have the choice of mysql or postgres. Use the mysql::server or postgreql::server classes to do this setup then the Class['keystone::db::mysql'] or Class['keystone::db::postgresql'] for adding the needed databases and users that will be needed by keystone. + +* For mysql + +```puppet +class { 'mysql::server': } + +class { 'keystone::db::mysql': + password => 'super_secret_db_password', + allowed_hosts => '%', +} +``` + +* For postgresql + +```puppet +class { 'postgresql::server': } + +class { 'keystone::db::postgresql': password => 'super_secret_db_password', } +``` + +Implementation +-------------- + +### keystone + +keystone is a combination of Puppet manifest and ruby code to delivery configuration and extra functionality through types and providers. + +Limitations +------------ + +* All the keystone types use the CLI tools and so need to be ran on the keystone node. + +### Upgrade warning + +* If you've setup Openstack using previous versions of this module you need to be aware that it used UUID as the dedault to the token_format parameter but now defaults to PKI. If you're using this module to manage a Grizzly Openstack deployment that was set up using a development release of the modules or are attempting an upgrade from Folsom then you'll need to make sure you set the token_format to UUID at classification time. + +Development +----------- + +Developer documentation for the entire puppet-openstack project. + +* https://wiki.openstack.org/wiki/Puppet-openstack#Developer_documentation + +Contributors +------------ + +* https://github.com/stackforge/puppet-keystone/graphs/contributors + +Release Notes +------------- + +**5.1.0** + +* Allow disabling or delaying the token_flush cron +* crontab: ensure the script is run with shell +* Use openstackclient for keystone_* providers +* Add lib directories to $LOAD_PATH if not present +* Remove keystone.rb provider for keystone_endpoint +* Add timeout to API requests +* Test keystone_user password with Net::HTTP +* service_identity: add user/role ordering +* Fix password check for SSL endpoints +* add require json for to_json dependency +* spec: pin rspec-puppet to 1.0.1 +* Switch to TLSv1 +* handle missing project/tenant when using ldap backend +* Add support for LDAP connection pools +* Sync keystone.py with upstream to function with Juno +* Create resource cache upon creation +* Implement caching lookup for keystone_user_role +* Remove warnings from openstack responses +* Properly handle embedded newlines in csv +* support the ldap user_enabled_invert parameter +* Shorten HTTP request timeout length +* Tag packages with 'openstack' +* Allow Keystone to be queried when using IPv6 ::0 +* Add ::keystone::policy class for policy management +* New option replace_password for keystone_user +* Pin puppetlabs-concat to 1.2.1 in fixtures +* Set WSGI process display-name +* Rename resource instance variable +* Add native types for keystone paste configuration +* Update .gitreview file for project rename + +**5.0.0** + +* Stable Juno release +* Updated token driver, logging, and ldap config parameters for Juno +* Changed admin_roles parameter to accept an array in order to configure multiple admin roles +* Installs python-ldappool package for ldap +* Added new parameters to keystone class to configure pki signing +* Changed keystone class to inherit from keystone::params +* Changed pki_setup to run regardless of token provider +* Made UUID the default token provider +* Made keystone_user_role idempotent +* Added parameters to control whether to configure users +* Stopped managing _member_ role since it is created automatically +* Stopped overriding token_flush log file +* Changed the usage of admin_endpoint to not include the API version +* Allowed keystone_user_role to accept email as username +* Added ability to set up keystone using Apache mod_wsgi +* Migrated the keystone::db::mysql class to use openstacklib::db::mysql and deprecated the mysql_module parameter +* Installs python-memcache when using token driver memcache +* Enabled setting cert and key paths for PKI token signing +* Added parameters for SSL communication between keystone and rabbitmq +* Added parameter ignore_default_tenant to keystone::role::admin +* Added parameter service_provider to keystone class +* Added parameters for service validation to keystone class + +**4.2.0** + +* Added class for extended logging options +* Fixed rabbit password leaking +* Added parameters to set tenant descriptions +* Fixed keystone user authorization error handling + +**4.1.0** + +* Added token flushing with cron. +* Updated database api for consistency with other projects. +* Fixed admin_token with secret parameter. +* Fixed deprecated catalog driver. + +**4.0.0** + +* Stable Icehouse release. +* Added template_file parameter to specify catalog. +* Added keystone::config to handle additional custom options. +* Added notification parameters. +* Added support for puppetlabs-mysql 2.2 and greater. +* Fixed deprecated sql section header in keystone.conf. +* Fixed deprecated bind_host parameter. +* Fixed example for native type keystone_service. +* Fixed LDAP module bugs. +* Fixed variable for host_access dependency. +* Reduced default token duration to one hour. + +**3.2.0** + +* Added ability to configure any catalog driver. +* Ensures log_file is absent when using syslog. + +**3.1.1** + +* Fixed inconsistent variable for mysql allowed hosts. + +**3.1.0** + +* Added ability to disable pki_setup. +* Load tenant un-lazily if needed. +* Add log_dir param, with option to disable. +* Updated endpoint argument. +* Added support to enable SSL. +* Removes setting of Keystone endpoint by default. +* Relaxed regex when keystone refuses connections. + +**3.0.0** + +* Major release for OpenStack Havana. +* Fixed duplicated keystone endpoints. +* Refactored keystone_endpoint to use prefetch and flush paradigm. +* Switched from signing/format to token/provider. +* Created memcache_servers option to allow for multiple cache servers. +* Enabled serving Keystone from Apache mod_wsgi. +* Moved db_sync to its own class. +* Removed creation of Member role. +* Improved performance of Keystone providers. +* Updated endpoints to support paths and ssl. +* Added support for token expiration parameter. + +**2.2.0** + +* Optimized tenant and user queries. +* Added syslog support. +* Added support for token driver backend. +* Various bug and lint fixes. + +**2.1.0** + +* Tracks release of puppet-quantum +* Fixed allowed_hosts contitional statement +* Pinned depedencies +* Select keystone endpoint based on SSL setting +* Improved tenant_hash usage in keystone_tenant +* Various cleanup and bug fixes. + +**2.0.0** + +* Upstream is now part of stackfoge. +* keystone_user can be used to change passwords. +* service tenant name now configurable. +* keystone_user is now idempotent. +* Various cleanups and bug fixes. diff --git a/3rdparty/modules/keystone/Rakefile b/3rdparty/modules/keystone/Rakefile new file mode 100644 index 000000000..b07ed10b2 --- /dev/null +++ b/3rdparty/modules/keystone/Rakefile @@ -0,0 +1,7 @@ +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' + +PuppetLint.configuration.fail_on_warnings = true +PuppetLint.configuration.send('disable_80chars') +PuppetLint.configuration.send('disable_class_inherits_from_params_class') +PuppetLint.configuration.send('disable_class_parameter_defaults') diff --git a/3rdparty/modules/keystone/checksums.json b/3rdparty/modules/keystone/checksums.json new file mode 100644 index 000000000..7f46630a8 --- /dev/null +++ b/3rdparty/modules/keystone/checksums.json @@ -0,0 +1,80 @@ +{ + "Gemfile": "bda594bd6e3cc9ee1db4c29e55220505", + "LICENSE": "88c9def20bf88cdd1cf474cfb53f16ab", + "README.md": "d150d6dc30f3dd54b319317b681e1e14", + "Rakefile": "68e2a46cd546eeb34bab6dc1512b549d", + "examples/apache_dropin.pp": "c40c6fe26b4211c85fe2c55926d10bb2", + "examples/apache_with_paths.pp": "3113e40e01bb70b391b52b7e17509678", + "examples/ldap_full.pp": "284fd9fd95fc7091b924177a4e3f5c76", + "examples/ldap_identity.pp": "63f00b0a413163542e348d96a87c9f68", + "ext/keystone_test.rb": "d403c8c80616f94d0cac9ff12c327b9a", + "files/httpd/keystone.py": "a359685b85254d738c13b167c7e84e6b", + "lib/puppet/provider/keystone.rb": "c754d86f1ef111030c17b3690c063a6c", + "lib/puppet/provider/keystone_config/ini_setting.rb": "b3c3813be1c155f49fedf0a1178fe905", + "lib/puppet/provider/keystone_endpoint/openstack.rb": "1864e99269b8f707cb16dbf501bc5587", + "lib/puppet/provider/keystone_paste_ini/ini_setting.rb": "df7e671676104f090a07942f774844e3", + "lib/puppet/provider/keystone_role/openstack.rb": "54d3dda0ac3427bd1180df9190a5166f", + "lib/puppet/provider/keystone_service/openstack.rb": "279e16db49cf59734ef98ce6cbf581f8", + "lib/puppet/provider/keystone_tenant/openstack.rb": "9f443449581c23e54cd5bf0b1d62172a", + "lib/puppet/provider/keystone_user/openstack.rb": "032358692dae948d29d9464c97793f78", + "lib/puppet/provider/keystone_user_role/openstack.rb": "a9a3ba9b455c7cb6d630d7b6235ebd14", + "lib/puppet/provider/openstack.rb": "86e27a181394e3e8630c5a3934ba320b", + "lib/puppet/type/keystone_config.rb": "01069a89da581af00fed130fc373c2c3", + "lib/puppet/type/keystone_endpoint.rb": "78ee04053d0e8362b3d57eecd4dbb020", + "lib/puppet/type/keystone_paste_ini.rb": "5429630bad1a33ab3f14b45f403ed2af", + "lib/puppet/type/keystone_role.rb": "31a7dc4bdf4179b19f01021d03327e93", + "lib/puppet/type/keystone_service.rb": "f1ceb0d168964a4211fed962cf0ff156", + "lib/puppet/type/keystone_tenant.rb": "a7c8b678ceec538cdc22d6dfc9861e13", + "lib/puppet/type/keystone_user.rb": "f0ba9956b6631a7ae07b763fa2c9479c", + "lib/puppet/type/keystone_user_role.rb": "01e72389db896e4cf4a3ed8b15fb771c", + "lib/puppet/util/openstack.rb": "34cea508fb3cbd0cf2ac426004842c21", + "manifests/client.pp": "519836300977db1d5476112864d4782c", + "manifests/config.pp": "5e27a3b503cd4931e410a2d41d89fda1", + "manifests/cron/token_flush.pp": "4f2ce0209fbb9696eda2758ef84c18d2", + "manifests/db/mysql.pp": "c3cb8dc2e1e61392f00f0dc54ee0bc1b", + "manifests/db/postgresql.pp": "18cea325841979f63426633794157254", + "manifests/db/sync.pp": "3caf7ccd37b6f62714bf3b77d0dbf0f9", + "manifests/dev/install.pp": "49ce7909a859d2424cf1fbe5404eab0c", + "manifests/endpoint.pp": "da60281981160a38c5e3ca8bc744dca7", + "manifests/init.pp": "f9e76044c913474134eb7f58c60a7e7d", + "manifests/ldap.pp": "c49c737867f03d49f3fdff6ac46e9c51", + "manifests/logging.pp": "5774990dea77d17dfceaad4a8777824c", + "manifests/params.pp": "b2cbc2011a21fa630022a36d2975f946", + "manifests/policy.pp": "c8a8998316ea42f611a1c7ae6a563461", + "manifests/python.pp": "036cd9a1f400a6a150a1967dcb6f1427", + "manifests/resource/service_identity.pp": "cd6a8d9c451c6310c840149d50decf79", + "manifests/roles/admin.pp": "45b2a2826ff205a28ba30f7c63b0cf45", + "manifests/service.pp": "bae5e366e100ea38d9fd5c1885b0cf3b", + "manifests/wsgi/apache.pp": "b4215a0b8a59d4c39919b6f893820c97", + "metadata.json": "0995a4802848cf7cb6a90293f45aa3a5", + "spec/classes/keystone_client_spec.rb": "85457ed6327e795237afca58be906da6", + "spec/classes/keystone_cron_token_flush_spec.rb": "4648a3bba9210d5b7d51b9a6c8fff586", + "spec/classes/keystone_db_mysql_spec.rb": "6cb71468e5610210be2955305938dcfe", + "spec/classes/keystone_db_postgresql_spec.rb": "88f188cea91bd3bc7c46ecc7033e62df", + "spec/classes/keystone_endpoint_spec.rb": "581f77946576aaebce9df3b4dad6800e", + "spec/classes/keystone_ldap_spec.rb": "c25daffe970799d8619aa690c4c396bb", + "spec/classes/keystone_logging_spec.rb": "fe193b49405672cbf75e41b140d3f9b9", + "spec/classes/keystone_policy_spec.rb": "24dfcbd1e807015214c31d9e4a313619", + "spec/classes/keystone_python_spec.rb": "84f15d4d969b2cb7ab2d770d7ab0278f", + "spec/classes/keystone_roles_admin_spec.rb": "6b11c426e9dd91c7b766ef8c707ca129", + "spec/classes/keystone_service_spec.rb": "688f35435c12152a021ae39020296186", + "spec/classes/keystone_spec.rb": "14dfbd437ce31988a43332752b586c91", + "spec/classes/keystone_wsgi_apache_spec.rb": "5af4f3b9ee305f99df34753db9aa8fe1", + "spec/defines/keystone_resource_service_identity_spec.rb": "485bd7d1a7d189d88d4b86f5d50df8d0", + "spec/shared_examples.rb": "172c63c57efca8c741f297494ed9ef0f", + "spec/spec.opts": "a600ded995d948e393fbe2320ba8e51c", + "spec/spec_helper.rb": "c6521798536b607695fa32a60c8466aa", + "spec/unit/provider/keystone_endpoint/openstack_spec.rb": "8417a7da443c4cfe7c779536c07a2972", + "spec/unit/provider/keystone_paste_ini/ini_setting_spec.rb": "8b583280cfc7c67d64a2dfd8caa7a130", + "spec/unit/provider/keystone_role/openstack_spec.rb": "3dabd6528075e0f4496b10f4faf769b5", + "spec/unit/provider/keystone_service/openstack_spec.rb": "1badc29e61628e320509ce86e076e641", + "spec/unit/provider/keystone_spec.rb": "3eaa3720884b2c3096102b1cb37334cb", + "spec/unit/provider/keystone_tenant/openstack_spec.rb": "63ac277a61271577ecbcd5c729868cf2", + "spec/unit/provider/keystone_user/openstack_spec.rb": "0c68dda06669b26d9d1285196cfed0ec", + "spec/unit/provider/keystone_user_role/openstack_spec.rb": "d78aab324756f7183997b2f8300e9309", + "spec/unit/provider/openstack_spec.rb": "f06998179568513c4b83d19212d6427b", + "spec/unit/type/keystone_endpoint_spec.rb": "5dbd0b540a452bae36218b2a8794a41e", + "spec/unit/type/keystone_paste_ini_spec.rb": "9037113f96850d5567e9dc7c540915ae", + "spec/unit/type/keystone_user_role_spec.rb": "a03cfa9f55028d6a7f2a351582c1a93d", + "tests/site.pp": "0b2eb2ec36b10520aad1517b9a116e50" +} \ No newline at end of file diff --git a/3rdparty/modules/keystone/examples/apache_dropin.pp b/3rdparty/modules/keystone/examples/apache_dropin.pp new file mode 100644 index 000000000..310f0a3fd --- /dev/null +++ b/3rdparty/modules/keystone/examples/apache_dropin.pp @@ -0,0 +1,49 @@ +# Example using apache to serve keystone +# +# To be sure everything is working, run: +# $ export OS_USERNAME=admin +# $ export OS_PASSWORD=ChangeMe +# $ export OS_TENANT_NAME=openstack +# $ export OS_AUTH_URL=http://keystone.local/keystone/main/v2.0 +# $ keystone catalog +# Service: identity +# +-------------+----------------------------------------------+ +# | Property | Value | +# +-------------+----------------------------------------------+ +# | adminURL | http://keystone.local:80/keystone/admin/v2.0 | +# | id | 4f0f55f6789d4c73a53c51f991559b72 | +# | internalURL | http://keystone.local:80/keystone/main/v2.0 | +# | publicURL | http://keystone.local:80/keystone/main/v2.0 | +# | region | RegionOne | +# +-------------+----------------------------------------------+ +# + +Exec { logoutput => 'on_failure' } + +class { 'mysql::server': } +class { 'keystone::db::mysql': + password => 'keystone', +} +class { 'keystone': + verbose => true, + debug => true, + sql_connection => 'mysql://keystone:keystone@127.0.0.1/keystone', + catalog_type => 'sql', + admin_token => 'admin_token', + enabled => false, +} +class { 'keystone::roles::admin': + email => 'test@puppetlabs.com', + password => 'ChangeMe', +} +class { 'keystone::endpoint': + public_url => "https://${::fqdn}:5000/", + admin_url => "https://${::fqdn}:35357/", +} + +keystone_config { 'ssl/enable': value => true } + +include apache +class { 'keystone::wsgi::apache': + ssl => true +} diff --git a/3rdparty/modules/keystone/examples/apache_with_paths.pp b/3rdparty/modules/keystone/examples/apache_with_paths.pp new file mode 100644 index 000000000..be28d395b --- /dev/null +++ b/3rdparty/modules/keystone/examples/apache_with_paths.pp @@ -0,0 +1,54 @@ +# Example using apache to serve keystone +# +# To be sure everything is working, run: +# $ export OS_USERNAME=admin +# $ export OS_PASSWORD=ChangeMe +# $ export OS_TENANT_NAME=openstack +# $ export OS_AUTH_URL=http://keystone.local/keystone/main/v2.0 +# $ keystone catalog +# Service: identity +# +-------------+----------------------------------------------+ +# | Property | Value | +# +-------------+----------------------------------------------+ +# | adminURL | http://keystone.local:80/keystone/admin/v2.0 | +# | id | 4f0f55f6789d4c73a53c51f991559b72 | +# | internalURL | http://keystone.local:80/keystone/main/v2.0 | +# | publicURL | http://keystone.local:80/keystone/main/v2.0 | +# | region | RegionOne | +# +-------------+----------------------------------------------+ +# + +Exec { logoutput => 'on_failure' } + +class { 'mysql::server': } +class { 'keystone::db::mysql': + password => 'keystone', +} +class { 'keystone': + verbose => true, + debug => true, + sql_connection => 'mysql://keystone_admin:keystone@127.0.0.1/keystone', + catalog_type => 'sql', + admin_token => 'admin_token', + enabled => true, +} +class { 'keystone::cron::token_flush': } +class { 'keystone::roles::admin': + email => 'test@puppetlabs.com', + password => 'ChangeMe', +} +class { 'keystone::endpoint': + public_url => "https://${::fqdn}:443/main/", + admin_address => "https://${::fqdn}:443/admin/", +} + +keystone_config { 'ssl/enable': ensure => absent } + +include apache +class { 'keystone::wsgi::apache': + ssl => true, + public_port => 443, + admin_port => 443, + public_path => '/main/', + admin_path => '/admin/' +} diff --git a/3rdparty/modules/keystone/examples/ldap_full.pp b/3rdparty/modules/keystone/examples/ldap_full.pp new file mode 100644 index 000000000..bc455690f --- /dev/null +++ b/3rdparty/modules/keystone/examples/ldap_full.pp @@ -0,0 +1,72 @@ +# A full example from a real deployment that allows Keystone to modify +# everything except users, uses enabled_emulation, and ldaps + +# Ensure this matches what is in LDAP or keystone will try to recreate +# the admin user +class { 'keystone::roles::admin': + email => 'test@example.com', + password => 'ChangeMe', +} + +# You can test this connection with ldapsearch first to ensure it works. +# LDAP configurations are *highly* dependent on your setup and this file +# will need to be tweaked. This sample talks to ldap.example.com, here is +# an example of ldapsearch that will search users on this box: +# ldapsearch -v -x -H 'ldap://example.com:389' -D \ +# "uid=bind,cn=users,cn=accounts,dc=example,dc=com" -w SecretPass \ +# -b cn=users,cn=accounts,dc=example,dc=com +class { 'keystone:ldap': + url => 'ldap://ldap.example.com:389', + user => 'uid=bind,cn=users,cn=accounts,dc=example,dc=com', + password => 'SecretPass', + suffix => 'dc=example,dc=com', + query_scope => 'sub', + user_tree_dn => 'cn=users,cn=accounts,dc=example,dc=com', + user_id_attribute => 'uid', + user_name_attribute => 'uid', + user_mail_attribute => 'mail', + user_allow_create => 'False', + user_allow_update => 'False', + user_allow_delete => 'False', + user_enabled_emulation => 'True', + user_enabled_emulation_dn => 'cn=openstack-enabled,cn=groups,cn=accounts,dc=example,dc=com', + group_tree_dn => 'ou=groups,ou=openstack,dc=example,dc=com', + group_objectclass => 'organizationalRole', + group_id_attribute => 'cn', + group_name_attribute => 'cn', + group_member_attribute => 'RoleOccupant', + group_desc_attribute => 'description', + group_allow_create => 'True', + group_allow_update => 'True', + group_allow_delete => 'True', + project_tree_dn => 'ou=projects,ou=openstack,dc=example,dc=com', + project_objectclass => 'organizationalUnit', + project_id_attribute => 'ou', + project_member_attribute => 'member', + project_name_attribute => 'ou', + project_desc_attribute => 'description', + project_allow_create => 'True', + project_allow_update => 'True', + project_allow_delete => 'True', + project_enabled_emulation => 'True', + project_enabled_emulation_dn=> 'cn=enabled,ou=openstack,dc=example,dc=com', + role_tree_dn => 'ou=roles,ou=openstack,dc=example,dc=com', + role_objectclass => 'organizationalRole', + role_id_attribute => 'cn', + role_name_attribute => 'cn', + role_member_attribute => 'roleOccupant', + role_allow_create => 'True', + role_allow_update => 'True', + role_allow_delete => 'True', + identity_driver => 'keystone.identity.backends.ldap.Identity', + assignment_driver => 'keystone.assignment.backends.ldap.Assignment', + use_tls => 'True', + tls_cacertfile => '/etc/ssl/certs/ca-certificates.crt', + tls_req_cert => 'demand', + use_pool => 'True', + use_auth_pool => 'True', + pool_size => 5, + auth_pool_size => 5, + pool_retry_max => 3, + pool_connection_timeout => 120, +} diff --git a/3rdparty/modules/keystone/examples/ldap_identity.pp b/3rdparty/modules/keystone/examples/ldap_identity.pp new file mode 100644 index 000000000..41272c52f --- /dev/null +++ b/3rdparty/modules/keystone/examples/ldap_identity.pp @@ -0,0 +1,28 @@ +# Example using LDAP to manage user identity only. +# This setup will not allow changes to users. + +# Ensure this matches what is in LDAP or keystone will try to recreate +# the admin user +class { 'keystone::roles::admin': + email => 'test@example.com', + password => 'ChangeMe', +} + +# You can test this connection with ldapsearch first to ensure it works. +# This was tested against a FreeIPA box, you will likely need to change the +# attributes to match your configuration. +class { 'keystone:ldap': + identity_driver => 'keystone.identity.backends.ldap.Identity', + url => 'ldap://ldap.example.com:389', + user => 'uid=bind,cn=users,cn=accounts,dc=example,dc=com', + password => 'SecretPass', + suffix => 'dc=example,dc=com', + query_scope => 'sub', + user_tree_dn => 'cn=users,cn=accounts,dc=example,dc=com', + user_id_attribute => 'uid', + user_name_attribute => 'uid', + user_mail_attribute => 'mail', + user_allow_create => 'False', + user_allow_update => 'False', + user_allow_delete => 'False' +} diff --git a/3rdparty/modules/keystone/ext/keystone_test.rb b/3rdparty/modules/keystone/ext/keystone_test.rb new file mode 100644 index 000000000..ed944bedd --- /dev/null +++ b/3rdparty/modules/keystone/ext/keystone_test.rb @@ -0,0 +1,55 @@ +#!/usr/bin/env ruby +# this script verifies that keystone has +# been successfully installed using the instructions +# found here: http://keystone.openstack.org/configuration.html + +begin + require 'rubygems' +rescue + puts 'Could not require rubygems. This assumes puppet is not installed as a gem' +end +require 'open3' +require 'fileutils' +require 'puppet' + +username='admin' +password='admin_password' +# required to get a real services catalog +tenant='openstack' + +# shared secret +service_token='service_token' + +def run_command(cmd) + Open3.popen3(cmd) do |stdin, stdout, stderr| + begin + stdout = stdout.read + puts "Response from token request:#{stdout}" + return stdout + rescue Exception => e + puts "Request failed, this sh*t is borked :( : details: #{e}" + exit 1 + end + end +end + +puts `puppet apply -e "package {curl: ensure => present }"` + +get_token = %(curl -d '{"auth":{"passwordCredentials":{"username": "#{username}", "password": "#{password}"}}}' -H "Content-type: application/json" http://localhost:35357/v2.0/tokens) +token = nil + +puts "Running auth command: #{get_token}" +token = PSON.load(run_command(get_token))["access"]["token"]["id"] + +if token + puts "We were able to retrieve a token" + puts token + verify_token = "curl -H 'X-Auth-Token: #{service_token}' http://localhost:35357/v2.0/tokens/#{token}" + puts 'verifying token' + run_command(verify_token) + ['endpoints', 'tenants', 'users'].each do |x| + puts "getting #{x}" + get_keystone_data = "curl -H 'X-Auth-Token: #{service_token}' http://localhost:35357/v2.0/#{x}" + run_command(get_keystone_data) + end +end diff --git a/3rdparty/modules/keystone/files/httpd/keystone.py b/3rdparty/modules/keystone/files/httpd/keystone.py new file mode 100644 index 000000000..f5ce498c5 --- /dev/null +++ b/3rdparty/modules/keystone/files/httpd/keystone.py @@ -0,0 +1,60 @@ +# Copyright 2013 OpenStack Foundation +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +import logging +import os + +from oslo import i18n + + +# NOTE(dstanek): i18n.enable_lazy() must be called before +# keystone.i18n._() is called to ensure it has the desired lazy lookup +# behavior. This includes cases, like keystone.exceptions, where +# keystone.i18n._() is called at import time. +i18n.enable_lazy() + + +from keystone import backends +from keystone.common import dependency +from keystone.common import environment +from keystone.common import sql +from keystone import config +from keystone.openstack.common import log +from keystone import service + + +CONF = config.CONF + +config.configure() +sql.initialize() +config.set_default_for_default_log_levels() + +CONF(project='keystone') +config.setup_logging() + +environment.use_stdlib() +name = os.path.basename(__file__) + +if CONF.debug: + CONF.log_opt_values(log.getLogger(CONF.prog), logging.DEBUG) + + +drivers = backends.load_backends() + +# NOTE(ldbragst): 'application' is required in this context by WSGI spec. +# The following is a reference to Python Paste Deploy documentation +# http://pythonpaste.org/deploy/ +application = service.loadapp('config:%s' % config.find_paste_config(), name) + +dependency.resolve_future_dependencies() diff --git a/3rdparty/modules/keystone/lib/puppet/provider/keystone.rb b/3rdparty/modules/keystone/lib/puppet/provider/keystone.rb new file mode 100644 index 000000000..b398a8e30 --- /dev/null +++ b/3rdparty/modules/keystone/lib/puppet/provider/keystone.rb @@ -0,0 +1,117 @@ +require 'puppet/util/inifile' +require 'puppet/provider/openstack' +class Puppet::Provider::Keystone < Puppet::Provider::Openstack + + def request(service, action, object, credentials, *properties) + begin + super + rescue Puppet::Error::OpenstackAuthInputError => error + keystone_request(service, action, object, credentials, error, *properties) + end + end + + def self.request(service, action, object, credentials, *properties) + begin + super + rescue Puppet::Error::OpenstackAuthInputError => error + keystone_request(service, action, object, credentials, error, *properties) + end + end + + def keystone_request(service, action, object, credentials, error, *properties) + self.class.keystone_request(service, action, object, credentials, error, *properties) + end + + def self.keystone_request(service, action, object, credentials, error, *properties) + credentials = { + 'token' => get_admin_token, + 'auth_url' => get_admin_endpoint, + } + raise error unless (credentials['token'] && credentials['auth_url']) + auth_args = token_auth_args(credentials) + args = [object, properties, auth_args].flatten.compact + authenticate_request(service, action, args) + end + + def self.admin_token + @admin_token ||= get_admin_token + end + + def self.get_admin_token + if keystone_file and keystone_file['DEFAULT'] and keystone_file['DEFAULT']['admin_token'] + return "#{keystone_file['DEFAULT']['admin_token'].strip}" + else + return nil + end + end + + def self.admin_endpoint + @admin_endpoint ||= get_admin_endpoint + end + + def get_admin_token + self.class.get_admin_token + end + + + def self.get_admin_endpoint + if keystone_file + if keystone_file['DEFAULT'] + if keystone_file['DEFAULT']['admin_endpoint'] + auth_url = keystone_file['DEFAULT']['admin_endpoint'].strip.chomp('/') + return "#{auth_url}/v2.0/" + end + + if keystone_file['DEFAULT']['admin_port'] + admin_port = keystone_file['DEFAULT']['admin_port'].strip + else + admin_port = '35357' + end + + if keystone_file['DEFAULT']['admin_bind_host'] + host = keystone_file['DEFAULT']['admin_bind_host'].strip + if host == "0.0.0.0" + host = "127.0.0.1" + elsif host == '::0' + host = '[::1]' + end + else + host = "127.0.0.1" + end + end + + if keystone_file['ssl'] && keystone_file['ssl']['enable'] && keystone_file['ssl']['enable'].strip.downcase == 'true' + protocol = 'https' + else + protocol = 'http' + end + end + + "#{protocol}://#{host}:#{admin_port}/v2.0/" + end + + def get_admin_endpoint + self.class.get_admin_endpoint + end + + def self.keystone_file + return @keystone_file if @keystone_file + @keystone_file = Puppet::Util::IniConfig::File.new + @keystone_file.read('/etc/keystone/keystone.conf') + @keystone_file + end + + def keystone_file + self.class.keystone_file + end + + # Helper functions to use on the pre-validated enabled field + def bool_to_sym(bool) + bool == true ? :true : :false + end + + def sym_to_bool(sym) + sym == :true ? true : false + end + +end diff --git a/3rdparty/modules/keystone/lib/puppet/provider/keystone_config/ini_setting.rb b/3rdparty/modules/keystone/lib/puppet/provider/keystone_config/ini_setting.rb new file mode 100644 index 000000000..4d7b5cbdb --- /dev/null +++ b/3rdparty/modules/keystone/lib/puppet/provider/keystone_config/ini_setting.rb @@ -0,0 +1,27 @@ +Puppet::Type.type(:keystone_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def self.file_path + '/etc/keystone/keystone.conf' + end + + # added for backwards compatibility with older versions of inifile + def file_path + self.class.file_path + end + +end diff --git a/3rdparty/modules/keystone/lib/puppet/provider/keystone_endpoint/openstack.rb b/3rdparty/modules/keystone/lib/puppet/provider/keystone_endpoint/openstack.rb new file mode 100644 index 000000000..ac7780d48 --- /dev/null +++ b/3rdparty/modules/keystone/lib/puppet/provider/keystone_endpoint/openstack.rb @@ -0,0 +1,122 @@ +require 'puppet/provider/keystone' + +Puppet::Type.type(:keystone_endpoint).provide( + :openstack, + :parent => Puppet::Provider::Keystone +) do + + desc "Provider to manage keystone endpoints." + + def initialize(value={}) + super(value) + @property_flush = {} + end + + def create + properties = [] + # The region property is just ignored. We should fix this in kilo. + region, name = resource[:name].split('/') + properties << '--region' + properties << region + if resource[:public_url] + properties << '--publicurl' + properties << resource[:public_url] + end + if resource[:internal_url] + properties << '--internalurl' + properties << resource[:internal_url] + end + if resource[:admin_url] + properties << '--adminurl' + properties << resource[:admin_url] + end + @instance = request('endpoint', 'create', name, resource[:auth], properties) + end + + def exists? + ! instance(resource[:name]).empty? + end + + def destroy + id = instance(resource[:name])[:id] + request('endpoint', 'delete', id, resource[:auth]) + end + + + def region + instance(resource[:name])[:region] + end + + + def public_url=(value) + @property_flush[:public_url] = value + end + + def public_url + instance(resource[:name])[:public_url] + end + + + def internal_url=(value) + @property_flush[:internal_url] = value + end + + def internal_url + instance(resource[:name])[:internal_url] + end + + + def admin_url=(value) + @property_flush[:admin_url] = value + end + + def admin_url + instance(resource[:name])[:admin_url] + end + + def id + instance(resource[:name])[:id] + end + + def self.instances + list = request('endpoint', 'list', nil, nil, '--long') + list.collect do |endpoint| + new( + :name => "#{endpoint[:region]}/#{endpoint[:service_name]}", + :ensure => :present, + :id => endpoint[:id], + :region => endpoint[:region], + :public_url => endpoint[:publicurl], + :internal_url => endpoint[:internalurl], + :admin_url => endpoint[:adminurl] + ) + end + end + + def instances + instances = request('endpoint', 'list', nil, resource[:auth], '--long') + instances.collect do |endpoint| + { + :name => "#{endpoint[:region]}/#{endpoint[:service_name]}", + :id => endpoint[:id], + :region => endpoint[:region], + :public_url => endpoint[:publicurl], + :internal_url => endpoint[:internalurl], + :admin_url => endpoint[:adminurl] + } + end + end + + def instance(name) + @instance ||= instances.select { |instance| instance[:name] == name }.first || {} + end + + def flush + if ! @property_flush.empty? + destroy + create + @property_flush.clear + end + end + +end diff --git a/3rdparty/modules/keystone/lib/puppet/provider/keystone_paste_ini/ini_setting.rb b/3rdparty/modules/keystone/lib/puppet/provider/keystone_paste_ini/ini_setting.rb new file mode 100644 index 000000000..23a47af65 --- /dev/null +++ b/3rdparty/modules/keystone/lib/puppet/provider/keystone_paste_ini/ini_setting.rb @@ -0,0 +1,27 @@ +Puppet::Type.type(:keystone_paste_ini).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def self.file_path + '/etc/keystone/keystone-paste.ini' + end + + # this needs to be removed. This has been replaced with the class method + def file_path + self.class.file_path + end + +end diff --git a/3rdparty/modules/keystone/lib/puppet/provider/keystone_role/openstack.rb b/3rdparty/modules/keystone/lib/puppet/provider/keystone_role/openstack.rb new file mode 100644 index 000000000..b3bd85621 --- /dev/null +++ b/3rdparty/modules/keystone/lib/puppet/provider/keystone_role/openstack.rb @@ -0,0 +1,52 @@ +require 'puppet/provider/keystone' + +Puppet::Type.type(:keystone_role).provide( + :openstack, + :parent => Puppet::Provider::Keystone +) do + + desc 'Provider for keystone roles.' + + def create + properties = [] + @instance = request('role', 'create', resource[:name], resource[:auth], properties) + end + + def exists? + ! instance(resource[:name]).empty? + end + + def destroy + request('role', 'delete', resource[:name], resource[:auth]) + end + + def id + instance(resource[:name])[:id] + end + + def self.instances + list = request('role', 'list', nil, nil) + list.collect do |role| + new( + :name => role[:name], + :ensure => :present, + :id => role[:id] + ) + end + end + + def instances + instances = request('role', 'list', nil, resource[:auth]) + instances.collect do |role| + { + :name => role[:name], + :id => role[:id] + } + end + end + + def instance(name) + @instance ||= instances.select { |instance| instance[:name] == name }.first || {} + end + +end diff --git a/3rdparty/modules/keystone/lib/puppet/provider/keystone_service/openstack.rb b/3rdparty/modules/keystone/lib/puppet/provider/keystone_service/openstack.rb new file mode 100644 index 000000000..54e75f596 --- /dev/null +++ b/3rdparty/modules/keystone/lib/puppet/provider/keystone_service/openstack.rb @@ -0,0 +1,98 @@ +require 'puppet/provider/keystone' + +Puppet::Type.type(:keystone_service).provide( + :openstack, + :parent => Puppet::Provider::Keystone +) do + + desc "Provider to manage keystone services." + + def initialize(value={}) + super(value) + @property_flush = {} + end + + def create + properties = [] + if resource[:description] + properties << '--description' + properties << resource[:description] + end + if resource[:type] + properties << '--type' + properties << resource[:type] + end + @instance = request('service', 'create', resource[:name], resource[:auth], properties) + end + + def exists? + ! instance(resource[:name]).empty? + end + + def destroy + request('service', 'delete', resource[:name], resource[:auth]) + end + + + def description=(value) + raise(Puppet::Error, "Updating the service is not currently supported.") + end + + def description + instance(resource[:name])[:description] + end + + + def type=(value) + raise(Puppet::Error, "Updating the service is not currently supported.") + end + + def type + instance(resource[:name])[:type] + end + + + def id + instance(resource[:name])[:id] + end + + def self.instances + list = request('service', 'list', nil, nil, '--long') + list.collect do |service| + new( + :name => service[:name], + :ensure => :present, + :type => service[:type], + :description => service[:description], + :id => service[:id] + ) + end + end + + def instances + instances = request('service', 'list', nil, resource[:auth], '--long') + instances.collect do |service| + { + :name => service[:name], + :type => service[:type], + :description => service[:description], + :id => service[:id] + } + end + end + + def instance(name) + @instance ||= instances.select { |instance| instance[:name] == name }.first || {} + end + + def flush + options = [] + if @property_flush + # There is a --description flag for the set command, but it does not work if the value is empty + (options << '--property' << "type=#{resource[:type]}") if @property_flush[:type] + (options << '--property' << "description=#{resource[:description]}") if @property_flush[:description] + request('project', 'set', resource[:name], resource[:auth], options) unless options.empty? + end + end + +end diff --git a/3rdparty/modules/keystone/lib/puppet/provider/keystone_tenant/openstack.rb b/3rdparty/modules/keystone/lib/puppet/provider/keystone_tenant/openstack.rb new file mode 100644 index 000000000..7d19fcef0 --- /dev/null +++ b/3rdparty/modules/keystone/lib/puppet/provider/keystone_tenant/openstack.rb @@ -0,0 +1,100 @@ +require 'puppet/provider/keystone' + +Puppet::Type.type(:keystone_tenant).provide( + :openstack, + :parent => Puppet::Provider::Keystone +) do + + desc "Provider to manage keystone tenants/projects." + + def initialize(value={}) + super(value) + @property_flush = {} + end + + def create + properties = [] + if resource[:enabled] == :true + properties << '--enable' + elsif resource[:enabled] == :false + properties << '--disable' + end + if resource[:description] + properties << '--description' + properties << resource[:description] + end + @instance = request('project', 'create', resource[:name], resource[:auth], properties) + end + + def exists? + ! instance(resource[:name]).empty? + end + + def destroy + request('project', 'delete', resource[:name], resource[:auth]) + end + + + def enabled=(value) + @property_flush[:enabled] = value + end + + def enabled + bool_to_sym(instance(resource[:name])[:enabled]) + end + + + def description=(value) + @property_flush[:description] = value + end + + def description + instance(resource[:name])[:description] + end + + + def id + instance(resource[:name])[:id] + end + + def self.instances + list = request('project', 'list', nil, nil, '--long') + list.collect do |project| + new( + :name => project[:name], + :ensure => :present, + :enabled => project[:enabled].downcase.chomp == 'true' ? true : false, + :description => project[:description], + :id => project[:id] + ) + end + end + + def instances + instances = request('project', 'list', nil, resource[:auth], '--long') + instances.collect do |project| + { + :name => project[:name], + :enabled => project[:enabled].downcase.chomp == 'true' ? true : false, + :description => project[:description], + :id => project[:id] + } + end + end + + def instance(name) + @instance ||= instances.select { |instance| instance[:name] == name }.first || {} + end + + def flush + options = [] + if @property_flush + (options << '--enable') if @property_flush[:enabled] == :true + (options << '--disable') if @property_flush[:enabled] == :false + # There is a --description flag for the set command, but it does not work if the value is empty + (options << '--property' << "description=#{resource[:description]}") if @property_flush[:description] + request('project', 'set', resource[:name], resource[:auth], options) unless options.empty? + end + end + +end diff --git a/3rdparty/modules/keystone/lib/puppet/provider/keystone_user/openstack.rb b/3rdparty/modules/keystone/lib/puppet/provider/keystone_user/openstack.rb new file mode 100644 index 000000000..6c8d04aa2 --- /dev/null +++ b/3rdparty/modules/keystone/lib/puppet/provider/keystone_user/openstack.rb @@ -0,0 +1,253 @@ +require 'net/http' +require 'json' +require 'puppet/provider/keystone' +Puppet::Type.type(:keystone_user).provide( + :openstack, + :parent => Puppet::Provider::Keystone +) do + + desc "Provider to manage keystone users." + + def initialize(value={}) + super(value) + @property_flush = {} + end + + def create + properties = [] + if resource[:enabled] == :true + properties << '--enable' + elsif resource[:enabled] == :false + properties << '--disable' + end + if resource[:password] + properties << '--password' + properties << resource[:password] + end + if resource[:tenant] + properties << '--project' + properties << resource[:tenant] + end + if resource[:email] + properties << '--email' + properties << resource[:email] + end + @instance = request('user', 'create', resource[:name], resource[:auth], properties) + end + + def exists? + ! instance(resource[:name]).empty? + end + + def destroy + request('user', 'delete', resource[:name], resource[:auth]) + end + + + def enabled=(value) + @property_flush[:enabled] = value + end + + def enabled + bool_to_sym(instance(resource[:name])[:enabled]) + end + + + def password=(value) + @property_flush[:password] = value + end + + def password + # if we don't know a password we can't test it + return nil if resource[:password] == nil + # if the user is disabled then the password can't be changed + return resource[:password] if resource[:enabled] == :false + # if replacing password is disabled, then don't change it + return resource[:password] if resource[:replace_password] == :false + # we can't get the value of the password but we can test to see if the one we know + # about works, if it doesn't then return nil, causing it to be reset + endpoint = nil + if password_credentials_set?(resource[:auth]) || service_credentials_set?(resource[:auth]) + endpoint = (resource[:auth])['auth_url'] + elsif openrc_set?(resource[:auth]) + endpoint = get_credentials_from_openrc(resource[:auth])['auth_url'] + elsif env_vars_set? + endpoint = ENV['OS_AUTH_URL'] + else + # try to get endpoint from keystone.conf + endpoint = get_admin_endpoint + end + if endpoint == nil + raise(Puppet::Error::OpenstackAuthInputError, 'Could not find auth url to check user password.') + else + auth_params = { + 'username' => resource[:name], + 'password' => resource[:password], + 'tenant_name' => resource[:tenant], + 'auth_url' => endpoint, + } + # LP#1408754 + # Ideally this would be checked with the `openstack token issue` command, + # but that command is not available with version 0.3.0 of openstackclient + # which is what ships on Ubuntu during Juno. + # Instead we'll check whether the user can authenticate with curl. + creds_hash = { + :auth => { + :passwordCredentials => { + :username => auth_params['username'], + :password => auth_params['password'], + } + } + } + url = URI.parse(endpoint) + # There is issue with ipv6 where address has to be in brackets, this causes the + # underlying ruby TCPSocket to fail. Net::HTTP.new will fail without brackets on + # joining the ipv6 address with :port or passing brackets to TCPSocket. It was + # found that if we use Net::HTTP.start with url.hostname the incriminated code + # won't be hit. + use_ssl = url.scheme == "https" ? true : false + http = Net::HTTP.start(url.hostname, url.port, {:use_ssl => use_ssl}) + request = Net::HTTP::Post.new('/v2.0/tokens') + request.body = creds_hash.to_json + request.content_type = 'application/json' + response = http.request(request) + if response.code.to_i == 401 || response.code.to_i == 403 # 401 => unauthorized, 403 => userDisabled + return nil + elsif ! (response.code == 200 || response.code == 203) + return resource[:password] + else + raise(Puppet::Error, "Received bad response while trying to authenticate user: #{response.body}") + end + end + end + + def tenant=(value) + begin + request('user', 'set', resource[:name], resource[:auth], '--project', value) + rescue Puppet::ExecutionFailure => e + if e.message =~ /You are not authorized to perform the requested action: LDAP user update/ + # read-only LDAP identity backend - just fall through + else + raise e + end + # note: read-write ldap will silently fail, not raise an exception + end + set_project(value) + end + + def tenant + return resource[:tenant] if sym_to_bool(resource[:ignore_default_tenant]) + # use the one returned from instances + tenant_name = instance(resource[:name])[:project] + if tenant_name.nil? or tenant_name.empty? + # if none (i.e. ldap backend) use the given one + tenant_name = resource[:tenant] + else + return tenant_name + end + if tenant_name.nil? or tenant_name.empty? + return nil # nothing found, nothing given + end + # If the user list command doesn't report the project, it might still be there + # We don't need to know exactly what it is, we just need to know whether it's + # the one we're trying to set. + roles = request('user role', 'list', resource[:name], resource[:auth], ['--project', tenant_name]) + if roles.empty? + return nil + else + return tenant_name + end + end + + def replace_password + instance(resource[:name])[:replace_password] + end + + def replace_password=(value) + @property_flush[:replace_password] = value + end + + def email=(value) + @property_flush[:email] = value + end + + def email + instance(resource[:name])[:email] + end + + def id + instance(resource[:name])[:id] + end + + def self.instances + list = request('user', 'list', nil, nil, '--long') + list.collect do |user| + new( + :name => user[:name], + :ensure => :present, + :enabled => user[:enabled].downcase.chomp == 'true' ? true : false, + :password => user[:password], + :tenant => user[:project], + :email => user[:email], + :id => user[:id] + ) + end + end + + def instances + instances = request('user', 'list', nil, resource[:auth], '--long') + instances.collect do |user| + { + :name => user[:name], + :enabled => user[:enabled].downcase.chomp == 'true' ? true : false, + :password => user[:password], + :project => user[:project], + :email => user[:email], + :id => user[:id] + } + end + end + + def instance(name) + @instance ||= instances.select { |instance| instance[:name] == name }.first || {} + end + + def set_project(newproject) + # some backends do not store the project/tenant in the user object, so we have to + # to modify the project/tenant instead + # First, see if the project actually needs to change + roles = request('user role', 'list', resource[:name], resource[:auth], ['--project', newproject]) + unless roles.empty? + return # if already set, just skip + end + # Currently the only way to assign a user to a tenant not using user-create + # is to use user-role-add - this means we also need a role - there is usual + # a default role called _member_ which can be used for this purpose. What + # usually happens in a puppet module is that immediately after calling + # keystone_user, the module will then assign a role to that user. It is + # ok for a user to have the _member_ role and another role. + default_role = "_member_" + begin + request('role', 'show', default_role, resource[:auth]) + rescue + debug("Keystone role #{default_role} does not exist - creating") + request('role', 'create', default_role, resource[:auth]) + end + request('role', 'add', default_role, resource[:auth], + '--project', newproject, '--user', resource[:name]) + end + + def flush + options = [] + if @property_flush + (options << '--enable') if @property_flush[:enabled] == :true + (options << '--disable') if @property_flush[:enabled] == :false + # There is a --description flag for the set command, but it does not work if the value is empty + (options << '--password' << resource[:password]) if @property_flush[:password] + (options << '--email' << resource[:email]) if @property_flush[:email] + # project handled in tenant= separately + request('user', 'set', resource[:name], resource[:auth], options) unless options.empty? + end + end + +end diff --git a/3rdparty/modules/keystone/lib/puppet/provider/keystone_user_role/openstack.rb b/3rdparty/modules/keystone/lib/puppet/provider/keystone_user_role/openstack.rb new file mode 100644 index 000000000..5b9a1b587 --- /dev/null +++ b/3rdparty/modules/keystone/lib/puppet/provider/keystone_user_role/openstack.rb @@ -0,0 +1,159 @@ +require 'puppet/provider/keystone' + +Puppet::Type.type(:keystone_user_role).provide( + :openstack, + :parent => Puppet::Provider::Keystone +) do + + desc "Provider to manage keystone role assignments to users." + + def create + properties = [] + properties << '--project' << get_project + properties << '--user' << get_user + if resource[:roles] + resource[:roles].each do |role| + request('role', 'add', role, resource[:auth], properties) + end + end + end + + def exists? + # If we just ran self.instances, no need to make the request again + # instance() will find it cached in @user_role_hash + if self.class.user_role_hash + return ! instance(resource[:name]).empty? + # If we don't have the hash ready, we don't need to rebuild the + # whole thing just to check on one particular user/role + else + roles = request('user role', 'list', nil, resource[:auth], ['--project', get_project, get_user]) + # Since requesting every combination of users, roles, and + # projects is so expensive, construct the property hash here + # instead of in self.instances so it can be used in the role + # and destroy methods + @property_hash[:name] = resource[:name] + if roles.empty? + @property_hash[:ensure] = :absent + else + @property_hash[:ensure] = :present + @property_hash[:roles] = roles.collect do |role| + role[:name] + end + end + return @property_hash[:ensure] == :present + end + end + + def destroy + properties = [] + properties << '--project' << get_project + properties << '--user' << get_user + if @property_hash[:roles] + @property_hash[:roles].each do |role| + request('role', 'remove', role, resource[:auth], properties) + end + end + @property_hash[:ensure] = :absent + end + + + def roles + @property_hash[:roles] + end + + def roles=(value) + current_roles = roles + # determine the roles to be added and removed + remove = current_roles - Array(value) + add = Array(value) - current_roles + user = get_user + project = get_project + add.each do |role_name| + request('role', 'add', role_name, resource[:auth], ['--project', project, '--user', user]) + end + remove.each do |role_name| + request('role', 'remove', role_name, resource[:auth], ['--project', project, '--user', user]) + end + end + + + def self.instances + instances = build_user_role_hash + instances.collect do |title, roles| + new( + :name => title, + :ensure => :present, + :roles => roles + ) + end + end + + def instance(name) + self.class.user_role_hash.select { |role_name, roles| role_name == name } || {} + end + + private + + def get_user + resource[:name].rpartition('@').first + end + + def get_project + resource[:name].rpartition('@').last + end + + # We split get_projects into class and instance methods + # so that the appropriate request method gets called + def get_projects + request('project', 'list', nil, resource[:auth]).collect do |project| + project[:name] + end + end + + def self.get_projects + request('project', 'list', nil, nil).collect do |project| + project[:name] + end + end + + def get_users(project) + request('user', 'list', nil, resource[:auth], ['--project', project]).collect do |user| + user[:name] + end + end + + def self.get_users(project) + request('user', 'list', nil, nil, ['--project', project]).collect do |user| + user[:name] + end + end + + # Class methods for caching user_role_hash so both class and instance + # methods can access the value + def self.set_user_role_hash(user_role_hash) + @user_role_hash = user_role_hash + end + + def self.user_role_hash + @user_role_hash + end + + def self.build_user_role_hash + hash = user_role_hash || {} + return hash unless hash.empty? + projects = get_projects + projects.each do |project| + users = get_users(project) + users.each do |user| + user_roles = request('user role', 'list', nil, nil, ['--project', project, user]) + hash["#{user}@#{project}"] = [] + user_roles.each do |role| + hash["#{user}@#{project}"] << role[:name] + end + end + end + set_user_role_hash(hash) + hash + end + +end diff --git a/3rdparty/modules/keystone/lib/puppet/provider/openstack.rb b/3rdparty/modules/keystone/lib/puppet/provider/openstack.rb new file mode 100644 index 000000000..8236df709 --- /dev/null +++ b/3rdparty/modules/keystone/lib/puppet/provider/openstack.rb @@ -0,0 +1,188 @@ +# TODO: This needs to be extracted out into openstacklib in the Kilo cycle +require 'csv' +require 'puppet' + +class Puppet::Error::OpenstackAuthInputError < Puppet::Error +end + +class Puppet::Error::OpenstackUnauthorizedError < Puppet::Error +end + +class Puppet::Provider::Openstack < Puppet::Provider + + initvars # so commands will work + commands :openstack => 'openstack' + + def request(service, action, object, credentials, *properties) + if password_credentials_set?(credentials) + auth_args = password_auth_args(credentials) + elsif openrc_set?(credentials) + credentials = get_credentials_from_openrc(credentials['openrc']) + auth_args = password_auth_args(credentials) + elsif service_credentials_set?(credentials) + auth_args = token_auth_args(credentials) + elsif env_vars_set? + # noop; auth needs no extra arguments + auth_args = nil + else # All authentication efforts failed + raise(Puppet::Error::OpenstackAuthInputError, 'No credentials provided.') + end + args = [object, properties, auth_args].flatten.compact + authenticate_request(service, action, args) + end + + def self.request(service, action, object, *properties) + if env_vars_set? + # noop; auth needs no extra arguments + auth_args = nil + else # All authentication efforts failed + raise(Puppet::Error::OpenstackAuthInputError, 'No credentials provided.') + end + args = [object, properties, auth_args].flatten.compact + authenticate_request(service, action, args) + end + + # Returns an array of hashes, where the keys are the downcased CSV headers + # with underscores instead of spaces + def self.authenticate_request(service, action, *args) + rv = nil + timeout = 10 + end_time = Time.now.to_i + timeout + loop do + begin + if(action == 'list') + response = openstack(service, action, '--quiet', '--format', 'csv', args) + response = parse_csv(response) + keys = response.delete_at(0) # ID,Name,Description,Enabled + rv = response.collect do |line| + hash = {} + keys.each_index do |index| + key = keys[index].downcase.gsub(/ /, '_').to_sym + hash[key] = line[index] + end + hash + end + elsif(action == 'show' || action == 'create') + rv = {} + # shell output is name="value"\nid="value2"\ndescription="value3" etc. + openstack(service, action, '--format', 'shell', args).split("\n").each do |line| + # key is everything before the first "=" + key, val = line.split("=", 2) + next unless val # Ignore warnings + # value is everything after the first "=", with leading and trailing double quotes stripped + val = val.gsub(/\A"|"\Z/, '') + rv[key.downcase.to_sym] = val + end + else + rv = openstack(service, action, args) + end + break + rescue Puppet::ExecutionFailure => e + if e.message =~ /HTTP 401/ + raise(Puppet::Error::OpenstackUnauthorizedError, 'Could not authenticate.') + elsif e.message =~ /Unable to establish connection/ + current_time = Time.now.to_i + if current_time > end_time + break + else + wait = end_time - current_time + Puppet::debug("Non-fatal error: \"#{e.message}\"; retrying for #{wait} more seconds.") + if wait > timeout - 2 # Only notice the first time + notice("#{service} service is unavailable. Will retry for up to #{wait} seconds.") + end + end + sleep(2) + else + raise e + end + end + end + return rv + end + + def authenticate_request(service, action, *args) + self.class.authenticate_request(service, action, *args) + end + + private + + def password_credentials_set?(auth_params) + auth_params && auth_params['username'] && auth_params['password'] && auth_params['tenant_name'] && auth_params['auth_url'] + end + + + def openrc_set?(auth_params) + auth_params && auth_params['openrc'] + end + + + def service_credentials_set?(auth_params) + auth_params && auth_params['token'] && auth_params['auth_url'] + end + + + def self.env_vars_set? + ENV['OS_USERNAME'] && ENV['OS_PASSWORD'] && ENV['OS_TENANT_NAME'] && ENV['OS_AUTH_URL'] + end + + + def env_vars_set? + self.class.env_vars_set? + end + + + + def self.password_auth_args(credentials) + ['--os-username', credentials['username'], + '--os-password', credentials['password'], + '--os-tenant-name', credentials['tenant_name'], + '--os-auth-url', credentials['auth_url']] + end + + def password_auth_args(credentials) + self.class.password_auth_args(credentials) + end + + + def self.token_auth_args(credentials) + ['--os-token', credentials['token'], + '--os-url', credentials['auth_url']] + end + + def token_auth_args(credentials) + self.class.token_auth_args(credentials) + end + + def get_credentials_from_openrc(file) + creds = {} + File.open(file).readlines.delete_if{|l| l=~ /^#/}.each do |line| + key, value = line.split('=') + key = key.split(' ').last.downcase.sub(/^os_/, '') + value = value.chomp.gsub(/'/, '') + creds[key] = value + end + return creds + end + + + def self.get_credentials_from_env + env = ENV.to_hash.dup.delete_if { |key, _| ! (key =~ /^OS_/) } + credentials = {} + env.each do |name, value| + credentials[name.downcase.sub(/^os_/, '')] = value + end + credentials + end + + def get_credentials_from_env + self.class.get_credentials_from_env + end + + def self.parse_csv(text) + # Ignore warnings - assume legitimate output starts with a double quoted + # string. Errors will be caught and raised prior to this + text = text.split("\n").drop_while { |line| line !~ /^\".*\"/ }.join("\n") + return CSV.parse(text + "\n") + end + +end diff --git a/3rdparty/modules/keystone/lib/puppet/type/keystone_config.rb b/3rdparty/modules/keystone/lib/puppet/type/keystone_config.rb new file mode 100644 index 000000000..fc6b82040 --- /dev/null +++ b/3rdparty/modules/keystone/lib/puppet/type/keystone_config.rb @@ -0,0 +1,44 @@ +Puppet::Type.newtype(:keystone_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from keystone.conf' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + newvalues(/^[\S ]*$/) + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end + +end diff --git a/3rdparty/modules/keystone/lib/puppet/type/keystone_endpoint.rb b/3rdparty/modules/keystone/lib/puppet/type/keystone_endpoint.rb new file mode 100644 index 000000000..4b0e6df9c --- /dev/null +++ b/3rdparty/modules/keystone/lib/puppet/type/keystone_endpoint.rb @@ -0,0 +1,47 @@ +# LP#1408531 +File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) } +require 'puppet/util/openstack' +Puppet::Type.newtype(:keystone_endpoint) do + + desc 'Type for managing keystone endpoints.' + + ensurable + + newparam(:name, :namevar => true) do + newvalues(/\S+\/\S+/) + end + + newproperty(:id) do + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:region) do + end + + newproperty(:public_url) do + end + + newproperty(:internal_url) do + end + + newproperty(:admin_url) do + end + + # we should not do anything until the keystone service is started + autorequire(:service) do + ['keystone'] + end + + autorequire(:keystone_service) do + (region, service_name) = self[:name].split('/') + [service_name] + end + + auth_param_doc=< true) do + desc 'Section/setting name to manage from keystone/keystone-paste.ini' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end + +end diff --git a/3rdparty/modules/keystone/lib/puppet/type/keystone_role.rb b/3rdparty/modules/keystone/lib/puppet/type/keystone_role.rb new file mode 100644 index 000000000..c6e7d1d45 --- /dev/null +++ b/3rdparty/modules/keystone/lib/puppet/type/keystone_role.rb @@ -0,0 +1,33 @@ +# LP#1408531 +File.expand_path('../..', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) } +require 'puppet/util/openstack' +Puppet::Type.newtype(:keystone_role) do + + desc <<-EOT + This is currently used to model the creation of + keystone roles. + EOT + + ensurable + + newparam(:name, :namevar => true) do + newvalues(/\S+/) + end + + newproperty(:id) do + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + # we should not do anything until the keystone service is started + autorequire(:service) do + ['keystone'] + end + + auth_param_doc=< true) do + desc 'The name of the service.' + newvalues(/\S+/) + end + + newproperty(:id) do + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:type) do + desc 'The type of service' + validate do |value| + fail('The service type is required.') unless value + end + end + + newproperty(:description) do + desc 'A description of the service.' + defaultto('') + end + + # This ensures the service is started and therefore the keystone + # config is configured IF we need them for authentication. + # If there is no keystone config, authentication credentials + # need to come from another source. + autorequire(:service) do + ['keystone'] + end + + auth_param_doc=< true) do + desc 'The name of the tenant.' + newvalues(/\w+/) + end + + newproperty(:enabled) do + desc 'Whether the tenant should be enabled. Defaults to true.' + newvalues(/(t|T)rue/, /(f|F)alse/, true, false ) + defaultto(true) + munge do |value| + value.to_s.downcase.to_sym + end + end + + newproperty(:description) do + desc 'A description of the tenant.' + defaultto('') + end + + newproperty(:id) do + desc 'Read-only property of the tenant.' + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + # This ensures the service is started and therefore the keystone + # config is configured IF we need them for authentication. + # If there is no keystone config, authentication credentials + # need to come from another source. + autorequire(:service) do + ['keystone'] + end + + auth_param_doc=< true) do + newvalues(/\S+/) + end + + newparam(:ignore_default_tenant) do + newvalues(/(t|T)rue/, /(f|F)alse/, true, false) + defaultto(false) + munge do |value| + value.to_s.downcase.to_sym + end + end + + newproperty(:enabled) do + newvalues(/(t|T)rue/, /(f|F)alse/, true, false) + defaultto(true) + munge do |value| + value.to_s.downcase.to_sym + end + end + + newproperty(:password) do + newvalues(/\S+/) + def change_to_s(currentvalue, newvalue) + if currentvalue == :absent + return "created password" + else + return "changed password" + end + end + + def is_to_s( currentvalue ) + return '[old password redacted]' + end + + def should_to_s( newvalue ) + return '[new password redacted]' + end + end + + newproperty(:tenant) do + newvalues(/\S+/) + end + + newproperty(:email) do + newvalues(/^(\S+@\S+)|$/) + end + + newproperty(:id) do + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newparam(:replace_password) do + newvalues(/(t|T)rue/, /(f|F)alse/, true, false) + defaultto(true) + munge do |value| + value.to_s.downcase.to_sym + end + end + + autorequire(:keystone_tenant) do + self[:tenant] + end + + # we should not do anything until the keystone service is started + autorequire(:service) do + ['keystone'] + end + + auth_param_doc=< true) do + newvalues(/^\S+@\S+$/) + end + + newproperty(:roles, :array_matching => :all) do + def insync?(is) + return false unless is.is_a? Array + # order of roles does not matter + is.sort == self.should.sort + end + end + + autorequire(:keystone_user) do + self[:name].rpartition('@').first + end + + autorequire(:keystone_tenant) do + self[:name].rpartition('@').last + end + + autorequire(:keystone_role) do + self[:roles] + end + + # we should not do anything until the keystone service is started + autorequire(:service) do + ['keystone'] + end + + auth_param_doc=< { + 'username' => 'test', + 'password' => 'passw0rd', + 'tenant_name' => 'test', + 'auth_url' => 'http://localhost:35357/v2.0', +} + +or a path to an openrc file containing these credentials, e.g.: + +auth => { + 'openrc' => '/root/openrc', +} + +or a service token and host, e.g.: + +auth => { + 'service_token' => 'ADMIN', + 'auth_url' => 'http://localhost:35357/v2.0', +} + +If not present, the provider will look for environment variables for +password credentials. + +#{comment} +EOT + + validate do |value| + raise(Puppet::Error, 'This property must be a hash') unless value.is_a?(Hash) + end + end + + type.autorequire(:package) do + 'python-openstackclient' + end + + end +end diff --git a/3rdparty/modules/keystone/manifests/client.pp b/3rdparty/modules/keystone/manifests/client.pp new file mode 100644 index 000000000..d400f3970 --- /dev/null +++ b/3rdparty/modules/keystone/manifests/client.pp @@ -0,0 +1,18 @@ +# == Class: keystone::client +# +# Installs Keystone client. +# +# === Parameters +# +# [*ensure*] +# (optional) Ensure state of the package. Defaults to 'present'. +# +class keystone::client ( + $ensure = 'present' +) { + + package { 'python-keystoneclient': + ensure => $ensure, + tag => 'openstack', + } +} diff --git a/3rdparty/modules/keystone/manifests/config.pp b/3rdparty/modules/keystone/manifests/config.pp new file mode 100644 index 000000000..5309fa711 --- /dev/null +++ b/3rdparty/modules/keystone/manifests/config.pp @@ -0,0 +1,30 @@ +# == Class: keystone::config +# +# This class is used to manage arbitrary keystone configurations. +# +# === Parameters +# +# [*keystone_config*] +# (optional) Allow configuration of arbitrary keystone configurations. +# The value is an hash of keystone_config resources. Example: +# { 'DEFAULT/foo' => { value => 'fooValue'}, +# 'DEFAULT/bar' => { value => 'barValue'} +# } +# In yaml format, Example: +# keystone_config: +# DEFAULT/foo: +# value: fooValue +# DEFAULT/bar: +# value: barValue +# +# NOTE: The configuration MUST NOT be already handled by this module +# or Puppet catalog compilation will fail with duplicate resources. +# +class keystone::config ( + $keystone_config = {}, +) { + + validate_hash($keystone_config) + + create_resources('keystone_config', $keystone_config) +} diff --git a/3rdparty/modules/keystone/manifests/cron/token_flush.pp b/3rdparty/modules/keystone/manifests/cron/token_flush.pp new file mode 100644 index 000000000..331eeba56 --- /dev/null +++ b/3rdparty/modules/keystone/manifests/cron/token_flush.pp @@ -0,0 +1,75 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Class: keystone::cron::token_flush +# +# Installs a cron job to purge expired tokens. +# +# === Parameters +# +# [*ensure*] +# (optional) Defaults to present. +# Valid values are present, absent. +# +# [*minute*] +# (optional) Defaults to '1'. +# +# [*hour*] +# (optional) Defaults to '0'. +# +# [*monthday*] +# (optional) Defaults to '*'. +# +# [*month*] +# (optional) Defaults to '*'. +# +# [*weekday*] +# (optional) Defaults to '*'. +# +# [*maxdelay*] +# (optional) Seconds. Defaults to 0. Should be a positive integer. +# Induces a random delay before running the cronjob to avoid running all +# cron jobs at the same time on all hosts this job is configured. +# +class keystone::cron::token_flush ( + $ensure = present, + $minute = 1, + $hour = 0, + $monthday = '*', + $month = '*', + $weekday = '*', + $maxdelay = 0, +) { + + if $maxdelay == 0 { + $sleep = '' + } else { + $sleep = "sleep `expr \${RANDOM} \\% ${maxdelay}`; " + } + + cron { 'keystone-manage token_flush': + ensure => $ensure, + command => "${sleep}keystone-manage token_flush >>/var/log/keystone/keystone-tokenflush.log 2>&1", + environment => 'PATH=/bin:/usr/bin:/usr/sbin SHELL=/bin/sh', + user => 'keystone', + minute => $minute, + hour => $hour, + monthday => $monthday, + month => $month, + weekday => $weekday + } +} diff --git a/3rdparty/modules/keystone/manifests/db/mysql.pp b/3rdparty/modules/keystone/manifests/db/mysql.pp new file mode 100644 index 000000000..3e046f4a2 --- /dev/null +++ b/3rdparty/modules/keystone/manifests/db/mysql.pp @@ -0,0 +1,62 @@ +# The keystone::db::mysql class implements mysql backend for keystone +# +# This class can be used to create tables, users and grant +# privelege for a mysql keystone database. +# +# == parameters +# +# [password] Password that will be used for the keystone db user. +# Optional. Defaults to: 'keystone_default_password' +# +# [dbname] Name of keystone database. Optional. Defaults to keystone. +# +# [user] Name of keystone user. Optional. Defaults to keystone. +# +# [host] Host where user should be allowed all priveleges for database. +# Optional. Defaults to 127.0.0.1. +# +# [allowed_hosts] Hosts allowed to use the database +# +# [*mysql_module*] Deprecated. Does nothing. +# +# == Dependencies +# Class['mysql::server'] +# +# == Examples +# == Authors +# +# Dan Bode dan@puppetlabs.com +# +# == Copyright +# +# Copyright 2012 Puppetlabs Inc, unless otherwise noted. +# +class keystone::db::mysql( + $password, + $dbname = 'keystone', + $user = 'keystone', + $host = '127.0.0.1', + $charset = 'utf8', + $collate = 'utf8_unicode_ci', + $mysql_module = undef, + $allowed_hosts = undef +) { + + if $mysql_module { + warning('The mysql_module parameter is deprecated. The latest 2.x mysql module will be used.') + } + + validate_string($password) + + ::openstacklib::db::mysql { 'keystone': + user => $user, + password_hash => mysql_password($password), + dbname => $dbname, + host => $host, + charset => $charset, + collate => $collate, + allowed_hosts => $allowed_hosts, + } + + ::Openstacklib::Db::Mysql['keystone'] ~> Exec<| title == 'keystone-manage db_sync' |> +} diff --git a/3rdparty/modules/keystone/manifests/db/postgresql.pp b/3rdparty/modules/keystone/manifests/db/postgresql.pp new file mode 100644 index 000000000..3d7eb73d7 --- /dev/null +++ b/3rdparty/modules/keystone/manifests/db/postgresql.pp @@ -0,0 +1,47 @@ +# +# implements postgresql backend for keystone +# +# This class can be used to create tables, users and grant +# privelege for a postgresql keystone database. +# +# Requires Puppetlabs Postgresql module. +# +# [*Parameters*] +# +# [password] Password that will be used for the keystone db user. +# Optional. Defaults to: 'keystone_default_password' +# +# [dbname] Name of keystone database. Optional. Defaults to keystone. +# +# [user] Name of keystone user. Optional. Defaults to keystone. +# +# == Dependencies +# Class['postgresql::server'] +# +# == Examples +# == Authors +# +# Etienne Pelletier epelletier@morphlabs.com +# +# == Copyright +# +# Copyright 2012 Etienne Pelletier, unless otherwise noted. +# +class keystone::db::postgresql( + $password, + $dbname = 'keystone', + $user = 'keystone' +) { + + Class['keystone::db::postgresql'] -> Service<| title == 'keystone' |> + + require postgresql::python + + postgresql::db { $dbname: + user => $user, + password => $password, + } + + Postgresql::Db[$dbname] ~> Exec<| title == 'keystone-manage db_sync' |> + +} diff --git a/3rdparty/modules/keystone/manifests/db/sync.pp b/3rdparty/modules/keystone/manifests/db/sync.pp new file mode 100644 index 000000000..5984a03a1 --- /dev/null +++ b/3rdparty/modules/keystone/manifests/db/sync.pp @@ -0,0 +1,14 @@ +# +# Class to execute "keystone-manage db_sync +# +class keystone::db::sync { + exec { 'keystone-manage db_sync': + path => '/usr/bin', + user => 'keystone', + refreshonly => true, + subscribe => [Package['keystone'], Keystone_config['database/connection']], + require => User['keystone'], + } + + Exec['keystone-manage db_sync'] ~> Service<| title == 'keystone' |> +} diff --git a/3rdparty/modules/keystone/manifests/dev/install.pp b/3rdparty/modules/keystone/manifests/dev/install.pp new file mode 100644 index 000000000..3e68113c2 --- /dev/null +++ b/3rdparty/modules/keystone/manifests/dev/install.pp @@ -0,0 +1,64 @@ +# +# Installs keystone from source. This is not yet fully implemented +# +# == Dependencies +# == Examples +# == Authors +# +# Dan Bode dan@puppetlabs.com +# +# == Copyright +# +# Copyright 2012 Puppetlabs Inc, unless otherwise noted. +# +class keystone::dev::install( + $source_dir = '/usr/local/keystone' +) { + # make sure that I have python 2.7 installed + + Class['openstack::dev'] -> Class['keystone::dev::install'] + + # there are likely conficts with other packages + # introduced by these resources + package { [ + 'python-dev', + 'libxml2-dev', + 'libxslt1-dev', + 'libsasl2-dev', + 'libsqlite3-dev', + 'libssl-dev', + 'libldap2-dev', + 'sqlite3' + ]: + ensure => latest, + } + + vcsrepo { $source_dir: + ensure => present, + provider => git, + source => 'git://github.com/openstack/keystone.git', + } + + Exec { + cwd => $source_dir, + path => '/usr/bin', + refreshonly => true, + subscribe => Vcsrepo[$source_dir], + logoutput => true, + # I have disabled timeout since this seems to take forever + # this may be a bad idea :) + timeout => 0, + } + + # TODO - really, I need a way to take this file and + # convert it into package resources + exec { 'install_dev_deps': + command => 'pip install -r tools/pip-requires', + } + + exec { 'install_keystone_source': + command => 'python setup.py develop', + require => Exec['install_dev_deps'], + } + +} diff --git a/3rdparty/modules/keystone/manifests/endpoint.pp b/3rdparty/modules/keystone/manifests/endpoint.pp new file mode 100644 index 000000000..c713800f1 --- /dev/null +++ b/3rdparty/modules/keystone/manifests/endpoint.pp @@ -0,0 +1,160 @@ +# == Class: keystone::endpoint +# +# Creates the auth endpoints for keystone +# +# === Parameters +# +# [*public_url*] +# (optional) Public url for keystone endpoint. (Defaults to 'http://127.0.0.1:5000') +# This url should *not* contain any version or trailing '/'. +# +# [*internal_url*] +# (optional) Internal url for keystone endpoint. (Defaults to $public_url) +# This url should *not* contain any version or trailing '/'. +# +# [*admin_url*] +# (optional) Admin url for keystone endpoint. (Defaults to 'http://127.0.0.1:35357') +# This url should *not* contain any version or trailing '/'. +# +# [*region*] +# (optional) Region for endpoint. (Defaults to 'RegionOne') +# +# [*version*] +# (optional) API version for endpoint. Appended to all endpoint urls. (Defaults to 'v2.0') +# +# [*public_protocol*] +# (optional) DEPRECATED: Use public_url instead. +# Protocol for public access to keystone endpoint. (Defaults to 'http') +# Setting this parameter overrides public_url parameter. +# +# [*public_address*] +# (optional) DEPRECATED: Use public_url instead. +# Public address for keystone endpoint. (Defaults to '127.0.0.1') +# Setting this parameter overrides public_url parameter. +# +# [*public_port*] +# (optional) DEPRECATED: Use public_url instead. +# Port for non-admin access to keystone endpoint. (Defaults to 5000) +# Setting this parameter overrides public_url parameter. +# +# [*internal_address*] +# (optional) DEPRECATED: Use internal_url instead. +# Internal address for keystone endpoint. (Defaults to '127.0.0.1') +# Setting this parameter overrides internal_url parameter. +# +# [*internal_port*] +# (optional) DEPRECATED: Use internal_url instead. +# Port for internal access to keystone endpoint. (Defaults to $public_port) +# Setting this parameter overrides internal_url parameter. +# +# [*admin_address*] +# (optional) DEPRECATED: Use admin_url instead. +# Admin address for keystone endpoint. (Defaults to '127.0.0.1') +# Setting this parameter overrides admin_url parameter. +# +# [*admin_port*] +# (optional) DEPRECATED: Use admin_url instead. +# Port for admin access to keystone endpoint. (Defaults to 35357) +# Setting this parameter overrides admin_url parameter. +# +# === Deprecation notes +# +# If any value is provided for public_protocol, public_address or public_port parameters, +# public_url will be completely ignored. The same applies for internal and admin parameters. +# +# === Examples +# +# class { 'keystone::endpoint': +# public_url => 'https://154.10.10.23:5000', +# internal_url => 'https://11.0.1.7:5000', +# admin_url => 'https://10.0.1.7:35357', +# } +# +class keystone::endpoint ( + $public_url = 'http://127.0.0.1:5000', + $internal_url = undef, + $admin_url = 'http://127.0.0.1:35357', + $version = 'v2.0', + $region = 'RegionOne', + # DEPRECATED PARAMETERS + $public_protocol = undef, + $public_address = undef, + $public_port = undef, + $internal_address = undef, + $internal_port = undef, + $admin_address = undef, + $admin_port = undef, +) { + + warning('keystone::endpoint class is deprecated, use keystone::resource::service_identity instead.') + + if $public_port { + warning('The public_port parameter is deprecated, use public_url instead.') + } + + if $public_protocol { + warning('The public_protocol parameter is deprecated, use public_url instead.') + } + + if $public_address { + warning('The public_address parameter is deprecated, use public_url instead.') + } + + if $internal_address { + warning('The internal_address parameter is deprecated, use internal_url instead.') + } + + if $internal_port { + warning('The internal_port parameter is deprecated, use internal_url instead.') + } + + if $admin_address { + warning('The admin_address parameter is deprecated, use admin_url instead.') + } + + if $admin_port { + warning('The admin_port parameter is deprecated, use admin_url instead.') + } + + $public_url_real = inline_template('<%= + if (!@public_protocol.nil?) || (!@public_address.nil?) || (!@public_port.nil?) + @public_protocol ||= "http" + @public_address ||= "127.0.0.1" + @public_port ||= "5000" + "#{@public_protocol}://#{@public_address}:#{@public_port}/#{@version}" + else + "#{@public_url}/#{@version}" + end %>') + + $internal_url_real = inline_template('<%= + if (!@internal_address.nil?) || (!@internal_port.nil?) || (!@public_port.nil?) + @internal_address ||= @public_address ||= "127.0.0.1" + @internal_port ||= @public_port ||= "5000" + "http://#{@internal_address}:#{@internal_port}/#{@version}" + elsif (!@internal_url.nil?) + "#{@internal_url}/#{@version}" + else + "#{@public_url}/#{@version}" + end %>') + + $admin_url_real = inline_template('<%= + if (!@admin_address.nil?) || (!@admin_port.nil?) + @admin_address ||= "127.0.0.1" + @admin_port ||= "35357" + "http://#{@admin_address}:#{@admin_port}/#{@version}" + else + "#{@admin_url}/#{@version}" + end %>') + + keystone::resource::service_identity { 'keystone': + configure_user => false, + configure_user_role => false, + service_type => 'identity', + service_description => 'OpenStack Identity Service', + public_url => $public_url_real, + admin_url => $admin_url_real, + internal_url => $internal_url_real, + region => $region, + } + +} diff --git a/3rdparty/modules/keystone/manifests/init.pp b/3rdparty/modules/keystone/manifests/init.pp new file mode 100644 index 000000000..d43bcd2ee --- /dev/null +++ b/3rdparty/modules/keystone/manifests/init.pp @@ -0,0 +1,743 @@ +# +# Module for managing keystone config. +# +# == Parameters +# +# [package_ensure] Desired ensure state of packages. Optional. Defaults to present. +# accepts latest or specific versions. +# [bind_host] Host that keystone binds to. +# [bind_port] Port that keystone binds to. +# [public_port] +# [compute_port] +# [admin_port] +# [admin_port] Port that can be used for admin tasks. +# [admin_token] Admin token that can be used to authenticate as a keystone +# admin. Required. +# [verbose] Rather keystone should log at verbose level. Optional. +# Defaults to False. +# [debug] Rather keystone should log at debug level. Optional. +# Defaults to False. +# [use_syslog] Use syslog for logging. Optional. +# Defaults to False. +# [log_facility] Syslog facility to receive log lines. Optional. +# [catalog_type] Type of catalog that keystone uses to store endpoints,services. Optional. +# Defaults to sql. (Also accepts template) +# [catalog_driver] Catalog driver used by Keystone to store endpoints and services. Optional. +# Setting this value will override and ignore catalog_type. +# [catalog_template_file] Path to the catalog used if catalog_type equals 'template'. +# Defaults to '/etc/keystone/default_catalog.templates' +# [token_provider] Format keystone uses for tokens. Optional. +# Defaults to 'keystone.token.providers.uuid.Provider' +# Supports PKI and UUID. +# [token_driver] Driver to use for managing tokens. +# Optional. Defaults to 'keystone.token.persistence.backends.sql.Token' +# [token_expiration] Amount of time a token should remain valid (seconds). +# Optional. Defaults to 3600 (1 hour). +# [token_format] Deprecated: Use token_provider instead. +# [cache_dir] Directory created when token_provider is pki. Optional. +# Defaults to /var/cache/keystone. +# +# [memcache_servers] +# List of memcache servers in format of server:port. +# Used with token_driver 'keystone.token.backends.memcache.Token'. +# Optional. Defaults to false. Example: ['localhost:11211'] +# +# [cache_backend] +# Dogpile.cache backend module. It is recommended that Memcache with pooling +# (keystone.cache.memcache_pool) or Redis (dogpile.cache.redis) be used in production. +# This has no effects unless 'memcache_servers' is set. +# Optional. Defaults to 'keystone.common.cache.noop' +# +# [cache_backend_argument] +# List of arguments in format of argname:value supplied to the backend module. +# Specify this option once per argument to be passed to the dogpile.cache backend. +# This has no effects unless 'memcache_servers' is set. +# Optional. Default to undef. +# +# [debug_cache_backend] +# Extra debugging from the cache backend (cache keys, get/set/delete calls). +# This has no effects unless 'memcache_servers' is set. +# Optional. Default to false. +# +# [token_caching] +# Toggle for token system caching. This has no effects unless 'memcache_servers' is set. +# Optional. Default to true. +# +# [enabled] If the keystone services should be enabled. Optional. Default to true. +# +# [*database_connection*] +# (optional) Url used to connect to database. +# Defaults to sqlite:////var/lib/keystone/keystone.db +# +# [*sql_connection*] +# (optional) Deprecated. Use database_connection instead. +# +# [*database_idle_timeout*] +# (optional) Timeout when db connections should be reaped. +# Defaults to 200. +# +# [*idle_timeout*] +# (optional) Deprecated. Use database_idle_timeout instead. +# +# [enable_pki_setup] Enable call to pki_setup to generate the cert for signing pki tokens and +# revocation lists if it doesn't already exist. This generates a cert and key stored in file +# locations based on the signing_certfile and signing_keyfile paramters below. If you are +# providing your own signing cert, make this false. +# [signing_certfile] Location of the cert file for signing pki tokens and revocation lists. +# Optional. Note that if this file already exists (i.e. you are providing your own signing cert), +# the file will not be overwritten, even if enable_pki_setup is set to true. +# Default: /etc/keystone/ssl/certs/signing_cert.pem +# [signing_keyfile] Location of the key file for signing pki tokens and revocation lists. Optional. +# Note that if this file already exists (i.e. you are providing your own signing cert), the file +# will not be overwritten, even if enable_pki_setup is set to true. +# Default: /etc/keystone/ssl/private/signing_key.pem +# [signing_ca_certs] Use this CA certs file along with signing_certfile/signing_keyfile for +# signing pki tokens and revocation lists. Optional. Default: /etc/keystone/ssl/certs/ca.pem +# [signing_ca_key] Use this CA key file along with signing_certfile/signing_keyfile for signing +# pki tokens and revocation lists. Optional. Default: /etc/keystone/ssl/private/cakey.pem +# +# [*signing_cert_subject*] +# (optional) Certificate subject (auto generated certificate) for token signing. +# Defaults to '/C=US/ST=Unset/L=Unset/O=Unset/CN=www.example.com' +# +# [*signing_key_size*] +# (optional) Key size (in bits) for token signing cert (auto generated certificate) +# Defaults to 2048 +# +# [rabbit_host] Location of rabbitmq installation. Optional. Defaults to localhost. +# [rabbit_port] Port for rabbitmq instance. Optional. Defaults to 5672. +# [rabbit_hosts] Location of rabbitmq installation. Optional. Defaults to undef. +# [rabbit_password] Password used to connect to rabbitmq. Optional. Defaults to guest. +# [rabbit_userid] User used to connect to rabbitmq. Optional. Defaults to guest. +# [rabbit_virtual_host] The RabbitMQ virtual host. Optional. Defaults to /. +# +# [*rabbit_use_ssl*] +# (optional) Connect over SSL for RabbitMQ +# Defaults to false +# +# [*kombu_ssl_ca_certs*] +# (optional) SSL certification authority file (valid only if SSL enabled). +# Defaults to undef +# +# [*kombu_ssl_certfile*] +# (optional) SSL cert file (valid only if SSL enabled). +# Defaults to undef +# +# [*kombu_ssl_keyfile*] +# (optional) SSL key file (valid only if SSL enabled). +# Defaults to undef +# +# [*kombu_ssl_version*] +# (optional) SSL version to use (valid only if SSL enabled). +# Valid values are TLSv1, SSLv23 and SSLv3. SSLv2 may be +# available on some distributions. +# Defaults to 'TLSv1' +# +# [notification_driver] RPC driver. Not enabled by default +# [notification_topics] AMQP topics to publish to when using the RPC notification driver. +# [control_exchange] AMQP exchange to connect to if using RabbitMQ or Qpid +# +# [*public_bind_host*] +# (optional) The IP address of the public network interface to listen on +# Deprecates bind_host +# Default to '0.0.0.0'. +# +# [*admin_bind_host*] +# (optional) The IP address of the public network interface to listen on +# Deprecates bind_host +# Default to '0.0.0.0'. +# +# [*log_dir*] +# (optional) Directory where logs should be stored +# If set to boolean false, it will not log to any directory +# Defaults to '/var/log/keystone' +# +# [*log_file*] +# (optional) Where to log +# Defaults to false +# +# [*public_endpoint*] +# (optional) The base public endpoint URL for keystone that are +# advertised to clients (NOTE: this does NOT affect how +# keystone listens for connections) (string value) +# If set to false, no public_endpoint will be defined in keystone.conf. +# Sample value: 'http://localhost:5000/' +# Defaults to false +# +# [*admin_endpoint*] +# (optional) The base admin endpoint URL for keystone that are +# advertised to clients (NOTE: this does NOT affect how keystone listens +# for connections) (string value) +# If set to false, no admin_endpoint will be defined in keystone.conf. +# Sample value: 'http://localhost:35357/' +# Defaults to false +# +# [*enable_ssl*] +# (optional) Toggle for SSL support on the keystone eventlet servers. +# (boolean value) +# Defaults to false +# +# [*ssl_certfile*] +# (optional) Path of the certfile for SSL. (string value) +# Defaults to '/etc/keystone/ssl/certs/keystone.pem' +# +# [*ssl_keyfile*] +# (optional) Path of the keyfile for SSL. (string value) +# Defaults to '/etc/keystone/ssl/private/keystonekey.pem' +# +# [*ssl_ca_certs*] +# (optional) Path of the ca cert file for SSL. (string value) +# Defaults to '/etc/keystone/ssl/certs/ca.pem' +# +# [*ssl_ca_key*] +# (optional) Path of the CA key file for SSL (string value) +# Defaults to '/etc/keystone/ssl/private/cakey.pem' +# +# [*ssl_cert_subject*] +# (optional) SSL Certificate Subject (auto generated certificate) +# (string value) +# Defaults to '/C=US/ST=Unset/L=Unset/O=Unset/CN=localhost' +# +# [*mysql_module*] +# (optional) Deprecated. Does nothing. +# +# [*validate_service*] +# (optional) Whether to validate keystone connections after +# the service is started. +# Defaults to false +# +# [*validate_insecure*] +# (optional) Whether to validate keystone connections +# using the --insecure option with keystone client. +# Defaults to false +# +# [*validate_cacert*] +# (optional) Whether to validate keystone connections +# using the specified argument with the --os-cacert option +# with keystone client. +# Defaults to undef +# +# [*validate_auth_url*] +# (optional) The url to validate keystone against +# Defaults to undef +# +# [*service_provider*] +# (optional) Provider, that can be used for keystone service. +# Default value defined in keystone::params for given operation system. +# If you use Pacemaker or another Cluster Resource Manager, you can make +# custom service provider for changing start/stop/status behavior of service, +# and set it here. +# +# [*service_name*] +# (optional) Name of the service that will be providing the +# server functionality of keystone. For example, the default +# is just 'keystone', which means keystone will be run as a +# standalone eventlet service, and will able to be managed +# separately by the operating system's service manager. For +# example, you will be able to use +# service openstack-keystone restart +# to restart the service. +# If the value is 'httpd', this means keystone will be a web +# service, and you must use another class to configure that +# web service. For example, after calling class {'keystone'...} +# use class { 'keystone::wsgi::apache'...} to make keystone be +# a web app using apache mod_wsgi. +# Defaults to 'keystone' +# NOTE: validate_service only applies if the value is 'keystone' +# +# == Dependencies +# None +# +# == Examples +# +# class { 'keystone': +# log_verbose => 'True', +# admin_token => 'my_special_token', +# } +# +# OR +# +# class { 'keystone': +# ... +# service_name => 'httpd', +# ... +# } +# class { 'keystone::wsgi::apache': +# ... +# } +# +# == Authors +# +# Dan Bode dan@puppetlabs.com +# +# == Copyright +# +# Copyright 2012 Puppetlabs Inc, unless otherwise noted. +# +class keystone( + $admin_token, + $package_ensure = 'present', + $bind_host = false, + $public_bind_host = '0.0.0.0', + $admin_bind_host = '0.0.0.0', + $public_port = '5000', + $admin_port = '35357', + $compute_port = '8774', + $verbose = false, + $debug = false, + $log_dir = '/var/log/keystone', + $log_file = false, + $use_syslog = false, + $log_facility = 'LOG_USER', + $catalog_type = 'sql', + $catalog_driver = false, + $catalog_template_file = '/etc/keystone/default_catalog.templates', + $token_format = false, + $token_provider = 'keystone.token.providers.uuid.Provider', + $token_driver = 'keystone.token.persistence.backends.sql.Token', + $token_expiration = 3600, + $public_endpoint = false, + $admin_endpoint = false, + $enable_ssl = false, + $ssl_certfile = '/etc/keystone/ssl/certs/keystone.pem', + $ssl_keyfile = '/etc/keystone/ssl/private/keystonekey.pem', + $ssl_ca_certs = '/etc/keystone/ssl/certs/ca.pem', + $ssl_ca_key = '/etc/keystone/ssl/private/cakey.pem', + $ssl_cert_subject = '/C=US/ST=Unset/L=Unset/O=Unset/CN=localhost', + $cache_dir = '/var/cache/keystone', + $memcache_servers = false, + $cache_backend = 'keystone.common.cache.noop', + $cache_backend_argument = undef, + $debug_cache_backend = false, + $token_caching = true, + $enabled = true, + $database_connection = 'sqlite:////var/lib/keystone/keystone.db', + $database_idle_timeout = '200', + $enable_pki_setup = true, + $signing_certfile = '/etc/keystone/ssl/certs/signing_cert.pem', + $signing_keyfile = '/etc/keystone/ssl/private/signing_key.pem', + $signing_ca_certs = '/etc/keystone/ssl/certs/ca.pem', + $signing_ca_key = '/etc/keystone/ssl/private/cakey.pem', + $signing_cert_subject = '/C=US/ST=Unset/L=Unset/O=Unset/CN=www.example.com', + $signing_key_size = 2048, + $rabbit_host = 'localhost', + $rabbit_hosts = false, + $rabbit_password = 'guest', + $rabbit_port = '5672', + $rabbit_userid = 'guest', + $rabbit_virtual_host = '/', + $rabbit_use_ssl = false, + $kombu_ssl_ca_certs = undef, + $kombu_ssl_certfile = undef, + $kombu_ssl_keyfile = undef, + $kombu_ssl_version = 'TLSv1', + $notification_driver = false, + $notification_topics = false, + $control_exchange = false, + $validate_service = false, + $validate_insecure = false, + $validate_auth_url = false, + $validate_cacert = undef, + $service_provider = $::keystone::params::service_provider, + $service_name = 'keystone', + # DEPRECATED PARAMETERS + $mysql_module = undef, + $sql_connection = undef, + $idle_timeout = undef, +) inherits keystone::params { + + if ! $catalog_driver { + validate_re($catalog_type, 'template|sql') + } + + if $mysql_module { + warning('The mysql_module parameter is deprecated. The latest 2.x mysql module will be used.') + } + + if $sql_connection { + warning('The sql_connection parameter is deprecated, use database_connection instead.') + $database_connection_real = $sql_connection + } else { + $database_connection_real = $database_connection + } + + if $idle_timeout { + warning('The idle_timeout parameter is deprecated, use database_idle_timeout instead.') + $database_idle_timeout_real = $idle_timeout + } else { + $database_idle_timeout_real = $database_idle_timeout + } + + if ($admin_endpoint and 'v2.0' in $admin_endpoint) { + warning('Version string /v2.0/ should not be included in keystone::admin_endpoint') + } + + if ($public_endpoint and 'v2.0' in $public_endpoint) { + warning('Version string /v2.0/ should not be included in keystone::public_endpoint') + } + + if $rabbit_use_ssl { + if !$kombu_ssl_ca_certs { + fail('The kombu_ssl_ca_certs parameter is required when rabbit_use_ssl is set to true') + } + if !$kombu_ssl_certfile { + fail('The kombu_ssl_certfile parameter is required when rabbit_use_ssl is set to true') + } + if !$kombu_ssl_keyfile { + fail('The kombu_ssl_keyfile parameter is required when rabbit_use_ssl is set to true') + } + } + + File['/etc/keystone/keystone.conf'] -> Keystone_config<||> ~> Service[$service_name] + Keystone_config<||> ~> Exec<| title == 'keystone-manage db_sync'|> + Keystone_config<||> ~> Exec<| title == 'keystone-manage pki_setup'|> + include ::keystone::params + + package { 'keystone': + ensure => $package_ensure, + name => $::keystone::params::package_name, + tag => 'openstack', + } + # TODO: Move this to openstacklib::openstackclient in Kilo + package { 'python-openstackclient': + ensure => present, + tag => 'openstack', + } + + group { 'keystone': + ensure => present, + system => true, + require => Package['keystone'], + } + + user { 'keystone': + ensure => 'present', + gid => 'keystone', + system => true, + require => Package['keystone'], + } + + file { ['/etc/keystone', '/var/log/keystone', '/var/lib/keystone']: + ensure => directory, + mode => '0750', + owner => 'keystone', + group => 'keystone', + require => Package['keystone'], + notify => Service[$service_name], + } + + file { '/etc/keystone/keystone.conf': + ensure => present, + mode => '0600', + owner => 'keystone', + group => 'keystone', + require => Package['keystone'], + notify => Service[$service_name], + } + + if $bind_host { + warning('The bind_host parameter is deprecated, use public_bind_host and admin_bind_host instead.') + $public_bind_host_real = $bind_host + $admin_bind_host_real = $bind_host + } else { + $public_bind_host_real = $public_bind_host + $admin_bind_host_real = $admin_bind_host + } + + # default config + keystone_config { + 'DEFAULT/admin_token': value => $admin_token, secret => true; + 'DEFAULT/public_bind_host': value => $public_bind_host_real; + 'DEFAULT/admin_bind_host': value => $admin_bind_host_real; + 'DEFAULT/public_port': value => $public_port; + 'DEFAULT/admin_port': value => $admin_port; + 'DEFAULT/compute_port': value => $compute_port; + 'DEFAULT/verbose': value => $verbose; + 'DEFAULT/debug': value => $debug; + } + + # Endpoint configuration + if $public_endpoint { + keystone_config { + 'DEFAULT/public_endpoint': value => $public_endpoint; + } + } else { + keystone_config { + 'DEFAULT/public_endpoint': ensure => absent; + } + } + if $admin_endpoint { + keystone_config { + 'DEFAULT/admin_endpoint': value => $admin_endpoint; + } + } else { + keystone_config { + 'DEFAULT/admin_endpoint': ensure => absent; + } + } + # requirements for memcache token driver + if ($token_driver =~ /memcache/ ) { + package { 'python-memcache': + ensure => present, + name => $::keystone::params::python_memcache_package_name, + } + } + + # token driver config + keystone_config { + 'token/driver': value => $token_driver; + 'token/expiration': value => $token_expiration; + } + + # ssl config + if ($enable_ssl) { + keystone_config { + 'ssl/enable': value => true; + 'ssl/certfile': value => $ssl_certfile; + 'ssl/keyfile': value => $ssl_keyfile; + 'ssl/ca_certs': value => $ssl_ca_certs; + 'ssl/ca_key': value => $ssl_ca_key; + 'ssl/cert_subject': value => $ssl_cert_subject; + } + } else { + keystone_config { + 'ssl/enable': value => false; + } + } + + if($database_connection_real =~ /mysql:\/\/\S+:\S+@\S+\/\S+/) { + require 'mysql::bindings' + require 'mysql::bindings::python' + } elsif($database_connection_real =~ /postgresql:\/\/\S+:\S+@\S+\/\S+/) { + + } elsif($database_connection_real =~ /sqlite:\/\//) { + + } else { + fail("Invalid db connection ${database_connection_real}") + } + + # memcache connection config + if $memcache_servers { + validate_array($memcache_servers) + Service<| title == 'memcached' |> -> Service['keystone'] + keystone_config { + 'cache/enabled': value => true; + 'cache/backend': value => $cache_backend; + 'cache/debug_cache_backend': value => $debug_cache_backend; + 'token/caching': value => $token_caching; + 'memcache/servers': value => join($memcache_servers, ','); + } + if $cache_backend_argument { + validate_array($cache_backend_argument) + keystone_config { + 'cache/backend_argument': value => join($cache_backend_argument, ','); + } + } else { + keystone_config { + 'cache/backend_argument': ensure => absent; + } + } + } else { + keystone_config { + 'cache/enabled': ensure => absent; + 'cache/backend': ensure => absent; + 'cache/backend_argument': ensure => absent; + 'cache/debug_cache_backend': ensure => absent; + 'token/caching': ensure => absent; + 'memcache/servers': ensure => absent; + } + } + + # db connection config + keystone_config { + 'database/connection': value => $database_connection_real, secret => true; + 'database/idle_timeout': value => $database_idle_timeout_real; + } + + # configure based on the catalog backend + if $catalog_driver { + $catalog_driver_real = $catalog_driver + } + elsif ($catalog_type == 'template') { + $catalog_driver_real = 'keystone.catalog.backends.templated.Catalog' + } + elsif ($catalog_type == 'sql') { + $catalog_driver_real = 'keystone.catalog.backends.sql.Catalog' + } + + keystone_config { + 'catalog/driver': value => $catalog_driver_real; + 'catalog/template_file': value => $catalog_template_file; + } + + if $token_format { + warning('token_format parameter is deprecated. Use token_provider instead.') + } + + # remove the old format in case of an upgrade + keystone_config { 'signing/token_format': ensure => absent } + + # Set the signing key/cert configuration values. + keystone_config { + 'signing/certfile': value => $signing_certfile; + 'signing/keyfile': value => $signing_keyfile; + 'signing/ca_certs': value => $signing_ca_certs; + 'signing/ca_key': value => $signing_ca_key; + 'signing/cert_subject': value => $signing_cert_subject; + 'signing/key_size': value => $signing_key_size; + } + + # Create cache directory used for signing. + file { $cache_dir: + ensure => directory, + } + + # Only do pki_setup if we were asked to do so. This is needed + # regardless of the token provider since token revocation lists + # are always signed. + if $enable_pki_setup { + exec { 'keystone-manage pki_setup': + path => '/usr/bin', + user => 'keystone', + refreshonly => true, + creates => $signing_keyfile, + notify => Service[$service_name], + subscribe => Package['keystone'], + require => User['keystone'], + } + } + + if ($token_format == false and $token_provider == 'keystone.token.providers.pki.Provider') or $token_format == 'PKI' { + keystone_config { 'token/provider': value => 'keystone.token.providers.pki.Provider' } + } elsif $token_format == 'UUID' { + keystone_config { 'token/provider': value => 'keystone.token.providers.uuid.Provider' } + } else { + keystone_config { 'token/provider': value => $token_provider } + } + + if $notification_driver { + keystone_config { 'DEFAULT/notification_driver': value => $notification_driver } + } else { + keystone_config { 'DEFAULT/notification_driver': ensure => absent } + } + if $notification_topics { + keystone_config { 'DEFAULT/notification_topics': value => $notification_topics } + } else { + keystone_config { 'DEFAULT/notification_topics': ensure => absent } + } + if $control_exchange { + keystone_config { 'DEFAULT/control_exchange': value => $control_exchange } + } else { + keystone_config { 'DEFAULT/control_exchange': ensure => absent } + } + + keystone_config { + 'DEFAULT/rabbit_password': value => $rabbit_password, secret => true; + 'DEFAULT/rabbit_userid': value => $rabbit_userid; + 'DEFAULT/rabbit_virtual_host': value => $rabbit_virtual_host; + } + + if $rabbit_hosts { + keystone_config { 'DEFAULT/rabbit_hosts': value => join($rabbit_hosts, ',') } + keystone_config { 'DEFAULT/rabbit_ha_queues': value => true } + } else { + keystone_config { 'DEFAULT/rabbit_host': value => $rabbit_host } + keystone_config { 'DEFAULT/rabbit_port': value => $rabbit_port } + keystone_config { 'DEFAULT/rabbit_hosts': value => "${rabbit_host}:${rabbit_port}" } + keystone_config { 'DEFAULT/rabbit_ha_queues': value => false } + } + + keystone_config { 'DEFAULT/rabbit_use_ssl': value => $rabbit_use_ssl } + if $rabbit_use_ssl { + keystone_config { + 'DEFAULT/kombu_ssl_ca_certs': value => $kombu_ssl_ca_certs; + 'DEFAULT/kombu_ssl_certfile': value => $kombu_ssl_certfile; + 'DEFAULT/kombu_ssl_keyfile': value => $kombu_ssl_keyfile; + 'DEFAULT/kombu_ssl_version': value => $kombu_ssl_version; + } + } else { + keystone_config { + 'DEFAULT/kombu_ssl_ca_certs': ensure => absent; + 'DEFAULT/kombu_ssl_certfile': ensure => absent; + 'DEFAULT/kombu_ssl_keyfile': ensure => absent; + 'DEFAULT/kombu_ssl_version': ensure => absent; + } + } + + if $enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + + if $service_name == 'keystone' { + if $validate_service { + if $validate_auth_url { + $v_auth_url = $validate_auth_url + } else { + $v_auth_url = $admin_endpoint + } + + class { 'keystone::service': + ensure => $service_ensure, + service_name => $::keystone::params::service_name, + enable => $enabled, + hasstatus => true, + hasrestart => true, + provider => $service_provider, + validate => true, + admin_endpoint => $v_auth_url, + admin_token => $admin_token, + insecure => $validate_insecure, + cacert => $validate_cacert, + } + } else { + class { 'keystone::service': + ensure => $service_ensure, + service_name => $::keystone::params::service_name, + enable => $enabled, + hasstatus => true, + hasrestart => true, + provider => $service_provider, + validate => false, + } + } + } + + if $enabled { + include ::keystone::db::sync + Class['::keystone::db::sync'] ~> Service[$service_name] + } + + # Syslog configuration + if $use_syslog { + keystone_config { + 'DEFAULT/use_syslog': value => true; + 'DEFAULT/syslog_log_facility': value => $log_facility; + } + } else { + keystone_config { + 'DEFAULT/use_syslog': value => false; + } + } + + if $log_file { + keystone_config { + 'DEFAULT/log_file': value => $log_file; + 'DEFAULT/log_dir': value => $log_dir; + } + } else { + if $log_dir { + keystone_config { + 'DEFAULT/log_dir': value => $log_dir; + 'DEFAULT/log_file': ensure => absent; + } + } else { + keystone_config { + 'DEFAULT/log_dir': ensure => absent; + 'DEFAULT/log_file': ensure => absent; + } + } + } + +} diff --git a/3rdparty/modules/keystone/manifests/ldap.pp b/3rdparty/modules/keystone/manifests/ldap.pp new file mode 100644 index 000000000..96ec8cd0a --- /dev/null +++ b/3rdparty/modules/keystone/manifests/ldap.pp @@ -0,0 +1,397 @@ +# +# Implements ldap configuration for keystone. +# +# == Dependencies +# == Examples +# == Authors +# +# Dan Bode dan@puppetlabs.com +# Matt Fischer matt.fischer@twcable.com +# +# == Copyright +# +# Copyright 2012 Puppetlabs Inc, unless otherwise noted. +# +class keystone::ldap( + $url = undef, + $user = undef, + $password = undef, + $suffix = undef, + $query_scope = undef, + $page_size = undef, + $user_tree_dn = undef, + $user_filter = undef, + $user_objectclass = undef, + $user_id_attribute = undef, + $user_name_attribute = undef, + $user_mail_attribute = undef, + $user_enabled_attribute = undef, + $user_enabled_mask = undef, + $user_enabled_default = undef, + $user_enabled_invert = undef, + $user_attribute_ignore = undef, + $user_default_project_id_attribute = undef, + $user_allow_create = undef, + $user_allow_update = undef, + $user_allow_delete = undef, + $user_pass_attribute = undef, + $user_enabled_emulation = undef, + $user_enabled_emulation_dn = undef, + $user_additional_attribute_mapping = undef, + $tenant_tree_dn = undef, #DEPRECATED + $project_tree_dn = undef, + $tenant_filter = undef, #DEPRECATED + $project_filter = undef, + $tenant_objectclass = undef, #DEPRECATED + $project_objectclass = undef, + $tenant_id_attribute = undef, #DEPRECATED + $project_id_attribute = undef, + $tenant_member_attribute = undef, #DEPRECATED + $project_member_attribute = undef, + $tenant_desc_attribute = undef, #DEPRECATED + $project_desc_attribute = undef, + $tenant_name_attribute = undef, #DEPRECATED + $project_name_attribute = undef, + $tenant_enabled_attribute = undef, #DEPRECATED + $project_enabled_attribute = undef, + $tenant_domain_id_attribute = undef, #DEPRECATED + $project_domain_id_attribute = undef, + $tenant_attribute_ignore = undef, #DEPRECATED + $project_attribute_ignore = undef, + $tenant_allow_create = undef, #DEPRECATED + $project_allow_create = undef, + $tenant_allow_update = undef, #DEPRECATED + $project_allow_update = undef, + $tenant_allow_delete = undef, #DEPRECATED + $project_allow_delete = undef, + $tenant_enabled_emulation = undef, #DEPRECATED + $project_enabled_emulation = undef, + $tenant_enabled_emulation_dn = undef, #DEPRECATED + $project_enabled_emulation_dn = undef, + $tenant_additional_attribute_mapping = undef, #DEPRECATED + $project_additional_attribute_mapping= undef, + $role_tree_dn = undef, + $role_filter = undef, + $role_objectclass = undef, + $role_id_attribute = undef, + $role_name_attribute = undef, + $role_member_attribute = undef, + $role_attribute_ignore = undef, + $role_allow_create = undef, + $role_allow_update = undef, + $role_allow_delete = undef, + $role_additional_attribute_mapping = undef, + $group_tree_dn = undef, + $group_filter = undef, + $group_objectclass = undef, + $group_id_attribute = undef, + $group_name_attribute = undef, + $group_member_attribute = undef, + $group_desc_attribute = undef, + $group_attribute_ignore = undef, + $group_allow_create = undef, + $group_allow_update = undef, + $group_allow_delete = undef, + $group_additional_attribute_mapping = undef, + $use_tls = undef, + $tls_cacertdir = undef, + $tls_cacertfile = undef, + $tls_req_cert = undef, + $identity_driver = undef, + $assignment_driver = undef, + $use_pool = false, + $pool_size = 10, + $pool_retry_max = 3, + $pool_retry_delay = 0.1, + $pool_connection_timeout = -1, + $pool_connection_lifetime = 600, + $use_auth_pool = false, + $auth_pool_size = 100, + $auth_pool_connection_lifetime = 60, +) { + + # In Juno the term "tenant" was deprecated in the config in favor of "project" + # Let's assume project_ is being used and warning otherwise. If both are set we will + # fail, because having both set may cause unexpected results in Keystone. + if ($tenant_tree_dn) { + $project_tree_dn_real = $tenant_tree_dn + warning ('tenant_tree_dn is deprecated in Juno. switch to project_tree_dn') + if ($project_tree_dn) { + fail ('tenant_tree_dn and project_tree_dn are both set. results may be unexpected') + } + } + else { + $project_tree_dn_real = $project_tree_dn + } + + if ($tenant_filter) { + $project_filter_real = $tenant_filter + warning ('tenant_filter is deprecated in Juno. switch to project_filter') + if ($project_filter) { + fail ('tenant_filter and project_filter are both set. results may be unexpected') + } + } + else { + $project_filter_real = $project_filter + } + + if ($tenant_objectclass) { + $project_objectclass_real = $tenant_objectclass + warning ('tenant_objectclass is deprecated in Juno. switch to project_objectclass') + if ($project_objectclass) { + fail ('tenant_objectclass and project_objectclass are both set. results may be unexpected') + } + } + else { + $project_objectclass_real = $project_objectclass + } + + if ($tenant_id_attribute) { + $project_id_attribute_real = $tenant_id_attribute + warning ('tenant_id_attribute is deprecated in Juno. switch to project_id_attribute') + if ($project_id_attribute) { + fail ('tenant_id_attribute and project_id_attribute are both set. results may be unexpected') + } + } + else { + $project_id_attribute_real = $project_id_attribute + } + + if ($tenant_member_attribute) { + $project_member_attribute_real = $tenant_member_attribute + warning ('tenant_member_attribute is deprecated in Juno. switch to project_member_attribute') + if ($project_member_attribute) { + fail ('tenant_member_attribute and project_member_attribute are both set. results may be unexpected') + } + } + else { + $project_member_attribute_real = $project_member_attribute + } + + if ($tenant_desc_attribute) { + $project_desc_attribute_real = $tenant_desc_attribute + warning ('tenant_desc_attribute is deprecated in Juno. switch to project_desc_attribute') + if ($project_desc_attribute) { + fail ('tenant_desc_attribute and project_desc_attribute are both set. results may be unexpected') + } + } + else { + $project_desc_attribute_real = $project_desc_attribute + } + + if ($tenant_name_attribute) { + $project_name_attribute_real = $tenant_name_attribute + warning ('tenant_name_attribute is deprecated in Juno. switch to project_name_attribute') + if ($project_name_attribute) { + fail ('tenant_name_attribute and project_name_attribute are both set. results may be unexpected') + } + } + else { + $project_name_attribute_real = $project_name_attribute + } + + if ($tenant_enabled_attribute) { + $project_enabled_attribute_real = $tenant_enabled_attribute + warning ('tenant_enabled_attribute is deprecated in Juno. switch to project_enabled_attribute') + if ($project_enabled_attribute) { + fail ('tenant_enabled_attribute and project_enabled_attribute are both set. results may be unexpected') + } + } + else { + $project_enabled_attribute_real = $project_enabled_attribute + } + + if ($tenant_attribute_ignore) { + $project_attribute_ignore_real = $tenant_attribute_ignore + warning ('tenant_attribute_ignore is deprecated in Juno. switch to project_attribute_ignore') + if ($project_attribute_ignore) { + fail ('tenant_attribute_ignore and project_attribute_ignore are both set. results may be unexpected') + } + } + else { + $project_attribute_ignore_real = $project_attribute_ignore + } + + if ($tenant_domain_id_attribute) { + $project_domain_id_attribute_real = $tenant_domain_id_attribute + warning ('tenant_domain_id_attribute is deprecated in Juno. switch to project_domain_id_attribute') + if ($project_domain_id_attribute) { + fail ('tenant_domain_id_attribute and project_domain_id_attribute are both set. results may be unexpected') + } + } + else { + $project_domain_id_attribute_real = $project_domain_id_attribute + } + + if ($tenant_allow_create) { + $project_allow_create_real = $tenant_allow_create + warning ('tenant_allow_create is deprecated in Juno. switch to project_allow_create') + if ($project_allow_create) { + fail ('tenant_allow_create and project_allow_create are both set. results may be unexpected') + } + } + else { + $project_allow_create_real = $project_allow_create + } + + if ($tenant_allow_update) { + $project_allow_update_real = $tenant_allow_update + warning ('tenant_allow_update is deprecated in Juno. switch to project_allow_update') + if ($project_allow_update) { + fail ('tenant_allow_update and project_allow_update are both set. results may be unexpected') + } + } + else { + $project_allow_update_real = $project_allow_update + } + + if ($tenant_allow_delete) { + $project_allow_delete_real = $tenant_allow_delete + warning ('tenant_allow_delete is deprecated in Juno. switch to project_allow_delete') + if ($project_allow_delete) { + fail ('tenant_allow_delete and project_allow_delete are both set. results may be unexpected') + } + } + else { + $project_allow_delete_real = $project_allow_delete + } + + if ($tenant_enabled_emulation) { + $project_enabled_emulation_real = $tenant_enabled_emulation + warning ('tenant_enabled_emulation is deprecated in Juno. switch to project_enabled_emulation') + if ($project_enabled_emulation) { + fail ('tenant_enabled_emulation and project_enabled_emulation are both set. results may be unexpected') + } + } + else { + $project_enabled_emulation_real = $project_enabled_emulation + } + + if ($tenant_enabled_emulation_dn) { + $project_enabled_emulation_dn_real = $tenant_enabled_emulation_dn + warning ('tenant_enabled_emulation_dn is deprecated in Juno. switch to project_enabled_emulation_dn') + if ($project_enabled_emulation_dn) { + fail ('tenant_enabled_emulation_dn and project_enabled_emulation_dn are both set. results may be unexpected') + } + } + else { + $project_enabled_emulation_dn_real = $project_enabled_emulation_dn + } + + if ($tenant_additional_attribute_mapping) { + $project_additional_attribute_mapping_real = $tenant_additional_attribute_mapping + warning ('tenant_additional_attribute_mapping is deprecated in Juno. switch to project_additional_attribute_mapping') + if ($project_additional_attribute_mapping) { + fail ('tenant_additional_attribute_mapping and project_additional_attribute_mapping are both set. results may be unexpected') + } + } + else { + $project_additional_attribute_mapping_real = $project_additional_attribute_mapping + } + + $ldap_packages = ['python-ldap', 'python-ldappool'] + package { $ldap_packages: + ensure => present, + } + + # check for some common driver name mistakes + if ($assignment_driver != undef) { + if ! ($assignment_driver =~ /^keystone.assignment.backends.*Assignment$/) { + fail('assigment driver should be of the form \'keystone.assignment.backends.*Assignment\'') + } + } + + if ($identity_driver != undef) { + if ! ($identity_driver =~ /^keystone.identity.backends.*Identity$/) { + fail('identity driver should be of the form \'keystone.identity.backends.*Identity\'') + } + } + + if ($tls_cacertdir != undef) { + file { $tls_cacertdir: + ensure => directory + } + } + + keystone_config { + 'ldap/url': value => $url; + 'ldap/user': value => $user; + 'ldap/password': value => $password, secret => true; + 'ldap/suffix': value => $suffix; + 'ldap/query_scope': value => $query_scope; + 'ldap/page_size': value => $page_size; + 'ldap/user_tree_dn': value => $user_tree_dn; + 'ldap/user_filter': value => $user_filter; + 'ldap/user_objectclass': value => $user_objectclass; + 'ldap/user_id_attribute': value => $user_id_attribute; + 'ldap/user_name_attribute': value => $user_name_attribute; + 'ldap/user_mail_attribute': value => $user_mail_attribute; + 'ldap/user_enabled_attribute': value => $user_enabled_attribute; + 'ldap/user_enabled_mask': value => $user_enabled_mask; + 'ldap/user_enabled_default': value => $user_enabled_default; + 'ldap/user_enabled_invert': value => $user_enabled_invert; + 'ldap/user_attribute_ignore': value => $user_attribute_ignore; + 'ldap/user_default_project_id_attribute': value => $user_default_project_id_attribute; + 'ldap/user_allow_create': value => $user_allow_create; + 'ldap/user_allow_update': value => $user_allow_update; + 'ldap/user_allow_delete': value => $user_allow_delete; + 'ldap/user_pass_attribute': value => $user_pass_attribute; + 'ldap/user_enabled_emulation': value => $user_enabled_emulation; + 'ldap/user_enabled_emulation_dn': value => $user_enabled_emulation_dn; + 'ldap/user_additional_attribute_mapping': value => $user_additional_attribute_mapping; + 'ldap/project_tree_dn': value => $project_tree_dn_real; + 'ldap/project_filter': value => $project_filter_real; + 'ldap/project_objectclass': value => $project_objectclass_real; + 'ldap/project_id_attribute': value => $project_id_attribute_real; + 'ldap/project_member_attribute': value => $project_member_attribute_real; + 'ldap/project_desc_attribute': value => $project_desc_attribute_real; + 'ldap/project_name_attribute': value => $project_name_attribute_real; + 'ldap/project_enabled_attribute': value => $project_enabled_attribute_real; + 'ldap/project_attribute_ignore': value => $project_attribute_ignore_real; + 'ldap/project_domain_id_attribute': value => $project_domain_id_attribute_real; + 'ldap/project_allow_create': value => $project_allow_create_real; + 'ldap/project_allow_update': value => $project_allow_update_real; + 'ldap/project_allow_delete': value => $project_allow_delete_real; + 'ldap/project_enabled_emulation': value => $project_enabled_emulation_real; + 'ldap/project_enabled_emulation_dn': value => $project_enabled_emulation_dn_real; + 'ldap/project_additional_attribute_mapping': value => $project_additional_attribute_mapping_real; + 'ldap/role_tree_dn': value => $role_tree_dn; + 'ldap/role_filter': value => $role_filter; + 'ldap/role_objectclass': value => $role_objectclass; + 'ldap/role_id_attribute': value => $role_id_attribute; + 'ldap/role_name_attribute': value => $role_name_attribute; + 'ldap/role_member_attribute': value => $role_member_attribute; + 'ldap/role_attribute_ignore': value => $role_attribute_ignore; + 'ldap/role_allow_create': value => $role_allow_create; + 'ldap/role_allow_update': value => $role_allow_update; + 'ldap/role_allow_delete': value => $role_allow_delete; + 'ldap/role_additional_attribute_mapping': value => $role_additional_attribute_mapping; + 'ldap/group_tree_dn': value => $group_tree_dn; + 'ldap/group_filter': value => $group_filter; + 'ldap/group_objectclass': value => $group_objectclass; + 'ldap/group_id_attribute': value => $group_id_attribute; + 'ldap/group_name_attribute': value => $group_name_attribute; + 'ldap/group_member_attribute': value => $group_member_attribute; + 'ldap/group_desc_attribute': value => $group_desc_attribute; + 'ldap/group_attribute_ignore': value => $group_attribute_ignore; + 'ldap/group_allow_create': value => $group_allow_create; + 'ldap/group_allow_update': value => $group_allow_update; + 'ldap/group_allow_delete': value => $group_allow_delete; + 'ldap/group_additional_attribute_mapping': value => $group_additional_attribute_mapping; + 'ldap/use_tls': value => $use_tls; + 'ldap/tls_cacertdir': value => $tls_cacertdir; + 'ldap/tls_cacertfile': value => $tls_cacertfile; + 'ldap/tls_req_cert': value => $tls_req_cert; + 'ldap/use_pool': value => $use_pool; + 'ldap/pool_size': value => $pool_size; + 'ldap/pool_retry_max': value => $pool_retry_max; + 'ldap/pool_retry_delay': value => $pool_retry_delay; + 'ldap/pool_connection_timeout': value => $pool_connection_timeout; + 'ldap/pool_connection_lifetime': value => $pool_connection_lifetime; + 'ldap/use_auth_pool': value => $use_auth_pool; + 'ldap/auth_pool_size': value => $auth_pool_size; + 'ldap/auth_pool_connection_lifetime': value => $auth_pool_connection_lifetime; + 'identity/driver': value => $identity_driver; + 'assignment/driver': value => $assignment_driver; + } +} diff --git a/3rdparty/modules/keystone/manifests/logging.pp b/3rdparty/modules/keystone/manifests/logging.pp new file mode 100644 index 000000000..dade7df73 --- /dev/null +++ b/3rdparty/modules/keystone/manifests/logging.pp @@ -0,0 +1,211 @@ +# Class keystone::logging +# +# keystone extended logging configuration +# +# == parameters +# +# [*logging_context_format_string*] +# (optional) Format string to use for log messages with context. +# Defaults to undef. +# Example: '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s\ +# [%(request_id)s %(user_identity)s] %(instance)s%(message)s' +# +# [*logging_default_format_string*] +# (optional) Format string to use for log messages without context. +# Defaults to undef. +# Example: '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s\ +# [-] %(instance)s%(message)s' +# +# [*logging_debug_format_suffix*] +# (optional) Formatted data to append to log format when level is DEBUG. +# Defaults to undef. +# Example: '%(funcName)s %(pathname)s:%(lineno)d' +# +# [*logging_exception_prefix*] +# (optional) Prefix each line of exception output with this format. +# Defaults to undef. +# Example: '%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s' +# +# [*log_config_append*] +# The name of an additional logging configuration file. +# Defaults to undef. +# See https://docs.python.org/2/howto/logging.html +# +# [*default_log_levels*] +# (optional) Hash of logger (keys) and level (values) pairs. +# Defaults to undef. +# Example: +# { 'amqp' => 'WARN', 'amqplib' => 'WARN', 'boto' => 'WARN', +# 'qpid' => 'WARN', 'sqlalchemy' => 'WARN', 'suds' => 'INFO', +# 'oslo.messaging' => 'INFO', 'iso8601' => 'WARN', +# 'requests.packages.urllib3.connectionpool' => 'WARN', +# 'urllib3.connectionpool' => 'WARN', +# 'websocket' => 'WARN', 'keystonemiddleware' => 'WARN', +# 'routes.middleware' => 'WARN', stevedore => 'WARN' } +# +# [*publish_errors*] +# (optional) Publish error events (boolean value). +# Defaults to undef (false if unconfigured). +# +# [*fatal_deprecations*] +# (optional) Make deprecations fatal (boolean value) +# Defaults to undef (false if unconfigured). +# +# [*instance_format*] +# (optional) If an instance is passed with the log message, format it +# like this (string value). +# Defaults to undef. +# Example: '[instance: %(uuid)s] ' +# +# [*instance_uuid_format*] +# (optional) If an instance UUID is passed with the log message, format +# it like this (string value). +# Defaults to undef. +# Example: instance_uuid_format='[instance: %(uuid)s] ' + +# [*log_date_format*] +# (optional) Format string for %%(asctime)s in log records. +# Defaults to undef. +# Example: 'Y-%m-%d %H:%M:%S' + +class keystone::logging( + $logging_context_format_string = undef, + $logging_default_format_string = undef, + $logging_debug_format_suffix = undef, + $logging_exception_prefix = undef, + $log_config_append = undef, + $default_log_levels = undef, + $publish_errors = undef, + $fatal_deprecations = undef, + $instance_format = undef, + $instance_uuid_format = undef, + $log_date_format = undef, +) { + + if $logging_context_format_string { + keystone_config { + 'DEFAULT/logging_context_format_string' : + value => $logging_context_format_string; + } + } + else { + keystone_config { + 'DEFAULT/logging_context_format_string' : ensure => absent; + } + } + + if $logging_default_format_string { + keystone_config { + 'DEFAULT/logging_default_format_string' : + value => $logging_default_format_string; + } + } + else { + keystone_config { + 'DEFAULT/logging_default_format_string' : ensure => absent; + } + } + + if $logging_debug_format_suffix { + keystone_config { + 'DEFAULT/logging_debug_format_suffix' : + value => $logging_debug_format_suffix; + } + } + else { + keystone_config { + 'DEFAULT/logging_debug_format_suffix' : ensure => absent; + } + } + + if $logging_exception_prefix { + keystone_config { + 'DEFAULT/logging_exception_prefix' : value => $logging_exception_prefix; + } + } + else { + keystone_config { + 'DEFAULT/logging_exception_prefix' : ensure => absent; + } + } + + if $log_config_append { + keystone_config { + 'DEFAULT/log_config_append' : value => $log_config_append; + } + } + else { + keystone_config { + 'DEFAULT/log_config_append' : ensure => absent; + } + } + + if $default_log_levels { + keystone_config { + 'DEFAULT/default_log_levels' : + value => join(sort(join_keys_to_values($default_log_levels, '=')), ','); + } + } + else { + keystone_config { + 'DEFAULT/default_log_levels' : ensure => absent; + } + } + + if $publish_errors { + keystone_config { + 'DEFAULT/publish_errors' : value => $publish_errors; + } + } + else { + keystone_config { + 'DEFAULT/publish_errors' : ensure => absent; + } + } + + if $fatal_deprecations { + keystone_config { + 'DEFAULT/fatal_deprecations' : value => $fatal_deprecations; + } + } + else { + keystone_config { + 'DEFAULT/fatal_deprecations' : ensure => absent; + } + } + + if $instance_format { + keystone_config { + 'DEFAULT/instance_format' : value => $instance_format; + } + } + else { + keystone_config { + 'DEFAULT/instance_format' : ensure => absent; + } + } + + if $instance_uuid_format { + keystone_config { + 'DEFAULT/instance_uuid_format' : value => $instance_uuid_format; + } + } + else { + keystone_config { + 'DEFAULT/instance_uuid_format' : ensure => absent; + } + } + + if $log_date_format { + keystone_config { + 'DEFAULT/log_date_format' : value => $log_date_format; + } + } + else { + keystone_config { + 'DEFAULT/log_date_format' : ensure => absent; + } + } + + +} diff --git a/3rdparty/modules/keystone/manifests/params.pp b/3rdparty/modules/keystone/manifests/params.pp new file mode 100644 index 000000000..f3f0f4d26 --- /dev/null +++ b/3rdparty/modules/keystone/manifests/params.pp @@ -0,0 +1,36 @@ +# +# This class contains the platform differences for keystone +# +class keystone::params { + $client_package_name = 'python-keystone' + + case $::osfamily { + 'Debian': { + $package_name = 'keystone' + $service_name = 'keystone' + $keystone_wsgi_script_path = '/usr/lib/cgi-bin/keystone' + $python_memcache_package_name = 'python-memcache' + case $::operatingsystem { + 'Debian': { + $service_provider = undef + $keystone_wsgi_script_source = '/usr/share/keystone/wsgi.py' + } + default: { + # NOTE: Ubuntu does not currently provide the keystone wsgi script in the + # keystone packages. When Ubuntu does provide the script, change this + # to use the correct path (which I'm assuming will be the same as Debian). + $service_provider = 'upstart' + $keystone_wsgi_script_source = 'puppet:///modules/keystone/httpd/keystone.py' + } + } + } + 'RedHat': { + $package_name = 'openstack-keystone' + $service_name = 'openstack-keystone' + $keystone_wsgi_script_path = '/var/www/cgi-bin/keystone' + $python_memcache_package_name = 'python-memcached' + $service_provider = undef + $keystone_wsgi_script_source = '/usr/share/keystone/keystone.wsgi' + } + } +} diff --git a/3rdparty/modules/keystone/manifests/policy.pp b/3rdparty/modules/keystone/manifests/policy.pp new file mode 100644 index 000000000..13be064b0 --- /dev/null +++ b/3rdparty/modules/keystone/manifests/policy.pp @@ -0,0 +1,39 @@ +# == Class: keystone::policy +# +# Configure the keystone policies +# +# === Parameters +# +# [*policies*] +# (optional) Set of policies to configure for keystone +# Example : +# { +# 'keystone-context_is_admin' => { +# 'key' => 'context_is_admin', +# 'value' => 'true' +# }, +# 'keystone-default' => { +# 'key' => 'default', +# 'value' => 'rule:admin_or_owner' +# } +# } +# Defaults to empty hash. +# +# [*policy_path*] +# (optional) Path to the nova policy.json file +# Defaults to /etc/keystone/policy.json +# +class keystone::policy ( + $policies = {}, + $policy_path = '/etc/keystone/policy.json', +) { + + validate_hash($policies) + + Openstacklib::Policy::Base { + file_path => $policy_path, + } + + create_resources('openstacklib::policy::base', $policies) + +} diff --git a/3rdparty/modules/keystone/manifests/python.pp b/3rdparty/modules/keystone/manifests/python.pp new file mode 100644 index 000000000..858fd6504 --- /dev/null +++ b/3rdparty/modules/keystone/manifests/python.pp @@ -0,0 +1,15 @@ +# +# installs client python libraries for keystone +# +# +class keystone::python ( + $client_package_name = $keystone::params::client_package_name, + $ensure = 'present' +) inherits keystone::params { + + package { 'python-keystone' : + ensure => $ensure, + name => $client_package_name, + } + +} diff --git a/3rdparty/modules/keystone/manifests/resource/service_identity.pp b/3rdparty/modules/keystone/manifests/resource/service_identity.pp new file mode 100644 index 000000000..08eaa7f5e --- /dev/null +++ b/3rdparty/modules/keystone/manifests/resource/service_identity.pp @@ -0,0 +1,164 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Definition: keystone::resource::service_identity +# +# This resource configures Keystone resources for an OpenStack service. +# +# == Parameters: +# +# [*password*] +# Password to create for the service user; +# string; required +# +# [*auth_name*] +# The name of the service user; +# string; optional; default to the $title of the resource, i.e. 'nova' +# +# [*service_name*] +# Name of the service; +# string; required +# +# [*service_type*] +# Type of the service; +# string; required +# +# [*service_description*] +# Description of the service; +# string; optional: default to '$name service' +# +# [*public_url*] +# Public endpoint URL; +# string; required +# +# [*internal_url*] +# Internal endpoint URL; +# string; required +# +# [*admin_url*] +# Admin endpoint URL; +# string; required +# +# [*region*] +# Endpoint region; +# string; optional: default to 'RegionOne' +# +# [*tenant*] +# Service tenant; +# string; optional: default to 'services' +# +# [*ignore_default_tenant*] +# Ignore setting the default tenant value when the user is created. +# string; optional: default to false +# +# [*roles*] +# List of roles; +# string; optional: default to ['admin'] +# +# [*domain*] +# User domain (keystone v3), not implemented yet. +# string; optional: default to undef +# +# [*email*] +# Service email; +# string; optional: default to '$auth_name@localhost' +# +# [*configure_endpoint*] +# Whether to create the endpoint. +# string; optional: default to True +# +# [*configure_user*] +# Whether to create the user. +# string; optional: default to True +# +# [*configure_user_role*] +# Whether to create the user role. +# string; optional: default to True +# +# [*configure_service*] +# Whether to create the service. +# string; optional: default to True +# +define keystone::resource::service_identity( + $admin_url = false, + $internal_url = false, + $password = false, + $public_url = false, + $service_type = false, + $auth_name = $name, + $configure_endpoint = true, + $configure_user = true, + $configure_user_role = true, + $configure_service = true, + $domain = undef, + $email = "${name}@localhost", + $region = 'RegionOne', + $service_name = undef, + $service_description = "${name} service", + $tenant = 'services', + $ignore_default_tenant = false, + $roles = ['admin'], +) { + + if $domain { + warning('Keystone domains are not yet managed by puppet-keystone.') + } + + if $service_name == undef { + $service_name_real = $auth_name + } else { + $service_name_real = $service_name + } + + if $configure_user { + ensure_resource('keystone_user', $auth_name, { + 'ensure' => 'present', + 'enabled' => true, + 'password' => $password, + 'email' => $email, + 'tenant' => $tenant, + 'ignore_default_tenant' => $ignore_default_tenant, + }) + } + + if $configure_user_role { + ensure_resource('keystone_user_role', "${auth_name}@${tenant}", { + 'ensure' => 'present', + 'roles' => $roles, + }) + if $configure_user { + Keystone_user[$auth_name] -> Keystone_user_role["${auth_name}@${tenant}"] + } + } + + if $configure_service { + ensure_resource('keystone_service', $service_name_real, { + 'ensure' => 'present', + 'type' => $service_type, + 'description' => $service_description, + }) + } + + if $configure_endpoint { + ensure_resource('keystone_endpoint', "${region}/${service_name_real}", { + 'ensure' => 'present', + 'public_url' => $public_url, + 'admin_url' => $admin_url, + 'internal_url' => $internal_url, + }) + } +} diff --git a/3rdparty/modules/keystone/manifests/roles/admin.pp b/3rdparty/modules/keystone/manifests/roles/admin.pp new file mode 100644 index 000000000..4fd5e0970 --- /dev/null +++ b/3rdparty/modules/keystone/manifests/roles/admin.pp @@ -0,0 +1,80 @@ +# +# This class implements some reasonable admin defaults for keystone. +# +# It creates the following keystone objects: +# * service tenant (tenant used by all service users) +# * "admin" tenant (defaults to "openstack") +# * admin user (that defaults to the "admin" tenant) +# * admin role +# * adds admin role to admin user on the "admin" tenant +# +# [*Parameters*] +# +# [email] The email address for the admin. Required. +# [password] The admin password. Required. +# [admin_roles] The list of the roles with admin privileges. Optional. Defaults to ['admin']. +# [admin_tenant] The name of the tenant to be used for admin privileges. Optional. Defaults to openstack. +# [admin] Admin user. Optional. Defaults to admin. +# [ignore_default_tenant] Ignore setting the default tenant value when the user is created. Optional. Defaults to false. +# [admin_tenant_desc] Optional. Description for admin tenant, defaults to 'admin tenant' +# [service_tenant_desc] Optional. Description for admin tenant, defaults to 'Tenant for the openstack services' +# [configure_user] Optional. Should the admin user be created? Defaults to 'true'. +# [configure_user_role] Optional. Should the admin role be configured for the admin user? Defaulst to 'true'. +# +# == Dependencies +# == Examples +# == Authors +# +# Dan Bode dan@puppetlabs.com +# +# == Copyright +# +# Copyright 2012 Puppetlabs Inc, unless otherwise noted. +# +class keystone::roles::admin( + $email, + $password, + $admin = 'admin', + $admin_tenant = 'openstack', + $admin_roles = ['admin'], + $service_tenant = 'services', + $ignore_default_tenant = false, + $admin_tenant_desc = 'admin tenant', + $service_tenant_desc = 'Tenant for the openstack services', + $configure_user = true, + $configure_user_role = true, +) { + + keystone_tenant { $service_tenant: + ensure => present, + enabled => true, + description => $service_tenant_desc, + } + keystone_tenant { $admin_tenant: + ensure => present, + enabled => true, + description => $admin_tenant_desc, + } + keystone_role { 'admin': + ensure => present, + } + + if $configure_user { + keystone_user { $admin: + ensure => present, + enabled => true, + tenant => $admin_tenant, + email => $email, + password => $password, + ignore_default_tenant => $ignore_default_tenant, + } + } + + if $configure_user_role { + keystone_user_role { "${admin}@${admin_tenant}": + ensure => present, + roles => $admin_roles, + } + } + +} diff --git a/3rdparty/modules/keystone/manifests/service.pp b/3rdparty/modules/keystone/manifests/service.pp new file mode 100644 index 000000000..63c148d3b --- /dev/null +++ b/3rdparty/modules/keystone/manifests/service.pp @@ -0,0 +1,124 @@ +# == Class keystone::service +# +# Encapsulates the keystone service to a class. +# This allows resources that require keystone to +# require this class, which can optionally +# validate that the service can actually accept +# connections. +# +# === Parameters +# +# [*ensure*] +# (optional) The desired state of the keystone service +# Defaults to 'running' +# +# [*service_name*] +# (optional) The name of the keystone service +# Defaults to $::keystone::params::service_name +# +# [*enable*] +# (optional) Whether to enable the keystone service +# Defaults to true +# +# [*hasstatus*] +# (optional) Whether the keystone service has status +# Defaults to true +# +# [*hasrestart*] +# (optional) Whether the keystone service has restart +# Defaults to true +# +# [*provider*] +# (optional) Provider for keystone service +# Defaults to $::keystone::params::service_provider +# +# [*validate*] +# (optional) Whether to validate the service is working +# after any service refreshes +# Defaults to false +# +# [*admin_token*] +# (optional) The admin token to use for validation +# Defaults to undef +# +# [*admin_endpoint*] +# (optional) The admin endpont to use for validation +# Defaults to 'http://localhost:35357/v2.0' +# +# [*retries*] +# (optional) Number of times to retry validation +# Defaults to 10 +# +# [*delay*] +# (optional) Number of seconds between validation attempts +# Defaults to 2 +# +# [*insecure*] +# (optional) Whether to validate keystone connections +# using the --insecure option with keystone client. +# Defaults to false +# +# [*cacert*] +# (optional) Whether to validate keystone connections +# using the specified argument with the --os-cacert option +# with keystone client. +# Defaults to undef +# +class keystone::service( + $ensure = 'running', + $service_name = $::keystone::params::service_name, + $enable = true, + $hasstatus = true, + $hasrestart = true, + $provider = $::keystone::params::service_provider, + $validate = false, + $admin_token = undef, + $admin_endpoint = 'http://localhost:35357/v2.0', + $retries = 10, + $delay = 2, + $insecure = false, + $cacert = undef, +) { + include keystone::params + + service { 'keystone': + ensure => $ensure, + name => $service_name, + enable => $enable, + hasstatus => $hasstatus, + hasrestart => $hasrestart, + provider => $provider + } + + if $insecure { + $insecure_s = '--insecure' + } else { + $insecure_s = '' + } + + if $cacert { + $cacert_s = "--os-cacert ${cacert}" + } else { + $cacert_s = '' + } + + if $validate and $admin_token and $admin_endpoint { + $cmd = "keystone --os-endpoint ${admin_endpoint} --os-token ${admin_token} ${insecure_s} ${cacert_s} user-list" + $catch = 'name' + exec { 'validate_keystone_connection': + path => '/usr/bin:/bin:/usr/sbin:/sbin', + provider => shell, + command => $cmd, + subscribe => Service['keystone'], + refreshonly => true, + tries => $retries, + try_sleep => $delay + } + + Exec['validate_keystone_connection'] -> Keystone_user<||> + Exec['validate_keystone_connection'] -> Keystone_role<||> + Exec['validate_keystone_connection'] -> Keystone_tenant<||> + Exec['validate_keystone_connection'] -> Keystone_service<||> + Exec['validate_keystone_connection'] -> Keystone_endpoint<||> + } +} diff --git a/3rdparty/modules/keystone/manifests/wsgi/apache.pp b/3rdparty/modules/keystone/manifests/wsgi/apache.pp new file mode 100644 index 000000000..42dec0622 --- /dev/null +++ b/3rdparty/modules/keystone/manifests/wsgi/apache.pp @@ -0,0 +1,232 @@ +# +# Class to serve keystone with apache mod_wsgi in place of keystone service +# +# Serving keystone from apache is the recommended way to go for production +# systems as the current keystone implementation is not multi-processor aware, +# thus limiting the performance for concurrent accesses. +# +# See the following URIs for reference: +# https://etherpad.openstack.org/havana-keystone-performance +# http://adam.younglogic.com/2012/03/keystone-should-move-to-apache-httpd/ +# +# When using this class you should disable your keystone service. +# +# == Parameters +# +# [*servername*] +# The servername for the virtualhost. +# Optional. Defaults to $::fqdn +# +# [*public_port*] +# The public port. +# Optional. Defaults to 5000 +# +# [*admin_port*] +# The admin port. +# Optional. Defaults to 35357 +# +# [*bind_host*] +# The host/ip address Apache will listen on. +# Optional. Defaults to undef (listen on all ip addresses). +# +# [*public_path*] +# The prefix for the public endpoint. +# Optional. Defaults to '/' +# +# [*admin_path*] +# The prefix for the admin endpoint. +# Optional. Defaults to '/' +# +# [*ssl*] +# Use ssl ? (boolean) +# Optional. Defaults to true +# +# [*workers*] +# Number of WSGI workers to spawn. +# Optional. Defaults to 1 +# +# [*ssl_cert*] +# [*ssl_key*] +# [*ssl_chain*] +# [*ssl_ca*] +# [*ssl_crl_path*] +# [*ssl_crl*] +# [*ssl_certs_dir*] +# apache::vhost ssl parameters. +# Optional. Default to apache::vhost 'ssl_*' defaults. +# +# == Dependencies +# +# requires Class['apache'] & Class['keystone'] +# +# == Examples +# +# include apache +# +# class { 'keystone::wsgi::apache': } +# +# == Note about ports & paths +# +# When using same port for both endpoints (443 anyone ?), you *MUST* use two +# different public_path & admin_path ! +# +# == Authors +# +# François Charlier +# +# == Copyright +# +# Copyright 2013 eNovance +# +class keystone::wsgi::apache ( + $servername = $::fqdn, + $public_port = 5000, + $admin_port = 35357, + $bind_host = undef, + $public_path = '/', + $admin_path = '/', + $ssl = true, + $workers = 1, + $ssl_cert = undef, + $ssl_key = undef, + $ssl_chain = undef, + $ssl_ca = undef, + $ssl_crl_path = undef, + $ssl_crl = undef, + $ssl_certs_dir = undef, + $threads = $::processorcount, + $priority = '10', +) { + + include ::keystone::params + include ::apache + include ::apache::mod::wsgi + if $ssl { + include ::apache::mod::ssl + } + + Package['keystone'] -> Package['httpd'] + Package['keystone'] ~> Service['httpd'] + Keystone_config <| |> ~> Service['httpd'] + Service['httpd'] -> Keystone_endpoint <| |> + Service['httpd'] -> Keystone_role <| |> + Service['httpd'] -> Keystone_service <| |> + Service['httpd'] -> Keystone_tenant <| |> + Service['httpd'] -> Keystone_user <| |> + Service['httpd'] -> Keystone_user_role <| |> + + ## Sanitize parameters + + # Ensure there's no trailing '/' except if this is also the only character + $public_path_real = regsubst($public_path, '(^/.*)/$', '\1') + # Ensure there's no trailing '/' except if this is also the only character + $admin_path_real = regsubst($admin_path, '(^/.*)/$', '\1') + + if $public_port == $admin_port and $public_path_real == $admin_path_real { + fail('When using the same port for public & private endpoints, public_path and admin_path should be different.') + } + + file { $::keystone::params::keystone_wsgi_script_path: + ensure => directory, + owner => 'keystone', + group => 'keystone', + require => Package['httpd'], + } + + file { 'keystone_wsgi_admin': + ensure => file, + path => "${::keystone::params::keystone_wsgi_script_path}/admin", + source => $::keystone::params::keystone_wsgi_script_source, + owner => 'keystone', + group => 'keystone', + mode => '0644', + # source file provided by keystone package + require => [File[$::keystone::params::keystone_wsgi_script_path], Package['keystone']], + } + + file { 'keystone_wsgi_main': + ensure => file, + path => "${::keystone::params::keystone_wsgi_script_path}/main", + source => $::keystone::params::keystone_wsgi_script_source, + owner => 'keystone', + group => 'keystone', + mode => '0644', + # source file provided by keystone package + require => [File[$::keystone::params::keystone_wsgi_script_path], Package['keystone']], + } + + $wsgi_daemon_process_options_main = { + user => 'keystone', + group => 'keystone', + processes => $workers, + threads => $threads, + display-name => 'keystone-main', + } + + $wsgi_daemon_process_options_admin = { + user => 'keystone', + group => 'keystone', + processes => $workers, + threads => $threads, + display-name => 'keystone-admin', + } + + $wsgi_script_aliases_main = hash([$public_path_real,"${::keystone::params::keystone_wsgi_script_path}/main"]) + $wsgi_script_aliases_admin = hash([$admin_path_real, "${::keystone::params::keystone_wsgi_script_path}/admin"]) + + if $public_port == $admin_port { + $wsgi_script_aliases_main_real = merge($wsgi_script_aliases_main, $wsgi_script_aliases_admin) + } else { + $wsgi_script_aliases_main_real = $wsgi_script_aliases_main + } + + ::apache::vhost { 'keystone_wsgi_main': + ensure => 'present', + servername => $servername, + ip => $bind_host, + port => $public_port, + docroot => $::keystone::params::keystone_wsgi_script_path, + docroot_owner => 'keystone', + docroot_group => 'keystone', + priority => $priority, + ssl => $ssl, + ssl_cert => $ssl_cert, + ssl_key => $ssl_key, + ssl_chain => $ssl_chain, + ssl_ca => $ssl_ca, + ssl_crl_path => $ssl_crl_path, + ssl_crl => $ssl_crl, + ssl_certs_dir => $ssl_certs_dir, + wsgi_daemon_process => 'keystone_main', + wsgi_daemon_process_options => $wsgi_daemon_process_options_main, + wsgi_process_group => 'keystone_main', + wsgi_script_aliases => $wsgi_script_aliases_main_real, + require => File['keystone_wsgi_main'], + } + + if $public_port != $admin_port { + ::apache::vhost { 'keystone_wsgi_admin': + ensure => 'present', + servername => $servername, + ip => $bind_host, + port => $admin_port, + docroot => $::keystone::params::keystone_wsgi_script_path, + docroot_owner => 'keystone', + docroot_group => 'keystone', + priority => $priority, + ssl => $ssl, + ssl_cert => $ssl_cert, + ssl_key => $ssl_key, + ssl_chain => $ssl_chain, + ssl_ca => $ssl_ca, + ssl_crl_path => $ssl_crl_path, + ssl_crl => $ssl_crl, + ssl_certs_dir => $ssl_certs_dir, + wsgi_daemon_process => 'keystone_admin', + wsgi_daemon_process_options => $wsgi_daemon_process_options_admin, + wsgi_process_group => 'keystone_admin', + wsgi_script_aliases => $wsgi_script_aliases_admin, + require => File['keystone_wsgi_admin'], + } + } +} diff --git a/3rdparty/modules/keystone/metadata.json b/3rdparty/modules/keystone/metadata.json new file mode 100644 index 000000000..6f40ac965 --- /dev/null +++ b/3rdparty/modules/keystone/metadata.json @@ -0,0 +1,55 @@ +{ + "name": "stackforge-keystone", + "version": "5.1.0", + "author": "Puppet Labs and OpenStack Contributors", + "summary": "Puppet module for OpenStack Keystone", + "license": "Apache-2.0", + "source": "git://github.com/openstack/puppet-keystone.git", + "project_page": "https://launchpad.net/puppet-keystone", + "issues_url": "https://bugs.launchpad.net/puppet-keystone", + "dependencies": [ + {"name":"puppetlabs/apache","version_requirement":">=1.0.0 <2.0.0"}, + {"name":"puppetlabs/inifile","version_requirement":">=1.0.0 <2.0.0"}, + {"name":"puppetlabs/stdlib","version_requirement":">=4.0.0 <5.0.0"}, + {"name":"stackforge/openstacklib","version_requirement":">=5.0.0 <6.0.0"} + ], + "requirements": [ + { + "name": "pe", + "version_requirement": "3.x" + }, + { + "name": "puppet", + "version_requirement": "3.x" + } + ], + "operatingsystem_support": [ + { + "operatingsystem": "Debian", + "operatingsystemrelease": [ + "7" + ] + }, + { + "operatingsystem": "Fedora", + "operatingsystemrelease": [ + "20" + ] + }, + { + "operatingsystem": "RedHat", + "operatingsystemrelease": [ + "6.5", + "7" + ] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": [ + "12.04", + "14.04" + ] + } + ], + "description": "Installs and configures OpenStack Keystone (Identity)." +} diff --git a/3rdparty/modules/keystone/spec/classes/keystone_client_spec.rb b/3rdparty/modules/keystone/spec/classes/keystone_client_spec.rb new file mode 100644 index 000000000..5ed6f6bb2 --- /dev/null +++ b/3rdparty/modules/keystone/spec/classes/keystone_client_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe 'keystone::client' do + + describe "with default parameters" do + it { should contain_package('python-keystoneclient').with( + 'ensure' => 'present', + 'tag' => 'openstack' + ) } + end + + describe "with specified version" do + let :params do + {:ensure => '2013.1'} + end + + it { should contain_package('python-keystoneclient').with( + 'ensure' => '2013.1', + 'tag' => 'openstack' + ) } + end +end diff --git a/3rdparty/modules/keystone/spec/classes/keystone_cron_token_flush_spec.rb b/3rdparty/modules/keystone/spec/classes/keystone_cron_token_flush_spec.rb new file mode 100644 index 000000000..597042b36 --- /dev/null +++ b/3rdparty/modules/keystone/spec/classes/keystone_cron_token_flush_spec.rb @@ -0,0 +1,68 @@ +require 'spec_helper' + +describe 'keystone::cron::token_flush' do + + let :facts do + { :osfamily => 'Debian' } + end + + describe 'with default parameters' do + it 'configures a cron' do + should contain_cron('keystone-manage token_flush').with( + :ensure => 'present', + :command => 'keystone-manage token_flush >>/var/log/keystone/keystone-tokenflush.log 2>&1', + :environment => 'PATH=/bin:/usr/bin:/usr/sbin SHELL=/bin/sh', + :user => 'keystone', + :minute => 1, + :hour => 0, + :monthday => '*', + :month => '*', + :weekday => '*' + ) + end + end + + describe 'when specifying a maxdelay param' do + let :params do + { + :maxdelay => 600 + } + end + + it 'configures a cron with delay' do + should contain_cron('keystone-manage token_flush').with( + :ensure => 'present', + :command => 'sleep `expr ${RANDOM} \\% 600`; keystone-manage token_flush >>/var/log/keystone/keystone-tokenflush.log 2>&1', + :environment => 'PATH=/bin:/usr/bin:/usr/sbin SHELL=/bin/sh', + :user => 'keystone', + :minute => 1, + :hour => 0, + :monthday => '*', + :month => '*', + :weekday => '*' + ) + end + end + + describe 'when specifying a maxdelay param' do + let :params do + { + :ensure => 'absent' + } + end + + it 'configures a cron with delay' do + should contain_cron('keystone-manage token_flush').with( + :ensure => 'absent', + :command => 'keystone-manage token_flush >>/var/log/keystone/keystone-tokenflush.log 2>&1', + :environment => 'PATH=/bin:/usr/bin:/usr/sbin SHELL=/bin/sh', + :user => 'keystone', + :minute => 1, + :hour => 0, + :monthday => '*', + :month => '*', + :weekday => '*' + ) + end + end +end diff --git a/3rdparty/modules/keystone/spec/classes/keystone_db_mysql_spec.rb b/3rdparty/modules/keystone/spec/classes/keystone_db_mysql_spec.rb new file mode 100644 index 000000000..f20ea9b2c --- /dev/null +++ b/3rdparty/modules/keystone/spec/classes/keystone_db_mysql_spec.rb @@ -0,0 +1,61 @@ +require 'spec_helper' + +describe 'keystone::db::mysql' do + + let :pre_condition do + [ + 'include mysql::server', + 'include keystone::db::sync' + ] + end + + let :facts do + { :osfamily => 'Debian' } + end + + let :params do + { + 'password' => 'keystone_default_password', + } + end + + describe 'with only required params' do + it { should contain_openstacklib__db__mysql('keystone').with( + 'user' => 'keystone', + 'password_hash' => '*B552157B14BCEDDCEAA06767A012F31BDAA9CE3D', + 'dbname' => 'keystone', + 'host' => '127.0.0.1', + 'charset' => 'utf8' + )} + end + + describe "overriding allowed_hosts param to array" do + let :params do + { + :password => 'keystonepass', + :allowed_hosts => ['127.0.0.1','%'] + } + end + + end + describe "overriding allowed_hosts param to string" do + let :params do + { + :password => 'keystonepass2', + :allowed_hosts => '192.168.1.1' + } + end + + end + + describe "overriding allowed_hosts param equals to host param " do + let :params do + { + :password => 'keystonepass2', + :allowed_hosts => '127.0.0.1' + } + end + + end + +end diff --git a/3rdparty/modules/keystone/spec/classes/keystone_db_postgresql_spec.rb b/3rdparty/modules/keystone/spec/classes/keystone_db_postgresql_spec.rb new file mode 100644 index 000000000..7efe94619 --- /dev/null +++ b/3rdparty/modules/keystone/spec/classes/keystone_db_postgresql_spec.rb @@ -0,0 +1,26 @@ +require 'spec_helper' + +describe 'keystone::db::postgresql' do + + let :req_params do + {:password => 'pw'} + end + + let :facts do + { + :postgres_default_version => '8.4', + :osfamily => 'RedHat', + } + end + + describe 'with only required params' do + let :params do + req_params + end + it { should contain_postgresql__db('keystone').with( + :user => 'keystone', + :password => 'pw' + ) } + end + +end diff --git a/3rdparty/modules/keystone/spec/classes/keystone_endpoint_spec.rb b/3rdparty/modules/keystone/spec/classes/keystone_endpoint_spec.rb new file mode 100644 index 000000000..61b596abd --- /dev/null +++ b/3rdparty/modules/keystone/spec/classes/keystone_endpoint_spec.rb @@ -0,0 +1,99 @@ +require 'spec_helper' + +describe 'keystone::endpoint' do + + it { should contain_keystone_service('keystone').with( + :ensure => 'present', + :type => 'identity', + :description => 'OpenStack Identity Service' + )} + + describe 'with default parameters' do + it { should contain_keystone_endpoint('RegionOne/keystone').with( + :ensure => 'present', + :public_url => 'http://127.0.0.1:5000/v2.0', + :admin_url => 'http://127.0.0.1:35357/v2.0', + :internal_url => 'http://127.0.0.1:5000/v2.0' + )} + end + + describe 'with overridden parameters' do + + let :params do + { :version => 'v42.6', + :public_url => 'https://identity.some.tld/the/main/endpoint', + :admin_url => 'https://identity-int.some.tld/some/admin/endpoint', + :internal_url => 'https://identity-int.some.tld/some/internal/endpoint' } + end + + it { should contain_keystone_endpoint('RegionOne/keystone').with( + :ensure => 'present', + :public_url => 'https://identity.some.tld/the/main/endpoint/v42.6', + :admin_url => 'https://identity-int.some.tld/some/admin/endpoint/v42.6', + :internal_url => 'https://identity-int.some.tld/some/internal/endpoint/v42.6' + )} + end + + describe 'without internal_url parameter' do + + let :params do + { :public_url => 'https://identity.some.tld/the/main/endpoint' } + end + + it 'internal_url should default to public_url' do + should contain_keystone_endpoint('RegionOne/keystone').with( + :ensure => 'present', + :public_url => 'https://identity.some.tld/the/main/endpoint/v2.0', + :internal_url => 'https://identity.some.tld/the/main/endpoint/v2.0' + ) + end + end + + describe 'with deprecated parameters' do + + let :params do + { :public_address => '10.0.0.1', + :admin_address => '10.0.0.2', + :internal_address => '10.0.0.3', + :public_port => '23456', + :admin_port => '12345', + :region => 'RegionTwo', + :version => 'v3.0' } + end + + it { should contain_keystone_endpoint('RegionTwo/keystone').with( + :ensure => 'present', + :public_url => 'http://10.0.0.1:23456/v3.0', + :admin_url => 'http://10.0.0.2:12345/v3.0', + :internal_url => 'http://10.0.0.3:23456/v3.0' + )} + + describe 'public_address overrides public_url' do + let :params do + { :public_address => '10.0.0.1', + :public_port => '12345', + :public_url => 'http://10.10.10.10:23456/v3.0' } + end + + it { should contain_keystone_endpoint('RegionOne/keystone').with( + :ensure => 'present', + :public_url => 'http://10.0.0.1:12345/v2.0' + )} + end + end + + describe 'with overridden deprecated internal_port' do + + let :params do + { :internal_port => '12345' } + end + + it { should contain_keystone_endpoint('RegionOne/keystone').with( + :ensure => 'present', + :public_url => 'http://127.0.0.1:5000/v2.0', + :admin_url => 'http://127.0.0.1:35357/v2.0', + :internal_url => 'http://127.0.0.1:12345/v2.0' + )} + end + +end diff --git a/3rdparty/modules/keystone/spec/classes/keystone_ldap_spec.rb b/3rdparty/modules/keystone/spec/classes/keystone_ldap_spec.rb new file mode 100644 index 000000000..088526e86 --- /dev/null +++ b/3rdparty/modules/keystone/spec/classes/keystone_ldap_spec.rb @@ -0,0 +1,243 @@ +require 'spec_helper' + +describe 'keystone::ldap' do + describe 'with basic params' do + let :params do + { + :url => 'ldap://foo', + :user => 'cn=foo,dc=example,dc=com', + :password => 'abcdefg', + :suffix => 'dc=example,dc=com', + :query_scope => 'sub', + :page_size => '50', + :user_tree_dn => 'cn=users,dc=example,dc=com', + :user_filter => '(memberOf=cn=openstack,cn=groups,cn=accounts,dc=example,dc=com)', + :user_objectclass => 'inetUser', + :user_id_attribute => 'uid', + :user_name_attribute => 'cn', + :user_mail_attribute => 'mail', + :user_enabled_attribute => 'UserAccountControl', + :user_enabled_mask => '2', + :user_enabled_default => '512', + :user_enabled_invert => 'False', + :user_attribute_ignore => '', + :user_default_project_id_attribute => 'defaultProject', + :user_allow_create => 'False', + :user_allow_update => 'False', + :user_allow_delete => 'False', + :user_pass_attribute => 'krbPassword', + :user_enabled_emulation => 'True', + :user_enabled_emulation_dn => 'cn=openstack-enabled,cn=groups,cn=accounts,dc=example,dc=com', + :user_additional_attribute_mapping => 'description:name, gecos:name', + :project_tree_dn => 'ou=projects,ou=openstack,dc=example,dc=com', + :project_filter => '', + :project_objectclass => 'organizationalUnit', + :project_id_attribute => 'ou', + :project_member_attribute => 'member', + :project_desc_attribute => 'description', + :project_name_attribute => 'ou', + :project_enabled_attribute => 'enabled', + :project_domain_id_attribute => 'businessCategory', + :project_attribute_ignore => '', + :project_allow_create => 'True', + :project_allow_update => 'True', + :project_allow_delete => 'True', + :project_enabled_emulation => 'False', + :project_enabled_emulation_dn => 'True', + :project_additional_attribute_mapping => 'cn=enabled,ou=openstack,dc=example,dc=com', + :role_tree_dn => 'ou=roles,ou=openstack,dc=example,dc=com', + :role_filter => '', + :role_objectclass => 'organizationalRole', + :role_id_attribute => 'cn', + :role_name_attribute => 'ou', + :role_member_attribute => 'roleOccupant', + :role_attribute_ignore => 'description', + :role_allow_create => 'True', + :role_allow_update => 'True', + :role_allow_delete => 'True', + :role_additional_attribute_mapping => '', + :group_tree_dn => 'ou=groups,ou=openstack,dc=example,dc=com', + :group_filter => 'cn=enabled-groups,cn=groups,cn=accounts,dc=example,dc=com', + :group_objectclass => 'organizationalRole', + :group_id_attribute => 'cn', + :group_name_attribute => 'cn', + :group_member_attribute => 'roleOccupant', + :group_desc_attribute => 'description', + :group_attribute_ignore => '', + :group_allow_create => 'False', + :group_allow_update => 'False', + :group_allow_delete => 'False', + :group_additional_attribute_mapping => '', + :use_tls => 'False', + :tls_cacertdir => '/etc/ssl/certs/', + :tls_cacertfile => '/etc/ssl/certs/ca-certificates.crt', + :tls_req_cert => 'demand', + :identity_driver => 'keystone.identity.backends.ldap.Identity', + :assignment_driver => 'keystone.assignment.backends.ldap.Assignment', + :use_pool => 'True', + :pool_size => 20, + :pool_retry_max => 2, + :pool_retry_delay => 0.2, + :pool_connection_timeout => 222, + :pool_connection_lifetime => 222, + :use_auth_pool => 'True', + :auth_pool_size => 20, + :auth_pool_connection_lifetime => 200, + } + end + it { should contain_package('python-ldap') } + it { should contain_package('python-ldappool') } + it 'should have basic params' do + # basic params + should contain_keystone_config('ldap/url').with_value('ldap://foo') + should contain_keystone_config('ldap/user').with_value('cn=foo,dc=example,dc=com') + should contain_keystone_config('ldap/password').with_value('abcdefg').with_secret(true) + should contain_keystone_config('ldap/suffix').with_value('dc=example,dc=com') + should contain_keystone_config('ldap/query_scope').with_value('sub') + should contain_keystone_config('ldap/page_size').with_value('50') + + # users + should contain_keystone_config('ldap/user_tree_dn').with_value('cn=users,dc=example,dc=com') + should contain_keystone_config('ldap/user_filter').with_value('(memberOf=cn=openstack,cn=groups,cn=accounts,dc=example,dc=com)') + should contain_keystone_config('ldap/user_objectclass').with_value('inetUser') + should contain_keystone_config('ldap/user_id_attribute').with_value('uid') + should contain_keystone_config('ldap/user_name_attribute').with_value('cn') + should contain_keystone_config('ldap/user_mail_attribute').with_value('mail') + should contain_keystone_config('ldap/user_enabled_attribute').with_value('UserAccountControl') + should contain_keystone_config('ldap/user_enabled_mask').with_value('2') + should contain_keystone_config('ldap/user_enabled_default').with_value('512') + should contain_keystone_config('ldap/user_enabled_invert').with_value('False') + should contain_keystone_config('ldap/user_attribute_ignore').with_value('') + should contain_keystone_config('ldap/user_default_project_id_attribute').with_value('defaultProject') + should contain_keystone_config('ldap/user_tree_dn').with_value('cn=users,dc=example,dc=com') + should contain_keystone_config('ldap/user_allow_create').with_value('False') + should contain_keystone_config('ldap/user_allow_update').with_value('False') + should contain_keystone_config('ldap/user_allow_delete').with_value('False') + should contain_keystone_config('ldap/user_pass_attribute').with_value('krbPassword') + should contain_keystone_config('ldap/user_enabled_emulation').with_value('True') + should contain_keystone_config('ldap/user_enabled_emulation_dn').with_value('cn=openstack-enabled,cn=groups,cn=accounts,dc=example,dc=com') + should contain_keystone_config('ldap/user_additional_attribute_mapping').with_value('description:name, gecos:name') + + # projects/tenants + should contain_keystone_config('ldap/project_tree_dn').with_value('ou=projects,ou=openstack,dc=example,dc=com') + should contain_keystone_config('ldap/project_filter').with_value('') + should contain_keystone_config('ldap/project_objectclass').with_value('organizationalUnit') + should contain_keystone_config('ldap/project_id_attribute').with_value('ou') + should contain_keystone_config('ldap/project_member_attribute').with_value('member') + should contain_keystone_config('ldap/project_desc_attribute').with_value('description') + should contain_keystone_config('ldap/project_name_attribute').with_value('ou') + should contain_keystone_config('ldap/project_enabled_attribute').with_value('enabled') + should contain_keystone_config('ldap/project_domain_id_attribute').with_value('businessCategory') + should contain_keystone_config('ldap/project_attribute_ignore').with_value('') + should contain_keystone_config('ldap/project_allow_create').with_value('True') + should contain_keystone_config('ldap/project_allow_update').with_value('True') + should contain_keystone_config('ldap/project_allow_delete').with_value('True') + should contain_keystone_config('ldap/project_enabled_emulation').with_value('False') + should contain_keystone_config('ldap/project_enabled_emulation_dn').with_value('True') + should contain_keystone_config('ldap/project_additional_attribute_mapping').with_value('cn=enabled,ou=openstack,dc=example,dc=com') + + # roles + should contain_keystone_config('ldap/role_tree_dn').with_value('ou=roles,ou=openstack,dc=example,dc=com') + should contain_keystone_config('ldap/role_filter').with_value('') + should contain_keystone_config('ldap/role_objectclass').with_value('organizationalRole') + should contain_keystone_config('ldap/role_id_attribute').with_value('cn') + should contain_keystone_config('ldap/role_name_attribute').with_value('ou') + should contain_keystone_config('ldap/role_member_attribute').with_value('roleOccupant') + should contain_keystone_config('ldap/role_attribute_ignore').with_value('description') + should contain_keystone_config('ldap/role_allow_create').with_value('True') + should contain_keystone_config('ldap/role_allow_update').with_value('True') + should contain_keystone_config('ldap/role_allow_delete').with_value('True') + should contain_keystone_config('ldap/role_additional_attribute_mapping').with_value('') + + # groups + should contain_keystone_config('ldap/group_tree_dn').with_value('ou=groups,ou=openstack,dc=example,dc=com') + should contain_keystone_config('ldap/group_filter').with_value('cn=enabled-groups,cn=groups,cn=accounts,dc=example,dc=com') + should contain_keystone_config('ldap/group_objectclass').with_value('organizationalRole') + should contain_keystone_config('ldap/group_id_attribute').with_value('cn') + should contain_keystone_config('ldap/group_member_attribute').with_value('roleOccupant') + should contain_keystone_config('ldap/group_desc_attribute').with_value('description') + should contain_keystone_config('ldap/group_name_attribute').with_value('cn') + should contain_keystone_config('ldap/group_attribute_ignore').with_value('') + should contain_keystone_config('ldap/group_allow_create').with_value('False') + should contain_keystone_config('ldap/group_allow_update').with_value('False') + should contain_keystone_config('ldap/group_allow_delete').with_value('False') + should contain_keystone_config('ldap/group_additional_attribute_mapping').with_value('') + + # tls + should contain_keystone_config('ldap/use_tls').with_value('False') + should contain_keystone_config('ldap/tls_cacertdir').with_value('/etc/ssl/certs/') + should contain_keystone_config('ldap/tls_cacertfile').with_value('/etc/ssl/certs/ca-certificates.crt') + should contain_keystone_config('ldap/tls_req_cert').with_value('demand') + + # ldap pooling + should contain_keystone_config('ldap/use_pool').with_value('True') + should contain_keystone_config('ldap/pool_size').with_value('20') + should contain_keystone_config('ldap/pool_retry_max').with_value('2') + should contain_keystone_config('ldap/pool_retry_delay').with_value('0.2') + should contain_keystone_config('ldap/pool_connection_timeout').with_value('222') + should contain_keystone_config('ldap/pool_connection_lifetime').with_value('222') + should contain_keystone_config('ldap/use_auth_pool').with_value('True') + should contain_keystone_config('ldap/auth_pool_size').with_value('20') + should contain_keystone_config('ldap/auth_pool_connection_lifetime').with_value('200') + + # drivers + should contain_keystone_config('identity/driver').with_value('keystone.identity.backends.ldap.Identity') + should contain_keystone_config('assignment/driver').with_value('keystone.assignment.backends.ldap.Assignment') + end + end + + describe 'with deprecated params' do + let :params do + { + :tenant_tree_dn => 'ou=projects,ou=openstack,dc=example,dc=com', + :tenant_filter => '', + :tenant_objectclass => 'organizationalUnit', + :tenant_id_attribute => 'ou', + :tenant_member_attribute => 'member', + :tenant_desc_attribute => 'description', + :tenant_name_attribute => 'ou', + :tenant_enabled_attribute => 'enabled', + :tenant_domain_id_attribute => 'businessCategory', + :tenant_attribute_ignore => '', + :tenant_allow_create => 'True', + :tenant_allow_update => 'True', + :tenant_allow_delete => 'True', + :tenant_enabled_emulation => 'False', + :tenant_enabled_emulation_dn => 'True', + :tenant_additional_attribute_mapping => 'cn=enabled,ou=openstack,dc=example,dc=com', + } + end + it 'should work with deprecated params' do + should contain_keystone_config('ldap/project_tree_dn').with_value('ou=projects,ou=openstack,dc=example,dc=com') + should contain_keystone_config('ldap/project_filter').with_value('') + should contain_keystone_config('ldap/project_objectclass').with_value('organizationalUnit') + should contain_keystone_config('ldap/project_id_attribute').with_value('ou') + should contain_keystone_config('ldap/project_member_attribute').with_value('member') + should contain_keystone_config('ldap/project_desc_attribute').with_value('description') + should contain_keystone_config('ldap/project_name_attribute').with_value('ou') + should contain_keystone_config('ldap/project_enabled_attribute').with_value('enabled') + should contain_keystone_config('ldap/project_domain_id_attribute').with_value('businessCategory') + should contain_keystone_config('ldap/project_attribute_ignore').with_value('') + should contain_keystone_config('ldap/project_allow_create').with_value('True') + should contain_keystone_config('ldap/project_allow_update').with_value('True') + should contain_keystone_config('ldap/project_allow_delete').with_value('True') + should contain_keystone_config('ldap/project_enabled_emulation').with_value('False') + should contain_keystone_config('ldap/project_enabled_emulation_dn').with_value('True') + should contain_keystone_config('ldap/project_additional_attribute_mapping').with_value('cn=enabled,ou=openstack,dc=example,dc=com') + end + end + + describe 'with deprecated and new params both set' do + let :params do + { + :tenant_tree_dn => 'ou=projects,ou=old-openstack,dc=example,dc=com', + :project_tree_dn => 'ou=projects,ou=new-openstack,dc=example,dc=com', + } + end + it 'should fail with deprecated and new params both set' do + expect { + should compile + }.to raise_error Puppet::Error, /tenant_tree_dn and project_tree_dn are both set. results may be unexpected/ + end + end +end diff --git a/3rdparty/modules/keystone/spec/classes/keystone_logging_spec.rb b/3rdparty/modules/keystone/spec/classes/keystone_logging_spec.rb new file mode 100644 index 000000000..7ae935201 --- /dev/null +++ b/3rdparty/modules/keystone/spec/classes/keystone_logging_spec.rb @@ -0,0 +1,107 @@ +require 'spec_helper' + +describe 'keystone::logging' do + + let :params do + { + } + end + + let :log_params do + { + :logging_context_format_string => '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s', + :logging_default_format_string => '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s', + :logging_debug_format_suffix => '%(funcName)s %(pathname)s:%(lineno)d', + :logging_exception_prefix => '%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s', + :log_config_append => '/etc/keystone/logging.conf', + :publish_errors => true, + :default_log_levels => { + 'amqp' => 'WARN', 'amqplib' => 'WARN', 'boto' => 'WARN', + 'qpid' => 'WARN', 'sqlalchemy' => 'WARN', 'suds' => 'INFO', + 'iso8601' => 'WARN', + 'requests.packages.urllib3.connectionpool' => 'WARN' }, + :fatal_deprecations => true, + :instance_format => '[instance: %(uuid)s] ', + :instance_uuid_format => '[instance: %(uuid)s] ', + :log_date_format => '%Y-%m-%d %H:%M:%S', + } + end + + shared_examples_for 'keystone-logging' do + + context 'with extended logging options' do + before { params.merge!( log_params ) } + it_configures 'logging params set' + end + + context 'without extended logging options' do + it_configures 'logging params unset' + end + + end + + shared_examples_for 'logging params set' do + it 'enables logging params' do + should contain_keystone_config('DEFAULT/logging_context_format_string').with_value( + '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s') + + should contain_keystone_config('DEFAULT/logging_default_format_string').with_value( + '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s') + + should contain_keystone_config('DEFAULT/logging_debug_format_suffix').with_value( + '%(funcName)s %(pathname)s:%(lineno)d') + + should contain_keystone_config('DEFAULT/logging_exception_prefix').with_value( + '%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s') + + should contain_keystone_config('DEFAULT/log_config_append').with_value( + '/etc/keystone/logging.conf') + should contain_keystone_config('DEFAULT/publish_errors').with_value( + true) + + should contain_keystone_config('DEFAULT/default_log_levels').with_value( + 'amqp=WARN,amqplib=WARN,boto=WARN,iso8601=WARN,qpid=WARN,requests.packages.urllib3.connectionpool=WARN,sqlalchemy=WARN,suds=INFO') + + should contain_keystone_config('DEFAULT/fatal_deprecations').with_value( + true) + + should contain_keystone_config('DEFAULT/instance_format').with_value( + '[instance: %(uuid)s] ') + + should contain_keystone_config('DEFAULT/instance_uuid_format').with_value( + '[instance: %(uuid)s] ') + + should contain_keystone_config('DEFAULT/log_date_format').with_value( + '%Y-%m-%d %H:%M:%S') + end + end + + + shared_examples_for 'logging params unset' do + [ :logging_context_format_string, :logging_default_format_string, + :logging_debug_format_suffix, :logging_exception_prefix, + :log_config_append, :publish_errors, + :default_log_levels, :fatal_deprecations, + :instance_format, :instance_uuid_format, + :log_date_format, ].each { |param| + it { should contain_keystone_config("DEFAULT/#{param}").with_ensure('absent') } + } + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'keystone-logging' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'keystone-logging' + end + +end diff --git a/3rdparty/modules/keystone/spec/classes/keystone_policy_spec.rb b/3rdparty/modules/keystone/spec/classes/keystone_policy_spec.rb new file mode 100644 index 000000000..81f69da5f --- /dev/null +++ b/3rdparty/modules/keystone/spec/classes/keystone_policy_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +describe 'keystone::policy' do + + shared_examples_for 'keystone policies' do + let :params do + { + :policy_path => '/etc/keystone/policy.json', + :policies => { + 'context_is_admin' => { + 'key' => 'context_is_admin', + 'value' => 'foo:bar' + } + } + } + end + + it 'set up the policies' do + should contain_openstacklib__policy__base('context_is_admin').with({ + :key => 'context_is_admin', + :value => 'foo:bar' + }) + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'keystone policies' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'keystone policies' + end +end diff --git a/3rdparty/modules/keystone/spec/classes/keystone_python_spec.rb b/3rdparty/modules/keystone/spec/classes/keystone_python_spec.rb new file mode 100644 index 000000000..1324fb2f6 --- /dev/null +++ b/3rdparty/modules/keystone/spec/classes/keystone_python_spec.rb @@ -0,0 +1,17 @@ +require 'spec_helper' + +describe 'keystone::python' do + + let :facts do + { :osfamily => 'Debian' } + end + + it { should contain_package('python-keystone').with_ensure("present") } + + describe 'override ensure' do + let(:params) { { :ensure => "latest" } } + + it { should contain_package('python-keystone').with_ensure("latest") } + end + +end diff --git a/3rdparty/modules/keystone/spec/classes/keystone_roles_admin_spec.rb b/3rdparty/modules/keystone/spec/classes/keystone_roles_admin_spec.rb new file mode 100644 index 000000000..ba7d53296 --- /dev/null +++ b/3rdparty/modules/keystone/spec/classes/keystone_roles_admin_spec.rb @@ -0,0 +1,108 @@ +require 'spec_helper' +describe 'keystone::roles::admin' do + + describe 'with only the required params set' do + + let :params do + { + :email => 'foo@bar', + :password => 'ChangeMe', + :service_tenant => 'services' + } + end + + it { should contain_keystone_tenant('services').with( + :ensure => 'present', + :enabled => true, + :description => 'Tenant for the openstack services' + )} + it { should contain_keystone_tenant('openstack').with( + :ensure => 'present', + :enabled => true, + :description => 'admin tenant' + )} + it { should contain_keystone_user('admin').with( + :ensure => 'present', + :enabled => true, + :tenant => 'openstack', + :email => 'foo@bar', + :password => 'ChangeMe', + :ignore_default_tenant => 'false' + )} + it { should contain_keystone_role('admin').with_ensure('present') } + it { should contain_keystone_user_role('admin@openstack').with( + :roles => ['admin'], + :ensure => 'present' + )} + + end + + describe 'when overriding optional params' do + + let :params do + { + :admin => 'admin', + :email => 'foo@baz', + :password => 'foo', + :admin_tenant => 'admin', + :admin_roles => ['admin', 'heat_stack_owner'], + :service_tenant => 'foobar', + :ignore_default_tenant => 'true', + :admin_tenant_desc => 'admin something else', + :service_tenant_desc => 'foobar description', + } + end + + it { should contain_keystone_tenant('foobar').with( + :ensure => 'present', + :enabled => true, + :description => 'foobar description' + )} + it { should contain_keystone_tenant('admin').with( + :ensure => 'present', + :enabled => true, + :description => 'admin something else' + )} + it { should contain_keystone_user('admin').with( + :ensure => 'present', + :enabled => true, + :tenant => 'admin', + :email => 'foo@baz', + :password => 'foo', + :ignore_default_tenant => 'true' + )} + it { should contain_keystone_user_role('admin@admin').with( + :roles => ['admin', 'heat_stack_owner'], + :ensure => 'present' + )} + + end + + describe 'when disabling user configuration' do + before do + let :params do + { + :configure_user => false + } + end + + it { should_not contain_keystone_user('keystone') } + it { should contain_keystone_user_role('keystone@openstack') } + end + end + + describe 'when disabling user and role configuration' do + before do + let :params do + { + :configure_user => false, + :configure_user_role => false + } + end + + it { should_not contain_keystone_user('keystone') } + it { should_not contain_keystone_user_role('keystone@openstack') } + end + end + +end diff --git a/3rdparty/modules/keystone/spec/classes/keystone_service_spec.rb b/3rdparty/modules/keystone/spec/classes/keystone_service_spec.rb new file mode 100644 index 000000000..29d90b0d5 --- /dev/null +++ b/3rdparty/modules/keystone/spec/classes/keystone_service_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' + +describe 'keystone::service' do + + describe "with default parameters" do + it { should contain_service('keystone').with( + :ensure => 'running', + :enable => true, + :hasstatus => true, + :hasrestart => true + ) } + it { should_not contain_exec('validate_keystone_connection') } + end + + describe "with validation on" do + let :params do + { + :validate => 'true', + :admin_token => 'admintoken' + } + end + + it { should contain_service('keystone').with( + :ensure => 'running', + :enable => true, + :hasstatus => true, + :hasrestart => true + ) } + it { should contain_exec('validate_keystone_connection') } + end +end diff --git a/3rdparty/modules/keystone/spec/classes/keystone_spec.rb b/3rdparty/modules/keystone/spec/classes/keystone_spec.rb new file mode 100644 index 000000000..ef6358550 --- /dev/null +++ b/3rdparty/modules/keystone/spec/classes/keystone_spec.rb @@ -0,0 +1,817 @@ +require 'spec_helper' + +describe 'keystone' do + + let :global_facts do + { + :processorcount => 42, + :concat_basedir => '/var/lib/puppet/concat', + :fqdn => 'some.host.tld' + } + end + + let :facts do + global_facts.merge({ + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => '7.0' + }) + end + + default_params = { + 'admin_token' => 'service_token', + 'package_ensure' => 'present', + 'public_bind_host' => '0.0.0.0', + 'admin_bind_host' => '0.0.0.0', + 'public_port' => '5000', + 'admin_port' => '35357', + 'admin_token' => 'service_token', + 'compute_port' => '8774', + 'verbose' => false, + 'debug' => false, + 'catalog_type' => 'sql', + 'catalog_driver' => false, + 'token_provider' => 'keystone.token.providers.uuid.Provider', + 'token_driver' => 'keystone.token.persistence.backends.sql.Token', + 'cache_dir' => '/var/cache/keystone', + 'enable_ssl' => false, + 'ssl_certfile' => '/etc/keystone/ssl/certs/keystone.pem', + 'ssl_keyfile' => '/etc/keystone/ssl/private/keystonekey.pem', + 'ssl_ca_certs' => '/etc/keystone/ssl/certs/ca.pem', + 'ssl_ca_key' => '/etc/keystone/ssl/private/cakey.pem', + 'ssl_cert_subject' => '/C=US/ST=Unset/L=Unset/O=Unset/CN=localhost', + 'enabled' => true, + 'database_connection' => 'sqlite:////var/lib/keystone/keystone.db', + 'database_idle_timeout' => '200', + 'enable_pki_setup' => true, + 'signing_certfile' => '/etc/keystone/ssl/certs/signing_cert.pem', + 'signing_keyfile' => '/etc/keystone/ssl/private/signing_key.pem', + 'signing_ca_certs' => '/etc/keystone/ssl/certs/ca.pem', + 'signing_ca_key' => '/etc/keystone/ssl/private/cakey.pem', + 'rabbit_host' => 'localhost', + 'rabbit_password' => 'guest', + 'rabbit_userid' => 'guest', + } + + override_params = { + 'package_ensure' => 'latest', + 'public_bind_host' => '0.0.0.0', + 'admin_bind_host' => '0.0.0.0', + 'public_port' => '5001', + 'admin_port' => '35358', + 'admin_token' => 'service_token_override', + 'compute_port' => '8778', + 'verbose' => true, + 'debug' => true, + 'catalog_type' => 'template', + 'token_provider' => 'keystone.token.providers.uuid.Provider', + 'token_driver' => 'keystone.token.backends.kvs.Token', + 'public_endpoint' => 'https://localhost:5000/v2.0/', + 'admin_endpoint' => 'https://localhost:35357/v2.0/', + 'enable_ssl' => true, + 'ssl_certfile' => '/etc/keystone/ssl/certs/keystone.pem', + 'ssl_keyfile' => '/etc/keystone/ssl/private/keystonekey.pem', + 'ssl_ca_certs' => '/etc/keystone/ssl/certs/ca.pem', + 'ssl_ca_key' => '/etc/keystone/ssl/private/cakey.pem', + 'ssl_cert_subject' => '/C=US/ST=Unset/L=Unset/O=Unset/CN=localhost', + 'enabled' => false, + 'database_connection' => 'mysql://a:b@c/d', + 'database_idle_timeout' => '300', + 'enable_pki_setup' => true, + 'signing_certfile' => '/etc/keystone/ssl/certs/signing_cert.pem', + 'signing_keyfile' => '/etc/keystone/ssl/private/signing_key.pem', + 'signing_ca_certs' => '/etc/keystone/ssl/certs/ca.pem', + 'signing_ca_key' => '/etc/keystone/ssl/private/cakey.pem', + 'rabbit_host' => '127.0.0.1', + 'rabbit_password' => 'openstack', + 'rabbit_userid' => 'admin', + } + + httpd_params = {'service_name' => 'httpd'}.merge(default_params) + + shared_examples_for 'core keystone examples' do |param_hash| + it { should contain_class('keystone::params') } + + it { should contain_package('keystone').with( + 'ensure' => param_hash['package_ensure'], + 'tag' => 'openstack' + ) } + + it { should contain_group('keystone').with( + 'ensure' => 'present', + 'system' => true + ) } + + it { should contain_user('keystone').with( + 'ensure' => 'present', + 'gid' => 'keystone', + 'system' => true + ) } + + it 'should contain the expected directories' do + ['/etc/keystone', '/var/log/keystone', '/var/lib/keystone'].each do |d| + should contain_file(d).with( + 'ensure' => 'directory', + 'owner' => 'keystone', + 'group' => 'keystone', + 'mode' => '0750', + 'require' => 'Package[keystone]' + ) + end + end + + it 'should only synchronize the db if $enabled is true' do + if param_hash['enabled'] + should contain_exec('keystone-manage db_sync').with( + :user => 'keystone', + :refreshonly => true, + :subscribe => ['Package[keystone]', 'Keystone_config[database/connection]'], + :require => 'User[keystone]' + ) + end + end + + it 'should contain correct config' do + [ + 'public_bind_host', + 'admin_bind_host', + 'public_port', + 'admin_port', + 'compute_port', + 'verbose', + 'debug' + ].each do |config| + should contain_keystone_config("DEFAULT/#{config}").with_value(param_hash[config]) + end + end + + it 'should contain correct admin_token config' do + should contain_keystone_config('DEFAULT/admin_token').with_value(param_hash['admin_token']).with_secret(true) + end + + it 'should contain correct mysql config' do + should contain_keystone_config('database/idle_timeout').with_value(param_hash['database_idle_timeout']) + should contain_keystone_config('database/connection').with_value(param_hash['database_connection']).with_secret(true) + end + + it { should contain_keystone_config('token/provider').with_value( + param_hash['token_provider'] + ) } + + it 'should contain correct token driver' do + should contain_keystone_config('token/driver').with_value(param_hash['token_driver']) + end + + it 'should ensure proper setting of admin_endpoint and public_endpoint' do + if param_hash['admin_endpoint'] + should contain_keystone_config('DEFAULT/admin_endpoint').with_value(param_hash['admin_endpoint']) + else + should contain_keystone_config('DEFAULT/admin_endpoint').with_ensure('absent') + end + if param_hash['public_endpoint'] + should contain_keystone_config('DEFAULT/public_endpoint').with_value(param_hash['public_endpoint']) + else + should contain_keystone_config('DEFAULT/public_endpoint').with_ensure('absent') + end + end + + it 'should contain correct rabbit_password' do + should contain_keystone_config('DEFAULT/rabbit_password').with_value(param_hash['rabbit_password']).with_secret(true) + end + end + + [default_params, override_params].each do |param_hash| + describe "when #{param_hash == default_params ? "using default" : "specifying"} class parameters for service" do + + let :params do + param_hash + end + + it_configures 'core keystone examples', param_hash + + it { should contain_service('keystone').with( + 'ensure' => param_hash['enabled'] ? 'running' : 'stopped', + 'enable' => param_hash['enabled'], + 'hasstatus' => true, + 'hasrestart' => true + ) } + + end + end + + describe "when using default class parameters for httpd" do + let :params do + httpd_params + end + + let :pre_condition do + 'include ::apache' + end + + it_configures 'core keystone examples', httpd_params + + it do + expect { + should contain_service('keystone') + }.to raise_error(RSpec::Expectations::ExpectationNotMetError, /expected that the catalogue would contain Service\[keystone\]/) + end + + end + + describe 'with deprecated sql_connection parameter' do + let :params do + { :admin_token => 'service_token', + :sql_connection => 'mysql://a:b@c/d' } + end + + it { should contain_keystone_config('database/connection').with_value(params[:sql_connection]) } + end + + describe 'with deprecated idle_timeout parameter' do + let :params do + { :admin_token => 'service_token', + :idle_timeout => 365 } + end + + it { should contain_keystone_config('database/idle_timeout').with_value(params[:idle_timeout]) } + end + + describe 'when configuring signing token provider' do + + describe 'when configuring as UUID' do + let :params do + { + 'admin_token' => 'service_token', + 'token_provider' => 'keystone.token.providers.uuid.Provider' + } + end + it { should contain_exec('keystone-manage pki_setup').with( + :creates => '/etc/keystone/ssl/private/signing_key.pem' + ) } + it { should contain_file('/var/cache/keystone').with_ensure('directory') } + + describe 'when overriding the cache dir' do + before do + params.merge!(:cache_dir => '/var/lib/cache/keystone') + end + it { should contain_file('/var/lib/cache/keystone') } + end + + describe 'when disable pki_setup' do + before do + params.merge!(:enable_pki_setup => false) + end + it { should_not contain_exec('keystone-manage pki_setup') } + end + end + + describe 'when configuring as PKI' do + let :params do + { + 'admin_token' => 'service_token', + 'token_provider' => 'keystone.token.providers.pki.Provider' + } + end + it { should contain_exec('keystone-manage pki_setup').with( + :creates => '/etc/keystone/ssl/private/signing_key.pem' + ) } + it { should contain_file('/var/cache/keystone').with_ensure('directory') } + + describe 'when overriding the cache dir' do + before do + params.merge!(:cache_dir => '/var/lib/cache/keystone') + end + it { should contain_file('/var/lib/cache/keystone') } + end + + describe 'when disable pki_setup' do + before do + params.merge!(:enable_pki_setup => false) + end + it { should_not contain_exec('keystone-manage pki_setup') } + end + end + + describe 'when configuring PKI signing cert paths with UUID and with pki_setup disabled' do + let :params do + { + 'admin_token' => 'service_token', + 'token_provider' => 'keystone.token.providers.uuid.Provider', + 'enable_pki_setup' => false, + 'signing_certfile' => 'signing_certfile', + 'signing_keyfile' => 'signing_keyfile', + 'signing_ca_certs' => 'signing_ca_certs', + 'signing_ca_key' => 'signing_ca_key', + 'signing_cert_subject' => 'signing_cert_subject', + 'signing_key_size' => 2048 + } + end + + it { should_not contain_exec('keystone-manage pki_setup') } + + it 'should contain correct PKI certfile config' do + should contain_keystone_config('signing/certfile').with_value('signing_certfile') + end + + it 'should contain correct PKI keyfile config' do + should contain_keystone_config('signing/keyfile').with_value('signing_keyfile') + end + + it 'should contain correct PKI ca_certs config' do + should contain_keystone_config('signing/ca_certs').with_value('signing_ca_certs') + end + + it 'should contain correct PKI ca_key config' do + should contain_keystone_config('signing/ca_key').with_value('signing_ca_key') + end + + it 'should contain correct PKI cert_subject config' do + should contain_keystone_config('signing/cert_subject').with_value('signing_cert_subject') + end + + it 'should contain correct PKI key_size config' do + should contain_keystone_config('signing/key_size').with_value('2048') + end + end + + describe 'when configuring PKI signing cert paths with pki_setup disabled' do + let :params do + { + 'admin_token' => 'service_token', + 'token_provider' => 'keystone.token.providers.pki.Provider', + 'enable_pki_setup' => false, + 'signing_certfile' => 'signing_certfile', + 'signing_keyfile' => 'signing_keyfile', + 'signing_ca_certs' => 'signing_ca_certs', + 'signing_ca_key' => 'signing_ca_key', + 'signing_cert_subject' => 'signing_cert_subject', + 'signing_key_size' => 2048 + } + end + + it { should_not contain_exec('keystone-manage pki_setup') } + + it 'should contain correct PKI certfile config' do + should contain_keystone_config('signing/certfile').with_value('signing_certfile') + end + + it 'should contain correct PKI keyfile config' do + should contain_keystone_config('signing/keyfile').with_value('signing_keyfile') + end + + it 'should contain correct PKI ca_certs config' do + should contain_keystone_config('signing/ca_certs').with_value('signing_ca_certs') + end + + it 'should contain correct PKI ca_key config' do + should contain_keystone_config('signing/ca_key').with_value('signing_ca_key') + end + + it 'should contain correct PKI cert_subject config' do + should contain_keystone_config('signing/cert_subject').with_value('signing_cert_subject') + end + + it 'should contain correct PKI key_size config' do + should contain_keystone_config('signing/key_size').with_value('2048') + end + end + + describe 'with invalid catalog_type' do + let :params do + { :admin_token => 'service_token', + :catalog_type => 'invalid' } + end + + it_raises "a Puppet::Error", /validate_re\(\): "invalid" does not match "template|sql"/ + end + + describe 'when configuring catalog driver' do + let :params do + { :admin_token => 'service_token', + :catalog_driver => 'keystone.catalog.backends.alien.AlienCatalog' } + end + + it { should contain_keystone_config('catalog/driver').with_value(params[:catalog_driver]) } + end + + describe 'when configuring deprecated token_format as UUID with enable_pki_setup' do + let :params do + { + 'admin_token' => 'service_token', + 'token_format' => 'UUID' + } + end + it { should contain_exec('keystone-manage pki_setup').with( + :creates => '/etc/keystone/ssl/private/signing_key.pem' + ) } + it { should contain_file('/var/cache/keystone').with_ensure('directory') } + describe 'when overriding the cache dir' do + let :params do + { + 'admin_token' => 'service_token', + 'token_provider' => 'keystone.token.providers.pki.Provider', + 'cache_dir' => '/var/lib/cache/keystone' + } + end + it { should contain_file('/var/lib/cache/keystone') } + end + end + + describe 'when configuring deprecated token_format as UUID without enable_pki_setup' do + let :params do + { + 'admin_token' => 'service_token', + 'token_format' => 'UUID', + 'enable_pki_setup' => false + } + end + it { should_not contain_exec('keystone-manage pki_setup') } + it { should contain_file('/var/cache/keystone').with_ensure('directory') } + describe 'when overriding the cache dir' do + let :params do + { + 'admin_token' => 'service_token', + 'token_provider' => 'keystone.token.providers.uuid.Provider', + 'cache_dir' => '/var/lib/cache/keystone' + } + end + it { should contain_file('/var/lib/cache/keystone') } + end + end + + describe 'when configuring deprecated token_format as PKI with enable_pki_setup' do + let :params do + { + 'admin_token' => 'service_token', + 'token_format' => 'PKI', + } + end + it { should contain_exec('keystone-manage pki_setup').with( + :creates => '/etc/keystone/ssl/private/signing_key.pem' + ) } + it { should contain_file('/var/cache/keystone').with_ensure('directory') } + describe 'when overriding the cache dir' do + let :params do + { + 'admin_token' => 'service_token', + 'token_provider' => 'keystone.token.providers.pki.Provider', + 'cache_dir' => '/var/lib/cache/keystone' + } + end + it { should contain_file('/var/lib/cache/keystone') } + end + end + + describe 'when configuring deprecated token_format as PKI without enable_pki_setup' do + let :params do + { + 'admin_token' => 'service_token', + 'token_format' => 'PKI', + 'enable_pki_setup' => false + } + end + it { should_not contain_exec('keystone-manage pki_setup') } + it { should contain_file('/var/cache/keystone').with_ensure('directory') } + describe 'when overriding the cache dir' do + let :params do + { + 'admin_token' => 'service_token', + 'token_provider' => 'keystone.token.providers.pki.Provider', + 'cache_dir' => '/var/lib/cache/keystone' + } + end + it { should contain_file('/var/lib/cache/keystone') } + end + end + + end + + describe 'when configuring token expiration' do + let :params do + { + 'admin_token' => 'service_token', + 'token_expiration' => '42', + } + end + + it { should contain_keystone_config("token/expiration").with_value('42') } + end + + describe 'when not configuring token expiration' do + let :params do + { + 'admin_token' => 'service_token', + } + end + + it { should contain_keystone_config("token/expiration").with_value('3600') } + end + + describe 'configure memcache servers if set' do + let :params do + { + 'admin_token' => 'service_token', + 'memcache_servers' => [ 'SERVER1:11211', 'SERVER2:11211' ], + 'token_driver' => 'keystone.token.backends.memcache.Token', + 'cache_backend' => 'dogpile.cache.memcached', + 'cache_backend_argument' => ['url:SERVER1:12211'], + } + end + + it { should contain_keystone_config("memcache/servers").with_value('SERVER1:11211,SERVER2:11211') } + it { should contain_keystone_config('cache/enabled').with_value(true) } + it { should contain_keystone_config('token/caching').with_value(true) } + it { should contain_keystone_config('cache/backend').with_value('dogpile.cache.memcached') } + it { should contain_keystone_config('cache/backend_argument').with_value('url:SERVER1:12211') } + it { should contain_package('python-memcache').with( + :name => 'python-memcache', + :ensure => 'present' + ) } + end + + describe 'do not configure memcache servers when not set' do + let :params do + default_params + end + + it { should contain_keystone_config("cache/enabled").with_ensure('absent') } + it { should contain_keystone_config("token/caching").with_ensure('absent') } + it { should contain_keystone_config("cache/backend").with_ensure('absent') } + it { should contain_keystone_config("cache/backend_argument").with_ensure('absent') } + it { should contain_keystone_config("cache/debug_cache_backend").with_ensure('absent') } + it { should contain_keystone_config("memcache/servers").with_ensure('absent') } + end + + describe 'raise error if memcache_servers is not an array' do + let :params do + { + 'admin_token' => 'service_token', + 'memcache_servers' => 'ANY_SERVER:11211' + } + end + + it { expect { should contain_class('keystone::params') }.to \ + raise_error(Puppet::Error, /is not an Array/) } + end + + describe 'with syslog disabled by default' do + let :params do + default_params + end + + it { should contain_keystone_config('DEFAULT/use_syslog').with_value(false) } + it { should_not contain_keystone_config('DEFAULT/syslog_log_facility') } + end + + describe 'with syslog enabled' do + let :params do + default_params.merge({ + :use_syslog => 'true', + }) + end + + it { should contain_keystone_config('DEFAULT/use_syslog').with_value(true) } + it { should contain_keystone_config('DEFAULT/syslog_log_facility').with_value('LOG_USER') } + end + + describe 'with syslog enabled and custom settings' do + let :params do + default_params.merge({ + :use_syslog => 'true', + :log_facility => 'LOG_LOCAL0' + }) + end + + it { should contain_keystone_config('DEFAULT/use_syslog').with_value(true) } + it { should contain_keystone_config('DEFAULT/syslog_log_facility').with_value('LOG_LOCAL0') } + end + + describe 'with log_file disabled by default' do + let :params do + default_params + end + it { should contain_keystone_config('DEFAULT/log_file').with_ensure('absent') } + end + + describe 'with log_file and log_dir enabled' do + let :params do + default_params.merge({ + :log_file => 'keystone.log', + :log_dir => '/var/lib/keystone' + }) + end + it { should contain_keystone_config('DEFAULT/log_file').with_value('keystone.log') } + it { should contain_keystone_config('DEFAULT/log_dir').with_value('/var/lib/keystone') } + end + + describe 'with log_file and log_dir disabled' do + let :params do + default_params.merge({ + :log_file => false, + :log_dir => false + }) + end + it { should contain_keystone_config('DEFAULT/log_file').with_ensure('absent') } + it { should contain_keystone_config('DEFAULT/log_dir').with_ensure('absent') } + end + + describe 'when configuring api binding with deprecated parameter' do + let :params do + default_params.merge({ + :bind_host => '10.0.0.2', + }) + end + it { should contain_keystone_config('DEFAULT/public_bind_host').with_value('10.0.0.2') } + it { should contain_keystone_config('DEFAULT/admin_bind_host').with_value('10.0.0.2') } + end + + describe 'when enabling SSL' do + let :params do + { + 'admin_token' => 'service_token', + 'enable_ssl' => true, + 'public_endpoint' => 'https://localhost:5000/v2.0/', + 'admin_endpoint' => 'https://localhost:35357/v2.0/', + } + end + it {should contain_keystone_config('ssl/enable').with_value(true)} + it {should contain_keystone_config('ssl/certfile').with_value('/etc/keystone/ssl/certs/keystone.pem')} + it {should contain_keystone_config('ssl/keyfile').with_value('/etc/keystone/ssl/private/keystonekey.pem')} + it {should contain_keystone_config('ssl/ca_certs').with_value('/etc/keystone/ssl/certs/ca.pem')} + it {should contain_keystone_config('ssl/ca_key').with_value('/etc/keystone/ssl/private/cakey.pem')} + it {should contain_keystone_config('ssl/cert_subject').with_value('/C=US/ST=Unset/L=Unset/O=Unset/CN=localhost')} + it {should contain_keystone_config('DEFAULT/public_endpoint').with_value('https://localhost:5000/v2.0/')} + it {should contain_keystone_config('DEFAULT/admin_endpoint').with_value('https://localhost:35357/v2.0/')} + end + describe 'when disabling SSL' do + let :params do + { + 'admin_token' => 'service_token', + 'enable_ssl' => false, + } + end + it {should contain_keystone_config('ssl/enable').with_value(false)} + it {should contain_keystone_config('DEFAULT/public_endpoint').with_ensure('absent')} + it {should contain_keystone_config('DEFAULT/admin_endpoint').with_ensure('absent')} + end + describe 'not setting notification settings by default' do + let :params do + default_params + end + + it { should contain_keystone_config('DEFAULT/notification_driver').with_value(nil) } + it { should contain_keystone_config('DEFAULT/notification_topics').with_vaule(nil) } + it { should contain_keystone_config('DEFAULT/control_exchange').with_vaule(nil) } + end + + describe 'with RabbitMQ communication SSLed' do + let :params do + default_params.merge!({ + :rabbit_use_ssl => true, + :kombu_ssl_ca_certs => '/path/to/ssl/ca/certs', + :kombu_ssl_certfile => '/path/to/ssl/cert/file', + :kombu_ssl_keyfile => '/path/to/ssl/keyfile', + :kombu_ssl_version => 'TLSv1' + }) + end + + it do + should contain_keystone_config('DEFAULT/rabbit_use_ssl').with_value('true') + should contain_keystone_config('DEFAULT/kombu_ssl_ca_certs').with_value('/path/to/ssl/ca/certs') + should contain_keystone_config('DEFAULT/kombu_ssl_certfile').with_value('/path/to/ssl/cert/file') + should contain_keystone_config('DEFAULT/kombu_ssl_keyfile').with_value('/path/to/ssl/keyfile') + should contain_keystone_config('DEFAULT/kombu_ssl_version').with_value('TLSv1') + end + end + + describe 'with RabbitMQ communication not SSLed' do + let :params do + default_params.merge!({ + :rabbit_use_ssl => false, + :kombu_ssl_ca_certs => 'undef', + :kombu_ssl_certfile => 'undef', + :kombu_ssl_keyfile => 'undef', + :kombu_ssl_version => 'TLSv1' + }) + end + + it do + should contain_keystone_config('DEFAULT/rabbit_use_ssl').with_value('false') + should contain_keystone_config('DEFAULT/kombu_ssl_ca_certs').with_ensure('absent') + should contain_keystone_config('DEFAULT/kombu_ssl_certfile').with_ensure('absent') + should contain_keystone_config('DEFAULT/kombu_ssl_keyfile').with_ensure('absent') + should contain_keystone_config('DEFAULT/kombu_ssl_version').with_ensure('absent') + end + end + + describe 'setting notification settings' do + let :params do + default_params.merge({ + :notification_driver => 'keystone.openstack.common.notifier.rpc_notifier', + :notification_topics => 'notifications', + :control_exchange => 'keystone' + }) + end + + it { should contain_keystone_config('DEFAULT/notification_driver').with_value('keystone.openstack.common.notifier.rpc_notifier') } + it { should contain_keystone_config('DEFAULT/notification_topics').with_value('notifications') } + it { should contain_keystone_config('DEFAULT/control_exchange').with_value('keystone') } + end + + describe 'setting sql (default) catalog' do + let :params do + default_params + end + + it { should contain_keystone_config('catalog/driver').with_value('keystone.catalog.backends.sql.Catalog') } + end + + describe 'setting default template catalog' do + let :params do + { + :admin_token => 'service_token', + :catalog_type => 'template' + } + end + + it { should contain_keystone_config('catalog/driver').with_value('keystone.catalog.backends.templated.Catalog') } + it { should contain_keystone_config('catalog/template_file').with_value('/etc/keystone/default_catalog.templates') } + end + + describe 'with overridden validation_auth_url' do + let :params do + { + :admin_token => 'service_token', + :validate_service => true, + :validate_auth_url => 'http://some.host:35357/v2.0', + :admin_endpoint => 'http://some.host:35357' + } + end + + it { should contain_keystone_config('DEFAULT/admin_endpoint').with_value('http://some.host:35357') } + it { should contain_class('keystone::service').with( + 'validate' => true, + 'admin_endpoint' => 'http://some.host:35357/v2.0' + )} + end + + describe 'with service validation' do + let :params do + { + :admin_token => 'service_token', + :validate_service => true, + :admin_endpoint => 'http://some.host:35357' + } + end + + it { should contain_class('keystone::service').with( + 'validate' => true, + 'admin_endpoint' => 'http://some.host:35357' + )} + end + + describe 'setting another template catalog' do + let :params do + { + :admin_token => 'service_token', + :catalog_type => 'template', + :catalog_template_file => '/some/template_file' + } + end + + it { should contain_keystone_config('catalog/driver').with_value('keystone.catalog.backends.templated.Catalog') } + it { should contain_keystone_config('catalog/template_file').with_value('/some/template_file') } + end + + describe 'setting service_provider' do + let :facts do + global_facts.merge({ + :osfamily => 'RedHat', + :operatingsystemrelease => '6.0' + }) + end + + describe 'with default service_provider' do + let :params do + { 'admin_token' => 'service_token' } + end + + it { should contain_service('keystone').with( + :provider => nil + )} + end + + describe 'with overrided service_provider' do + let :params do + { + 'admin_token' => 'service_token', + 'service_provider' => 'pacemaker' + } + end + + it { should contain_service('keystone').with( + :provider => 'pacemaker' + )} + end + end +end diff --git a/3rdparty/modules/keystone/spec/classes/keystone_wsgi_apache_spec.rb b/3rdparty/modules/keystone/spec/classes/keystone_wsgi_apache_spec.rb new file mode 100644 index 000000000..f2a22d619 --- /dev/null +++ b/3rdparty/modules/keystone/spec/classes/keystone_wsgi_apache_spec.rb @@ -0,0 +1,253 @@ +require 'spec_helper' + +describe 'keystone::wsgi::apache' do + + let :global_facts do + { + :processorcount => 42, + :concat_basedir => '/var/lib/puppet/concat', + :fqdn => 'some.host.tld' + } + end + + let :pre_condition do + [ + 'class { keystone: admin_token => "dummy", service_name => "httpd", enable_ssl => true }' + ] + end + + shared_examples_for 'apache serving keystone with mod_wsgi' do + it { should contain_service('httpd').with_name(platform_parameters[:httpd_service_name]) } + it { should contain_class('keystone::params') } + it { should contain_class('apache') } + it { should contain_class('apache::mod::wsgi') } + it { should contain_class('keystone::db::sync') } + + describe 'with default parameters' do + + it { should contain_file("#{platform_parameters[:wsgi_script_path]}").with( + 'ensure' => 'directory', + 'owner' => 'keystone', + 'group' => 'keystone', + 'require' => 'Package[httpd]' + )} + + it { should contain_file('keystone_wsgi_admin').with( + 'ensure' => 'file', + 'path' => "#{platform_parameters[:wsgi_script_path]}/admin", + 'source' => platform_parameters[:wsgi_script_source], + 'owner' => 'keystone', + 'group' => 'keystone', + 'mode' => '0644', + 'require' => ["File[#{platform_parameters[:wsgi_script_path]}]", "Package[keystone]"] + )} + + it { should contain_file('keystone_wsgi_main').with( + 'ensure' => 'file', + 'path' => "#{platform_parameters[:wsgi_script_path]}/main", + 'source' => platform_parameters[:wsgi_script_source], + 'owner' => 'keystone', + 'group' => 'keystone', + 'mode' => '0644', + 'require' => ["File[#{platform_parameters[:wsgi_script_path]}]", "Package[keystone]"] + )} + + it { should contain_apache__vhost('keystone_wsgi_admin').with( + 'servername' => 'some.host.tld', + 'ip' => nil, + 'port' => '35357', + 'docroot' => "#{platform_parameters[:wsgi_script_path]}", + 'docroot_owner' => 'keystone', + 'docroot_group' => 'keystone', + 'ssl' => 'true', + 'wsgi_daemon_process' => 'keystone_admin', + 'wsgi_daemon_process_options' => { + 'user' => 'keystone', + 'group' => 'keystone', + 'processes' => '1', + 'threads' => '42', + 'display-name' => 'keystone-admin', + }, + 'wsgi_process_group' => 'keystone_admin', + 'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/admin" }, + 'require' => 'File[keystone_wsgi_admin]' + )} + + it { should contain_apache__vhost('keystone_wsgi_main').with( + 'servername' => 'some.host.tld', + 'ip' => nil, + 'port' => '5000', + 'docroot' => "#{platform_parameters[:wsgi_script_path]}", + 'docroot_owner' => 'keystone', + 'docroot_group' => 'keystone', + 'ssl' => 'true', + 'wsgi_daemon_process' => 'keystone_main', + 'wsgi_daemon_process_options' => { + 'user' => 'keystone', + 'group' => 'keystone', + 'processes' => '1', + 'threads' => '42', + 'display-name' => 'keystone-main', + }, + 'wsgi_process_group' => 'keystone_main', + 'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/main" }, + 'require' => 'File[keystone_wsgi_main]' + )} + it { should contain_file("#{platform_parameters[:httpd_ports_file]}") } + end + + describe 'when overriding parameters using different ports' do + let :params do + { + :servername => 'dummy.host', + :bind_host => '10.42.51.1', + :public_port => 12345, + :admin_port => 4142, + :ssl => false, + :workers => 37, + } + end + + it { should contain_apache__vhost('keystone_wsgi_admin').with( + 'servername' => 'dummy.host', + 'ip' => '10.42.51.1', + 'port' => '4142', + 'docroot' => "#{platform_parameters[:wsgi_script_path]}", + 'docroot_owner' => 'keystone', + 'docroot_group' => 'keystone', + 'ssl' => 'false', + 'wsgi_daemon_process' => 'keystone_admin', + 'wsgi_daemon_process_options' => { + 'user' => 'keystone', + 'group' => 'keystone', + 'processes' => '37', + 'threads' => '42', + 'display-name' => 'keystone-admin', + }, + 'wsgi_process_group' => 'keystone_admin', + 'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/admin" }, + 'require' => 'File[keystone_wsgi_admin]' + )} + + it { should contain_apache__vhost('keystone_wsgi_main').with( + 'servername' => 'dummy.host', + 'ip' => '10.42.51.1', + 'port' => '12345', + 'docroot' => "#{platform_parameters[:wsgi_script_path]}", + 'docroot_owner' => 'keystone', + 'docroot_group' => 'keystone', + 'ssl' => 'false', + 'wsgi_daemon_process' => 'keystone_main', + 'wsgi_daemon_process_options' => { + 'user' => 'keystone', + 'group' => 'keystone', + 'processes' => '37', + 'threads' => '42', + 'display-name' => 'keystone-main', + }, + 'wsgi_process_group' => 'keystone_main', + 'wsgi_script_aliases' => { '/' => "#{platform_parameters[:wsgi_script_path]}/main" }, + 'require' => 'File[keystone_wsgi_main]' + )} + + it { should contain_file("#{platform_parameters[:httpd_ports_file]}") } + end + + describe 'when overriding parameters using same port' do + let :params do + { + :servername => 'dummy.host', + :public_port => 4242, + :admin_port => 4242, + :public_path => '/main/endpoint/', + :admin_path => '/admin/endpoint/', + :ssl => true, + :workers => 37, + } + end + + it { should_not contain_apache__vhost('keystone_wsgi_admin') } + + it { should contain_apache__vhost('keystone_wsgi_main').with( + 'servername' => 'dummy.host', + 'ip' => nil, + 'port' => '4242', + 'docroot' => "#{platform_parameters[:wsgi_script_path]}", + 'docroot_owner' => 'keystone', + 'docroot_group' => 'keystone', + 'ssl' => 'true', + 'wsgi_daemon_process' => 'keystone_main', + 'wsgi_daemon_process_options' => { + 'user' => 'keystone', + 'group' => 'keystone', + 'processes' => '37', + 'threads' => '42', + 'display-name' => 'keystone-main', + }, + 'wsgi_process_group' => 'keystone_main', + 'wsgi_script_aliases' => { + '/main/endpoint' => "#{platform_parameters[:wsgi_script_path]}/main", + '/admin/endpoint' => "#{platform_parameters[:wsgi_script_path]}/admin" + }, + 'require' => 'File[keystone_wsgi_main]' + )} + end + + describe 'when overriding parameters using same port and same path' do + let :params do + { + :servername => 'dummy.host', + :public_port => 4242, + :admin_port => 4242, + :public_path => '/endpoint/', + :admin_path => '/endpoint/', + :ssl => true, + :workers => 37, + } + end + + it_raises 'a Puppet::Error', /When using the same port for public & private endpoints, public_path and admin_path should be different\./ + end + end + + context 'on RedHat platforms' do + let :facts do + global_facts.merge({ + :osfamily => 'RedHat', + :operatingsystemrelease => '6.0' + }) + end + + let :platform_parameters do + { + :httpd_service_name => 'httpd', + :httpd_ports_file => '/etc/httpd/conf/ports.conf', + :wsgi_script_path => '/var/www/cgi-bin/keystone', + :wsgi_script_source => '/usr/share/keystone/keystone.wsgi' + } + end + + it_configures 'apache serving keystone with mod_wsgi' + end + + context 'on Debian platforms' do + let :facts do + global_facts.merge({ + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => '7.0' + }) + end + + let :platform_parameters do + { + :httpd_service_name => 'apache2', + :httpd_ports_file => '/etc/apache2/ports.conf', + :wsgi_script_path => '/usr/lib/cgi-bin/keystone', + :wsgi_script_source => '/usr/share/keystone/wsgi.py' + } + end + + it_configures 'apache serving keystone with mod_wsgi' + end +end diff --git a/3rdparty/modules/keystone/spec/defines/keystone_resource_service_identity_spec.rb b/3rdparty/modules/keystone/spec/defines/keystone_resource_service_identity_spec.rb new file mode 100644 index 000000000..d7d0a62c5 --- /dev/null +++ b/3rdparty/modules/keystone/spec/defines/keystone_resource_service_identity_spec.rb @@ -0,0 +1,89 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +require 'spec_helper' + +describe 'keystone::resource::service_identity' do + + let (:title) { 'neutron' } + + let :required_params do + { :password => 'secrete', + :service_type => 'network', + :admin_url => 'http://192.168.0.1:9696', + :internal_url => 'http://10.0.0.1:9696', + :public_url => 'http://7.7.7.7:9696' } + end + + shared_examples 'keystone::resource::service_identity examples' do + + context 'with only required parameters' do + let :params do + required_params + end + + it { should contain_keystone_user(title).with( + :ensure => 'present', + :password => 'secrete', + :email => 'neutron@localhost', + :tenant => 'services', + )} + + it { should contain_keystone_user_role("#{title}@services").with( + :ensure => 'present', + :roles => 'admin', + )} + + it { should contain_keystone_service(title).with( + :ensure => 'present', + :type => 'network', + :description => 'neutron service', + )} + + it { should contain_keystone_endpoint("RegionOne/#{title}").with( + :ensure => 'present', + :public_url => 'http://7.7.7.7:9696', + :internal_url => 'http://10.0.0.1:9696', + :admin_url => 'http://192.168.0.1:9696', + )} + end + + context 'when omitting a required parameter password' do + let :params do + required_params.delete(:password) + end + it { expect { should raise_error(Puppet::Error) } } + end + + end + + context 'on a Debian osfamily' do + let :facts do + { :osfamily => "Debian" } + end + + include_examples 'keystone::resource::service_identity examples' + end + + context 'on a RedHat osfamily' do + let :facts do + { :osfamily => 'RedHat' } + end + + include_examples 'keystone::resource::service_identity examples' + end +end diff --git a/3rdparty/modules/keystone/spec/shared_examples.rb b/3rdparty/modules/keystone/spec/shared_examples.rb new file mode 100644 index 000000000..d92156a36 --- /dev/null +++ b/3rdparty/modules/keystone/spec/shared_examples.rb @@ -0,0 +1,5 @@ +shared_examples_for "a Puppet::Error" do |description| + it "with message matching #{description.inspect}" do + expect { should have_class_count(1) }.to raise_error(Puppet::Error, description) + end +end diff --git a/3rdparty/modules/keystone/spec/spec.opts b/3rdparty/modules/keystone/spec/spec.opts new file mode 100644 index 000000000..91cd6427e --- /dev/null +++ b/3rdparty/modules/keystone/spec/spec.opts @@ -0,0 +1,6 @@ +--format +s +--colour +--loadby +mtime +--backtrace diff --git a/3rdparty/modules/keystone/spec/spec_helper.rb b/3rdparty/modules/keystone/spec/spec_helper.rb new file mode 100644 index 000000000..a6c4788bd --- /dev/null +++ b/3rdparty/modules/keystone/spec/spec_helper.rb @@ -0,0 +1,10 @@ +# Load libraries from openstacklib here to simulate how they live together in a real puppet run (for provider unit tests) +$LOAD_PATH.push(File.join(File.dirname(__FILE__), 'fixtures', 'modules', 'openstacklib', 'lib')) +require 'puppetlabs_spec_helper/module_spec_helper' +require 'shared_examples' + +RSpec.configure do |c| + c.alias_it_should_behave_like_to :it_configures, 'configures' + c.alias_it_should_behave_like_to :it_raises, 'raises' +end + diff --git a/3rdparty/modules/keystone/spec/unit/provider/keystone_endpoint/openstack_spec.rb b/3rdparty/modules/keystone/spec/unit/provider/keystone_endpoint/openstack_spec.rb new file mode 100644 index 000000000..a0ac7523e --- /dev/null +++ b/3rdparty/modules/keystone/spec/unit/provider/keystone_endpoint/openstack_spec.rb @@ -0,0 +1,113 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/keystone_endpoint/openstack' + +provider_class = Puppet::Type.type(:keystone_endpoint).provider(:openstack) + +describe provider_class do + + describe 'when updating an endpoint' do + + let(:endpoint_attrs) do + { + :name => 'foo/bar', + :ensure => 'present', + :public_url => 'http://127.0.0.1:5000/v2.0', + :internal_url => 'http://127.0.0.1:5001/v2.0', + :admin_url => 'http://127.0.0.1:5002/v2.0', + :auth => { + 'username' => 'test', + 'password' => 'abc123', + 'tenant_name' => 'foo', + 'auth_url' => 'http://127.0.0.1:5000/v2.0', + } + } + end + + let(:resource) do + Puppet::Type::Keystone_endpoint.new(endpoint_attrs) + end + + let(:provider) do + provider_class.new(resource) + end + + describe '#create' do + it 'creates an endpoint' do + provider.class.stubs(:openstack) + .with('endpoint', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Region","Service Name","Service Type","PublicURL","AdminURL","InternalURL" +"1cb05cfed7c24279be884ba4f6520262","foo","bar","","http://127.0.0.1:5000/v2.0","http://127.0.0.1:5001/v2.0","http://127.0.0.1:5002/v2.0" +') + provider.class.stubs(:openstack) + .with('endpoint', 'create', '--format', 'shell', [['bar', '--region', 'foo', '--publicurl', 'http://127.0.0.1:5000/v2.0', '--internalurl', 'http://127.0.0.1:5001/v2.0', '--adminurl', 'http://127.0.0.1:5002/v2.0', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('adminurl="http://127.0.0.1:5002/v2.0" +id="3a5c4378981e4112a0d44902a43e16ef" +internalurl="http://127.0.0.1:5001/v2.0" +publicurl="http://127.0.0.1:5000/v2.0" +region="foo" +service_id="8137d72980fd462192f276585a002426" +service_name="bar" +service_type="test" +') + provider.create + expect(provider.exists?).to be_truthy + end + end + + describe '#destroy' do + it 'destroys an endpoint' do + provider.class.stubs(:openstack) + .with('endpoint', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Region","Service Name","Service Type","PublicURL","AdminURL","InternalURL" +"1cb05cfed7c24279be884ba4f6520262","foo","bar","","http://127.0.0.1:5000/v2.0","http://127.0.0.1:5001/v2.0","http://127.0.0.1:5002/v2.0" +') + provider.class.stubs(:openstack) + .with('endpoint', 'delete', [['1cb05cfed7c24279be884ba4f6520262', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + expect(provider.destroy).to be_nil # We don't really care that it's nil, only that it runs successfully + end + + end + + describe '#exists' do + context 'when endpoint exists' do + + subject(:response) do + provider.class.stubs(:openstack) + .with('endpoint', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Region","Service Name","Service Type","PublicURL","AdminURL","InternalURL" +"1cb05cfed7c24279be884ba4f6520262","foo","bar","","http://127.0.0.1:5000/v2.0","http://127.0.0.1:5001/v2.0","http://127.0.0.1:5002/v2.0" +') + response = provider.exists? + end + + it { is_expected.to be_truthy } + end + + context 'when tenant does not exist' do + + subject(:response) do + provider.class.stubs(:openstack) + .with('endpoint', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Region","Service Name","Service Type","PublicURL","AdminURL","InternalURL"') + response = provider.exists? + end + + it { is_expected.to be_falsey } + end + end + + describe '#instances' do + it 'finds every tenant' do + provider.class.stubs(:openstack) + .with('endpoint', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Region","Service Name","Service Type","PublicURL","AdminURL","InternalURL" +"1cb05cfed7c24279be884ba4f6520262","foo","bar","","http://127.0.0.1:5000/v2.0","http://127.0.0.1:5001/v2.0","http://127.0.0.1:5002/v2.0" +') + instances = provider.instances + expect(instances.count).to eq(1) + end + end + + end +end diff --git a/3rdparty/modules/keystone/spec/unit/provider/keystone_paste_ini/ini_setting_spec.rb b/3rdparty/modules/keystone/spec/unit/provider/keystone_paste_ini/ini_setting_spec.rb new file mode 100644 index 000000000..2eff5d63f --- /dev/null +++ b/3rdparty/modules/keystone/spec/unit/provider/keystone_paste_ini/ini_setting_spec.rb @@ -0,0 +1,29 @@ +# +# these tests are a little concerning b/c they are hacking around the +# modulepath, so these tests will not catch issues that may eventually arise +# related to loading these plugins. +# I could not, for the life of me, figure out how to programatcally set the modulepath +$LOAD_PATH.push( + File.join( + File.dirname(__FILE__), + '..', + '..', + '..', + 'fixtures', + 'modules', + 'inifile', + 'lib') +) +require 'spec_helper' +provider_class = Puppet::Type.type(:keystone_paste_ini).provider(:ini_setting) +describe provider_class do + + it 'should allow setting to be set explicitly' do + resource = Puppet::Type::Keystone_paste_ini.new( + {:name => 'dude/foo', :value => 'bar'} + ) + provider = provider_class.new(resource) + provider.section.should == 'dude' + provider.setting.should == 'foo' + end +end diff --git a/3rdparty/modules/keystone/spec/unit/provider/keystone_role/openstack_spec.rb b/3rdparty/modules/keystone/spec/unit/provider/keystone_role/openstack_spec.rb new file mode 100644 index 000000000..179574fea --- /dev/null +++ b/3rdparty/modules/keystone/spec/unit/provider/keystone_role/openstack_spec.rb @@ -0,0 +1,101 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/keystone_role/openstack' + +provider_class = Puppet::Type.type(:keystone_role).provider(:openstack) + +describe provider_class do + + describe 'when creating a role' do + + let(:role_attrs) do + { + :name => 'foo', + :ensure => 'present', + :auth => { + 'username' => 'test', + 'password' => 'abc123', + 'tenant_name' => 'foo', + 'auth_url' => 'http://127.0.0.1:5000/v2.0', + } + } + end + + let(:resource) do + Puppet::Type::Keystone_role.new(role_attrs) + end + + let(:provider) do + provider_class.new(resource) + end + + describe '#create' do + it 'creates a role' do + provider.class.stubs(:openstack) + .with('role', 'list', '--quiet', '--format', 'csv', [['--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name" +"1cb05cfed7c24279be884ba4f6520262","foo" +') + provider.class.stubs(:openstack) + .with('role', 'create', '--format', 'shell', [['foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('name="foo"') + provider.create + expect(provider.exists?).to be_truthy + end + end + + describe '#destroy' do + it 'destroys a role' do + provider.class.stubs(:openstack) + .with('role', 'list', '--quiet', '--format', 'csv', [['--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name"') + provider.class.stubs(:openstack) + .with('role', 'delete', [['foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + provider.destroy + expect(provider.exists?).to be_falsey + end + + end + + describe '#exists' do + context 'when role exists' do + + subject(:response) do + provider.class.stubs(:openstack) + .with('role', 'list', '--quiet', '--format', 'csv', [['--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name" +"1cb05cfed7c24279be884ba4f6520262","foo" +') + response = provider.exists? + end + + it { is_expected.to be_truthy } + end + + context 'when role does not exist' do + + subject(:response) do + provider.class.stubs(:openstack) + .with('role', 'list', '--quiet', '--format', 'csv', [['--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name"') + response = provider.exists? + end + + it { is_expected.to be_falsey } + end + end + + describe '#instances' do + it 'finds every role' do + provider.class.stubs(:openstack) + .with('role', 'list', '--quiet', '--format', 'csv', [['--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name" +"1cb05cfed7c24279be884ba4f6520262","foo" +') + instances = provider.instances + expect(instances.count).to eq(1) + end + end + + end +end diff --git a/3rdparty/modules/keystone/spec/unit/provider/keystone_service/openstack_spec.rb b/3rdparty/modules/keystone/spec/unit/provider/keystone_service/openstack_spec.rb new file mode 100644 index 000000000..5b9814f91 --- /dev/null +++ b/3rdparty/modules/keystone/spec/unit/provider/keystone_service/openstack_spec.rb @@ -0,0 +1,108 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/keystone_service/openstack' + +provider_class = Puppet::Type.type(:keystone_service).provider(:openstack) + +describe provider_class do + + describe 'when creating a service' do + + let(:service_attrs) do + { + :name => 'foo', + :description => 'foo', + :ensure => 'present', + :type => 'foo', + :auth => { + 'username' => 'test', + 'password' => 'abc123', + 'tenant_name' => 'foo', + 'auth_url' => 'http://127.0.0.1:5000/v2.0', + } + } + end + + let(:resource) do + Puppet::Type::Keystone_service.new(service_attrs) + end + + let(:provider) do + provider_class.new(resource) + end + + describe '#create' do + it 'creates a service' do + provider.class.stubs(:openstack) + .with('service', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Type","Description" +"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo" +') + provider.class.stubs(:openstack) + .with('service', 'create', '--format', 'shell', [['foo', '--description', 'foo', '--type', 'foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('description="foo" +enabled="True" +id="8f0dd4c0abc44240998fbb3f5089ecbf" +name="foo" +type="foo" +') + provider.create + expect(provider.exists?).to be_truthy + end + end + + describe '#destroy' do + it 'destroys a service' do + provider.class.stubs(:openstack) + .with('service', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Type","Description"') + provider.class.stubs(:openstack) + .with('service', 'delete', [['foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + provider.destroy + expect(provider.exists?).to be_falsey + end + + end + + describe '#exists' do + context 'when service exists' do + + subject(:response) do + provider.class.stubs(:openstack) + .with('service', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Type","Description" +"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo" +') + response = provider.exists? + end + + it { is_expected.to be_truthy } + end + + context 'when service does not exist' do + + subject(:response) do + provider.class.stubs(:openstack) + .with('service', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Type","Description"') + response = provider.exists? + end + + it { is_expected.to be_falsey } + end + end + + describe '#instances' do + it 'finds every service' do + provider.class.stubs(:openstack) + .with('service', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Type","Description" +"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo" +') + instances = provider.instances + expect(instances.count).to eq(1) + end + end + + end +end diff --git a/3rdparty/modules/keystone/spec/unit/provider/keystone_spec.rb b/3rdparty/modules/keystone/spec/unit/provider/keystone_spec.rb new file mode 100644 index 000000000..de9ceb0d1 --- /dev/null +++ b/3rdparty/modules/keystone/spec/unit/provider/keystone_spec.rb @@ -0,0 +1,115 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/keystone' +require 'tempfile' + + +klass = Puppet::Provider::Keystone + +class Puppet::Provider::Keystone + def self.reset + @admin_endpoint = nil + @tenant_hash = nil + @admin_token = nil + @keystone_file = nil + end +end + +describe Puppet::Provider::Keystone do + + after :each do + klass.reset + end + + + describe 'when retrieving the security token' do + + it 'should return nothing if there is no keystone config file' do + ini_file = Puppet::Util::IniConfig::File.new + t = Tempfile.new('foo') + path = t.path + t.unlink + ini_file.read(path) + expect(klass.get_admin_token).to be_nil + end + + it 'should return nothing if the keystone config file does not have a DEFAULT section' do + mock = {} + Puppet::Util::IniConfig::File.expects(:new).returns(mock) + mock.expects(:read).with('/etc/keystone/keystone.conf') + expect(klass.get_admin_token).to be_nil + end + + it 'should fail if the keystone config file does not contain an admin token' do + mock = {'DEFAULT' => {'not_a_token' => 'foo'}} + Puppet::Util::IniConfig::File.expects(:new).returns(mock) + mock.expects(:read).with('/etc/keystone/keystone.conf') + expect(klass.get_admin_token).to be_nil + end + + it 'should parse the admin token if it is in the config file' do + mock = {'DEFAULT' => {'admin_token' => 'foo'}} + Puppet::Util::IniConfig::File.expects(:new).returns(mock) + mock.expects(:read).with('/etc/keystone/keystone.conf') + klass.get_admin_token.should == 'foo' + end + + it 'should use the specified bind_host in the admin endpoint' do + mock = {'DEFAULT' => {'admin_bind_host' => '192.168.56.210', 'admin_port' => '35357' }} + Puppet::Util::IniConfig::File.expects(:new).returns(mock) + mock.expects(:read).with('/etc/keystone/keystone.conf') + klass.get_admin_endpoint.should == 'http://192.168.56.210:35357/v2.0/' + end + + it 'should use localhost in the admin endpoint if bind_host is 0.0.0.0' do + mock = {'DEFAULT' => { 'admin_bind_host' => '0.0.0.0', 'admin_port' => '35357' }} + Puppet::Util::IniConfig::File.expects(:new).returns(mock) + mock.expects(:read).with('/etc/keystone/keystone.conf') + klass.get_admin_endpoint.should == 'http://127.0.0.1:35357/v2.0/' + end + + it 'should use [::1] in the admin endpoint if bind_host is ::0' do + mock = {'DEFAULT' => { 'admin_bind_host' => '::0', 'admin_port' => '35357' }} + Puppet::Util::IniConfig::File.expects(:new).returns(mock) + mock.expects(:read).with('/etc/keystone/keystone.conf') + klass.get_admin_endpoint.should == 'http://[::1]:35357/v2.0/' + end + + it 'should use localhost in the admin endpoint if bind_host is unspecified' do + mock = {'DEFAULT' => { 'admin_port' => '35357' }} + Puppet::Util::IniConfig::File.expects(:new).returns(mock) + mock.expects(:read).with('/etc/keystone/keystone.conf') + klass.get_admin_endpoint.should == 'http://127.0.0.1:35357/v2.0/' + end + + it 'should use https if ssl is enabled' do + mock = {'DEFAULT' => {'admin_bind_host' => '192.168.56.210', 'admin_port' => '35357' }, 'ssl' => {'enable' => 'True'}} + Puppet::Util::IniConfig::File.expects(:new).returns(mock) + mock.expects(:read).with('/etc/keystone/keystone.conf') + klass.get_admin_endpoint.should == 'https://192.168.56.210:35357/v2.0/' + end + + it 'should use http if ssl is disabled' do + mock = {'DEFAULT' => {'admin_bind_host' => '192.168.56.210', 'admin_port' => '35357' }, 'ssl' => {'enable' => 'False'}} + Puppet::Util::IniConfig::File.expects(:new).returns(mock) + mock.expects(:read).with('/etc/keystone/keystone.conf') + klass.get_admin_endpoint.should == 'http://192.168.56.210:35357/v2.0/' + end + + it 'should use the defined admin_endpoint if available' do + mock = {'DEFAULT' => {'admin_endpoint' => 'https://keystone.example.com' }, 'ssl' => {'enable' => 'False'}} + Puppet::Util::IniConfig::File.expects(:new).returns(mock) + mock.expects(:read).with('/etc/keystone/keystone.conf') + klass.get_admin_endpoint.should == 'https://keystone.example.com/v2.0/' + end + + it 'should handle an admin_endpoint with a trailing slash' do + mock = {'DEFAULT' => {'admin_endpoint' => 'https://keystone.example.com/' }, 'ssl' => {'enable' => 'False'}} + Puppet::Util::IniConfig::File.expects(:new).returns(mock) + mock.expects(:read).with('/etc/keystone/keystone.conf') + klass.get_admin_endpoint.should == 'https://keystone.example.com/v2.0/' + end + + end + +end diff --git a/3rdparty/modules/keystone/spec/unit/provider/keystone_tenant/openstack_spec.rb b/3rdparty/modules/keystone/spec/unit/provider/keystone_tenant/openstack_spec.rb new file mode 100644 index 000000000..11861fc8b --- /dev/null +++ b/3rdparty/modules/keystone/spec/unit/provider/keystone_tenant/openstack_spec.rb @@ -0,0 +1,106 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/keystone_tenant/openstack' + +provider_class = Puppet::Type.type(:keystone_tenant).provider(:openstack) + +describe provider_class do + + describe 'when updating a tenant' do + + let(:tenant_attrs) do + { + :name => 'foo', + :description => 'foo', + :ensure => 'present', + :enabled => 'True', + :auth => { + 'username' => 'test', + 'password' => 'abc123', + 'tenant_name' => 'foo', + 'auth_url' => 'http://127.0.0.1:5000/v2.0', + } + } + end + + let(:resource) do + Puppet::Type::Keystone_tenant.new(tenant_attrs) + end + + let(:provider) do + provider_class.new(resource) + end + + describe '#create' do + it 'creates a tenant' do + provider.class.stubs(:openstack) + .with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Description","Enabled" +"1cb05cfed7c24279be884ba4f6520262","foo","foo",True +') + provider.class.stubs(:openstack) + .with('project', 'create', '--format', 'shell', [['foo', '--enable', '--description', 'foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('description="foo" +enabled="True" +name="foo" +') + provider.create + expect(provider.exists?).to be_truthy + end + end + + describe '#destroy' do + it 'destroys a tenant' do + provider.class.stubs(:openstack) + .with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Description","Enabled"') + provider.class.stubs(:openstack) + .with('project', 'delete', [['foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + provider.destroy + expect(provider.exists?).to be_falsey + end + + end + + describe '#exists' do + context 'when tenant exists' do + + subject(:response) do + provider.class.stubs(:openstack) + .with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Description","Enabled" +"1cb05cfed7c24279be884ba4f6520262","foo","foo",True +') + response = provider.exists? + end + + it { is_expected.to be_truthy } + end + + context 'when tenant does not exist' do + + subject(:response) do + provider.class.stubs(:openstack) + .with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Description","Enabled"') + response = provider.exists? + end + + it { is_expected.to be_falsey } + end + end + + describe '#instances' do + it 'finds every tenant' do + provider.class.stubs(:openstack) + .with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Description","Enabled" +"1cb05cfed7c24279be884ba4f6520262","foo","foo",True +') + instances = provider.instances + expect(instances.count).to eq(1) + end + end + + end +end diff --git a/3rdparty/modules/keystone/spec/unit/provider/keystone_user/openstack_spec.rb b/3rdparty/modules/keystone/spec/unit/provider/keystone_user/openstack_spec.rb new file mode 100644 index 000000000..1a74c636c --- /dev/null +++ b/3rdparty/modules/keystone/spec/unit/provider/keystone_user/openstack_spec.rb @@ -0,0 +1,288 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/keystone_user/openstack' + +provider_class = Puppet::Type.type(:keystone_user).provider(:openstack) + +describe provider_class do + + let(:user_attrs) do + { + :name => 'foo', + :ensure => 'present', + :enabled => 'True', + :password => 'foo', + :tenant => 'foo', + :email => 'foo@example.com', + :auth => { + 'username' => 'test', + 'password' => 'abc123', + 'tenant_name' => 'foo', + 'auth_url' => 'http://127.0.0.1:5000/v2.0', + } + } + end + + let(:resource) do + Puppet::Type::Keystone_user.new(user_attrs) + end + + let(:provider) do + provider_class.new(resource) + end + + describe 'when updating a user' do + + describe '#create' do + it 'creates a user' do + provider.class.stubs(:openstack) + .with('user', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Project","Email","Enabled" +"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo@example.com",True +') + provider.class.stubs(:openstack) + .with('user', 'create', '--format', 'shell', [['foo', '--enable', '--password', 'foo', '--project', 'foo', '--email', 'foo@example.com', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('email="foo@example.com" +enabled="True" +id="12b23f07d4a3448d8189521ab09610b0" +name="foo" +project_id="5e2001b2248540f191ff22627dc0c2d7" +username="foo" +') + provider.create + expect(provider.exists?).to be_truthy + end + end + + describe '#destroy' do + it 'destroys a user' do + provider.class.stubs(:openstack) + .with('user', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Project","Email","Enabled"') + provider.class.stubs(:openstack) + .with('user', 'delete', [['foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + provider.destroy + expect(provider.exists?).to be_falsey + end + + end + + describe '#exists' do + context 'when user exists' do + + subject(:response) do + provider.class.stubs(:openstack) + .with('user', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Project","Email","Enabled" +"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo@example.com",True +') + response = provider.exists? + end + + it { is_expected.to be_truthy } + end + + context 'when user does not exist' do + + subject(:response) do + provider.class.stubs(:openstack) + .with('user', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Project","Email","Enabled"') + response = provider.exists? + end + + it { is_expected.to be_falsey } + end + end + + describe '#instances' do + it 'finds every user' do + provider.class.stubs(:openstack) + .with('user', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Project","Email","Enabled" +"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo@example.com",True +') + instances = provider.instances + expect(instances.count).to eq(1) + end + end + + describe '#tenant' do + it 'gets the tenant with default backend' do + provider.class.stubs(:openstack) + .with('user', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Project","Email","Enabled" +"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo@example.com",True +') + tenant = provider.tenant + expect(tenant).to eq('foo') + end + it 'gets the tenant with LDAP backend' do + provider.class.stubs(:openstack) + .with('user', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Project","Email","Enabled" +"1cb05cfed7c24279be884ba4f6520262","foo","","foo@example.com",True +') + provider.class.expects(:openstack) + .with('user role', 'list', '--quiet', '--format', 'csv', [['foo', '--project', 'foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Project","User" +"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo" +') + tenant = provider.tenant + expect(tenant).to eq('foo') + end + end + describe '#tenant=' do + context 'when using default backend' do + it 'sets the tenant' do + provider.class.expects(:openstack) + .with('user', 'set', [['foo', '--project', 'bar', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + provider.class.expects(:openstack) + .with('user role', 'list', '--quiet', '--format', 'csv', [['foo', '--project', 'bar', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Project","User" +"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo" +') + provider.tenant=('bar') + end + end + context 'when using LDAP read-write backend' do + it 'sets the tenant when _member_ role exists' do + provider.class.expects(:openstack) + .with('user', 'set', [['foo', '--project', 'bar', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + provider.class.expects(:openstack) + .with('user role', 'list', '--quiet', '--format', 'csv', [['foo', '--project', 'bar', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('') + provider.class.expects(:openstack) + .with('role', 'show', '--format', 'shell', [['_member_', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('name="_member_"') + provider.class.expects(:openstack) + .with('role', 'add', [['_member_', '--project', 'bar', '--user', 'foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + provider.tenant=('bar') + end + it 'sets the tenant when _member_ role does not exist' do + provider.class.expects(:openstack) + .with('user', 'set', [['foo', '--project', 'bar', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + provider.class.expects(:openstack) + .with('user role', 'list', '--quiet', '--format', 'csv', [['foo', '--project', 'bar', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('') + provider.class.expects(:openstack) + .with('role', 'show', '--format', 'shell', [['_member_', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .raises(Puppet::ExecutionFailure, 'no such role _member_') + provider.class.expects(:openstack) + .with('role', 'create', '--format', 'shell', [['_member_', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('name="_member_"') + provider.class.expects(:openstack) + .with('role', 'add', [['_member_', '--project', 'bar', '--user', 'foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + provider.tenant=('bar') + end + end + context 'when using LDAP read-only backend' do + it 'sets the tenant when _member_ role exists' do + provider.class.expects(:openstack) + .with('user', 'set', [['foo', '--project', 'bar', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .raises(Puppet::ExecutionFailure, 'You are not authorized to perform the requested action: LDAP user update') + provider.class.expects(:openstack) + .with('user role', 'list', '--quiet', '--format', 'csv', [['foo', '--project', 'bar', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('') + provider.class.expects(:openstack) + .with('role', 'show', '--format', 'shell', [['_member_', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('name="_member_"') + provider.class.expects(:openstack) + .with('role', 'add', [['_member_', '--project', 'bar', '--user', 'foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + provider.tenant=('bar') + end + it 'sets the tenant and gets an unexpected exception message' do + provider.class.expects(:openstack) + .with('user', 'set', [['foo', '--project', 'bar', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .raises(Puppet::ExecutionFailure, 'unknown error message') + expect{ provider.tenant=('bar') }.to raise_error(Puppet::ExecutionFailure, /unknown error message/) + end + end + end + + end + + describe "#password" do + let(:user_attrs) do + { + :name => 'foo', + :ensure => 'present', + :enabled => 'True', + :password => 'foo', + :tenant => 'foo', + :email => 'foo@example.com', + :auth => { + 'username' => 'test', + 'password' => 'abc123', + 'tenant_name' => 'foo', + 'auth_url' => 'https://127.0.0.1:5000/v2.0', + } + } + end + + it 'checks the password with HTTPS' do + httpobj = mock('Net::HTTP') + httpobj.stubs(:use_ssl=).with(true) + httpobj.stubs(:verify_mode=) + Net::HTTP.stubs(:start).returns(httpobj) + reqobj = mock('Net::HTTP::Post') + reqobj.stubs(:body=) + reqobj.stubs(:content_type=) + Net::HTTP::Post.stubs(:start).returns(reqobj) + respobj = mock('Net::HTTPResponse') + respobj.stubs(:code).returns('200') + httpobj.stubs(:request).returns(respobj) + password = provider.password + expect(password).to eq('foo') + end + it 'fails the password check with HTTPS' do + httpobj = mock('Net::HTTP') + httpobj.stubs(:use_ssl=).with(true) + httpobj.stubs(:verify_mode=) + Net::HTTP.stubs(:start).returns(httpobj) + reqobj = mock('Net::HTTP::Post') + reqobj.stubs(:body=) + reqobj.stubs(:content_type=) + Net::HTTP::Post.stubs(:start).returns(reqobj) + respobj = mock('Net::HTTPResponse') + respobj.stubs(:code).returns('401') + httpobj.stubs(:request).returns(respobj) + password = provider.password + expect(password).to eq(nil) + end + + describe 'when updating a user with unmanaged password' do + + let(:user_attrs) do + { + :name => 'foo', + :ensure => 'present', + :enabled => 'True', + :password => 'foo', + :replace_password => 'False', + :tenant => 'foo', + :email => 'foo@example.com', + :auth => { + 'username' => 'test', + 'password' => 'abc123', + 'tenant_name' => 'foo', + 'auth_url' => 'http://127.0.0.1:5000/v2.0', + } + } + end + + let(:resource) do + Puppet::Type::Keystone_user.new(user_attrs) + end + + let :provider do + provider_class.new(resource) + end + + it 'should not try to check password' do + expect(provider.password).to eq('foo') + end + end + + end +end diff --git a/3rdparty/modules/keystone/spec/unit/provider/keystone_user_role/openstack_spec.rb b/3rdparty/modules/keystone/spec/unit/provider/keystone_user_role/openstack_spec.rb new file mode 100644 index 000000000..f3c35dcf6 --- /dev/null +++ b/3rdparty/modules/keystone/spec/unit/provider/keystone_user_role/openstack_spec.rb @@ -0,0 +1,94 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/keystone_user_role/openstack' + +provider_class = Puppet::Type.type(:keystone_user_role).provider(:openstack) + +describe provider_class do + + describe 'when updating a user\'s role' do + + let(:user_role_attrs) do + { + :name => 'foo@example.com@foo', + :ensure => 'present', + :roles => ['foo', 'bar'], + :auth => { + 'username' => 'test', + 'password' => 'abc123', + 'tenant_name' => 'foo', + 'auth_url' => 'http://127.0.0.1:5000/v2.0', + } + } + end + + let(:resource) do + Puppet::Type::Keystone_user_role.new(user_role_attrs) + end + + let(:provider) do + provider_class.new(resource) + end + + before(:each) do + provider.class.stubs(:openstack) + .with('user', 'list', '--quiet', '--format', 'csv', [['--project', 'foo', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name" +"1cb05cfed7c24279be884ba4f6520262","foo@example.com" +') + provider.class.stubs(:openstack) + .with('project', 'list', '--quiet', '--format', 'csv', [['--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name" +"1cb05cfed7c24279be884ba4f6520262","foo" +') + end + + describe '#create' do + it 'adds all the roles to the user' do + provider.class.stubs(:openstack) + .with('user role', 'list', '--quiet', '--format', 'csv', [['--project', 'foo', 'foo@example.com', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Project","User" +"1cb05cfed7c24279be884ba4f6520262","foo","foo","foo@example.com" +"1cb05cfed7c24279be884ba4f6520263","bar","foo","foo@example.com" +') + provider.class.stubs(:openstack) + .with('role', 'add', [['foo', '--project', 'foo', '--user', 'foo@example.com', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + provider.class.stubs(:openstack) + .with('role', 'add', [['bar', '--project', 'foo', '--user', 'foo@example.com', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + provider.create + expect(provider.exists?).to be_truthy + end + end + + describe '#destroy' do + it 'removes all the roles from a user' do + provider.class.stubs(:openstack) + .with('user role', 'list', '--quiet', '--format', 'csv', [['--project', 'foo', 'foo@example.com', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Project","User"') + provider.class.stubs(:openstack) + .with('role', 'remove', [['foo', '--project', 'foo', '--user', 'foo@example.com', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + provider.class.stubs(:openstack) + .with('role', 'remove', [['bar', '--project', 'foo', '--user', 'foo@example.com', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + provider.destroy + expect(provider.exists?).to be_falsey + end + + end + + describe '#exists' do + subject(:response) do + provider.class.stubs(:openstack) + .with('user role', 'list', '--quiet', '--format', 'csv', [['--project', 'foo', 'foo@example.com', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'foo', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Project","User" +"1cb05ed7c24279be884ba4f6520262","foo","foo","foo@example.com" +"1cb05ed7c24279be884ba4f6520262","bar","foo","foo@example.com" +') + response = provider.exists? + end + + it { is_expected.to be_truthy } + + end + + end +end diff --git a/3rdparty/modules/keystone/spec/unit/provider/openstack_spec.rb b/3rdparty/modules/keystone/spec/unit/provider/openstack_spec.rb new file mode 100644 index 000000000..fa431fd21 --- /dev/null +++ b/3rdparty/modules/keystone/spec/unit/provider/openstack_spec.rb @@ -0,0 +1,261 @@ +# TODO: This should be extracted into openstacklib during the Kilo cycle +# Load libraries from aviator here to simulate how they live together in a real puppet run +$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'modules', 'aviator', 'lib')) +require 'puppet' +require 'spec_helper' +require 'puppet/provider/openstack' + + +describe Puppet::Provider::Openstack do + + before(:each) do + ENV['OS_USERNAME'] = nil + ENV['OS_PASSWORD'] = nil + ENV['OS_TENANT_NAME'] = nil + ENV['OS_AUTH_URL'] = nil + end + + let(:type) do + Puppet::Type.newtype(:test_resource) do + newparam(:name, :namevar => true) + newparam(:auth) + newparam(:log_file) + end + end + + shared_examples 'authenticating with environment variables' do + it 'makes a successful request' do + ENV['OS_USERNAME'] = 'test' + ENV['OS_PASSWORD'] = 'abc123' + ENV['OS_TENANT_NAME'] = 'test' + ENV['OS_AUTH_URL'] = 'http://127.0.0.1:35357/v2.0' + if provider.class == Class + provider.stubs(:openstack) + .with('project', 'list', '--quiet', '--format', 'csv', [[ '--long' ]]) + .returns('"ID","Name","Description","Enabled" +"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True +') + else + provider.class.stubs(:openstack) + .with('project', 'list', '--quiet', '--format', 'csv', [[ '--long' ]]) + .returns('"ID","Name","Description","Enabled" +"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True +') + end + response = provider.request('project', 'list', nil, nil, '--long' ) + expect(response.first[:description]).to match /Test tenant/ + end + end + + shared_examples 'it has no credentials' do + it 'fails to authenticate' do + expect{ provider.request('project', 'list', nil, nil, '--long') }.to raise_error(Puppet::Error::OpenstackAuthInputError, /No credentials provided/) + end + end + + describe '#request' do + + context 'with valid password credentials in parameters' do + let(:resource_attrs) do + { + :name => 'stubresource', + :auth => { + 'username' => 'test', + 'password' => 'abc123', + 'tenant_name' => 'test', + 'auth_url' => 'http://127.0.0.1:5000/v2.0', + } + } + end + let(:provider) do + Puppet::Provider::Openstack.new(type.new(resource_attrs)) + end + + it 'makes a successful request' do + provider.class.stubs(:openstack) + .with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'test', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Description","Enabled" +"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True +') + response = provider.request('project', 'list', nil, resource_attrs[:auth], '--long') + expect(response.first[:description]).to match /Test tenant/ + end + end + + context 'with valid openrc file in parameters' do + mock = "export OS_USERNAME='test'\nexport OS_PASSWORD='abc123'\nexport OS_TENANT_NAME='test'\nexport OS_AUTH_URL='http://127.0.0.1:5000/v2.0'" + let(:resource_attrs) do + { + :name => 'stubresource', + :auth => { + 'openrc' => '/root/openrc' + } + } + end + let(:provider) do + Puppet::Provider::Openstack.new(type.new(resource_attrs)) + end + + it 'makes a successful request' do + File.expects(:open).with('/root/openrc').returns(StringIO.new(mock)) + provider.class.stubs(:openstack) + .with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'test', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Description","Enabled" +"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True +') + response = provider.request('project', 'list', nil, resource_attrs[:auth], '--long') + expect(response.first[:description]).to match /Test tenant/ + end + end + + context 'with valid service token in parameters' do + let(:resource_attrs) do + { + :name => 'stubresource', + :auth => { + 'token' => 'secrettoken', + 'auth_url' => 'http://127.0.0.1:5000/v2.0' + } + } + end + let(:provider) do + Puppet::Provider::Openstack.new(type.new(resource_attrs)) + end + + it 'makes a successful request' do + provider.class.stubs(:openstack) + .with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-token', 'secrettoken', '--os-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('"ID","Name","Description","Enabled" +"1cb05cfed7c24279be884ba4f6520262","test","Test tenant",True +') + response = provider.request('project', 'list', nil, resource_attrs[:auth], '--long') + expect(response.first[:description]).to match /Test tenant/ + end + + it 'makes a successful show request' do + provider.class.stubs(:openstack) + .with('project', 'show', '--format', 'shell', [['test', '--os-token', 'secrettoken', '--os-url', 'http://127.0.0.1:5000/v2.0']]) + .returns('ID="1cb05cfed7c24279be884ba4f6520262" +Name="test" +Description="Test Tenant" +Enabled="True" +') + response = provider.request('project', 'show', 'test', resource_attrs[:auth]) + expect(response[:description]).to match /Test Tenant/ + expect(response[:id]).to match /1cb05cfed7c24279be884ba4f6520262/ + expect(response[:name]).to match /test/ + expect(response[:enabled]).to match /True/ + end + + end + + context 'with valid password credentials in environment variables' do + it_behaves_like 'authenticating with environment variables' do + let(:resource_attrs) do + { + :name => 'stubresource', + } + end + let(:provider) do + Puppet::Provider::Openstack.new(type.new(resource_attrs)) + end + end + end + + context 'with no valid credentials' do + it_behaves_like 'it has no credentials' do + let(:resource_attrs) do + { + :name => 'stubresource', + } + end + let(:provider) do + Puppet::Provider::Openstack.new(type.new(resource_attrs)) + end + end + end + + context 'it retries on connection errors' do + let(:resource_attrs) do + { + :name => 'stubresource', + :auth => { + 'username' => 'test', + 'password' => 'abc123', + 'tenant_name' => 'test', + 'auth_url' => 'http://127.0.0.1:5000/v2.0', + } + } + end + let(:provider) do + Puppet::Provider::Openstack.new(type.new(resource_attrs)) + end + it 'retries' do + provider.class.stubs(:openstack) + .with('project', 'list', '--quiet', '--format', 'csv', [['--long', '--os-username', 'test', '--os-password', 'abc123', '--os-tenant-name', 'test', '--os-auth-url', 'http://127.0.0.1:5000/v2.0']]) + .raises(Puppet::ExecutionFailure, 'Unable to establish connection') + .then + .returns('') + provider.class.expects(:sleep).with(2).returns(nil) + provider.request('project', 'list', nil, resource_attrs[:auth], '--long') + end + end + end + + + describe '::request' do + + context 'with valid password credentials in environment variables' do + it_behaves_like 'authenticating with environment variables' do + let(:resource_attrs) do + { + :name => 'stubresource', + } + end + let(:provider) do + Puppet::Provider::Openstack.dup + end + end + end + + context 'with no valid credentials' do + it_behaves_like 'it has no credentials' do + let(:provider) { Puppet::Provider::Openstack.dup } + end + end + + end + + describe 'parse_csv' do + context 'with mixed stderr' do + text = "ERROR: Testing\n\"field\",\"test\",1,2,3\n" + csv = Puppet::Provider::Openstack.parse_csv(text) + it 'should ignore non-CSV text at the beginning of the input' do + expect(csv).to be_kind_of(Array) + expect(csv[0]).to match_array(['field', 'test', '1', '2', '3']) + expect(csv.size).to eq(1) + end + end + + context 'with \r\n line endings' do + text = "ERROR: Testing\r\n\"field\",\"test\",1,2,3\r\n" + csv = Puppet::Provider::Openstack.parse_csv(text) + it 'ignore the carriage returns' do + expect(csv).to be_kind_of(Array) + expect(csv[0]).to match_array(['field', 'test', '1', '2', '3']) + expect(csv.size).to eq(1) + end + end + + context 'with embedded newlines' do + text = "ERROR: Testing\n\"field\",\"te\nst\",1,2,3\n" + csv = Puppet::Provider::Openstack.parse_csv(text) + it 'should parse correctly' do + expect(csv).to be_kind_of(Array) + expect(csv[0]).to match_array(['field', "te\nst", '1', '2', '3']) + expect(csv.size).to eq(1) + end + end + end + +end diff --git a/3rdparty/modules/keystone/spec/unit/type/keystone_endpoint_spec.rb b/3rdparty/modules/keystone/spec/unit/type/keystone_endpoint_spec.rb new file mode 100644 index 000000000..a3667c546 --- /dev/null +++ b/3rdparty/modules/keystone/spec/unit/type/keystone_endpoint_spec.rb @@ -0,0 +1,9 @@ +describe Puppet::Type.type(:keystone_endpoint) do + + it 'should fail when the namevar does not contain a region' do + expect do + Puppet::Type.type(:keystone_endpoint).new(:name => 'foo') + end.to raise_error(Puppet::Error, /Invalid value/) + end + +end diff --git a/3rdparty/modules/keystone/spec/unit/type/keystone_paste_ini_spec.rb b/3rdparty/modules/keystone/spec/unit/type/keystone_paste_ini_spec.rb new file mode 100644 index 000000000..98f7157b6 --- /dev/null +++ b/3rdparty/modules/keystone/spec/unit/type/keystone_paste_ini_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' +# this hack is required for now to ensure that the path is set up correctly +# to retrive the parent provider +$LOAD_PATH.push( + File.join( + File.dirname(__FILE__), + '..', + '..', + 'fixtures', + 'modules', + 'inifile', + 'lib') +) +require 'puppet/type/keystone_paste_ini' +describe 'Puppet::Type.type(:keystone_paste_ini)' do + before :each do + @keystone_paste_ini = Puppet::Type.type(:keystone_paste_ini).new(:name => 'DEFAULT/foo', :value => 'bar') + end + it 'should accept a valid value' do + @keystone_paste_ini[:value] = 'bar' + @keystone_paste_ini[:value].should == 'bar' + end +end diff --git a/3rdparty/modules/keystone/spec/unit/type/keystone_user_role_spec.rb b/3rdparty/modules/keystone/spec/unit/type/keystone_user_role_spec.rb new file mode 100644 index 000000000..82c32688f --- /dev/null +++ b/3rdparty/modules/keystone/spec/unit/type/keystone_user_role_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' +require 'puppet' +require 'puppet/type/keystone_user_role' + +describe Puppet::Type.type(:keystone_user_role) do + + before :each do + @user_roles = Puppet::Type.type(:keystone_user_role).new( + :name => 'foo@bar', + :roles => ['a', 'b'] + ) + + @roles = @user_roles.parameter('roles') + end + + it 'should not be in sync for' do + expect(@roles.insync?(['a', 'b', 'c'])).to be false + expect(@roles.insync?('a')).to be false + expect(@roles.insync?(['a'])).to be false + expect(@roles.insync?(nil)).to be false + end + + it 'should be in sync for' do + expect(@roles.insync?(['a', 'b'])).to be true + expect(@roles.insync?(['b', 'a'])).to be true + end + +end diff --git a/3rdparty/modules/keystone/tests/site.pp b/3rdparty/modules/keystone/tests/site.pp new file mode 100644 index 000000000..ddd335590 --- /dev/null +++ b/3rdparty/modules/keystone/tests/site.pp @@ -0,0 +1,68 @@ +Exec { logoutput => 'on_failure' } + +package { 'curl': ensure => present } + +# example of how to build a single node +# keystone instance backed by sqlite +# with all of the default admin roles +node keystone_sqlite { + class { 'keystone': + verbose => true, + debug => true, + catalog_type => 'sql', + admin_token => 'admin_token', + } + class { 'keystone::roles::admin': + email => 'example@abc.com', + password => 'ChangeMe', + } + class { 'keystone::endpoint': + public_url => "http://${::fqdn}:5000/", + admin_url => "http://${::fqdn}:35357/", + } +} + +node keystone_mysql { + class { 'mysql::server': } + class { 'keystone::db::mysql': + password => 'keystone', + } + class { 'keystone': + verbose => true, + debug => true, + sql_connection => 'mysql://keystone:keystone@127.0.0.1/keystone', + catalog_type => 'sql', + admin_token => 'admin_token', + } + class { 'keystone::roles::admin': + email => 'test@puppetlabs.com', + password => 'ChangeMe', + } +} + + +# keystone with mysql on another node +node keystone { + class { 'keystone': + verbose => true, + debug => true, + sql_connection => 'mysql://keystone:password@127.0.0.1/keystone', + catalog_type => 'sql', + admin_token => 'admin_token', + } + class { 'keystone::db::mysql': + password => 'keystone', + } + class { 'keystone::roles::admin': + email => 'example@abc.com', + password => 'ChangeMe', + } + class { 'keystone::endpoint': + public_url => "http://${::fqdn}:5000/", + admin_url => "http://${::fqdn}:35357/", + } +} + +node default { + fail("could not find a matching node entry for ${clientcert}") +} diff --git a/3rdparty/modules/memcached/Gemfile b/3rdparty/modules/memcached/Gemfile new file mode 100644 index 000000000..087b51f83 --- /dev/null +++ b/3rdparty/modules/memcached/Gemfile @@ -0,0 +1,9 @@ +source "https://rubygems.org" + +puppetversion = ENV.key?('PUPPET_VERSION') ? "= #{ENV['PUPPET_VERSION']}" : ['>= 3.3'] +gem 'puppet', puppetversion +gem 'puppetlabs_spec_helper', '>= 0.1.0' +gem 'rspec', '< 3.2.0', {"platforms"=>["ruby_18"]} +gem 'puppet-lint', '>= 0.3.2' +gem 'facter', '>= 1.7.0', "< 1.8.0" +gem 'rspec-puppet', '=1.0.1' diff --git a/3rdparty/modules/memcached/LICENSE b/3rdparty/modules/memcached/LICENSE new file mode 100644 index 000000000..7c6618932 --- /dev/null +++ b/3rdparty/modules/memcached/LICENSE @@ -0,0 +1,14 @@ + Copyright 2011 Steffen Zieger + Copyright 2014 Garrett Honeycutt + + 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. diff --git a/3rdparty/modules/memcached/README-DEVELOPER b/3rdparty/modules/memcached/README-DEVELOPER new file mode 100644 index 000000000..e6c4dab93 --- /dev/null +++ b/3rdparty/modules/memcached/README-DEVELOPER @@ -0,0 +1,9 @@ +In order to run tests: + - puppet and facter must be installed and available in Ruby's LOADPATH + - the latest revision of rspec-puppet must be installed + - rake, and rspec2 must be install + + - the name of the module directory needs to be memcached + +to run all tests: + rake spec diff --git a/3rdparty/modules/memcached/README.md b/3rdparty/modules/memcached/README.md new file mode 100644 index 000000000..7218b3e18 --- /dev/null +++ b/3rdparty/modules/memcached/README.md @@ -0,0 +1,52 @@ +# puppet-memcached [![Build Status](https://secure.travis-ci.org/saz/puppet-memcached.png)](http://travis-ci.org/saz/puppet-memcached) + +Manage memcached via Puppet + +## Show some love +If you find this module useful, send some bitcoins to 1Na3YFUmdxKxJLiuRXQYJU2kiNqA3KY2j9 + +## How to use + +### Use roughly 90% of memory + +```ruby + class { 'memcached': } +``` + +### Set a fixed memory limit in MB + +```ruby + class { 'memcached': + max_memory => 2048 + } +``` + +### Use 12% of available memory + +```ruby + class { 'memcached': + max_memory => '12%' + } +``` + +### Other class parameters + +* $package_ensure = 'present' +* $logfile = '/var/log/memcached.log' +* $pidfile = '/var/run/memcached.pid' (Debian family only, set to false to disable pidfile) +* $max_memory = false +* $item_size = false +* $lock_memory = false (WARNING: good if used intelligently, google for -k key) +* $listen_ip = '0.0.0.0' +* $tcp_port = 11211 +* $udp_port = 11211 +* $manage_firewall = false +* $user = '' (OS specific setting, see params.pp) +* $max_connections = 8192 +* $verbosity = undef +* $unix_socket = undef +* $install_dev = false (TRUE if 'libmemcached-dev' package should be installed) +* $processorcount = $::processorcount +* $service_restart = true (restart service after configuration changes, false to prevent restarts) +* $use_sasl = false (start memcached with SASL support) +* $large_mem_pages = false (try to use large memory pages) diff --git a/3rdparty/modules/memcached/Rakefile b/3rdparty/modules/memcached/Rakefile new file mode 100644 index 000000000..06f1ab4fb --- /dev/null +++ b/3rdparty/modules/memcached/Rakefile @@ -0,0 +1,19 @@ +require 'rubygems' +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' +PuppetLint.configuration.send('disable_80chars') +PuppetLint.configuration.relative = true +PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"] + +desc "Run puppet in noop mode and check for syntax errors." +task :validate do + Dir['manifests/**/*.pp'].each do |manifest| + sh "puppet parser validate --noop #{manifest}" + end + Dir['spec/**/*.rb','lib/**/*.rb'].each do |ruby_file| + sh "ruby -c #{ruby_file}" unless ruby_file =~ /spec\/fixtures/ + end + Dir['templates/**/*.erb'].each do |template| + sh "erb -P -x -T '-' #{template} | ruby -c" + end +end diff --git a/3rdparty/modules/memcached/checksums.json b/3rdparty/modules/memcached/checksums.json new file mode 100644 index 000000000..d1da9daa2 --- /dev/null +++ b/3rdparty/modules/memcached/checksums.json @@ -0,0 +1,18 @@ +{ + "Gemfile": "e3862348ae1ca9aebf98f138880db601", + "LICENSE": "d42ad7f00d233260ac2fba922b7fd83c", + "README-DEVELOPER": "d45048731ddb158a56a1b26293fb5dbf", + "README.md": "2b7283f5540df8576f90cf1afd136cbc", + "Rakefile": "791f8cad5f4e5d67cd261728d52a5bdf", + "lib/puppet/parser/functions/memcached_max_memory.rb": "edc87a9d229013298027a075e3eb8795", + "manifests/init.pp": "439ab80209902b9cf20c61049b7be4a9", + "manifests/params.pp": "b7e13ad9db1731e103c8a0b37f041b76", + "metadata.json": "4774f96927f32d3cbef5595de2ba2765", + "spec/classes/memcached_spec.rb": "5c96b78e1bd716c252728ac08fda7641", + "spec/spec.opts": "a600ded995d948e393fbe2320ba8e51c", + "spec/spec_helper.rb": "3ea886dd135e120afa31e0aab12e85b0", + "templates/memcached.conf.erb": "853ac472c6f1ca921921afce43053802", + "templates/memcached_sysconfig.erb": "16e8a675e51d28299adcc216c710910b", + "templates/memcached_windows.erb": "4df8529a690cfe5b10013237bc320513", + "tests/init.pp": "e798f4999ba392f3c0fce0d5290c263f" +} \ No newline at end of file diff --git a/3rdparty/modules/memcached/lib/puppet/parser/functions/memcached_max_memory.rb b/3rdparty/modules/memcached/lib/puppet/parser/functions/memcached_max_memory.rb new file mode 100644 index 000000000..fac25fdb3 --- /dev/null +++ b/3rdparty/modules/memcached/lib/puppet/parser/functions/memcached_max_memory.rb @@ -0,0 +1,38 @@ +module Puppet::Parser::Functions + newfunction(:memcached_max_memory, :type => :rvalue, :doc => <<-EOS + Calculate max_memory size from fact 'memsize' and passed argument. + EOS + ) do |arguments| + + raise(Puppet::ParseError, "memcached_max_memory(): " + + "Wrong number of arguments given " + + "(#{arguments.size} for 1)") if arguments.size != 1 + + arg = arguments[0] + memsize = lookupvar('memorysize') + + if arg and !arg.to_s.end_with?('%') + result_in_mb = arg.to_i + else + max_memory_percent = arg ? arg : '95%' + + # Taken from puppetlabs-stdlib to_bytes() function + value,prefix = */([0-9.e+-]*)\s*([^bB]?)/.match(memsize)[1,2] + + value = value.to_f + case prefix + when '' then value = value + when 'k' then value *= (1<<10) + when 'M' then value *= (1<<20) + when 'G' then value *= (1<<30) + when 'T' then value *= (1<<40) + when 'E' then value *= (1<<50) + else raise Puppet::ParseError, "memcached_max_memory(): Unknown prefix #{prefix}" + end + value = value.to_i + result_in_mb = ( (value / (1 << 20) ) * (max_memory_percent.to_f / 100.0) ).floor + end + + return result_in_mb + end +end diff --git a/3rdparty/modules/memcached/manifests/init.pp b/3rdparty/modules/memcached/manifests/init.pp new file mode 100644 index 000000000..761efcb0e --- /dev/null +++ b/3rdparty/modules/memcached/manifests/init.pp @@ -0,0 +1,123 @@ +# == Class: memcached +# +# Manage memcached +# +# == Parameters +# [* syslog *] +# Boolean. +# If true will pipe output to /bin/logger, sends to syslog. +# +class memcached ( + $package_ensure = 'present', + $service_manage = true, + $logfile = $::memcached::params::logfile, + $syslog = false, + $pidfile = '/var/run/memcached.pid', + $manage_firewall = false, + $max_memory = false, + $item_size = false, + $lock_memory = false, + $listen_ip = '0.0.0.0', + $tcp_port = 11211, + $udp_port = 11211, + $user = $::memcached::params::user, + $max_connections = '8192', + $verbosity = undef, + $unix_socket = undef, + $install_dev = false, + $processorcount = $::processorcount, + $service_restart = true, + $auto_removal = false, + $use_sasl = false, + $use_registry = $::memcached::params::use_registry, + $registry_key = 'HKLM\System\CurrentControlSet\services\memcached\ImagePath', + $large_mem_pages = false +) inherits memcached::params { + + # validate type and convert string to boolean if necessary + if is_string($manage_firewall) { + $manage_firewall_bool = str2bool($manage_firewall) + } else { + $manage_firewall_bool = $manage_firewall + } + validate_bool($manage_firewall_bool) + validate_bool($service_restart) + validate_bool($service_manage) + + validate_bool($syslog) + + # Logging to syslog and file are mutually exclusive + # Fail if both options are defined + if $syslog and str2bool($logfile) { + fail 'Define either syslog or logfile as logging destinations but not both.' + } + + if $package_ensure == 'absent' { + $service_ensure = 'stopped' + $service_enable = false + } else { + $service_ensure = 'running' + $service_enable = true + } + + package { $memcached::params::package_name: + ensure => $package_ensure, + provider => $memcached::params::package_provider + } + + if $install_dev { + package { $memcached::params::dev_package_name: + ensure => $package_ensure, + require => Package[$memcached::params::package_name] + } + } + + if $manage_firewall_bool == true { + firewall { "100_tcp_${tcp_port}_for_memcached": + port => $tcp_port, + proto => 'tcp', + action => 'accept', + } + + firewall { "100_udp_${udp_port}_for_memcached": + port => $udp_port, + proto => 'udp', + action => 'accept', + } + } + + if $service_restart and $service_manage { + $service_notify_real = Service[$memcached::params::service_name] + } else { + $service_notify_real = undef + } + + if ( $memcached::params::config_file ) { + file { $memcached::params::config_file: + owner => 'root', + group => 'root', + mode => '0644', + content => template($memcached::params::config_tmpl), + require => Package[$memcached::params::package_name], + notify => $service_notify_real, + } + } + + if $service_manage { + service { $memcached::params::service_name: + ensure => $service_ensure, + enable => $service_enable, + hasrestart => true, + hasstatus => $memcached::params::service_hasstatus, + } + } + + if $use_registry { + registry_value{ $registry_key: + ensure => 'present', + type => 'string', + data => template($memcached::params::config_tmpl), + notify => $service_notify_real, + } + } +} diff --git a/3rdparty/modules/memcached/manifests/params.pp b/3rdparty/modules/memcached/manifests/params.pp new file mode 100644 index 000000000..1469a4b4d --- /dev/null +++ b/3rdparty/modules/memcached/manifests/params.pp @@ -0,0 +1,61 @@ +# == Class: memcached::params +# +class memcached::params { + case $::osfamily { + 'Debian': { + $package_name = 'memcached' + $package_provider = undef + $service_name = 'memcached' + $service_hasstatus = false + $dev_package_name = 'libmemcached-dev' + $config_file = '/etc/memcached.conf' + $config_tmpl = "${module_name}/memcached.conf.erb" + $user = 'nobody' + $logfile = '/var/log/memcached.log' + $use_registry = false + } + /RedHat|Suse/: { + $package_name = 'memcached' + $package_provider = undef + $service_name = 'memcached' + $service_hasstatus = true + $dev_package_name = 'libmemcached-devel' + $config_file = '/etc/sysconfig/memcached' + $config_tmpl = "${module_name}/memcached_sysconfig.erb" + $user = 'memcached' + $logfile = '/var/log/memcached.log' + $use_registry = false + } + /windows/: { + $package_name = 'memcached' + $package_provider = 'chocolatey' + $service_name = 'memcached' + $service_hasstatus = true + $dev_package_name = 'libmemcached-devel' + $config_file = undef + $config_tmpl = "${module_name}/memcached_windows.erb" + $user = 'BUILTIN\Administrators' + $logfile = undef + $use_registry = true + } + default: { + case $::operatingsystem { + 'Amazon': { + $package_name = 'memcached' + $package_provider = undef + $service_name = 'memcached' + $service_hasstatus = true + $dev_package_name = 'libmemcached-devel' + $config_file = '/etc/sysconfig/memcached' + $config_tmpl = "${module_name}/memcached_sysconfig.erb" + $user = 'memcached' + $logfile = '/var/log/memcached.log' + $use_registry = false + } + default: { + fail("Unsupported platform: ${::osfamily}/${::operatingsystem}") + } + } + } + } +} diff --git a/3rdparty/modules/memcached/metadata.json b/3rdparty/modules/memcached/metadata.json new file mode 100644 index 000000000..71d0c7a2d --- /dev/null +++ b/3rdparty/modules/memcached/metadata.json @@ -0,0 +1,48 @@ +{ + "name": "saz-memcached", + "version": "2.8.1", + "author": "saz", + "summary": "Manage memcached via Puppet", + "license": "Apache License, Version 2.0", + "source": "git://github.com/saz/puppet-memcached.git", + "project_page": "https://github.com/saz/puppet-memcached", + "issues_url": "https://github.com/saz/puppet-memcached/issues", + "operatingsystem_support": [ + { + "operatingsystem": "RedHat" + }, + { + "operatingsystem": "CentOS" + }, + { + "operatingsystem": "OracleLinux" + }, + { + "operatingsystem": "Scientific" + }, + { + "operatingsystem": "Debian" + }, + { + "operatingsystem": "Ubuntu" + }, + { + "operatingsystem": "Windows" + } + ], + "requirements": [ + { + "name": "pe", + "version_requirement": ">= 3.2.0 < 3.4.0" + }, + { + "name": "puppet", + "version_requirement": "3.x" + } + ], + "description": "Manage memcached via Puppet", + "dependencies": [ + {"name":"puppetlabs/stdlib","version_requirement":">= 3.2.0"}, + {"name":"puppetlabs/firewall","version_requirement":">= 0.1.0"} + ] +} diff --git a/3rdparty/modules/memcached/spec/classes/memcached_spec.rb b/3rdparty/modules/memcached/spec/classes/memcached_spec.rb new file mode 100644 index 000000000..d8f2981c8 --- /dev/null +++ b/3rdparty/modules/memcached/spec/classes/memcached_spec.rb @@ -0,0 +1,231 @@ +require 'spec_helper' +describe 'memcached' do + + describe 'with manage_firewall parameter' do + ['Debian','RedHat'].each do |osfam| + context "on osfamily #{osfam}" do + let(:facts) do + { :osfamily => osfam, + :memorysize => '1000 MB', + :processorcount => '1', + } + end + + ['true',true].each do |value| + context "set to #{value}" do + let(:params) { { :manage_firewall => value } } + + it { should contain_class('memcached') } + + it { should contain_firewall('100_tcp_11211_for_memcached') } + it { should contain_firewall('100_udp_11211_for_memcached') } + end + end + + ['false',false].each do |value| + context "set to #{value}" do + let(:params) { { :manage_firewall => value } } + + it { should contain_class('memcached') } + + it { should_not contain_firewall('100_tcp_11211_for_memcached') } + it { should_not contain_firewall('100_udp_11211_for_memcached') } + end + end + + context 'set to an invalid type (array)' do + let(:params) { { :manage_firewall => ['invalid','type'] } } + + it do + expect { + should contain_class('memcached') + }.to raise_error(Puppet::Error) + end + end + end + end + end + + let :default_params do + { + :package_ensure => 'present', + :logfile => '/var/log/memcached.log', + :max_memory => false, + :item_size => false, + :lock_memory => false, + :listen_ip => '0.0.0.0', + :tcp_port => '11211', + :udp_port => '11211', + :user => 'nobody', + :max_connections => '8192', + :install_dev => false, + :processorcount => 1, + :use_sasl => false, + :large_mem_pages => false, + } + end + + [ {}, + { + :package_ensure => 'latest', + :logfile => '/var/log/memcached.log', + :max_memory => '2', + :item_size => false, + :lock_memory => true, + :listen_ip => '127.0.0.1', + :tcp_port => '11212', + :udp_port => '11213', + :user => 'somebdy', + :max_connections => '8193', + :verbosity => 'vvv', + :processorcount => 3, + :use_sasl => true, + :large_mem_pages => true, + }, + { + :package_ensure => 'present', + :logfile => '/var/log/memcached.log', + :max_memory => '20%', + :lock_memory => false, + :listen_ip => '127.0.0.1', + :tcp_port => '11212', + :udp_port => '11213', + :user => 'somebdy', + :max_connections => '8193', + :verbosity => 'vvv', + :install_dev => true, + :processorcount => 1 + }, + { + :listen_ip => '', + }, + { + :pidfile => false, + }, + { + :pidfile => '/var/log/memcached.pid', + }, + { + :package_ensure => 'absent', + :install_dev => true + }, + { + :service_manage => false + } + ].each do |param_set| + describe "when #{param_set == {} ? "using default" : "specifying"} class parameters" do + + let :param_hash do + default_params.merge(param_set) + end + + let :params do + param_set + end + + ['Debian'].each do |osfamily| + + let :facts do + { + :osfamily => osfamily, + :memorysize => '1000 MB', + :processorcount => '1', + } + end + + describe "on supported osfamily: #{osfamily}" do + + it { should contain_class("memcached::params") } + + it { should contain_package("memcached").with_ensure(param_hash[:package_ensure]) } + + it { should_not contain_firewall('100_tcp_11211_for_memcached') } + it { should_not contain_firewall('100_udp_11211_for_memcached') } + + it { + if param_hash[:install_dev] + should contain_package("libmemcached-dev").with_ensure(param_hash[:package_ensure]) + end + } + + it { should contain_file("/etc/memcached.conf").with( + 'owner' => 'root', + 'group' => 'root' + )} + + it { + if param_hash[:service_manage] == false + should_not contain_service('memcached') + elsif param_hash[:package_ensure] == 'absent' + should contain_service("memcached").with( + 'ensure' => 'stopped', + 'enable' => false + ) + else + should contain_service("memcached").with( + 'ensure' => 'running', + 'enable' => true, + 'hasrestart' => true, + 'hasstatus' => false + ) + end + } + + it 'should compile the template based on the class parameters' do + content = param_value( + subject, + 'file', + '/etc/memcached.conf', + 'content' + ) + expected_lines = [ + "logfile #{param_hash[:logfile]}", + "-p #{param_hash[:tcp_port]}", + "-U #{param_hash[:udp_port]}", + "-u #{param_hash[:user]}", + "-c #{param_hash[:max_connections]}", + "-t #{param_hash[:processorcount]}" + ] + if(param_hash[:max_memory]) + if(param_hash[:max_memory].end_with?('%')) + expected_lines.push("-m 200") + else + expected_lines.push("-m #{param_hash[:max_memory]}") + end + else + expected_lines.push("-m 950") + end + if(param_hash[:listen_ip] != '') + expected_lines.push("-l #{param_hash[:listen_ip]}") + end + if(param_hash[:lock_memory]) + expected_lines.push("-k") + end + if(param_hash[:pidfile]) + expected_lines.push("-P #{param_hash[:pidfile]}") + end + if(param_hash[:verbosity]) + expected_lines.push("-vvv") + end + if(param_hash[:use_sasl]) + expected_lines.push("-S") + end + if(param_hash[:large_mem_pages]) + expected_lines.push("-L") + end + (content.split("\n") & expected_lines).should =~ expected_lines + end + end + end + ['Redhat'].each do |osfamily| + describe 'on supported platform' do + it 'should fail' do + + end + end + end + end + end +end + +# vim: expandtab shiftwidth=2 softtabstop=2 diff --git a/3rdparty/modules/memcached/spec/spec.opts b/3rdparty/modules/memcached/spec/spec.opts new file mode 100644 index 000000000..91cd6427e --- /dev/null +++ b/3rdparty/modules/memcached/spec/spec.opts @@ -0,0 +1,6 @@ +--format +s +--colour +--loadby +mtime +--backtrace diff --git a/3rdparty/modules/memcached/spec/spec_helper.rb b/3rdparty/modules/memcached/spec/spec_helper.rb new file mode 100644 index 000000000..dc7e9f4a0 --- /dev/null +++ b/3rdparty/modules/memcached/spec/spec_helper.rb @@ -0,0 +1,2 @@ +require 'rubygems' +require 'puppetlabs_spec_helper/module_spec_helper' diff --git a/3rdparty/modules/memcached/templates/memcached.conf.erb b/3rdparty/modules/memcached/templates/memcached.conf.erb new file mode 100644 index 000000000..0dae0bcf7 --- /dev/null +++ b/3rdparty/modules/memcached/templates/memcached.conf.erb @@ -0,0 +1,72 @@ +# File managed by puppet + +# Run memcached as a daemon. +-d + +<% if @pidfile -%> +# pidfile +-P <%= @pidfile %> +<% end -%> + +# Log memcached's output +logfile <%= @logfile -%> + +<% if @verbosity -%> +# Verbosity +-<%= @verbosity %> +<% end -%> + +# Use MB memory max to use for object storage. +<% Puppet::Parser::Functions.function('memcached_max_memory') -%> +-m <%= scope.function_memcached_max_memory([@max_memory]) %> + +<% if @lock_memory -%> +# Lock down all paged memory. There is a limit on how much memory you may lock. +-k +<% end -%> + +<% if @use_sasl -%> +# Start with SASL support +-S +<% end -%> + +<% if @unix_socket -%> +# UNIX socket path to listen on +-s <%= @unix_socket %> +<% else -%> + +<% if @listen_ip != '' -%> +# IP to listen on +-l <%= @listen_ip %> +<% end -%> + +# TCP port to listen on +-p <%= @tcp_port %> + +# UDP port to listen on +-U <%= @udp_port %> +<% end -%> + +# Run daemon as user +-u <%= @user %> + +<% if @large_mem_pages -%> +# Try to use large memory pages (if available) +-L +<% end -%> + +# Limit the number of simultaneous incoming connections. +-c <%= @max_connections %> + +# Number of threads to use to process incoming requests. +-t <%= @processorcount %> + +<% if @item_size -%> +# Override the default size of each slab page +-I <%= @item_size %> +<% end -%> + +<% if @auto_removal -%> +# Disable automatic removal of items from the cache when out of memory +-M +<% end -%> diff --git a/3rdparty/modules/memcached/templates/memcached_sysconfig.erb b/3rdparty/modules/memcached/templates/memcached_sysconfig.erb new file mode 100644 index 000000000..825d46061 --- /dev/null +++ b/3rdparty/modules/memcached/templates/memcached_sysconfig.erb @@ -0,0 +1,57 @@ +<%- +result = [] +if @verbosity + result << '-' + @verbosity.to_s +end +if @lock_memory + result << '-k' +end +if @listen_ip + result << '-l ' + @listen_ip +end +if @udp_port + result << '-U ' + @udp_port.to_s +end +if @item_size + result << '-I ' + @item_size.to_s +end +result << '-t ' + @processorcount.to_s + +# log to syslog via logger +if @syslog && @logfile.empty? + result << '2>&1 |/bin/logger &' +# log to log file +elsif !@logfile.empty? && !@syslog + result << '>> ' + @logfile + ' 2>&1' +end +-%> +<%- if scope['osfamily'] != 'Suse' -%> +PORT="<%= @tcp_port %>" +USER="<%= @user %>" +MAXCONN="<%= @max_connections %>" +<% Puppet::Parser::Functions.function('memcached_max_memory') -%> +CACHESIZE="<%= scope.function_memcached_max_memory([@max_memory]) %>" +OPTIONS="<%= result.join(' ') %>" +<%- else -%> +MEMCACHED_PARAMS="<%= result.join(' ') %>" + +## Path: Network/WWW/Memcached +## Description: username memcached should run as +## Type: string +## Default: "memcached" +## Config: memcached +# +# username memcached should run as +# +MEMCACHED_USER="<%= @user %>" + +## Path: Network/WWW/Memcached +## Description: group memcached should be run as +## Type: string +## Default: "memcached" +## Config: memcached +# +# group memcached should be run as +# +MEMCACHED_GROUP="<%= @user %>" +<%- end -%> diff --git a/3rdparty/modules/memcached/templates/memcached_windows.erb b/3rdparty/modules/memcached/templates/memcached_windows.erb new file mode 100644 index 000000000..3964f2a91 --- /dev/null +++ b/3rdparty/modules/memcached/templates/memcached_windows.erb @@ -0,0 +1,28 @@ +<%- +result = [] +if @verbosity + result << '-' + @verbosity.to_s +end +if @lock_memory + result << '-k' +end +if @listen_ip + result << '-l ' + @listen_ip +end +if @tcp_port + result << '-p ' + @tcp_port.to_s +end +if @udp_port + result << '-U ' + @udp_port.to_s +end +if @item_size + result << '-I ' + @item_size.to_s +end +result << '-t ' + @processorcount +if @max_connections + result << '-c ' + @max_connections +end +if @logfile + result << '>> ' + @logfile + ' 2>&1' +end -%> +c:\memcached\memcached.exe -d runservice <%= result.join(' ') %> diff --git a/3rdparty/modules/memcached/tests/init.pp b/3rdparty/modules/memcached/tests/init.pp new file mode 100644 index 000000000..22eecc327 --- /dev/null +++ b/3rdparty/modules/memcached/tests/init.pp @@ -0,0 +1 @@ +include memcached diff --git a/3rdparty/modules/neutron/Gemfile b/3rdparty/modules/neutron/Gemfile new file mode 100644 index 000000000..dfa26719b --- /dev/null +++ b/3rdparty/modules/neutron/Gemfile @@ -0,0 +1,21 @@ +source 'https://rubygems.org' + +group :development, :test do + gem 'puppetlabs_spec_helper', :require => false + + gem 'metadata-json-lint' + gem 'puppet-lint', '~> 0.3.2' + gem 'rspec-puppet', '~> 1.0.1' + gem 'rake', '10.1.1' + gem 'rspec', '< 2.99' + gem 'json' + gem 'webmock' +end + +if puppetversion = ENV['PUPPET_GEM_VERSION'] + gem 'puppet', puppetversion, :require => false +else + gem 'puppet', :require => false +end + +# vim:ft=ruby diff --git a/3rdparty/modules/neutron/LICENSE b/3rdparty/modules/neutron/LICENSE new file mode 100644 index 000000000..68c771a09 --- /dev/null +++ b/3rdparty/modules/neutron/LICENSE @@ -0,0 +1,176 @@ + + 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. + diff --git a/3rdparty/modules/neutron/README.md b/3rdparty/modules/neutron/README.md new file mode 100644 index 000000000..ff4c9123c --- /dev/null +++ b/3rdparty/modules/neutron/README.md @@ -0,0 +1,296 @@ +neutron +=================================== + +5.1.0 - 2014.2 - Juno + +#### Table of Contents + +1. [Overview - What is the neutron module?](#overview) +2. [Module Description - What does the module do?](#module-description) +3. [Setup - Tha basics of getting started with neutron.](#setup) +4. [Implementation - An under-the-hood peek at what the module is doing.](#implementation) +5. [Limitations - OS compatibility, etc.](#limitations) +6. [Development - Guide for contributing to the module](#development) +7. [Contributors - Those with commits](#contributors) +8. [Release Notes - Notes on the most recent updates to the module](#release-notes) + +Overview +-------- + +The neutron module is a part of [Stackforge](https://github.com/stackforge), 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 flexibly configure and manage the newtork service for Openstack. + +Module Description +------------------ + +The neutron module is an attempt to make Puppet capable of managing the entirety of neutron. This includes manifests to provision such things as keystone endpoints, RPC configurations specific to neutron, database connections, and network driver plugins. Types are shipped as part of the neutron module to assist in manipulation of the Openstack configuration files. + +This module is tested in combination with other modules needed to build and leverage an entire Openstack installation. These modules can be found, all pulled together in the [openstack module](https://github.com/stackforge/puppet-openstack). + +Setup +----- + +**What the neutron module affects:** + +* [Neutron](https://wiki.openstack.org/wiki/Neutron), the network service for Openstack. + +### Installing neutron + + puppet module install puppetlabs/neutron + +### Beginning with neutron + +To utilize the neutron module's functionality you will need to declare multiple resources. The following is a modified excerpt from the [openstack module](httpd://github.com/stackforge/puppet-openstack). It provides an example of setting up an Open vSwitch neutron installation. This is not an exhaustive list of all the components needed. We recommend that you consult and understand the [openstack module](https://github.com/stackforge/puppet-openstack) and the [core openstack](http://docs.openstack.org) documentation to assist you in understanding the available deployment options. + +```puppet +# enable the neutron service +class { '::neutron': + enabled => true, + bind_host => '127.0.0.1', + rabbit_host => '127.0.0.1', + rabbit_user => 'neutron', + rabbit_password => 'rabbit_secret', + verbose => false, + debug => false, +} + +# configure authentication +class { 'neutron::server': + auth_host => '127.0.0.1', # the keystone host address + auth_password => 'keystone_neutron_secret', + sql_connection => 'mysql://neutron:neutron_sql_secret@127.0.0.1/neutron?charset=utf8', +} + +# enable the Open VSwitch plugin server +class { 'neutron::plugins::ovs': + tenant_network_type => 'gre', + network_vlan_ranges => 'physnet:1000:2000', +} +``` + +Other neutron network drivers include: + +* dhcp, +* metadata, +* and l3. + +Nova will also need to be configured to connect to the neutron service. Setting up the `nova::network::neutron` class sets +the `network_api_class` parameter in nova to use neutron instead of nova-network. + +```puppet +class { 'nova::network::neutron': + neutron_admin_password => 'neutron_admin_secret', +} +``` + + +The `examples` directory also provides a quick tutorial on how to use this module. + +Implementation +-------------- + +### neutron + +neutron is a combination of Puppet manifest and ruby code to deliver configuration and extra functionality through *types* and *providers*. + + +Limitations +----------- + +This module supports the following neutron plugins: + +* Open vSwitch +* linuxbridge +* cisco-neutron + +The following platforms are supported: + +* Ubuntu 12.04 (Precise) +* Debian (Wheezy) +* RHEL 6 +* Fedora 18 + +Development +----------- + +The puppet-openstack modules follow the Openstack development model. Developer documentation for the entire puppet-openstack project is at: + +* https://wiki.openstack.org/wiki/Puppet-openstack#Developerdocumentation + +Contributors +------------ +The github [contributor graph](https://github.com/stackforge/puppet-neutron/graphs/contributors). + +Release Notes +------------- + +**5.1.0** + +* Fix l3_ha enablement +* spec: pin rspec-puppet to 1.0.1 +* Switch to TLSv1 +* Support SR-IOV mechanism driver in ML2 +* Implement better nova_admin_tenant_id_setter exists? method +* OVS Agent with ML2: fix symlink on RH plateforms +* Adding portdb and fastpath_flood to n1kv.conf +* Make cisco plugin symlink coherent +* Fix status messages checks for neutron provider +* Make neutron_plugin_ml2 before db-sync +* Pin puppetlabs-concat to 1.2.1 in fixtures +* change default MySQL collate to utf8_general_ci +* Fix neutron file_line dependency +* Corrects "ip link set" command +* Adding vxlan network type support for neutron ML2 plug-in +* Raise puppet error, if nova-api unavailable +* Do not run neutron-ovs-cleanup for each Puppet run +* Unescape value in parse_allocation_pool +* Fix neutron_network for --router:external setting +* Add MidoNet plugin support +* Allow l3_ha to be turned back off after it has been enabled +* Update .gitreview file for project rename +* Fix support for auth_uri setting in neutron provider +* Reduce neutron API timeout to 10 seconds + +**5.0.0** + +* Stable Juno release +* Added neutron::policy to control policy.json +* Added parameter allow_automatic_l3agent_failover to neutron::agents::l3 +* Added parameter metadata_memory_cache_ttl to neutron::agents::metadata +* Added l3_ext as a provider_network_type property for neutron_network type +* Changed user_group parameter in neutron::agents::lbaas to have different defaults depending on operating system +* Changed openswan package to libreswan for RHEL 7 for vpnaas +* Ensured neutron package was installed before nova_admin_tenant_id_setter is called +* Added api_extensions_path parameter to neutron class +* Added database tuning parameters +* Changed management of file lines in /etc/default/neutron-server only for Ubuntu +* Add parameters to enable DVR and HA support in neutron::agents::l3 for Juno +* Fixed meaning of manage_service parameter in neutron::agents::ovs +* Made keystone user creation optional when creating a service +* Fixed the enable_dhcp property of neutron_subnet +* Added the ability to override the keystone service name in neutron::keystone::auth +* Fixed bug in parsing allocation pools in neutron_subnet type +* Added relationship to refresh neutron-server when nova_admin_tenant_id_setter changes +* Migrated the neutron::db::mysql class to use openstacklib::db::mysql and deprecated the mysql_module parameter +* Fixed the relationship between the HA proxy package and the neutron-lbaas-agent package +* Added kombu_reconnect_delay parameter to neutron class +* Fixed plugin.ini error when cisco class is used +* Fixed relationship between vs_pridge types and the neutron-plugin-ovs service +* Added neutron::agents::n1kv_vem to deploy N1KV VEM +* Added SSL support for nova_admin_tenant_id_setter +* Fixed relationship between neutron-server package and neutron_plugin_ml2 types +* Stopped puppet from trying to manage the ovs cleanup service +* Deprecated the network_device_mtu parameter in neutron::agents::l3 and moved it to the neutron class +* Added vpnaas_agent_package parameter to neutron::services::fwaas to install the vpnaas agent package + +**4.3.0** + +* Added parameter to specify number of RPC workers to spawn +* Added ability to manage Neutron ML2 plugin +* Fixed ssl parameter requirements when using kombu and rabbit +* Added ability to hide secret neutron configs from logs and fixed password leaking +* Added neutron plugin config file specification in neutron-server config +* Fixed installation of ML2 plugin on Ubuntu +* Added support for Cisco ML2 Mech Driver +* Fixed quotas parameters in neutron config +* Added parameter to configure dhcp_agent_notification in neutron config +* Added class for linuxbridge support +* Fixed neutron-server restart +* Undeprecated enable_security_group parameter + +**4.2.0** + +* Added ml2/ovs support. +* Added multi-region support. +* Set default metadata backlog to 4096. +* Fixed neutron-server refresh bug. + +**4.1.0** + +* Added parameter to set veth MTU. +* Added RabbitMQ SSL support. +* Added support for '' as a valid value for gateway_ip. +* Fixed potential OVS resource duplication. +* Pinned major gems. + +**4.0.0** + +* Stable Icehouse release. +* Added Neutron-Nova interactions support. +* Added external network bridge and interface driver for vpn agent. +* Added support for puppetlabs-mysql 2.2 and greater. +* Added neutron::config to handle additional custom options. +* Added https support to metadata agent. +* Added manage_service paraneter. +* Added quota parameters. +* Added support to configure ovs without installing package. +* Added support for optional haproxy package management. +* Added support to configure plugins by name rather than class name. +* Added multi-worker support. +* Added isolated network support. +* Updated security group option for ml2 plugin. +* Updated packaging changes for Red Hat and Ubuntu systems. +* Updated parameter defaults to track upstream (Icehouse). +* Fixed bug for subnets with empty values. +* Fixed typos and misconfiguration in neutron.conf. +* Fixed max_retries parameter warning. +* Fixed database creation bugs. + +**3.3.0** + +* Added neutron_port resource. +* Added external network bridge for vpn agent. +* Changed dhcp_lease_duration to Havana default of 86400 +* Fixed VPNaaS installation for Red Hat systems. +* Fixed conflicting symlink. +* Fixed network_vlan_ranges parameter for OVS plugin + +**3.2.0** + +* Added write support for dns, allocation pools, and host routes to Neutron router provider. +* Fixed multi-line attribute detection in base Neutron provider. +* Fixed bugs with neutron router gateway id parsing. + +**3.1.0** + +* Added VXLAN support. +* Configures security group when using ML2 plugin. +* Ensures installation of ML2 plugin. +* Fixed server deprecated warnings. +* Tuned report and downtime intervals for l2 agent. +* Added support for neutron nvp plugin. +* Ensures linuxbridge dependency is installed on RHEL. +* Improved L3 scheduler support. +* Fixed improper test for tunnel_types param. +* Allows log_dir to be set to false in order to disable file logging. +* Improves consistency with other puppet modules for OpenStack by prefixing database related parameters with database. +* Removed strict checks for vlan_ranges. +* Fixed neutron-metering-agent package for Ubuntu. +* Fixed VPNaaS service name for Ubuntu. +* Fixed FWaaS race condition. +* Fixed ML2 package dependency for Ubuntu. +* Removed erronious check for service_plugins. +* Added support for https auth endpoints. +* Makes haproxy package management optional. + +**3.0.0** + +* Major release for OpenStack Havana. +* Renamed project from quantum to neutron. +* Changed the default quota_driver. +* Removed provider setting requirement. +* Fixed file permissions. +* Fixed bug to ensure that keystone endpoint is set before service starts. +* Added database configuration support for Havana. +* Ensured dnsmasq package resource for compatibility with modules that define the same resource +* Added multi-worker support. +* Added metering agent support. +* Added vpnaas agent support. +* Added ml2 plugin support. +* Fixed lbass driver name. + +**2.2.0** + +* Improved documentation. +* Added syslog support. +* Added quantum-plugin-cisco package resource. +* Various lint and bug fixes. diff --git a/3rdparty/modules/neutron/Rakefile b/3rdparty/modules/neutron/Rakefile new file mode 100644 index 000000000..4c2b2ed07 --- /dev/null +++ b/3rdparty/modules/neutron/Rakefile @@ -0,0 +1,6 @@ +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' + +PuppetLint.configuration.fail_on_warnings = true +PuppetLint.configuration.send('disable_80chars') +PuppetLint.configuration.send('disable_class_parameter_defaults') diff --git a/3rdparty/modules/neutron/checksums.json b/3rdparty/modules/neutron/checksums.json new file mode 100644 index 000000000..23b2d89d5 --- /dev/null +++ b/3rdparty/modules/neutron/checksums.json @@ -0,0 +1,140 @@ +{ + "Gemfile": "f93ba14b05fa243d0d7b3318f321061b", + "LICENSE": "1dece7821bf3fd70fe1309eaa37d52a2", + "README.md": "a711928de801edef3d9ddda6ac0f3001", + "Rakefile": "2ca4ff31c946a19edd44348fbfdc2aab", + "examples/base_provision.pp": "34b6dc4a44b49eb061a9e8433f6a7b9d", + "examples/create_network.sh": "32256ea9c0a927dd6b02e2907cd97bc7", + "examples/neutron.pp": "f60e2ca82ff7fa97fa3180b79781f8a5", + "examples/neutron_with_pacemaker.pp": "89229318ebaba36b92d5fe3b5c0a2c64", + "lib/puppet/parser/functions/validate_network_vlan_ranges.rb": "c6b943bebabce85fb665d70f31d0868a", + "lib/puppet/parser/functions/validate_tunnel_id_ranges.rb": "147a6488352ab5cca8b7c08a8b98d13c", + "lib/puppet/parser/functions/validate_vni_ranges.rb": "d3a0272b5ee197164c32abc3d96f3ad8", + "lib/puppet/parser/functions/validate_vxlan_udp_port.rb": "2e7a8f9b954c23d5e254e1d6f59f7377", + "lib/puppet/provider/neutron.rb": "0f2aef481040f2e31e8eb131ced8a63d", + "lib/puppet/provider/neutron_api_config/ini_setting.rb": "631c8cae1605073b6cf73e9a88b0fbe4", + "lib/puppet/provider/neutron_config/ini_setting.rb": "3be345702d91cd43744f8eceed6bb658", + "lib/puppet/provider/neutron_dhcp_agent_config/ini_setting.rb": "34c4ef3300240a85fa59683307ae0a6a", + "lib/puppet/provider/neutron_fwaas_service_config/ini_setting.rb": "c3bc43b3a671cbb279eeb6c228bba0fe", + "lib/puppet/provider/neutron_l3_agent_config/ini_setting.rb": "b58b66445b7dcb8faaea1284fc24a718", + "lib/puppet/provider/neutron_l3_ovs_bridge/neutron.rb": "ee4cf0682ed941fcc6729e42818578f1", + "lib/puppet/provider/neutron_lbaas_agent_config/ini_setting.rb": "0f11d60319915d4b7866768ff127d5b2", + "lib/puppet/provider/neutron_metadata_agent_config/ini_setting.rb": "2792cdfdd3c7d1cd4c10e5a7a467a6cb", + "lib/puppet/provider/neutron_metering_agent_config/ini_setting.rb": "f0fd02e858a785389bcb46bd90561423", + "lib/puppet/provider/neutron_network/neutron.rb": "d9ea7607abe144c4870e331d2449f4c0", + "lib/puppet/provider/neutron_plugin_cisco/ini_setting.rb": "548797197bac607556f341fb9d0bf375", + "lib/puppet/provider/neutron_plugin_cisco_credentials/ini_setting.rb": "85b730f62749cf862b7fcac0bac7f621", + "lib/puppet/provider/neutron_plugin_cisco_db_conn/ini_setting.rb": "6594e6554e11d8d0ca92768d04dc5d38", + "lib/puppet/provider/neutron_plugin_cisco_l2network/ini_setting.rb": "ff993835dc8b1160b4b50817c2540635", + "lib/puppet/provider/neutron_plugin_linuxbridge/ini_setting.rb": "14b51050879956a077ee186107faafba", + "lib/puppet/provider/neutron_plugin_midonet/ini_setting.rb": "ab2f7fc7e309c759a87f5a83c9457942", + "lib/puppet/provider/neutron_plugin_ml2/ini_setting.rb": "e95fefe41a89fa9869809f0bca76197a", + "lib/puppet/provider/neutron_plugin_nvp/ini_setting.rb": "ab156e44fbc7017f24d2a5a9b5acdac5", + "lib/puppet/provider/neutron_plugin_ovs/ini_setting.rb": "8c2b5c9cc51704ed29026673b3bc4d55", + "lib/puppet/provider/neutron_port/neutron.rb": "05e3553a9906af9f904782bd82de71d5", + "lib/puppet/provider/neutron_router/neutron.rb": "1984ad8b3f538818f95d314142ed7226", + "lib/puppet/provider/neutron_router_interface/neutron.rb": "4d49f586c59c38367bfe5e06fb3371fd", + "lib/puppet/provider/neutron_subnet/neutron.rb": "b9a9037c13b14906a704459ebff64611", + "lib/puppet/provider/neutron_vpnaas_agent_config/ini_setting.rb": "a38a2e680c1bd9c812462be1c907d83b", + "lib/puppet/provider/nova_admin_tenant_id_setter/ini_setting.rb": "ccc25a372c66c6eec8cf43b357f79b96", + "lib/puppet/type/neutron_api_config.rb": "497d26f17bd767ee01e2d8012e989753", + "lib/puppet/type/neutron_config.rb": "e65d7bc227ebb8059c2916e5b442654b", + "lib/puppet/type/neutron_dhcp_agent_config.rb": "1d84a246988a9dc694d78c8d11e0a786", + "lib/puppet/type/neutron_fwaas_service_config.rb": "e6f8fd329610b5870606f069f5aa5895", + "lib/puppet/type/neutron_l3_agent_config.rb": "e6569c8eb8229dcade9a0e1bf243e1e3", + "lib/puppet/type/neutron_l3_ovs_bridge.rb": "058d18a7e7cc88d446aa07cf25a657fe", + "lib/puppet/type/neutron_lbaas_agent_config.rb": "e9ff6b363708eff717c89b4a83d6126e", + "lib/puppet/type/neutron_metadata_agent_config.rb": "90f5fc5fb3fd9114af9d0909e9ee1caf", + "lib/puppet/type/neutron_metering_agent_config.rb": "92e2ec411b06e777e6a54be07f953108", + "lib/puppet/type/neutron_network.rb": "fabd4b2bd1514c5bb9969162b4746161", + "lib/puppet/type/neutron_plugin_cisco.rb": "786a00022ecf3a063e6141052023e3f5", + "lib/puppet/type/neutron_plugin_cisco_credentials.rb": "f7952f721f9b124a9b520246c7120e9b", + "lib/puppet/type/neutron_plugin_cisco_db_conn.rb": "c282caef28a928e2be91998f177ff6bd", + "lib/puppet/type/neutron_plugin_cisco_l2network.rb": "69fde6803ee5cb7e8294037ef571fc60", + "lib/puppet/type/neutron_plugin_linuxbridge.rb": "ce1461b91660a20a4944f64d208cfe85", + "lib/puppet/type/neutron_plugin_midonet.rb": "e905bc85573f20cb1ff2e5e79db64051", + "lib/puppet/type/neutron_plugin_ml2.rb": "91878082ae1568839f28f593ce6579c5", + "lib/puppet/type/neutron_plugin_nvp.rb": "78fd92be12311329aa5513d44b3c9ec1", + "lib/puppet/type/neutron_plugin_ovs.rb": "8c9bbb54baa51424106cd852a0a465b0", + "lib/puppet/type/neutron_port.rb": "0d702eedd1cd17a97e1d1d85db568658", + "lib/puppet/type/neutron_router.rb": "cbfbf082bf43612d9c896547dea78988", + "lib/puppet/type/neutron_router_interface.rb": "84c220a451fe665fc65fae11db239c28", + "lib/puppet/type/neutron_subnet.rb": "d4972409dc4a4ebe4dd03fcedc4a8d17", + "lib/puppet/type/neutron_vpnaas_agent_config.rb": "11ebe4cb0655013cb551390df1f046f4", + "lib/puppet/type/nova_admin_tenant_id_setter.rb": "1d0ebff9c3fbd8fb0f6e06a248f9a96f", + "manifests/agents/dhcp.pp": "4a985c277471f45aa9c687e629c68a66", + "manifests/agents/l3.pp": "90eb74dc016520317fa45a03a099a675", + "manifests/agents/lbaas.pp": "cdf9ae43439638c3afd16cfbd1b3fe94", + "manifests/agents/linuxbridge.pp": "94588d7e4fcb20c4c80e5996e025032f", + "manifests/agents/metadata.pp": "8f356738317f7d3fc9e83e1f4b491172", + "manifests/agents/metering.pp": "2e8ad9f04fe4b9a8313a9f394df633cb", + "manifests/agents/ml2/linuxbridge.pp": "ca17e506553ed7f42fdf43b699d883f3", + "manifests/agents/ml2/ovs.pp": "43aa38b2bfbaf94d311c153594fb03d0", + "manifests/agents/ml2/sriov.pp": "fdb6a5064efa723749e2ad5a9ad77961", + "manifests/agents/n1kv_vem.pp": "382c4266b1bb78e08faa7cc2db380c78", + "manifests/agents/ovs.pp": "fecde78932dc53ca849c94e6a05016dd", + "manifests/agents/vpnaas.pp": "931e1c85535e762e9995b7752f8b8b72", + "manifests/client.pp": "338584745b937ea3309bcee01cb735e5", + "manifests/config.pp": "1b465879e63c4061d042ea178cb604c6", + "manifests/db/mysql.pp": "110b8ce2bf7546977e225fb59ef75850", + "manifests/init.pp": "2025193859c0ca12fb36b7a48061f5db", + "manifests/keystone/auth.pp": "2d0d0f222344207dd7db9902942516c0", + "manifests/params.pp": "37f40d24ec282296344e2a87b0edce81", + "manifests/plugins/cisco.pp": "ee720284596fa0da64f3bfb004303cab", + "manifests/plugins/linuxbridge.pp": "d4671296d29c34b29b315f0ec642169a", + "manifests/plugins/midonet.pp": "7ddf242e08ef6f741a3ca09eb9ca88d9", + "manifests/plugins/ml2/cisco/nexus.pp": "e02b74aa780ff282d7c3ed2b45cc9f1f", + "manifests/plugins/ml2/cisco/nexus_creds.pp": "661a5a5467185ad94521606c1940d777", + "manifests/plugins/ml2/mech_driver.pp": "fec5102482a5f6fbfb33b562f15528d3", + "manifests/plugins/ml2/type_driver.pp": "ad33efa9326e645ba76d17874ccb0531", + "manifests/plugins/ml2.pp": "bace949db4ab7ffd48f7c30dc3d24230", + "manifests/plugins/nvp.pp": "b2a96c3bd91c919b556611dd518542eb", + "manifests/plugins/ovs/bridge.pp": "1a895380424cdf378d7f5966c656e250", + "manifests/plugins/ovs/port.pp": "7e22b5aa08d31091126fc5af05434e10", + "manifests/plugins/ovs.pp": "b88a50cfd24f3fabe6c872a121a8d6a2", + "manifests/policy.pp": "38864a0040b8982602adf90c7c9c9fab", + "manifests/quota.pp": "76410c1ffcd5e9e24c77402a7167bde2", + "manifests/server/notifications.pp": "9672b4ae1942e65c914181fef61036aa", + "manifests/server.pp": "4ede23648510fb43b464e4b48c781e40", + "manifests/services/fwaas.pp": "cbf1672bf1cf91703c3fd5135a8dfcd7", + "metadata.json": "764fee4245270e7a15ed881b5333d62d", + "spec/classes/neutron_agents_dhcp_spec.rb": "6e12bcf8e0c178680609cf0ef22892a1", + "spec/classes/neutron_agents_l3_spec.rb": "95ac9bec49d9e9fa5310d30dba9f738e", + "spec/classes/neutron_agents_lbaas_spec.rb": "7939f7c1be52cba46745fe6b60fcbe47", + "spec/classes/neutron_agents_linuxbridge_spec.rb": "2d65edcf7d94c6e58e80b3618c32ea98", + "spec/classes/neutron_agents_metadata_spec.rb": "805c9859fe9185b83d867f3097c28625", + "spec/classes/neutron_agents_metering_spec.rb": "8a2db0506adb2f7d1659d7113c9f9169", + "spec/classes/neutron_agents_ml2_linuxbridge_spec.rb": "d38edb07d5ff5bfd32e4d6a1ac0b2318", + "spec/classes/neutron_agents_ml2_ovs_spec.rb": "28fd29fd65c0292a06e593e220a639e9", + "spec/classes/neutron_agents_ml2_sriov_spec.rb": "ffa63b00f230f999bc956bbb49443b5b", + "spec/classes/neutron_agents_n1kv_vem_spec.rb": "1e0b13375c3082382c6d782d4b05dec0", + "spec/classes/neutron_agents_ovs_spec.rb": "901bdb678238dc7298667a4f2893937c", + "spec/classes/neutron_agents_vpnaas_spec.rb": "9f958ddf82036576234a95e1bc95809a", + "spec/classes/neutron_client_spec.rb": "2a1472c314dc3bcd2ebfb0d3e468a4d6", + "spec/classes/neutron_db_mysql_spec.rb": "f57ff493a4d27898532e81d483b0a925", + "spec/classes/neutron_init_spec.rb": "bc735df6e4c19f999a4c8f22833433c8", + "spec/classes/neutron_keystone_auth_spec.rb": "dd2ad544aac117edb7f3bf61026c2464", + "spec/classes/neutron_plugins_cisco_ml2_spec.rb": "1576e872f97686e348b5e3255eab064c", + "spec/classes/neutron_plugins_cisco_spec.rb": "1145b460622989959663759589411538", + "spec/classes/neutron_plugins_linuxbridge_spec.rb": "fa1e1b7013a4999e5c82d4b7fa4b2de2", + "spec/classes/neutron_plugins_midonet_spec.rb": "5e717468a759d272a3fc5520525c7ad9", + "spec/classes/neutron_plugins_ml2_spec.rb": "990f8a7796f9954563aa2d25313155a2", + "spec/classes/neutron_plugins_nvp_spec.rb": "b9850d8c03ee1e7eeb812b04c9128d52", + "spec/classes/neutron_plugins_ovs_spec.rb": "cf4b52e03b1349f90e97f43f42cfbb8e", + "spec/classes/neutron_policy_spec.rb": "b2d4e8c43957d460e9fdd015ee2c3487", + "spec/classes/neutron_quota_spec.rb": "899025d4bc26aaacc4961bdf026d2261", + "spec/classes/neutron_server_notifications_spec.rb": "64ca340b17cd4c3135e51327cdd77986", + "spec/classes/neutron_server_spec.rb": "584b1c6024370588ebde5957dcd99b7e", + "spec/classes/neutron_services_fwaas_spec.rb": "b1a022004ae82e4b34dc8f7d94e25470", + "spec/shared_examples.rb": "172c63c57efca8c741f297494ed9ef0f", + "spec/spec_helper.rb": "e1b4b0bef7dd351a1207b4eb5b501f54", + "spec/unit/provider/neutron_l3_ovs_bridge/neutron_spec.rb": "4f0f61cd1d2ad500dd5fd8f6bd457377", + "spec/unit/provider/neutron_network/neutron_spec.rb": "c43db78403136ffab698a62927e6d929", + "spec/unit/provider/neutron_router/neutron_spec.rb": "ea39b71183502e06ae46503b633de7ca", + "spec/unit/provider/neutron_router_interface/neutron_spec.rb": "03d425ae2fd6e4ee354179c9f239bd39", + "spec/unit/provider/neutron_spec.rb": "74478bbac967e057aac4b30cdaf7e532", + "spec/unit/provider/neutron_subnet/neutron_spec.rb": "afe012a07de9b7711bb0a6583f3599ca", + "spec/unit/provider/nova_admin_tenant_id_setter/neutron_spec.rb": "3f8fad151f02775bea3f4f552a1b0b84", + "templates/ml2_conf_cisco.ini.erb": "b878b350a34700a8c8ef083e4e0c84b7", + "templates/n1kv.conf.erb": "d4233d228592977f684214e3b173f4d9" +} \ No newline at end of file diff --git a/3rdparty/modules/neutron/examples/base_provision.pp b/3rdparty/modules/neutron/examples/base_provision.pp new file mode 100644 index 000000000..8a760e4be --- /dev/null +++ b/3rdparty/modules/neutron/examples/base_provision.pp @@ -0,0 +1,54 @@ +# +# This manifest is intended to demonstrate how to provision the +# resources necessary to boot a vm with network connectivity provided +# by neutron. +# +# Note that a neutron_router resource must declare a dependency on the +# first subnet of the gateway network. Other dependencies for the +# resources used in this example can be automatically determined. +# + +keystone_tenant { 'admin': + ensure => present, +} + +neutron_network { 'public': + ensure => present, + router_external => 'True', + tenant_name => 'admin', +} + +neutron_subnet { 'public_subnet': + ensure => 'present', + cidr => '172.24.4.224/28', + network_name => 'public', + tenant_name => 'admin', +} + +keystone_tenant { 'demo': + ensure => present, +} + +neutron_network { 'private': + ensure => present, + tenant_name => 'demo', +} + +neutron_subnet { 'private_subnet': + ensure => present, + cidr => '10.0.0.0/24', + network_name => 'private', + tenant_name => 'demo', +} + +# Tenant-private router - assumes network namespace isolation +neutron_router { 'demo_router': + ensure => present, + tenant_name => 'demo', + gateway_network_name => 'public', + require => Neutron_subnet['public_subnet'], +} + +neutron_router_interface { 'demo_router:private_subnet': + ensure => present, +} diff --git a/3rdparty/modules/neutron/examples/create_network.sh b/3rdparty/modules/neutron/examples/create_network.sh new file mode 100644 index 000000000..7e8b9b3c7 --- /dev/null +++ b/3rdparty/modules/neutron/examples/create_network.sh @@ -0,0 +1,8 @@ +#!/bin/bash +# This example script shows how to create a simple subnet for Neutron. + +source /root/openrc +neutron net-create mynet +neutron subnet-create --name mynet-subnet mynet 10.0.0.0/24 +neutron router-create myrouter +neutron router-interface-add myrouter mynet-subnet diff --git a/3rdparty/modules/neutron/examples/neutron.pp b/3rdparty/modules/neutron/examples/neutron.pp new file mode 100644 index 000000000..7522e5ef2 --- /dev/null +++ b/3rdparty/modules/neutron/examples/neutron.pp @@ -0,0 +1,74 @@ +### Cloud Controller: + +# General Neutron stuff +# Configures everything in neutron.conf +class { 'neutron': + verbose => true, + allow_overlapping_ips => true, + rabbit_password => 'password', + rabbit_user => 'guest', + rabbit_host => 'localhost', + service_plugins => ['metering'] +} + +# The API server talks to keystone for authorisation +class { 'neutron::server': + keystone_password => 'password', + connection => 'mysql://neutron:password@192.168.1.1/neutron', +} + +# Configure nova notifications system +class { 'neutron::server::notifications': + nova_admin_tenant_name => 'admin', + nova_admin_password => 'secrete', +} + +# Various agents +class { 'neutron::agents::dhcp': } +class { 'neutron::agents::l3': } +class { 'neutron::agents::lbaas': } +class { 'neutron::agents::vpnaas': } +class { 'neutron::agents::metering': } + +# This plugin configures Neutron for OVS on the server +# Agent +class { 'neutron::agents::ovs': + local_ip => '192.168.1.1', + enable_tunneling => true, +} + +# Plugin +class { 'neutron::plugins::ovs': + tenant_network_type => 'gre', +} + +# ml2 plugin with vxlan as ml2 driver and ovs as mechanism driver +class { 'neutron::plugins::ml2': + type_drivers => ['vxlan'], + tenant_network_types => ['vxlan'], + vxlan_group => '239.1.1.1', + mechanism_drivers => ['openvswitch'], + vni_ranges => ['0:300'] +} + +### Compute Nodes: +# Generally, any machine with a neutron element running on it talks +# over Rabbit and needs to know if overlapping IPs (namespaces) are in use +class { 'neutron': + allow_overlapping_ips => true, + rabbit_password => 'password', + rabbit_user => 'guest', + rabbit_host => 'localhost', +} + +# The agent/plugin combo also needs installed on clients +# Agent +class { 'neutron::agents::ovs': + local_ip => '192.168.1.11', + enable_tunneling => true, +} + +# Plugin +class { 'neutron::plugins::ovs': + tenant_network_type => 'gre', +} diff --git a/3rdparty/modules/neutron/examples/neutron_with_pacemaker.pp b/3rdparty/modules/neutron/examples/neutron_with_pacemaker.pp new file mode 100644 index 000000000..880385166 --- /dev/null +++ b/3rdparty/modules/neutron/examples/neutron_with_pacemaker.pp @@ -0,0 +1,47 @@ +# Example: managing neutron controller services with pacemaker +# +# By setting enabled to false, these services will not be started at boot. By setting +# manage_service to false, puppet will not kill these services on every run. This +# allows the Pacemaker resource manager to dynamically determine on which node each +# service should run. +# +# The puppet commands below would ideally be applied to at least three nodes. +# +# Note that neutron-server is associated with the virtual IP address as +# it is called from external services. The remaining services connect to the +# database and/or message broker independently. +# +# Example pacemaker resource configuration commands (configured once per cluster): +# +# sudo pcs resource create neutron_vip ocf:heartbeat:IPaddr2 params ip=192.0.2.3 \ +# cidr_netmask=24 op monitor interval=10s +# +# sudo pcs resource create neutron_server_service lsb:neutron-server +# sudo pcs resource create neutron_dhcp_agent_service lsb:neutron-dhcp-agent +# sudo pcs resource create neutron_l3_agent_service lsb:neutron-l3-agent +# +# sudo pcs constraint colocation add neutron_server_service with neutron_vip + +class { 'neutron': + verbose => true, + allow_overlapping_ips => true, + service_plugins => [ 'dhcp', 'l3' ] +} + +class { 'neutron::server': + enabled => false, + manage_service => false, + keystone_password => 'password', + connection => 'mysql://neutron:password@192.168.1.1/neutron', +} + +class { 'neutron::agents::dhcp': + enabled => false, + manage_service => false, +} + +class { 'neutron::agents::l3': + enabled => false, + manage_service => false, +} + diff --git a/3rdparty/modules/neutron/lib/puppet/parser/functions/validate_network_vlan_ranges.rb b/3rdparty/modules/neutron/lib/puppet/parser/functions/validate_network_vlan_ranges.rb new file mode 100644 index 000000000..f363ef52b --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/parser/functions/validate_network_vlan_ranges.rb @@ -0,0 +1,47 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# Martin Magr +# +# 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. +# +# Advanced validation for VLAN configuration +# + +module Puppet::Parser::Functions + newfunction(:validate_network_vlan_ranges) do |args| + value = args[0] + if not value.kind_of?(Array) + value = [value] + end + + value.each do |range| + if m = /^(.+:)?(\d+):(\d+)$/.match(range) + first_id = Integer(m[-2]) + second_id = Integer(m[-1]) + if (first_id > 4094) || (second_id > 4094) + raise Puppet::Error, "vlan id are invalid." + end + if ((second_id - first_id) < 0 ) + raise Puppet::Error, "network vlan ranges are invalid." + end + elsif m = /^([^:]+)?(:\d+)?$/.match(range) + # Either only name of physical network or single vlan id has + # been passed. This is also correct. + elsif range + raise Puppet::Error, "network vlan ranges are invalid." + end + end + end +end diff --git a/3rdparty/modules/neutron/lib/puppet/parser/functions/validate_tunnel_id_ranges.rb b/3rdparty/modules/neutron/lib/puppet/parser/functions/validate_tunnel_id_ranges.rb new file mode 100644 index 000000000..d13d5530f --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/parser/functions/validate_tunnel_id_ranges.rb @@ -0,0 +1,44 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# Martin Magr +# +# 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. +# +# Advanced validation when using GRE +# + +module Puppet::Parser::Functions + newfunction(:validate_tunnel_id_ranges) do |args| + value = args[0] + if not value.kind_of?(Array) + value = [value] + end + + value.each do |range| + if m = /^(\d+):(\d+)$/.match(range) + first_id = Integer(m[1]) + second_id = Integer(m[2]) + if ((second_id - first_id) > 1000000) + raise Puppet::Error, "tunnel id ranges are to large." + end + if ((second_id - first_id) < 0 ) + raise Puppet::Error, "tunnel id ranges are invalid." + end + elsif range + raise Puppet::Error, "tunnel id ranges are invalid." + end + end + end +end diff --git a/3rdparty/modules/neutron/lib/puppet/parser/functions/validate_vni_ranges.rb b/3rdparty/modules/neutron/lib/puppet/parser/functions/validate_vni_ranges.rb new file mode 100644 index 000000000..d222bdb85 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/parser/functions/validate_vni_ranges.rb @@ -0,0 +1,47 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# Martin Magr +# +# 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. +# +# Advanced validation when using VXLAN +# + +module Puppet::Parser::Functions + newfunction(:validate_vni_ranges) do |args| + value = args[0] + if not value.kind_of?(Array) + value = [value] + end + + value.each do |range| + if m = /^(\d+):(\d+)$/.match(range) + first_id = Integer(m[1]) + second_id = Integer(m[2]) + if not (0 <= first_id && first_id <= 16777215) + raise Puppet::Error, "vni ranges are invalid." + end + if not (0 <= second_id && second_id <= 16777215) + raise Puppet::Error, "vni ranges are invalid." + end + if (second_id < first_id) + raise Puppet::Error, "vni ranges are invalid." + end + elsif range + raise Puppet::Error, "vni ranges are invalid." + end + end + end +end diff --git a/3rdparty/modules/neutron/lib/puppet/parser/functions/validate_vxlan_udp_port.rb b/3rdparty/modules/neutron/lib/puppet/parser/functions/validate_vxlan_udp_port.rb new file mode 100644 index 000000000..25b711032 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/parser/functions/validate_vxlan_udp_port.rb @@ -0,0 +1,32 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# Martin Magr +# +# 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. +# +# Advanced validation for VXLAN UDP port configuration +# + +module Puppet::Parser::Functions + newfunction(:validate_vxlan_udp_port) do |args| + value = Integer(args[0]) + + # check if port is either default value or one of the private ports + # according to http://tools.ietf.org/html/rfc6056 + if value != 4789 or (49151 >= value and value > 65535) + raise Puppet::Error, "vxlan udp port is invalid." + end + end +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron.rb new file mode 100644 index 000000000..b3c9d9812 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron.rb @@ -0,0 +1,221 @@ +require 'csv' +require 'puppet/util/inifile' + +class Puppet::Provider::Neutron < Puppet::Provider + + def self.conf_filename + '/etc/neutron/neutron.conf' + end + + def self.withenv(hash, &block) + saved = ENV.to_hash + hash.each do |name, val| + ENV[name.to_s] = val + end + + yield + ensure + ENV.clear + saved.each do |name, val| + ENV[name] = val + end + end + + def self.neutron_credentials + @neutron_credentials ||= get_neutron_credentials + end + + def self.get_neutron_credentials + auth_keys = ['admin_tenant_name', 'admin_user', 'admin_password'] + deprecated_auth_url = ['auth_host', 'auth_port', 'auth_protocol'] + conf = neutron_conf + if conf and conf['keystone_authtoken'] and + auth_keys.all?{|k| !conf['keystone_authtoken'][k].nil?} and + ( deprecated_auth_url.all?{|k| !conf['keystone_authtoken'][k].nil?} or + !conf['keystone_authtoken']['auth_uri'].nil? ) + creds = Hash[ auth_keys.map \ + { |k| [k, conf['keystone_authtoken'][k].strip] } ] + if !conf['keystone_authtoken']['auth_uri'].nil? + creds['auth_uri'] = conf['keystone_authtoken']['auth_uri'] + else + q = conf['keystone_authtoken'] + creds['auth_uri'] = "#{q['auth_protocol']}://#{q['auth_host']}:#{q['auth_port']}/v2.0/" + end + if conf['DEFAULT'] and !conf['DEFAULT']['nova_region_name'].nil? + creds['nova_region_name'] = conf['DEFAULT']['nova_region_name'] + end + return creds + else + raise(Puppet::Error, "File: #{conf_filename} does not contain all \ +required sections. Neutron types will not work if neutron is not \ +correctly configured.") + end + end + + def neutron_credentials + self.class.neutron_credentials + end + + def self.auth_endpoint + @auth_endpoint ||= get_auth_endpoint + end + + def self.get_auth_endpoint + q = neutron_credentials + if q['auth_uri'].nil? + return "#{q['auth_protocol']}://#{q['auth_host']}:#{q['auth_port']}/v2.0/" + else + return "#{q['auth_uri']}".strip + end + end + + def self.neutron_conf + return @neutron_conf if @neutron_conf + @neutron_conf = Puppet::Util::IniConfig::File.new + @neutron_conf.read(conf_filename) + @neutron_conf + end + + def self.auth_neutron(*args) + q = neutron_credentials + authenv = { + :OS_AUTH_URL => self.auth_endpoint, + :OS_USERNAME => q['admin_user'], + :OS_TENANT_NAME => q['admin_tenant_name'], + :OS_PASSWORD => q['admin_password'] + } + if q.key?('nova_region_name') + authenv[:OS_REGION_NAME] = q['nova_region_name'] + end + rv = nil + timeout = 10 + end_time = Time.now.to_i + timeout + loop do + begin + withenv authenv do + rv = neutron(args) + end + break + rescue Puppet::ExecutionFailure => e + if ! e.message =~ /(\(HTTP\s+400\))| + (400-\{\'message\'\:\s+\'\'\})| + (\[Errno 111\]\s+Connection\s+refused)| + (503\s+Service\s+Unavailable)| + (504\s+Gateway\s+Time-out)| + (\:\s+Maximum\s+attempts\s+reached)| + (Unauthorized\:\s+bad\s+credentials)| + (Max\s+retries\s+exceeded)/ + raise(e) + end + current_time = Time.now.to_i + if current_time > end_time + break + else + wait = end_time - current_time + Puppet::debug("Non-fatal error: \"#{e.message}\"") + notice("Neutron API not avalaible. Wait up to #{wait} sec.") + end + sleep(2) + # Note(xarses): Don't remove, we know that there is one of the + # Recoverable erros above, So we will retry a few more times + end + end + return rv + end + + def auth_neutron(*args) + self.class.auth_neutron(args) + end + + def self.reset + @neutron_conf = nil + @neutron_credentials = nil + end + + def self.list_neutron_resources(type) + ids = [] + list = auth_neutron("#{type}-list", '--format=csv', + '--column=id', '--quote=none') + if list.nil? + raise(Puppet::ExecutionFailure, "Can't retrieve #{type}-list because Neutron or Keystone API is not avalaible.") + end + + (list.split("\n")[1..-1] || []).compact.collect do |line| + ids << line.strip + end + return ids + end + + def self.get_neutron_resource_attrs(type, id) + attrs = {} + net = auth_neutron("#{type}-show", '--format=shell', id) + if net.nil? + raise(Puppet::ExecutionFailure, "Can't retrieve #{type}-show because Neutron or Keystone API is not avalaible.") + end + + last_key = nil + (net.split("\n") || []).compact.collect do |line| + if line.include? '=' + k, v = line.split('=', 2) + attrs[k] = v.gsub(/\A"|"\Z/, '') + last_key = k + else + # Handle the case of a list of values + v = line.gsub(/\A"|"\Z/, '') + attrs[last_key] = [attrs[last_key], v].flatten + end + end + return attrs + end + + def self.list_router_ports(router_name_or_id) + results = [] + cmd_output = auth_neutron("router-port-list", + '--format=csv', + router_name_or_id) + if ! cmd_output + return results + end + + headers = nil + CSV.parse(cmd_output) do |row| + if headers == nil + headers = row + else + result = Hash[*headers.zip(row).flatten] + match_data = /.*"subnet_id": "(.*)", .*/.match(result['fixed_ips']) + if match_data + result['subnet_id'] = match_data[1] + end + results << result + end + end + return results + end + + def self.get_tenant_id(catalog, name) + instance_type = 'keystone_tenant' + instance = catalog.resource("#{instance_type.capitalize!}[#{name}]") + if ! instance + instance = Puppet::Type.type(instance_type).instances.find do |i| + i.provider.name == name + end + end + if instance + return instance.provider.id + else + fail("Unable to find #{instance_type} for name #{name}") + end + end + + def self.parse_creation_output(data) + hash = {} + data.split("\n").compact.each do |line| + if line.include? '=' + hash[line.split('=').first] = line.split('=', 2)[1].gsub(/\A"|"\Z/, '') + end + end + hash + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_api_config/ini_setting.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_api_config/ini_setting.rb new file mode 100644 index 000000000..cc9e81e19 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_api_config/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_api_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/api-paste.ini' + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_config/ini_setting.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_config/ini_setting.rb new file mode 100644 index 000000000..a1e97b06e --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_config/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/neutron.conf' + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_dhcp_agent_config/ini_setting.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_dhcp_agent_config/ini_setting.rb new file mode 100644 index 000000000..88f2d31ba --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_dhcp_agent_config/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_dhcp_agent_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/dhcp_agent.ini' + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_fwaas_service_config/ini_setting.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_fwaas_service_config/ini_setting.rb new file mode 100644 index 000000000..9196679ab --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_fwaas_service_config/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_fwaas_service_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/fwaas_driver.ini' + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_l3_agent_config/ini_setting.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_l3_agent_config/ini_setting.rb new file mode 100644 index 000000000..c52c0cee7 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_l3_agent_config/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_l3_agent_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/l3_agent.ini' + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_l3_ovs_bridge/neutron.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_l3_ovs_bridge/neutron.rb new file mode 100644 index 000000000..5ae0167b2 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_l3_ovs_bridge/neutron.rb @@ -0,0 +1,54 @@ +Puppet::Type.type(:neutron_l3_ovs_bridge).provide(:neutron) do + desc <<-EOT + Neutron provider to manage neutron_l3_ovs_bridge type. + + The provider ensures that the gateway ip of the subnet is + configured on the ovs bridge. + EOT + + commands :ip => '/sbin/ip' + + mk_resource_methods + + def gateway_ip + if @gateway_ip == nil + subnet = Puppet::Type.type('neutron_subnet').instances.find do |instance| + instance.provider.name == @resource[:subnet_name] + end + if subnet + provider = subnet.provider + @gateway_ip = "#{provider.gateway_ip}/#{provider.cidr.split('/')[1]}" + else + fail("Unable to find subnet for name #{@resource[:subnet_name]}") + end + end + @gateway_ip + end + + def bridge_ip_addresses + addresses = [] + result = ip('addr', 'show', @resource[:name]) + (result.split("\n") || []).compact.each do |line| + if match = line.match(/\sinet ([^\s]*) .*/) + addresses << match.captures[0] + end + end + return addresses + end + + def exists? + bridge_ip_addresses.include?(gateway_ip) + end + + def create + ip('addr', 'add', gateway_ip, 'dev', @resource[:name]) + ip('link', 'set', 'dev', @resource[:name], 'up') + @property_hash[:ensure] = :present + end + + def destroy + ip('addr', 'del', gateway_ip, 'dev', @resource[:name]) + @property_hash[:ensure] = :absent + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_lbaas_agent_config/ini_setting.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_lbaas_agent_config/ini_setting.rb new file mode 100644 index 000000000..908c77d1e --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_lbaas_agent_config/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_lbaas_agent_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/lbaas_agent.ini' + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_metadata_agent_config/ini_setting.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_metadata_agent_config/ini_setting.rb new file mode 100644 index 000000000..94a5c8555 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_metadata_agent_config/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_metadata_agent_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/metadata_agent.ini' + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_metering_agent_config/ini_setting.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_metering_agent_config/ini_setting.rb new file mode 100644 index 000000000..0abd3db4e --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_metering_agent_config/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_metering_agent_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/metering_agent.ini' + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_network/neutron.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_network/neutron.rb new file mode 100644 index 000000000..e5a0c39bf --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_network/neutron.rb @@ -0,0 +1,141 @@ +require File.join(File.dirname(__FILE__), '..','..','..', + 'puppet/provider/neutron') + +Puppet::Type.type(:neutron_network).provide( + :neutron, + :parent => Puppet::Provider::Neutron +) do + desc <<-EOT + Neutron provider to manage neutron_network type. + + Assumes that the neutron service is configured on the same host. + EOT + + commands :neutron => 'neutron' + + mk_resource_methods + + def self.neutron_type + 'net' + end + + def self.instances + list_neutron_resources(neutron_type).collect do |id| + attrs = get_neutron_resource_attrs(neutron_type, id) + new( + :ensure => :present, + :name => attrs['name'], + :id => attrs['id'], + :admin_state_up => attrs['admin_state_up'], + :provider_network_type => attrs['provider:network_type'], + :provider_physical_network => attrs['provider:physical_network'], + :provider_segmentation_id => attrs['provider:segmentation_id'], + :router_external => attrs['router:external'], + :shared => attrs['shared'], + :tenant_id => attrs['tenant_id'] + ) + end + end + + def self.prefetch(resources) + networks = instances + resources.keys.each do |name| + if provider = networks.find{ |net| net.name == name } + resources[name].provider = provider + end + end + end + + def exists? + @property_hash[:ensure] == :present + end + + def create + network_opts = Array.new + + if @resource[:shared] + network_opts << '--shared' + end + + if @resource[:tenant_name] + tenant_id = self.class.get_tenant_id(model.catalog, + @resource[:tenant_name]) + network_opts << "--tenant_id=#{tenant_id}" + elsif @resource[:tenant_id] + network_opts << "--tenant_id=#{@resource[:tenant_id]}" + end + + if @resource[:provider_network_type] + network_opts << \ + "--provider:network_type=#{@resource[:provider_network_type]}" + end + + if @resource[:provider_physical_network] + network_opts << \ + "--provider:physical_network=#{@resource[:provider_physical_network]}" + end + + if @resource[:provider_segmentation_id] + network_opts << \ + "--provider:segmentation_id=#{@resource[:provider_segmentation_id]}" + end + + if @resource[:router_external] == 'True' + network_opts << '--router:external' + end + + results = auth_neutron('net-create', '--format=shell', + network_opts, resource[:name]) + + if results =~ /Created a new network:/ + attrs = self.class.parse_creation_output(results) + @property_hash = { + :ensure => :present, + :name => resource[:name], + :id => attrs['id'], + :admin_state_up => attrs['admin_state_up'], + :provider_network_type => attrs['provider:network_type'], + :provider_physical_network => attrs['provider:physical_network'], + :provider_segmentation_id => attrs['provider:segmentation_id'], + :router_external => attrs['router:external'], + :shared => attrs['shared'], + :tenant_id => attrs['tenant_id'], + } + else + fail("did not get expected message on network creation, got #{results}") + end + end + + def destroy + auth_neutron('net-delete', name) + @property_hash[:ensure] = :absent + end + + def admin_state_up=(value) + auth_neutron('net-update', "--admin_state_up=#{value}", name) + end + + def shared=(value) + auth_neutron('net-update', "--shared=#{value}", name) + end + + def router_external=(value) + if value == 'False' + auth_neutron('net-update', "--router:external=#{value}", name) + else + auth_neutron('net-update', "--router:external", name) + end + end + + [ + :provider_network_type, + :provider_physical_network, + :provider_segmentation_id, + :tenant_id, + ].each do |attr| + define_method(attr.to_s + "=") do |value| + fail("Property #{attr.to_s} does not support being updated") + end + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_cisco/ini_setting.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_cisco/ini_setting.rb new file mode 100644 index 000000000..4bc621a06 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_cisco/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_plugin_cisco).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/plugins/cisco/cisco_plugins.ini' + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_cisco_credentials/ini_setting.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_cisco_credentials/ini_setting.rb new file mode 100644 index 000000000..758b1ed16 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_cisco_credentials/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_plugin_cisco_credentials).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/plugins/cisco/credentials.ini' + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_cisco_db_conn/ini_setting.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_cisco_db_conn/ini_setting.rb new file mode 100644 index 000000000..472132fc1 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_cisco_db_conn/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_plugin_cisco_db_conn).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/plugins/cisco/db_conn.ini' + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_cisco_l2network/ini_setting.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_cisco_l2network/ini_setting.rb new file mode 100644 index 000000000..07b223eac --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_cisco_l2network/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_plugin_cisco_l2network).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/plugins/cisco/l2network_plugin.ini' + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_linuxbridge/ini_setting.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_linuxbridge/ini_setting.rb new file mode 100644 index 000000000..8d6c9a748 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_linuxbridge/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_plugin_linuxbridge).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/plugins/linuxbridge/linuxbridge_conf.ini' + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_midonet/ini_setting.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_midonet/ini_setting.rb new file mode 100644 index 000000000..ad3e48313 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_midonet/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_plugin_midonet).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/plugins/midonet/midonet.ini' + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_ml2/ini_setting.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_ml2/ini_setting.rb new file mode 100644 index 000000000..9f724b517 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_ml2/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_plugin_ml2).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/plugins/ml2/ml2_conf.ini' + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_nvp/ini_setting.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_nvp/ini_setting.rb new file mode 100644 index 000000000..b967f486c --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_nvp/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_plugin_nvp).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/plugins/nicira/nvp.ini' + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_ovs/ini_setting.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_ovs/ini_setting.rb new file mode 100644 index 000000000..191eeb17d --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_plugin_ovs/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_plugin_ovs).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini' + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_port/neutron.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_port/neutron.rb new file mode 100644 index 000000000..609bc63a8 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_port/neutron.rb @@ -0,0 +1,191 @@ +require File.join(File.dirname(__FILE__), "..","..","..", + "puppet/provider/neutron") + +Puppet::Type.type(:neutron_port).provide( + :neutron, + :parent => Puppet::Provider::Neutron +) do + desc <<-EOT + Neutron provider to manage neutron_port type. + + Assumes that the neutron service is configured on the same host. + EOT + #TODO No security group support + + commands :neutron => "neutron" + + mk_resource_methods + + def self.instances + list_neutron_resources("port").collect do |id| + attrs = get_neutron_resource_attrs("port", id) + attrs["name"] = attrs["id"] if attrs["name"].empty? + new( + :ensure => :present, + :name => attrs["name"], + :id => attrs["id"], + :status => attrs["status"], + :tenant_id => attrs["tenant_id"], + :network_id => attrs["network_id"], + :admin_state_up => attrs["admin_state_up"], + :network_name => get_network_name(attrs["network_id"]), + :subnet_name => get_subnet_name(parse_subnet_id(attrs["fixed_ips"])), + :subnet_id => parse_subnet_id(attrs["fixed_ips"]), + :ip_address => parse_ip_address(attrs["fixed_ips"]) + ) + end + end + + def self.prefetch(resources) + instances_ = instances + resources.keys.each do |name| + if provider = instances_.find{ |instance| instance.name == name } + resources[name].provider = provider + end + end + end + + def exists? + @property_hash[:ensure] == :present + end + + def create + opts = Array.new + + if @resource[:admin_state_up] == "False" + opts << "--admin-state-down" + end + + if @resource[:ip_address] + # The spec says that multiple ip addresses may be specified, but this + # doesn't seem to work yet. + opts << "--fixed-ip" + opts << @resource[:ip_address].map{|ip|"ip_address=#{ip}"}.join(',') + end + + if @resource[:subnet_name] + # The spec says that multiple subnets may be specified, but this doesn't + # seem to work yet. + opts << "--fixed-ip" + opts << @resource[:subnet_name].map{|s|"subnet_id=#{s}"}.join(',') + end + + if @resource[:tenant_name] + tenant_id = self.class.get_tenant_id( + model.catalog, + @resource[:tenant_name] + ) + opts << "--tenant_id=#{tenant_id}" + elsif @resource[:tenant_id] + opts << "--tenant_id=#{@resource[:tenant_id]}" + end + + results = auth_neutron( + "port-create", + "--format=shell", + "--name=#{resource[:name]}", + opts, + resource[:network_name] + ) + + if results =~ /Created a new port:/ + attrs = self.class.parse_creation_output(results) + @property_hash = { + :ensure => :present, + :name => resource[:name], + :id => attrs["id"], + :status => attrs["status"], + :tenant_id => attrs["tenant_id"], + :network_id => attrs["network_id"], + :admin_state_up => attrs["admin_state_up"], + :network_name => resource[:network_name], + :subnet_name => resource[:subnet_name], + :subnet_id => self.class.parse_subnet_id(attrs["fixed_ips"]), + :ip_address => self.class.parse_ip_address(attrs["fixed_ips"]) + } + else + fail("did not get expected message on port creation, got #{results}") + end + end + + def destroy + auth_neutron("port-delete", name) + @property_hash[:ensure] = :absent + end + + def admin_state_up=(value) + auth_neutron("port-update", "--admin-state-up=#{value}", name) + end + + private + + def self.get_network_name(network_id_) + if network_id_ + network_instances = Puppet::Type.type("neutron_network").instances + network_name = network_instances.find do |instance| + instance.provider.id == network_id_ + end.provider.name + end + network_name + end + + def get_network_name(network_id_) + @get_network_name ||= self.class.get_network_name(network_id_) + end + + def self.get_subnet_name(subnet_id_) + if subnet_id_ + subnet_ids = Array(subnet_id_) + subnet_instances = Puppet::Type.type("neutron_subnet").instances + subnet_names = subnet_instances.collect do |instance| + if subnet_ids.include?(instance.provider.id) + instance.provider.name + else + nil + end + end.compact + if subnet_names.length > 1 + subnet_names + else + subnet_names.first + end + end + end + + def get_subnet_name(subnet_id_) + @subnet_name ||= self.class.subnet_name(subnet_id_) + end + + def self.parse_subnet_id(fixed_ips_) + subnet_ids = Array(fixed_ips_).collect do |json| + match_data = /\{"subnet_id": "(.*)", /.match(json) + if match_data + match_data[1] + else + nil + end + end.compact + if subnet_ids.length > 1 + subnet_ids + else + subnet_ids.first + end + end + + def self.parse_ip_address(fixed_ips_) + ip_addresses = Array(fixed_ips_).collect do |json| + match_data = /"ip_address": "(.*)"\}/.match(json) + if match_data + match_data[1] + else + nil + end + end.compact + if ip_addresses.length > 1 + ip_addresses + else + ip_addresses.first + end + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_router/neutron.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_router/neutron.rb new file mode 100644 index 000000000..fa5f7f02a --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_router/neutron.rb @@ -0,0 +1,138 @@ +require File.join(File.dirname(__FILE__), '..','..','..', + 'puppet/provider/neutron') + +Puppet::Type.type(:neutron_router).provide( + :neutron, + :parent => Puppet::Provider::Neutron +) do + desc <<-EOT + Neutron provider to manage neutron_router type. + + Assumes that the neutron service is configured on the same host. + EOT + + commands :neutron => 'neutron' + + mk_resource_methods + + def self.instances + list_neutron_resources('router').collect do |id| + attrs = get_neutron_resource_attrs('router', id) + new( + :ensure => :present, + :name => attrs['name'], + :id => attrs['id'], + :admin_state_up => attrs['admin_state_up'], + :external_gateway_info => attrs['external_gateway_info'], + :status => attrs['status'], + :tenant_id => attrs['tenant_id'] + ) + end + end + + def self.prefetch(resources) + instances_ = instances + resources.keys.each do |name| + if provider = instances_.find{ |instance| instance.name == name } + resources[name].provider = provider + end + end + end + + def exists? + @property_hash[:ensure] == :present + end + + def create + opts = Array.new + + if @resource[:admin_state_up] == 'False' + opts << '--admin-state-down' + end + + if @resource[:tenant_name] + tenant_id = self.class.get_tenant_id(model.catalog, + @resource[:tenant_name]) + opts << "--tenant_id=#{tenant_id}" + elsif @resource[:tenant_id] + opts << "--tenant_id=#{@resource[:tenant_id]}" + end + + results = auth_neutron("router-create", '--format=shell', + opts, resource[:name]) + + if results =~ /Created a new router:/ + attrs = self.class.parse_creation_output(results) + @property_hash = { + :ensure => :present, + :name => resource[:name], + :id => attrs['id'], + :admin_state_up => attrs['admin_state_up'], + :external_gateway_info => attrs['external_gateway_info'], + :status => attrs['status'], + :tenant_id => attrs['tenant_id'], + } + + if @resource[:gateway_network_name] + results = auth_neutron('router-gateway-set', + @resource[:name], + @resource[:gateway_network_name]) + if results =~ /Set gateway for router/ + attrs = self.class.get_neutron_resource_attrs('router', + @resource[:name]) + @property_hash[:external_gateway_info] = \ + attrs['external_gateway_info'] + else + fail(<<-EOT +did not get expected message on setting router gateway, got #{results} +EOT + ) + end + end + else + fail("did not get expected message on router creation, got #{results}") + end + end + + def destroy + auth_neutron('router-delete', name) + @property_hash[:ensure] = :absent + end + + def gateway_network_name + if @gateway_network_name == nil and gateway_network_id + Puppet::Type.type('neutron_network').instances.each do |instance| + if instance.provider.id == gateway_network_id + @gateway_network_name = instance.provider.name + end + end + end + @gateway_network_name + end + + def gateway_network_name=(value) + if value == '' + auth_neutron('router-gateway-clear', name) + else + auth_neutron('router-gateway-set', name, value) + end + end + + def parse_gateway_network_id(external_gateway_info_) + match_data = /\{"network_id": "(.*?)"/.match(external_gateway_info_) + if match_data + match_data[1] + else + '' + end + end + + def gateway_network_id + @gateway_network_id ||= parse_gateway_network_id(external_gateway_info) + end + + def admin_state_up=(value) + auth_neutron('router-update', "--admin-state-up=#{value}", name) + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_router_interface/neutron.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_router_interface/neutron.rb new file mode 100644 index 000000000..4637846b5 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_router_interface/neutron.rb @@ -0,0 +1,93 @@ +require File.join(File.dirname(__FILE__), '..','..','..', + 'puppet/provider/neutron') + +Puppet::Type.type(:neutron_router_interface).provide( + :neutron, + :parent => Puppet::Provider::Neutron +) do + desc <<-EOT + Neutron provider to manage neutron_router_interface type. + + Assumes that the neutron service is configured on the same host. + + It is not possible to manage an interface for the subnet used by + the gateway network, and such an interface will appear in the list + of resources ('puppet resource [type]'). Attempting to manage the + gateway interfae will result in an error. + + EOT + + commands :neutron => 'neutron' + + mk_resource_methods + + def self.instances + subnet_name_hash = {} + Puppet::Type.type('neutron_subnet').instances.each do |instance| + subnet_name_hash[instance.provider.id] = instance.provider.name + end + instances_ = [] + Puppet::Type.type('neutron_router').instances.each do |instance| + list_router_ports(instance.provider.id).each do |port_hash| + router_name = instance.provider.name + subnet_name = subnet_name_hash[port_hash['subnet_id']] + name = "#{router_name}:#{subnet_name}" + instances_ << new( + :ensure => :present, + :name => name, + :id => port_hash['id'], + :port => port_hash['name'] + ) + end + end + return instances_ + end + + def self.prefetch(resources) + instances_ = instances + resources.keys.each do |name| + if provider = instances_.find{ |instance| instance.name == name } + resources[name].provider = provider + end + end + end + + def exists? + @property_hash[:ensure] == :present + end + + def create + router,subnet = resource[:name].split(':', 2) + port = resource[:port] + args = ["router-interface-add", "--format=shell", router] + if port + args << "port=#{port}" + else + args << "subnet=#{subnet}" + end + results = auth_neutron(args) + + if results =~ /Added interface.* to router/ + @property_hash = { + :ensure => :present, + :name => resource[:name], + } + else + fail("did not get expected message on interface addition, got #{results}") + end + end + + def router_name + name.split(':', 2).first + end + + def subnet_name + name.split(':', 2).last + end + + def destroy + auth_neutron('router-interface-delete', router_name, subnet_name) + @property_hash[:ensure] = :absent + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_subnet/neutron.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_subnet/neutron.rb new file mode 100644 index 000000000..0da21804d --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_subnet/neutron.rb @@ -0,0 +1,219 @@ +require File.join(File.dirname(__FILE__), '..','..','..', + 'puppet/provider/neutron') + +Puppet::Type.type(:neutron_subnet).provide( + :neutron, + :parent => Puppet::Provider::Neutron +) do + desc <<-EOT + Neutron provider to manage neutron_subnet type. + + Assumes that the neutron service is configured on the same host. + EOT + + commands :neutron => 'neutron' + + mk_resource_methods + + def self.neutron_type + 'subnet' + end + + def self.instances + list_neutron_resources(neutron_type).collect do |id| + attrs = get_neutron_resource_attrs(neutron_type, id) + new( + :ensure => :present, + :name => attrs['name'], + :id => attrs['id'], + :cidr => attrs['cidr'], + :ip_version => attrs['ip_version'], + :gateway_ip => parse_gateway_ip(attrs['gateway_ip']), + :allocation_pools => parse_allocation_pool(attrs['allocation_pools']), + :host_routes => parse_host_routes(attrs['host_routes']), + :dns_nameservers => parse_dns_nameservers(attrs['dns_nameservers']), + :enable_dhcp => attrs['enable_dhcp'], + :network_id => attrs['network_id'], + :tenant_id => attrs['tenant_id'] + ) + end + end + + def self.prefetch(resources) + subnets = instances + resources.keys.each do |name| + if provider = subnets.find{ |subnet| subnet.name == name } + resources[name].provider = provider + end + end + end + + def self.parse_gateway_ip(value) + return '' if value.nil? + return value + end + + def self.parse_allocation_pool(values) + allocation_pools = [] + return [] if values.empty? + for value in Array(values) + matchdata = /\{\s*"start"\s*:\s*"(.*)"\s*,\s*"end"\s*:\s*"(.*)"\s*\}/.match(value.gsub(/\\"/,'"')) + start_ip = matchdata[1] + end_ip = matchdata[2] + allocation_pools << "start=#{start_ip},end=#{end_ip}" + end + return allocation_pools + end + + def self.parse_host_routes(values) + host_routes = [] + return [] if values.empty? + for value in Array(values) + matchdata = /\{\s*"destination"\s*:\s*"(.*)"\s*,\s*"nexthop"\s*:\s*"(.*)"\s*\}/.match(value.gsub(/\\"/,'"')) + destination = matchdata[1] + nexthop = matchdata[2] + host_routes << "destination=#{destination},nexthop=#{nexthop}" + end + return host_routes + end + + def self.parse_dns_nameservers(values) + # just enforce that this is actually an array + return Array(values) + end + + def exists? + @property_hash[:ensure] == :present + end + + def create + opts = ["--name=#{@resource[:name]}"] + + if @resource[:ip_version] + opts << "--ip-version=#{@resource[:ip_version]}" + end + + if @resource[:gateway_ip] + if @resource[:gateway_ip] == '' + opts << '--no-gateway' + else + opts << "--gateway-ip=#{@resource[:gateway_ip]}" + end + end + + if @resource[:enable_dhcp] == 'False' + opts << "--disable-dhcp" + else + opts << "--enable-dhcp" + end + + if @resource[:allocation_pools] + Array(@resource[:allocation_pools]).each do |allocation_pool| + opts << "--allocation-pool=#{allocation_pool}" + end + end + + if @resource[:dns_nameservers] + Array(@resource[:dns_nameservers]).each do |nameserver| + opts << "--dns-nameserver=#{nameserver}" + end + end + + if @resource[:host_routes] + Array(@resource[:host_routes]).each do |host_route| + opts << "--host-route=#{host_route}" + end + end + + if @resource[:tenant_name] + tenant_id = self.class.get_tenant_id(model.catalog, + @resource[:tenant_name]) + opts << "--tenant_id=#{tenant_id}" + elsif @resource[:tenant_id] + opts << "--tenant_id=#{@resource[:tenant_id]}" + end + + if @resource[:network_name] + opts << resource[:network_name] + elsif @resource[:network_id] + opts << resource[:network_id] + end + + results = auth_neutron('subnet-create', '--format=shell', + opts, resource[:cidr]) + + if results =~ /Created a new subnet:/ + attrs = self.class.parse_creation_output(results) + @property_hash = { + :ensure => :present, + :name => resource[:name], + :id => attrs['id'], + :cidr => attrs['cidr'], + :ip_version => attrs['ip_version'], + :gateway_ip => self.class.parse_gateway_ip(attrs['gateway_ip']), + :allocation_pools => self.class.parse_allocation_pool(attrs['allocation_pools']), + :host_routes => self.class.parse_host_routes(attrs['host_routes']), + :dns_nameservers => self.class.parse_dns_nameservers(attrs['dns_nameservers']), + :enable_dhcp => attrs['enable_dhcp'], + :network_id => attrs['network_id'], + :tenant_id => attrs['tenant_id'], + } + else + fail("did not get expected message on subnet creation, got #{results}") + end + end + + def destroy + auth_neutron('subnet-delete', name) + @property_hash[:ensure] = :absent + end + + def gateway_ip=(value) + if value == '' + auth_neutron('subnet-update', '--no-gateway', name) + else + auth_neutron('subnet-update', "--gateway-ip=#{value}", name) + end + end + + def enable_dhcp=(value) + if value == 'False' + auth_neutron('subnet-update', "--disable-dhcp", name) + else + auth_neutron('subnet-update', "--enable-dhcp", name) + end + end + + def dns_nameservers=(values) + unless values.empty? + opts = ["#{name}", "--dns-nameservers", "list=true"] + for value in values + opts << value + end + auth_neutron('subnet-update', opts) + end + end + + def host_routes=(values) + unless values.empty? + opts = ["#{name}", "--host-routes", "type=dict", "list=true"] + for value in values + opts << value + end + auth_neutron('subnet-update', opts) + end + end + + [ + :cidr, + :ip_version, + :network_id, + :allocation_pools, + :tenant_id, + ].each do |attr| + define_method(attr.to_s + "=") do |value| + fail("Property #{attr.to_s} does not support being updated") + end + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/neutron_vpnaas_agent_config/ini_setting.rb b/3rdparty/modules/neutron/lib/puppet/provider/neutron_vpnaas_agent_config/ini_setting.rb new file mode 100644 index 000000000..ee6b74425 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/neutron_vpnaas_agent_config/ini_setting.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:neutron_vpnaas_agent_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def file_path + '/etc/neutron/vpn_agent.ini' + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/provider/nova_admin_tenant_id_setter/ini_setting.rb b/3rdparty/modules/neutron/lib/puppet/provider/nova_admin_tenant_id_setter/ini_setting.rb new file mode 100644 index 000000000..fbef6990f --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/provider/nova_admin_tenant_id_setter/ini_setting.rb @@ -0,0 +1,196 @@ +## NB: This must work with Ruby 1.8! + +# This providers permits the nova_admin_tenant_id paramter in neutron.conf +# to be set by providing a nova_admin_tenant_name to the Puppet module and +# using the Keystone REST API to translate the name into the corresponding +# UUID. +# +# This requires that tenant names be unique. If there are multiple matches +# for a given tenant name, this provider will raise an exception. + +require 'rubygems' +require 'net/http' +require 'net/https' +require 'json' +require 'puppet/util/inifile' + +class KeystoneError < Puppet::Error +end + +class KeystoneConnectionError < KeystoneError +end + +class KeystoneAPIError < KeystoneError +end + +# Provides common request handling semantics to the other methods in +# this module. +# +# +req+:: +# An HTTPRequest object +# +url+:: +# A parsed URL (returned from URI.parse) +def handle_request(req, url) + begin + # There is issue with ipv6 where address has to be in brackets, this causes the + # underlying ruby TCPSocket to fail. Net::HTTP.new will fail without brackets on + # joining the ipv6 address with :port or passing brackets to TCPSocket. It was + # found that if we use Net::HTTP.start with url.hostname the incriminated code + # won't be hit. + use_ssl = url.scheme == "https" ? true : false + http = Net::HTTP.start(url.hostname, url.port, {:use_ssl => use_ssl}) + res = http.request(req) + + if res.code != '200' + raise KeystoneAPIError, "Received error response from Keystone server at #{url}: #{res.message}" + end + rescue Errno::ECONNREFUSED => detail + raise KeystoneConnectionError, "Failed to connect to Keystone server at #{url}: #{detail}" + rescue SocketError => detail + raise KeystoneConnectionError, "Failed to connect to Keystone server at #{url}: #{detail}" + end + + res +end + +# Authenticates to a Keystone server and obtains an authentication token. +# It returns a 2-element +[token, authinfo]+, where +token+ is a token +# suitable for passing to openstack apis in the +X-Auth-Token+ header, and +# +authinfo+ is the complete response from Keystone, including the service +# catalog (if available). +# +# +auth_url+:: +# Keystone endpoint URL. This function assumes API version +# 2.0 and an administrative endpoint, so this will typically look like +# +http://somehost:35357/v2.0+. +# +# +username+:: +# Username for authentication. +# +# +password+:: +# Password for authentication +# +# +tenantID+:: +# Tenant UUID +# +# +tenantName+:: +# Tenant name +# +def keystone_v2_authenticate(auth_url, + username, + password, + tenantId=nil, + tenantName=nil) + + post_args = { + 'auth' => { + 'passwordCredentials' => { + 'username' => username, + 'password' => password + }, + }} + + if tenantId + post_args['auth']['tenantId'] = tenantId + end + + if tenantName + post_args['auth']['tenantName'] = tenantName + end + + url = URI.parse("#{auth_url}/tokens") + req = Net::HTTP::Post.new url.path + req['content-type'] = 'application/json' + req.body = post_args.to_json + + res = handle_request(req, url) + data = JSON.parse res.body + return data['access']['token']['id'] +end + +# Queries a Keystone server to a list of all tenants. +# +# +auth_url+:: +# Keystone endpoint. See the notes for +auth_url+ in +# +keystone_v2_authenticate+. +# +# +token+:: +# A Keystone token that will be passed in requests as the value of the +# +X-Auth-Token+ header. +# +def keystone_v2_tenants(auth_url, + token) + + url = URI.parse("#{auth_url}/tenants") + req = Net::HTTP::Get.new url.path + req['content-type'] = 'application/json' + req['x-auth-token'] = token + + res = handle_request(req, url) + data = JSON.parse res.body + data['tenants'] +end + +Puppet::Type.type(:nova_admin_tenant_id_setter).provide(:ruby) do + @tenant_id = nil + + def authenticate + keystone_v2_authenticate( + @resource[:auth_url], + @resource[:auth_username], + @resource[:auth_password], + nil, + @resource[:auth_tenant_name]) + end + + def find_tenant_by_name (token) + tenants = keystone_v2_tenants( + @resource[:auth_url], + token) + + tenants.select{|tenant| tenant['name'] == @resource[:tenant_name]} + end + + def exists? + ini_file = Puppet::Util::IniConfig::File.new + ini_file.read("/etc/neutron/neutron.conf") + ini_file['DEFAULT'] && ini_file['DEFAULT']['nova_admin_tenant_id'] && ini_file['DEFAULT']['nova_admin_tenant_id'] == tenant_id + end + + def create + config + end + + def tenant_id + @tenant_id ||= get_tenant_id + end + + # This looks for the tenant specified by the 'tenant_name' parameter to + # the resource and returns the corresponding UUID if there is a single + # match. + # + # Raises a KeystoneAPIError if: + # + # - There are multiple matches, or + # - There are zero matches + def get_tenant_id + token = authenticate + tenants = find_tenant_by_name(token) + + if tenants.length == 1 + return tenants[0]['id'] + elsif tenants.length > 1 + raise KeystoneAPIError, 'Found multiple matches for tenant name' + else + raise KeystoneAPIError, 'Unable to find matching tenant' + end + end + + def config + Puppet::Type.type(:neutron_config).new( + {:name => 'DEFAULT/nova_admin_tenant_id', :value => "#{tenant_id}"} + ).create + end + +end + diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_api_config.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_api_config.rb new file mode 100644 index 000000000..eed70e105 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_api_config.rb @@ -0,0 +1,43 @@ +Puppet::Type.newtype(:neutron_api_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from api-paste.ini' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_config.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_config.rb new file mode 100644 index 000000000..e83547b53 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_config.rb @@ -0,0 +1,47 @@ +Puppet::Type.newtype(:neutron_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from neutron.conf' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end + + def create + provider.create + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_dhcp_agent_config.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_dhcp_agent_config.rb new file mode 100644 index 000000000..947c86b09 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_dhcp_agent_config.rb @@ -0,0 +1,18 @@ +Puppet::Type.newtype(:neutron_dhcp_agent_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from dhcp_agent.ini' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_fwaas_service_config.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_fwaas_service_config.rb new file mode 100644 index 000000000..c9f7fb477 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_fwaas_service_config.rb @@ -0,0 +1,18 @@ +Puppet::Type.newtype(:neutron_fwaas_service_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from fwaas_driver.ini' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_l3_agent_config.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_l3_agent_config.rb new file mode 100644 index 000000000..3d55f22ac --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_l3_agent_config.rb @@ -0,0 +1,18 @@ +Puppet::Type.newtype(:neutron_l3_agent_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from l3_agent.ini' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_l3_ovs_bridge.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_l3_ovs_bridge.rb new file mode 100644 index 000000000..f7608c9fb --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_l3_ovs_bridge.rb @@ -0,0 +1,26 @@ +Puppet::Type.newtype(:neutron_l3_ovs_bridge) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Symbolic name for the ovs bridge' + newvalues(/.*/) + end + + newparam(:subnet_name) do + desc 'Name of the subnet that will use the bridge as gateway' + end + + autorequire(:service) do + ['neutron-server'] + end + + autorequire(:vs_bridge) do + [self[:name]] + end + + autorequire(:neutron_subnet) do + [self[:subnet_name]] if self[:subnet_name] + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_lbaas_agent_config.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_lbaas_agent_config.rb new file mode 100644 index 000000000..d34936b18 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_lbaas_agent_config.rb @@ -0,0 +1,18 @@ +Puppet::Type.newtype(:neutron_lbaas_agent_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from lbaas_agent.ini' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_metadata_agent_config.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_metadata_agent_config.rb new file mode 100644 index 000000000..e7b07bd0f --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_metadata_agent_config.rb @@ -0,0 +1,43 @@ +Puppet::Type.newtype(:neutron_metadata_agent_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from metadata_agent.ini' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_metering_agent_config.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_metering_agent_config.rb new file mode 100644 index 000000000..31b75c84d --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_metering_agent_config.rb @@ -0,0 +1,18 @@ +Puppet::Type.newtype(:neutron_metering_agent_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from metering_agent.ini' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_network.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_network.rb new file mode 100644 index 000000000..8ceecc059 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_network.rb @@ -0,0 +1,90 @@ +Puppet::Type.newtype(:neutron_network) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Symbolic name for the network' + newvalues(/.*/) + end + + newproperty(:id) do + desc 'The unique id of the network' + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:admin_state_up) do + desc 'The administrative status of the network' + newvalues(/(t|T)rue/, /(f|F)alse/) + munge do |v| + v.to_s.capitalize + end + end + + newproperty(:shared) do + desc 'Whether this network should be shared across all tenants or not' + newvalues(/(t|T)rue/, /(f|F)alse/) + munge do |v| + v.to_s.capitalize + end + end + + newparam(:tenant_name) do + desc 'The name of the tenant which will own the network.' + end + + newproperty(:tenant_id) do + desc 'A uuid identifying the tenant which will own the network.' + end + + newproperty(:provider_network_type) do + desc 'The physical mechanism by which the virtual network is realized.' + newvalues(:flat, :vlan, :local, :gre, :l3_ext, :vxlan) + end + + newproperty(:provider_physical_network) do + desc <<-EOT + The name of the physical network over which the virtual network + is realized for flat and VLAN networks. + EOT + newvalues(/\S+/) + end + + newproperty(:provider_segmentation_id) do + desc 'Identifies an isolated segment on the physical network.' + munge do |v| + Integer(v) + end + end + + newproperty(:router_external) do + desc 'Whether this router will route traffic to an external network' + newvalues(/(t|T)rue/, /(f|F)alse/) + munge do |v| + v.to_s.capitalize + end + end + + # Require the neutron-server service to be running + autorequire(:service) do + ['neutron-server'] + end + + autorequire(:keystone_tenant) do + [self[:tenant_name]] if self[:tenant_name] + end + + validate do + if self[:ensure] != :present + return + end + if self[:tenant_id] && self[:tenant_name] + raise(Puppet::Error, <<-EOT +Please provide a value for only one of tenant_name and tenant_id. +EOT + ) + end + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_cisco.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_cisco.rb new file mode 100644 index 000000000..bfa2769bb --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_cisco.rb @@ -0,0 +1,47 @@ +Puppet::Type.newtype(:neutron_plugin_cisco) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from cisco_plugins.ini' + newvalues(/\S+\/\S+/) + end + + autorequire(:file) do + ['/etc/neutron/plugins/cisco'] + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_cisco_credentials.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_cisco_credentials.rb new file mode 100644 index 000000000..0cdf5094b --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_cisco_credentials.rb @@ -0,0 +1,47 @@ +Puppet::Type.newtype(:neutron_plugin_cisco_credentials) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from credentials.ini' + newvalues(/\S+\/\S+/) + end + + autorequire(:file) do + ['/etc/neutron/plugins/cisco'] + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + + end +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_cisco_db_conn.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_cisco_db_conn.rb new file mode 100644 index 000000000..ffa34c34c --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_cisco_db_conn.rb @@ -0,0 +1,22 @@ +Puppet::Type.newtype(:neutron_plugin_cisco_db_conn) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from plugins/cisco/db_conn.ini' + newvalues(/\S+\/\S+/) + end + + autorequire(:file) do + ['/etc/neutron/plugins/cisco'] + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_cisco_l2network.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_cisco_l2network.rb new file mode 100644 index 000000000..9d6df4929 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_cisco_l2network.rb @@ -0,0 +1,22 @@ +Puppet::Type.newtype(:neutron_plugin_cisco_l2network) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from plugins/cisco/l2network_plugin.ini' + newvalues(/\S+\/\S+/) + end + + autorequire(:file) do + ['/etc/neutron/plugins/cisco'] + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_linuxbridge.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_linuxbridge.rb new file mode 100644 index 000000000..1c848744b --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_linuxbridge.rb @@ -0,0 +1,18 @@ +Puppet::Type.newtype(:neutron_plugin_linuxbridge) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from linuxbridge_conf.ini' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_midonet.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_midonet.rb new file mode 100644 index 000000000..7d8e69c22 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_midonet.rb @@ -0,0 +1,49 @@ +Puppet::Type.newtype(:neutron_plugin_midonet) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from midonet.ini' + newvalues(/\S+\/\S+/) + end + + autorequire(:file) do + ['/etc/neutron/plugins/midonet'] + end + + autorequire(:package) do ['neutron'] end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_ml2.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_ml2.rb new file mode 100644 index 000000000..e121a11c5 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_ml2.rb @@ -0,0 +1,20 @@ +Puppet::Type.newtype(:neutron_plugin_ml2) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from ml2_conf.ini' + newvalues(/\S+\/\S+/) + end + + autorequire(:package) do ['neutron'] end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_nvp.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_nvp.rb new file mode 100644 index 000000000..2c8a47644 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_nvp.rb @@ -0,0 +1,43 @@ +Puppet::Type.newtype(:neutron_plugin_nvp) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from nvp.ini' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_ovs.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_ovs.rb new file mode 100644 index 000000000..205ef763d --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_plugin_ovs.rb @@ -0,0 +1,18 @@ +Puppet::Type.newtype(:neutron_plugin_ovs) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from ovs_neutron_plugin.ini' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_port.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_port.rb new file mode 100644 index 000000000..03d2d9b56 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_port.rb @@ -0,0 +1,98 @@ +Puppet::Type.newtype(:neutron_port) do + desc <<-EOT + This is currently used to model the creation of neutron ports. + + Ports are used when associating a network and a router interface. + EOT + + ensurable + + newparam(:name, :namevar => true) do + desc 'Symbolic name for the port' + newvalues(/.*/) + end + + newproperty(:id) do + desc 'The unique id of the port' + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:admin_state_up) do + desc 'The administrative status of the router' + newvalues(/(t|T)rue/, /(f|F)alse/) + munge do |v| + v.to_s.capitalize + end + end + + newproperty(:network_name) do + desc <<-EOT + The name of the network that this port is assigned to on creation. + EOT + end + + newproperty(:network_id) do + desc <<-EOT + The uuid of the network that this port is assigned to on creation. + EOT + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:subnet_name) do + desc 'A subnet to which the port is assigned on creation.' + end + + newproperty(:subnet_id) do + desc <<-EOT + The uuid of the subnet on which this ports ip exists. + EOT + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:ip_address) do + desc 'A static ip address given to the port on creation.' + end + + newproperty(:status) do + desc 'Whether the port is currently operational or not.' + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newparam(:tenant_name) do + desc 'The name of the tenant which will own the port.' + end + + newproperty(:tenant_id) do + desc 'A uuid identifying the tenant which will own the port.' + end + + autorequire(:service) do + ['neutron-server'] + end + + autorequire(:keystone_tenant) do + [self[:tenant_name]] if self[:tenant_name] + end + + autorequire(:neutron_network) do + [self[:name]] + end + + validate do + if self[:tenant_id] && self[:tenant_name] + raise(Puppet::Error, 'Please provide a value for only one of tenant_name and tenant_id.') + end + if self[:ip_address] && self[:subnet_name] + raise(Puppet::Error, 'Please provide a value for only one of ip_address and subnet_name.') + end + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_router.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_router.rb new file mode 100644 index 000000000..36835f0e4 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_router.rb @@ -0,0 +1,91 @@ +Puppet::Type.newtype(:neutron_router) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Symbolic name for the router' + newvalues(/.*/) + end + + newproperty(:id) do + desc 'The unique id of the router' + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:admin_state_up) do + desc 'The administrative status of the router' + newvalues(/(t|T)rue/, /(f|F)alse/) + munge do |v| + v.to_s.capitalize + end + end + + newproperty(:external_gateway_info) do + desc <<-EOT + External network that this router connects to for gateway services + (e.g., NAT). + EOT + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:gateway_network_name) do + desc <<-EOT + The name of the external network that this router connects to + for gateway services (e.g. NAT). + EOT + end + + newproperty(:gateway_network_id) do + desc <<-EOT + The uuid of the external network that this router connects to + for gateway services (e.g. NAT). + EOT + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:status) do + desc 'Whether the router is currently operational or not.' + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newparam(:tenant_name) do + desc 'The name of the tenant which will own the router.' + end + + newproperty(:tenant_id) do + desc 'A uuid identifying the tenant which will own the router.' + end + + autorequire(:service) do + ['neutron-server'] + end + + autorequire(:keystone_tenant) do + [self[:tenant_name]] if self[:tenant_name] + end + + autorequire(:neutron_network) do + [self[:gateway_network_name]] if self[:gateway_network_name] + end + + validate do + if self[:ensure] != :present + return + end + if self[:tenant_id] && self[:tenant_name] + raise(Puppet::Error, <<-EOT +Please provide a value for only one of tenant_name and tenant_id. +EOT + ) + end + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_router_interface.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_router_interface.rb new file mode 100644 index 000000000..b4d15b65b --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_router_interface.rb @@ -0,0 +1,51 @@ +Puppet::Type.newtype(:neutron_router_interface) do + + desc <<-EOT + This is currently used to model the creation of + neutron router interfaces. + + Router interfaces are an association between a router and a + subnet. + EOT + + ensurable + + newparam(:name, :namevar => true) do + newvalues(/^\S+:\S+$/) + end + + newproperty(:id) do + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:router_name) do + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:subnet_name) do + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:port) do + desc 'An existing neutron port to which a rounter interface should be assigned' + end + + autorequire(:service) do + ['neutron-server'] + end + + autorequire(:neutron_router) do + self[:name].split(':', 2).first + end + + autorequire(:neutron_subnet) do + self[:name].split(':', 2).last + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_subnet.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_subnet.rb new file mode 100644 index 000000000..fb3736332 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_subnet.rb @@ -0,0 +1,114 @@ +Puppet::Type.newtype(:neutron_subnet) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Symbolic name for the subnet' + newvalues(/.*/) + end + + newproperty(:id) do + desc 'The unique id of the subnet' + validate do |v| + raise(Puppet::Error, 'This is a read only property') + end + end + + newproperty(:cidr) do + desc 'CIDR representing IP range for this subnet, based on IP version' + end + + newproperty(:ip_version) do + desc 'The IP version of the CIDR' + newvalues('4', '6') + end + + newproperty(:allocation_pools, :array_matching => :all) do + desc <<-EOT + Array of Sub-ranges of cidr available for dynamic allocation to ports. + Syntax:["start=IPADDR,end=IPADDR", ...] + EOT + end + + newproperty(:gateway_ip) do + desc <<-EOT + The default gateway provided by DHCP to devices in this subnet. If set to + '' then no gateway IP address will be provided via DHCP. + EOT + end + + newproperty(:enable_dhcp) do + desc 'Whether DHCP is enabled for this subnet or not.' + newvalues(/(t|T)rue/, /(f|F)alse/) + munge do |v| + v.to_s.capitalize + end + end + + newproperty(:host_routes, :array_matching => :all) do + desc <<-EOT + Array of routes that should be used by devices with IPs from this subnet + (not including local subnet route). + Syntax:["destination=CIDR,nexhop=IP_ADDR", ...] + EOT + end + + newproperty(:dns_nameservers, :array_matching => :all) do + desc <<-EOT + 'Array of DNS name servers used by hosts in this subnet.' + EOT + end + + newproperty(:network_id) do + desc 'A uuid identifying the network this subnet is associated with.' + end + + newparam(:network_name) do + desc 'The name of the network this subnet is associated with.' + end + + newparam(:tenant_name) do + desc 'The name of the tenant which will own the subnet.' + end + + newproperty(:tenant_id) do + desc 'A uuid identifying the tenant which will own the subnet.' + end + + autorequire(:service) do + ['neutron-server'] + end + + autorequire(:keystone_tenant) do + [self[:tenant_name]] if self[:tenant_name] + end + + autorequire(:neutron_network) do + [self[:network_name]] if self[:network_name] + end + + validate do + if self[:ensure] != :present + return + end + if ! self[:cidr] + raise(Puppet::Error, 'Please provide a valid CIDR') + elsif ! (self[:network_id] || self[:network_name]) + raise(Puppet::Error, <<-EOT +A value for one of network_name or network_id must be provided. +EOT + ) + elsif self[:network_id] && self[:network_name] + raise(Puppet::Error, <<-EOT +Please provide a value for only one of network_name and network_id. +EOT + ) + elsif self[:tenant_id] && self[:tenant_name] + raise(Puppet::Error, <<-EOT +Please provide a value for only one of tenant_name and tenant_id. +EOT + ) + end + end + +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/neutron_vpnaas_agent_config.rb b/3rdparty/modules/neutron/lib/puppet/type/neutron_vpnaas_agent_config.rb new file mode 100644 index 000000000..a9e082d7a --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/neutron_vpnaas_agent_config.rb @@ -0,0 +1,18 @@ +Puppet::Type.newtype(:neutron_vpnaas_agent_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from vpn_agent.ini' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + end +end diff --git a/3rdparty/modules/neutron/lib/puppet/type/nova_admin_tenant_id_setter.rb b/3rdparty/modules/neutron/lib/puppet/type/nova_admin_tenant_id_setter.rb new file mode 100644 index 000000000..d79e86c72 --- /dev/null +++ b/3rdparty/modules/neutron/lib/puppet/type/nova_admin_tenant_id_setter.rb @@ -0,0 +1,32 @@ +Puppet::Type.newtype(:nova_admin_tenant_id_setter) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'The name of the setting to update' + end + + newparam(:tenant_name) do + desc 'The nova admin tenant name' + end + + newparam(:auth_url) do + desc 'The Keystone endpoint URL' + defaultto 'http://localhost:35357/v2.0' + end + + newparam(:auth_username) do + desc 'Username with which to authenticate' + defaultto 'admin' + end + + newparam(:auth_password) do + desc 'Password with which to authenticate' + end + + newparam(:auth_tenant_name) do + desc 'Tenant name with which to authenticate' + defaultto 'admin' + end +end + diff --git a/3rdparty/modules/neutron/manifests/agents/dhcp.pp b/3rdparty/modules/neutron/manifests/agents/dhcp.pp new file mode 100644 index 000000000..256d1bee3 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/agents/dhcp.pp @@ -0,0 +1,160 @@ +# == Class: neutron::agents::dhcp +# +# Setups Neutron DHCP agent. +# +# === Parameters +# +# [*package_ensure*] +# (optional) Ensure state for package. Defaults to 'present'. +# +# [*enabled*] +# (optional) Enable state for service. Defaults to 'true'. +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*debug*] +# (optional) Show debugging output in log. Defaults to false. +# +# [*state_path*] +# (optional) Where to store dnsmasq state files. This directory must be +# writable by the user executing the agent. Defaults to '/var/lib/neutron'. +# +# [*resync_interval*] +# (optional) The DHCP agent will resync its state with Neutron to recover +# from any transient notification or rpc errors. The interval is number of +# seconds between attempts. Defaults to 30. +# +# [*interface_driver*] +# (optional) Defaults to 'neutron.agent.linux.interface.OVSInterfaceDriver'. +# +# [*dhcp_driver*] +# (optional) Defaults to 'neutron.agent.linux.dhcp.Dnsmasq'. +# +# [*root_helper*] +# (optional) Defaults to 'sudo neutron-rootwrap /etc/neutron/rootwrap.conf'. +# Addresses bug: https://bugs.launchpad.net/neutron/+bug/1182616 +# Note: This can safely be removed once the module only targets the Havana release. +# +# [*use_namespaces*] +# (optional) Allow overlapping IP (Must have kernel build with +# CONFIG_NET_NS=y and iproute2 package that supports namespaces). +# Defaults to true. +# +# [*dnsmasq_config_file*] +# (optional) Override the default dnsmasq settings with this file. +# Defaults to undef +# +# [*dhcp_delete_namespaces*] +# (optional) Delete namespace after removing a dhcp server +# Defaults to false. +# +# [*enable_isolated_metadata*] +# (optional) enable metadata support on isolated networks. +# Defaults to false. +# +# [*enable_metadata_network*] +# (optional) Allows for serving metadata requests coming from a dedicated metadata +# access network whose cidr is 169.254.169.254/16 (or larger prefix), and is +# connected to a Neutron router from which the VMs send metadata request. +# This option requires enable_isolated_metadata = True +# Defaults to false. +# +class neutron::agents::dhcp ( + $package_ensure = present, + $enabled = true, + $manage_service = true, + $debug = false, + $state_path = '/var/lib/neutron', + $resync_interval = 30, + $interface_driver = 'neutron.agent.linux.interface.OVSInterfaceDriver', + $dhcp_driver = 'neutron.agent.linux.dhcp.Dnsmasq', + $root_helper = 'sudo neutron-rootwrap /etc/neutron/rootwrap.conf', + $use_namespaces = true, + $dnsmasq_config_file = undef, + $dhcp_delete_namespaces = false, + $enable_isolated_metadata = false, + $enable_metadata_network = false +) { + + include neutron::params + + Neutron_config<||> ~> Service['neutron-dhcp-service'] + Neutron_dhcp_agent_config<||> ~> Service['neutron-dhcp-service'] + + case $dhcp_driver { + /\.Dnsmasq/: { + Package[$::neutron::params::dnsmasq_packages] -> Package<| title == 'neutron-dhcp-agent' |> + ensure_packages($::neutron::params::dnsmasq_packages) + } + /^midonet.*/: { + ensure_packages($::neutron::params::midonet_server_package) + } + default: { + fail("Unsupported dhcp_driver ${dhcp_driver}") + } + } + + if (! $enable_isolated_metadata) and $enable_metadata_network { + fail('enable_metadata_network to true requires enable_isolated_metadata also enabled.') + } else { + neutron_dhcp_agent_config { + 'DEFAULT/enable_isolated_metadata': value => $enable_isolated_metadata; + 'DEFAULT/enable_metadata_network': value => $enable_metadata_network; + } + } + + # The DHCP agent loads both neutron.ini and its own file. + # This only lists config specific to the agent. neutron.ini supplies + # the rest. + neutron_dhcp_agent_config { + 'DEFAULT/debug': value => $debug; + 'DEFAULT/state_path': value => $state_path; + 'DEFAULT/resync_interval': value => $resync_interval; + 'DEFAULT/interface_driver': value => $interface_driver; + 'DEFAULT/dhcp_driver': value => $dhcp_driver; + 'DEFAULT/use_namespaces': value => $use_namespaces; + 'DEFAULT/root_helper': value => $root_helper; + 'DEFAULT/dhcp_delete_namespaces': value => $dhcp_delete_namespaces; + } + + if $dnsmasq_config_file { + neutron_dhcp_agent_config { + 'DEFAULT/dnsmasq_config_file': value => $dnsmasq_config_file; + } + } else { + neutron_dhcp_agent_config { + 'DEFAULT/dnsmasq_config_file': ensure => absent; + } + } + + if $::neutron::params::dhcp_agent_package { + Package['neutron'] -> Package['neutron-dhcp-agent'] + Package['neutron-dhcp-agent'] -> Neutron_config<||> + Package['neutron-dhcp-agent'] -> Neutron_dhcp_agent_config<||> + package { 'neutron-dhcp-agent': + ensure => $package_ensure, + name => $::neutron::params::dhcp_agent_package, + } + } else { + # Some platforms (RedHat) do not provide a neutron DHCP agent package. + # The neutron DHCP agent config file is provided by the neutron package. + Package['neutron'] -> Neutron_dhcp_agent_config<||> + } + + if $manage_service { + if $enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + } + + service { 'neutron-dhcp-service': + ensure => $service_ensure, + name => $::neutron::params::dhcp_agent_service, + enable => $enabled, + require => Class['neutron'], + } +} diff --git a/3rdparty/modules/neutron/manifests/agents/l3.pp b/3rdparty/modules/neutron/manifests/agents/l3.pp new file mode 100644 index 000000000..55d303a30 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/agents/l3.pp @@ -0,0 +1,205 @@ +# == Class: neutron::agents::l3 +# +# Installs and configures the Neutron L3 service +# +# TODO: create ability to have multiple L3 services +# +# === Parameters +# +# [*package_ensure*] +# (optional) The state of the package +# Defaults to present +# +# [*enabled*] +# (optional) The state of the service +# Defaults to true +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*debug*] +# (optional) Print debug info in logs +# Defaults to false +# +# [*external_network_bridge*] +# (optional) The name of the external bridge +# Defaults to br-ex +# +# [*use_namespaces*] +# (optional) Enable overlapping IPs / network namespaces +# Defaults to false +# +# [*interface_driver*] +# (optional) Driver to interface with neutron +# Defaults to OVSInterfaceDriver +# +# [*router_id*] +# (optional) The ID of the external router in neutron +# Defaults to blank +# +# [*gateway_external_network_id*] +# (optional) The ID of the external network in neutron +# Defaults to blank +# +# [*handle_internal_only_routers*] +# (optional) L3 Agent will handle non-external routers +# Defaults to true +# +# [*metadata_port*] +# (optional) The port of the metadata server +# Defaults to 9697 +# +# [*send_arp_for_ha*] +# (optional) Send this many gratuitous ARPs for HA setup. Set it below or equal to 0 +# to disable this feature. +# Defaults to 3 +# +# [*periodic_interval*] +# (optional) seconds between re-sync routers' data if needed +# Defaults to 40 +# +# [*periodic_fuzzy_delay*] +# (optional) seconds to start to sync routers' data after starting agent +# Defaults to 5 +# +# [*enable_metadata_proxy*] +# (optional) can be set to False if the Nova metadata server is not available +# Defaults to True +# +# [*network_device_mtu*] +# (optional) The MTU size for the interfaces managed by the L3 agent +# Defaults to undef +# Should be deprecated in the next major release in favor of a global parameter +# +# [*router_delete_namespaces*] +# (optional) namespaces can be deleted cleanly on the host running the L3 agent +# Defaults to False +# +# [*ha_enabled*] +# (optional) Enabled or not HA for L3 agent. +# Defaults to false +# +# [*ha_vrrp_auth_type*] +# (optional) VRRP authentication type. Can be AH or PASS. +# Defaults to "PASS" +# +# [*ha_vrrp_auth_password*] +# (optional) VRRP authentication password. Required if ha_enabled = true. +# Defaults to undef +# +# [*ha_vrrp_advert_int*] +# (optional) The advertisement interval in seconds. +# Defaults to '2' +# +# [*agent_mode*] +# (optional) The working mode for the agent. +# 'legacy': default behavior (without DVR) +# 'dvr': enable DVR for an L3 agent running on compute node (DVR in production) +# 'dvr_snat': enable DVR with centralized SNAT support (DVR for single-host, for testing only) +# Defaults to 'legacy' +# +# [*allow_automatic_l3agent_failover*] +# (optional) Automatically reschedule routers from offline L3 agents to online +# L3 agents. +# This is another way to run virtual routers in highly available way but with slow +# failover performances compared to Keepalived feature in Neutron L3 Agent. +# Defaults to 'False' +# +class neutron::agents::l3 ( + $package_ensure = 'present', + $enabled = true, + $manage_service = true, + $debug = false, + $external_network_bridge = 'br-ex', + $use_namespaces = true, + $interface_driver = 'neutron.agent.linux.interface.OVSInterfaceDriver', + $router_id = undef, + $gateway_external_network_id = undef, + $handle_internal_only_routers = true, + $metadata_port = '9697', + $send_arp_for_ha = '3', + $periodic_interval = '40', + $periodic_fuzzy_delay = '5', + $enable_metadata_proxy = true, + $network_device_mtu = undef, + $router_delete_namespaces = false, + $ha_enabled = false, + $ha_vrrp_auth_type = 'PASS', + $ha_vrrp_auth_password = undef, + $ha_vrrp_advert_int = '3', + $agent_mode = 'legacy', + $allow_automatic_l3agent_failover = false, +) { + + include neutron::params + + Neutron_config<||> ~> Service['neutron-l3'] + Neutron_l3_agent_config<||> ~> Service['neutron-l3'] + + if $ha_enabled { + neutron_l3_agent_config { + 'DEFAULT/ha_vrrp_auth_type': value => $ha_vrrp_auth_type; + 'DEFAULT/ha_vrrp_auth_password': value => $ha_vrrp_auth_password; + 'DEFAULT/ha_vrrp_advert_int': value => $ha_vrrp_advert_int; + } + } + + neutron_l3_agent_config { + 'DEFAULT/debug': value => $debug; + 'DEFAULT/external_network_bridge': value => $external_network_bridge; + 'DEFAULT/use_namespaces': value => $use_namespaces; + 'DEFAULT/interface_driver': value => $interface_driver; + 'DEFAULT/router_id': value => $router_id; + 'DEFAULT/gateway_external_network_id': value => $gateway_external_network_id; + 'DEFAULT/handle_internal_only_routers': value => $handle_internal_only_routers; + 'DEFAULT/metadata_port': value => $metadata_port; + 'DEFAULT/send_arp_for_ha': value => $send_arp_for_ha; + 'DEFAULT/periodic_interval': value => $periodic_interval; + 'DEFAULT/periodic_fuzzy_delay': value => $periodic_fuzzy_delay; + 'DEFAULT/enable_metadata_proxy': value => $enable_metadata_proxy; + 'DEFAULT/router_delete_namespaces': value => $router_delete_namespaces; + 'DEFAULT/agent_mode': value => $agent_mode; + 'DEFAULT/allow_automatic_l3agent_failover': value => $allow_automatic_l3agent_failover; + } + + if $network_device_mtu { + warning('The neutron::l3_agent::newtork_device_mtu parameter is deprecated, use neutron::newtork_device_mtu instead.') + neutron_l3_agent_config { + 'DEFAULT/network_device_mtu': value => $network_device_mtu; + } + } else { + warning('The neutron::l3_agent::newtork_device_mtu parameter is deprecated, use neutron::newtork_device_mtu instead.') + neutron_l3_agent_config { + 'DEFAULT/network_device_mtu': ensure => absent; + } + } + + if $::neutron::params::l3_agent_package { + Package['neutron-l3'] -> Neutron_l3_agent_config<||> + package { 'neutron-l3': + ensure => $package_ensure, + name => $::neutron::params::l3_agent_package, + require => Package['neutron'], + } + } else { + # Some platforms (RedHat) does not provide a neutron L3 agent package. + # The neutron L3 agent config file is provided by the neutron package. + Package['neutron'] -> Neutron_l3_agent_config<||> + } + + if $manage_service { + if $enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + } + + service { 'neutron-l3': + ensure => $service_ensure, + name => $::neutron::params::l3_agent_service, + enable => $enabled, + require => Class['neutron'], + } +} diff --git a/3rdparty/modules/neutron/manifests/agents/lbaas.pp b/3rdparty/modules/neutron/manifests/agents/lbaas.pp new file mode 100644 index 000000000..ac967ca65 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/agents/lbaas.pp @@ -0,0 +1,108 @@ +# == Class: neutron::agents:lbaas: +# +# Setups Neutron Load Balancing agent. +# +# === Parameters +# +# [*package_ensure*] +# (optional) Ensure state for package. Defaults to 'present'. +# +# [*enabled*] +# (optional) Enable state for service. Defaults to 'true'. +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*debug*] +# (optional) Show debugging output in log. Defaults to false. +# +# [*interface_driver*] +# (optional) Defaults to 'neutron.agent.linux.interface.OVSInterfaceDriver'. +# +# [*device_driver*] +# (optional) Defaults to 'neutron.services.loadbalancer.drivers.haproxy.namespace_driver.HaproxyNSDriver'. +# +# [*use_namespaces*] +# (optional) Allow overlapping IP (Must have kernel build with +# CONFIG_NET_NS=y and iproute2 package that supports namespaces). +# Defaults to true. +# +# [*user_group*] +# (optional) The user group. +# Defaults to $::neutron::params::nobody_user_group +# +# [*manage_haproxy_package*] +# (optional) Whether to manage the haproxy package. +# Disable this if you are using the puppetlabs-haproxy module +# Defaults to true +# +class neutron::agents::lbaas ( + $package_ensure = present, + $enabled = true, + $manage_service = true, + $debug = false, + $interface_driver = 'neutron.agent.linux.interface.OVSInterfaceDriver', + $device_driver = 'neutron.services.loadbalancer.drivers.haproxy.namespace_driver.HaproxyNSDriver', + $use_namespaces = true, + $user_group = $::neutron::params::nobody_user_group, + $manage_haproxy_package = true, +) { + + include neutron::params + + Neutron_config<||> ~> Service['neutron-lbaas-service'] + Neutron_lbaas_agent_config<||> ~> Service['neutron-lbaas-service'] + + case $device_driver { + /\.haproxy/: { + Package <| title == $::neutron::params::haproxy_package |> -> Package <| title == 'neutron-lbaas-agent' |> + if $manage_haproxy_package { + ensure_packages([$::neutron::params::haproxy_package]) + } + } + default: { + fail("Unsupported device_driver ${device_driver}") + } + } + + # The LBaaS agent loads both neutron.ini and its own file. + # This only lists config specific to the agent. neutron.ini supplies + # the rest. + neutron_lbaas_agent_config { + 'DEFAULT/debug': value => $debug; + 'DEFAULT/interface_driver': value => $interface_driver; + 'DEFAULT/device_driver': value => $device_driver; + 'DEFAULT/use_namespaces': value => $use_namespaces; + 'haproxy/user_group': value => $user_group; + } + + if $::neutron::params::lbaas_agent_package { + Package['neutron'] -> Package['neutron-lbaas-agent'] + Package['neutron-lbaas-agent'] -> Neutron_config<||> + Package['neutron-lbaas-agent'] -> Neutron_lbaas_agent_config<||> + package { 'neutron-lbaas-agent': + ensure => $package_ensure, + name => $::neutron::params::lbaas_agent_package, + } + } else { + # Some platforms (RedHat) do not provide a neutron LBaaS agent package. + # The neutron LBaaS agent config file is provided by the neutron package. + Package['neutron'] -> Neutron_lbaas_agent_config<||> + } + + if $manage_service { + if $enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + } + + service { 'neutron-lbaas-service': + ensure => $service_ensure, + name => $::neutron::params::lbaas_agent_service, + enable => $enabled, + require => Class['neutron'], + } +} diff --git a/3rdparty/modules/neutron/manifests/agents/linuxbridge.pp b/3rdparty/modules/neutron/manifests/agents/linuxbridge.pp new file mode 100644 index 000000000..4a800fdae --- /dev/null +++ b/3rdparty/modules/neutron/manifests/agents/linuxbridge.pp @@ -0,0 +1,79 @@ +# == Class: neutron::agents::linuxbridge +# +# Setups linuxbridge neutron agent. +# +# === Parameters +# +# [*physical_interface_mappings*] +# (required) Comma-separated list of : +# tuples mapping physical network names to agent's node-specific physical +# network interfaces. +# +# [*firewall_driver*] +# (optional) Firewall driver for realizing neutron security group function. +# Defaults to 'neutron.agent.linux.iptables_firewall.IptablesFirewallDriver'. +# +# [*package_ensure*] +# (optional) Ensure state for package. Defaults to 'present'. +# +# [*enable*] +# (optional) Enable state for service. Defaults to 'true'. +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +class neutron::agents::linuxbridge ( + $physical_interface_mappings, + $firewall_driver = 'neutron.agent.linux.iptables_firewall.IptablesFirewallDriver', + $package_ensure = 'present', + $enable = true, + $manage_service = true +) { + + include neutron::params + + Neutron_config<||> ~> Service['neutron-plugin-linuxbridge-service'] + Neutron_plugin_linuxbridge<||> ~> Service<| title == 'neutron-plugin-linuxbridge-service' |> + + if $::neutron::params::linuxbridge_agent_package { + Package['neutron'] -> Package['neutron-plugin-linuxbridge-agent'] + Package['neutron-plugin-linuxbridge-agent'] -> Neutron_plugin_linuxbridge<||> + Package['neutron-plugin-linuxbridge-agent'] -> Service['neutron-plugin-linuxbridge-service'] + package { 'neutron-plugin-linuxbridge-agent': + ensure => $package_ensure, + name => $::neutron::params::linuxbridge_agent_package, + } + } else { + # Some platforms (RedHat) do not provide a separate neutron plugin + # linuxbridge agent package. The configuration file for the linuxbridge + # agent is provided by the neutron linuxbridge plugin package. + Package['neutron-plugin-linuxbridge'] -> Neutron_plugin_linuxbridge<||> + + if ! defined(Package['neutron-plugin-linuxbridge']) { + package { 'neutron-plugin-linuxbridge': + ensure => $package_ensure, + name => $::neutron::params::linuxbridge_server_package, + } + } + } + + neutron_plugin_linuxbridge { + 'LINUX_BRIDGE/physical_interface_mappings': value => $physical_interface_mappings; + 'SECURITYGROUP/firewall_driver': value => $firewall_driver; + } + + if $manage_service { + if $enable { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + } + + service { 'neutron-plugin-linuxbridge-service': + ensure => $service_ensure, + name => $::neutron::params::linuxbridge_agent_service, + enable => $enable, + } +} diff --git a/3rdparty/modules/neutron/manifests/agents/metadata.pp b/3rdparty/modules/neutron/manifests/agents/metadata.pp new file mode 100644 index 000000000..24d4f691c --- /dev/null +++ b/3rdparty/modules/neutron/manifests/agents/metadata.pp @@ -0,0 +1,156 @@ +# == Class: neutron::agents::metadata +# +# Setup and configure Neutron metadata agent. +# +# === Parameters +# +# [*auth_password*] +# (required) The password for the administrative user. +# +# [*shared_secret*] +# (required) Shared secret to validate proxies Neutron metadata requests. +# +# [*package_ensure*] +# Ensure state of the package. Defaults to 'present'. +# +# [*enabled*] +# State of the service. Defaults to true. +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*debug*] +# Debug. Defaults to false. +# +# [*auth_tenant*] +# The administrative user's tenant name. Defaults to 'services'. +# +# [*auth_user*] +# The administrative user name for OpenStack Networking. +# Defaults to 'neutron'. +# +# [*auth_url*] +# The URL used to validate tokens. Defaults to 'http://localhost:35357/v2.0'. +# +# [*auth_insecure*] +# turn off verification of the certificate for ssl (Defaults to false) +# +# [*auth_ca_cert*] +# CA cert to check against with for ssl keystone. (Defaults to undef) +# +# [*auth_region*] +# The authentication region. Defaults to 'RegionOne'. +# +# [*metadata_ip*] +# The IP address of the metadata service. Defaults to '127.0.0.1'. +# +# [*metadata_port*] +# The TCP port of the metadata service. Defaults to 8775. +# +# [*metadata_workers*] +# (optional) Number of separate worker processes to spawn. +# The default, count of machine's processors, runs the worker thread in the +# current process. +# Greater than 0 launches that number of child processes as workers. +# The parent process manages them. Having more workers will help to improve performances. +# Defaults to: $::processorcount +# +# [*metadata_backlog*] +# (optional) Number of backlog requests to configure the metadata server socket with. +# Defaults to 4096 +# +# [*metadata_memory_cache_ttl*] +# (optional) Specifies time in seconds a metadata cache entry is valid in +# memory caching backend. +# Set to 0 will cause cache entries to never expire. +# Set to undef or false to disable cache. +# Defaults to 5 +# + +class neutron::agents::metadata ( + $auth_password, + $shared_secret, + $package_ensure = 'present', + $enabled = true, + $manage_service = true, + $debug = false, + $auth_tenant = 'services', + $auth_user = 'neutron', + $auth_url = 'http://localhost:35357/v2.0', + $auth_insecure = false, + $auth_ca_cert = undef, + $auth_region = 'RegionOne', + $metadata_ip = '127.0.0.1', + $metadata_port = '8775', + $metadata_workers = $::processorcount, + $metadata_backlog = '4096', + $metadata_memory_cache_ttl = 5, + ) { + + include neutron::params + + Package['neutron'] -> Neutron_metadata_agent_config<||> + Neutron_config<||> ~> Service['neutron-metadata'] + Neutron_metadata_agent_config<||> ~> Service['neutron-metadata'] + + neutron_metadata_agent_config { + 'DEFAULT/debug': value => $debug; + 'DEFAULT/auth_url': value => $auth_url; + 'DEFAULT/auth_insecure': value => $auth_insecure; + 'DEFAULT/auth_region': value => $auth_region; + 'DEFAULT/admin_tenant_name': value => $auth_tenant; + 'DEFAULT/admin_user': value => $auth_user; + 'DEFAULT/admin_password': value => $auth_password, secret => true; + 'DEFAULT/nova_metadata_ip': value => $metadata_ip; + 'DEFAULT/nova_metadata_port': value => $metadata_port; + 'DEFAULT/metadata_proxy_shared_secret': value => $shared_secret; + 'DEFAULT/metadata_workers': value => $metadata_workers; + 'DEFAULT/metadata_backlog': value => $metadata_backlog; + } + + if $metadata_memory_cache_ttl { + neutron_metadata_agent_config { + 'DEFAULT/cache_url': value => "memory://?default_ttl=${metadata_memory_cache_ttl}"; + } + } else { + neutron_metadata_agent_config { + 'DEFAULT/cache_url': ensure => absent; + } + } + + if $auth_ca_cert { + neutron_metadata_agent_config { + 'DEFAULT/auth_ca_cert': value => $auth_ca_cert; + } + } else { + neutron_metadata_agent_config { + 'DEFAULT/auth_ca_cert': ensure => absent; + } + } + + if $::neutron::params::metadata_agent_package { + Package['neutron-metadata'] -> Neutron_metadata_agent_config<||> + Package['neutron-metadata'] -> Service['neutron-metadata'] + package { 'neutron-metadata': + ensure => $package_ensure, + name => $::neutron::params::metadata_agent_package, + require => Package['neutron'], + } + } + + if $manage_service { + if $enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + } + + service { 'neutron-metadata': + ensure => $service_ensure, + name => $::neutron::params::metadata_agent_service, + enable => $enabled, + require => Class['neutron'], + } +} diff --git a/3rdparty/modules/neutron/manifests/agents/metering.pp b/3rdparty/modules/neutron/manifests/agents/metering.pp new file mode 100644 index 000000000..917215ceb --- /dev/null +++ b/3rdparty/modules/neutron/manifests/agents/metering.pp @@ -0,0 +1,108 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Class: neutron::agents:metering +# +# Setups Neutron metering agent. +# +# === Parameters +# +# [*package_ensure*] +# (optional) Ensure state for package. Defaults to 'present'. +# +# [*enabled*] +# (optional) Enable state for service. Defaults to 'true'. +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*debug*] +# (optional) Show debugging output in log. Defaults to false. +# +# [*interface_driver*] +# (optional) Defaults to 'neutron.agent.linux.interface.OVSInterfaceDriver'. +# +# [*use_namespaces*] +# (optional) Allow overlapping IP (Must have kernel build with +# CONFIG_NET_NS=y and iproute2 package that supports namespaces). +# Defaults to true. +# +# [*measure_interval*] +# (optional) Interval between two metering measures. +# Defaults to 30. +# +# [*report_interval*] +# (optional) Interval between two metering reports. +# Defaults to 300. +# + +class neutron::agents::metering ( + $package_ensure = present, + $enabled = true, + $manage_service = true, + $debug = false, + $interface_driver = 'neutron.agent.linux.interface.OVSInterfaceDriver', + $use_namespaces = true, + $measure_interval = '30', + $report_interval = '300' +) { + + include neutron::params + + Neutron_config<||> ~> Service['neutron-metering-service'] + Neutron_metering_agent_config<||> ~> Service['neutron-metering-service'] + + # The metering agent loads both neutron.ini and its own file. + # This only lists config specific to the agent. neutron.ini supplies + # the rest. + neutron_metering_agent_config { + 'DEFAULT/debug': value => $debug; + 'DEFAULT/interface_driver': value => $interface_driver; + 'DEFAULT/use_namespaces': value => $use_namespaces; + 'DEFAULT/measure_interval': value => $measure_interval; + 'DEFAULT/report_interval': value => $report_interval; + } + + if $::neutron::params::metering_agent_package { + Package['neutron'] -> Package['neutron-metering-agent'] + Package['neutron-metering-agent'] -> Neutron_config<||> + Package['neutron-metering-agent'] -> Neutron_metering_agent_config<||> + package { 'neutron-metering-agent': + ensure => $package_ensure, + name => $::neutron::params::metering_agent_package, + } + } else { + # Default dependency if the system does not provide a neutron metering agent package. + Package['neutron'] -> Neutron_metering_agent_config<||> + } + + if $manage_service { + if $enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + } + + service { 'neutron-metering-service': + ensure => $service_ensure, + name => $::neutron::params::metering_agent_service, + enable => $enabled, + require => Class['neutron'], + } +} diff --git a/3rdparty/modules/neutron/manifests/agents/ml2/linuxbridge.pp b/3rdparty/modules/neutron/manifests/agents/ml2/linuxbridge.pp new file mode 100644 index 000000000..62e13785a --- /dev/null +++ b/3rdparty/modules/neutron/manifests/agents/ml2/linuxbridge.pp @@ -0,0 +1,156 @@ +# == Class: neutron::agents::ml2::linuxbridge +# +# Setups Linuxbridge Neutron agent for ML2 plugin. +# +# === Parameters +# +# [*package_ensure*] +# (optional) Package ensure state. +# Defaults to 'present'. +# +# [*enabled*] +# (required) Whether or not to enable the agent. +# Defaults to true. +# +# [*tunnel_types*] +# (optional) List of types of tunnels to use when utilizing tunnels. +# Supported tunnel types are: vxlan. +# Defaults to an empty list. +# +# [*local_ip*] +# (optional) Local IP address to use for VXLAN endpoints. +# Required when enabling tunneling. +# Defaults to false. +# +# [*vxlan_group*] +# (optional) Multicast group for vxlan interface. If unset, disables VXLAN +# multicast mode. Should be an Multicast IP (v4 or v6) address. +# Default to '224.0.0.1'. +# +# [*vxlan_ttl*] +# (optional) TTL for vxlan interface protocol packets.. +# Default to undef. +# +# [*vxlan_tos*] +# (optional) TOS for vxlan interface protocol packets.. +# Defaults to undef. +# +# [*polling_interval*] +# (optional) The number of seconds the agent will wait between +# polling for local device changes. +# Defaults to 2. +# +# [*l2_population*] +# (optional) Extension to use alongside ml2 plugin's l2population +# mechanism driver. It enables the plugin to populate VXLAN forwarding table. +# Defaults to false. +# +# [*physical_interface_mappings*] +# (optional) List of : +# tuples mapping physical network names to agent's node-specific physical +# network interfaces. Defaults to empty list. +# +# [*firewall_driver*] +# (optional) Firewall driver for realizing neutron security group function. +# Defaults to 'neutron.agent.linux.iptables_firewall.IptablesFirewallDriver'. +# +class neutron::agents::ml2::linuxbridge ( + $package_ensure = 'present', + $enabled = true, + $tunnel_types = [], + $local_ip = false, + $vxlan_group = '224.0.0.1', + $vxlan_ttl = false, + $vxlan_tos = false, + $polling_interval = 2, + $l2_population = false, + $physical_interface_mappings = [], + $firewall_driver = 'neutron.agent.linux.iptables_firewall.IptablesFirewallDriver' +) { + + validate_array($tunnel_types) + validate_array($physical_interface_mappings) + + include neutron::params + + Package['neutron-plugin-linuxbridge-agent'] -> Neutron_plugin_linuxbridge<||> + Neutron_plugin_linuxbridge<||> ~> Service['neutron-plugin-linuxbridge-agent'] + + if ('vxlan' in $tunnel_types) { + + if ! $local_ip { + fail('The local_ip parameter is required when vxlan tunneling is enabled') + } + + if $vxlan_group { + neutron_plugin_linuxbridge { 'vxlan/vxlan_group': value => $vxlan_group } + } else { + neutron_plugin_linuxbridge { 'vxlan/vxlan_group': ensure => absent } + } + + if $vxlan_ttl { + neutron_plugin_linuxbridge { 'vxlan/vxlan_ttl': value => $vxlan_ttl } + } else { + neutron_plugin_linuxbridge { 'vxlan/vxlan_ttl': ensure => absent } + } + + if $vxlan_tos { + neutron_plugin_linuxbridge { 'vxlan/vxlan_tos': value => $vxlan_tos } + } else { + neutron_plugin_linuxbridge { 'vxlan/vxlan_tos': ensure => absent } + } + + neutron_plugin_linuxbridge { + 'vxlan/enable_vxlan': value => true; + 'vxlan/local_ip': value => $local_ip; + 'vxlan/l2_population': value => $l2_population; + } + } else { + neutron_plugin_linuxbridge { + 'vxlan/enable_vxlan': value => false; + 'vxlan/local_ip': ensure => absent; + 'vxlan/vxlan_group': ensure => absent; + 'vxlan/l2_population': ensure => absent; + } + } + + neutron_plugin_linuxbridge { + 'agent/polling_interval': value => $polling_interval; + 'linux_bridge/physical_interface_mappings': value => join($physical_interface_mappings, ','); + } + + if $firewall_driver { + neutron_plugin_linuxbridge { 'securitygroup/firewall_driver': value => $firewall_driver } + } else { + neutron_plugin_linuxbridge { 'securitygroup/firewall_driver': ensure => absent } + } + + if $::neutron::params::linuxbridge_agent_package { + package { 'neutron-plugin-linuxbridge-agent': + ensure => $package_ensure, + name => $::neutron::params::linuxbridge_agent_package, + } + } else { + # Some platforms (RedHat) do not provide a separate + # neutron plugin linuxbridge agent package. + if ! defined(Package['neutron-plugin-linuxbridge-agent']) { + package { 'neutron-plugin-linuxbridge-agent': + ensure => $package_ensure, + name => $::neutron::params::linuxbridge_server_package, + } + } + } + + if $enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + + service { 'neutron-plugin-linuxbridge-agent': + ensure => $service_ensure, + name => $::neutron::params::linuxbridge_agent_service, + enable => $enabled, + require => Class['neutron'] + } +} diff --git a/3rdparty/modules/neutron/manifests/agents/ml2/ovs.pp b/3rdparty/modules/neutron/manifests/agents/ml2/ovs.pp new file mode 100644 index 000000000..11753e813 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/agents/ml2/ovs.pp @@ -0,0 +1,249 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Class: neutron::agents::ml2::ovs +# +# Setups OVS neutron agent when using ML2 plugin +# +# === Parameters +# +# [*package_ensure*] +# (optional) The state of the package +# Defaults to 'present' +# +# [*enabled*] +# (required) Whether or not to enable the OVS Agent +# Defaults to true +# +# [*bridge_uplinks*] +# (optional) List of interfaces to connect to the bridge when doing +# bridge mapping. +# Defaults to empty list +# +# [*bridge_mapping*] +# (optional) List of : +# Defaults to empty list +# +# [*integration_bridge*] +# (optional) Integration bridge in OVS +# Defaults to 'br-int' +# +# [*enable_tunneling*] +# (optional) Enable or not tunneling +# Defaults to false +# +# [*tunnel_types*] +# (optional) List of types of tunnels to use when utilizing tunnels, +# either 'gre' or 'vxlan'. +# Defaults to false +# +# [*local_ip*] +# (optional) Local IP address of GRE tunnel endpoints. +# Required when enabling tunneling +# Defaults to false +# +# [*tunnel_bridge*] +# (optional) Bridge used to transport tunnels +# Defaults to 'br-tun' +# +# [*vxlan_udp_port*] +# (optional) The UDP port to use for VXLAN tunnels. +# Defaults to '4789' +# +# [*polling_interval*] +# (optional) The number of seconds the agent will wait between +# polling for local device changes. +# Defaults to '2" +# +# [*l2_population*] +# (optional) Extension to use alongside ml2 plugin's l2population +# mechanism driver. +# Defaults to false +# +# [*arp_responder*] +# (optional) Enable or not the ARP responder. +# Recommanded when using l2 population mechanism driver. +# Defaults to false +# +# [*firewall_driver*] +# (optional) Firewall driver for realizing neutron security group function. +# Defaults to 'neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver'. +# +# [*enable_distributed_routing*] +# (optional) Set to True on L2 agents to enable support +# for distributed virtual routing. +# Defaults to false +# +class neutron::agents::ml2::ovs ( + $package_ensure = 'present', + $enabled = true, + $bridge_uplinks = [], + $bridge_mappings = [], + $integration_bridge = 'br-int', + $enable_tunneling = false, + $tunnel_types = [], + $local_ip = false, + $tunnel_bridge = 'br-tun', + $vxlan_udp_port = 4789, + $polling_interval = 2, + $l2_population = false, + $arp_responder = false, + $firewall_driver = 'neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver', + $enable_distributed_routing = false, +) { + + include neutron::params + require vswitch::ovs + + if $enable_tunneling and ! $local_ip { + fail('Local ip for ovs agent must be set when tunneling is enabled') + } + + if $enable_distributed_routing and ! $l2_population { + fail('L2 population must be enabled when DVR is enabled') + } + + Neutron_plugin_ml2<||> ~> Service['neutron-ovs-agent-service'] + + if ($bridge_mappings != []) { + # bridge_mappings are used to describe external networks that are + # *directly* attached to this machine. + # (This has nothing to do with VM-VM comms over neutron virtual networks.) + # Typically, the network node - running L3 agent - will want one external + # network (often this is on the control node) and the other nodes (all the + # compute nodes) will want none at all. The only other reason you will + # want to add networks here is if you're using provider networks, in which + # case you will name the network with bridge_mappings and add the server's + # interfaces that are attached to that network with bridge_uplinks. + # (The bridge names can be nearly anything, they just have to match between + # mappings and uplinks; they're what the OVS switches will get named.) + + # Set config for bridges that we're going to create + # The OVS neutron plugin will talk in terms of the networks in the bridge_mappings + $br_map_str = join($bridge_mappings, ',') + neutron_plugin_ml2 { + 'ovs/bridge_mappings': value => $br_map_str; + } + neutron::plugins::ovs::bridge{ $bridge_mappings: + before => Service['neutron-ovs-agent-service'], + } + neutron::plugins::ovs::port{ $bridge_uplinks: + before => Service['neutron-ovs-agent-service'], + } + } + + neutron_plugin_ml2 { + 'agent/polling_interval': value => $polling_interval; + 'agent/l2_population': value => $l2_population; + 'agent/arp_responder': value => $arp_responder; + 'agent/enable_distributed_routing': value => $enable_distributed_routing; + 'ovs/integration_bridge': value => $integration_bridge; + } + + if ($firewall_driver) { + neutron_plugin_ml2 { 'securitygroup/firewall_driver': + value => $firewall_driver + } + } else { + neutron_plugin_ml2 { 'securitygroup/firewall_driver': ensure => absent } + } + + vs_bridge { $integration_bridge: + ensure => present, + before => Service['neutron-ovs-agent-service'], + } + + if $enable_tunneling { + vs_bridge { $tunnel_bridge: + ensure => present, + before => Service['neutron-ovs-agent-service'], + } + neutron_plugin_ml2 { + 'ovs/enable_tunneling': value => true; + 'ovs/tunnel_bridge': value => $tunnel_bridge; + 'ovs/local_ip': value => $local_ip; + } + + if size($tunnel_types) > 0 { + neutron_plugin_ml2 { + 'agent/tunnel_types': value => join($tunnel_types, ','); + } + } + if 'vxlan' in $tunnel_types { + validate_vxlan_udp_port($vxlan_udp_port) + neutron_plugin_ml2 { + 'agent/vxlan_udp_port': value => $vxlan_udp_port; + } + } + } else { + neutron_plugin_ml2 { + 'ovs/enable_tunneling': value => false; + 'ovs/tunnel_bridge': ensure => absent; + 'ovs/local_ip': ensure => absent; + } + } + + + if $::neutron::params::ovs_agent_package { + Package['neutron-ovs-agent'] -> Neutron_plugin_ml2<||> + package { 'neutron-ovs-agent': + ensure => $package_ensure, + name => $::neutron::params::ovs_agent_package, + } + } else { + # Some platforms (RedHat) do not provide a separate + # neutron plugin ovs agent package. The configuration file for + # the ovs agent is provided by the neutron ovs plugin package. + Package['neutron-ovs-agent'] -> Neutron_plugin_ml2<||> + Package['neutron-ovs-agent'] -> Service['ovs-cleanup-service'] + + if ! defined(Package['neutron-ovs-agent']) { + package { 'neutron-ovs-agent': + ensure => $package_ensure, + name => $::neutron::params::ovs_server_package, + } -> + # https://bugzilla.redhat.com/show_bug.cgi?id=1087647 + # Causes init script for agent to load the old ovs file + # instead of the ml2 config file. + file { '/etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini': + ensure => link, + target => '/etc/neutron/plugins/ml2/ml2_conf.ini' + } ~> Service<| title == 'neutron-ovs-agent-service' |> + } + } + + if $enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + + service { 'neutron-ovs-agent-service': + ensure => $service_ensure, + name => $::neutron::params::ovs_agent_service, + enable => $enabled, + require => Class['neutron'], + } + + if $::neutron::params::ovs_cleanup_service { + Package['neutron-ovs-agent'] -> Service['ovs-cleanup-service'] + service { 'ovs-cleanup-service': + name => $::neutron::params::ovs_cleanup_service, + enable => $enabled, + } + } +} diff --git a/3rdparty/modules/neutron/manifests/agents/ml2/sriov.pp b/3rdparty/modules/neutron/manifests/agents/ml2/sriov.pp new file mode 100644 index 000000000..68e580005 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/agents/ml2/sriov.pp @@ -0,0 +1,88 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Class: neutron::agents::ml2::sriov +# +# Setups SR-IOV neutron agent when using ML2 plugin +# +# === Parameters +# +# [*package_ensure*] +# (optional) The state of the package +# Defaults to 'present' +# +# [*enabled*] +# (required) Whether or not to enable the OVS Agent +# Defaults to true +# +# [*physical_device_mappings*] +# (optional) List of : +# All physical networks listed in network_vlan_ranges +# on the server should have mappings to appropriate +# interfaces on each agent. +# Defaults to empty list +# +# [*polling_interval*] +# (optional) The number of seconds the agent will wait between +# polling for local device changes. +# Defaults to '2" +# +# [*exclude_devices*] +# (optional) List of : mapping +# network_device to the agent's node-specific list of virtual functions +# that should not be used for virtual networking. excluded_devices is a +# semicolon separated list of virtual functions to exclude from network_device. +# The network_device in the mapping should appear in the physical_device_mappings list. +class neutron::agents::ml2::sriov ( + $package_ensure = 'present', + $enabled = true, + $physical_device_mappings = [], + $polling_interval = 2, + $exclude_devices = [], +) { + + include neutron::params + + Neutron_plugin_ml2<||> ~> Service['neutron-sriov-nic-agent-service'] + + neutron_plugin_ml2 { + 'sriov_nic/polling_interval': value => $polling_interval; + 'sriov_nic/exclude_devices': value => join($exclude_devices, ','); + 'sriov_nic/physical_device_mappings': value => join($physical_device_mappings, ','); + } + + + Package['neutron-sriov-nic-agent'] -> Neutron_plugin_ml2<||> + package { 'neutron-sriov-nic-agent': + ensure => $package_ensure, + name => $::neutron::params::sriov_nic_agent_package, + } + + if $enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + + service { 'neutron-sriov-nic-agent-service': + ensure => $service_ensure, + name => $::neutron::params::sriov_nic_agent_service, + enable => $enabled, + require => Class['neutron'], + } + +} diff --git a/3rdparty/modules/neutron/manifests/agents/n1kv_vem.pp b/3rdparty/modules/neutron/manifests/agents/n1kv_vem.pp new file mode 100644 index 000000000..dc740c0e2 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/agents/n1kv_vem.pp @@ -0,0 +1,241 @@ +# == Class: n1kv_vem +# +# Deploy N1KV VEM on compute and network nodes. +# Support exists and tested for RedHat. +# (For Ubuntu/Debian platforms few changes and testing pending.) +# +# === Parameters +# [*n1kv_vsm_ip*] +# (required) N1KV VSM(Virtual Supervisor Module) VM's IP. +# Defaults to 127.0.0.1 +# +# [*n1kv_vsm_domainid*] +# (required) N1KV VSM DomainID. +# Defaults to 1000 +# +# [*host_mgmt_intf*] +# (required) Management Interface of node where VEM will be installed. +# Defaults to eth1 +# +# [*uplink_profile*] +# (optional) Uplink Interfaces that will be managed by VEM. The uplink +# port-profile that configures these interfaces should also be specified. +# (format) +# $uplink_profile = { 'eth1' => 'profile1', +# 'eth2' => 'profile2' +# }, +# Defaults to empty +# +# [*vtep_config*] +# (optional) Virtual tunnel interface configuration. +# Eg:VxLAN tunnel end-points. +# (format) +# $vtep_config = { 'vtep1' => { 'profile' => 'virtprof1', +# 'ipmode' => 'dhcp' +# }, +# 'vtep2' => { 'profile' => 'virtprof2', +# 'ipmode' => 'static', +# 'ipaddress' => '192.168.1.1', +# 'netmask' => '255.255.255.0' +# } +# }, +# Defaults to empty +# +# [*node_type*] +# (optional). Specify the type of node: 'compute' (or) 'network'. +# Defaults to 'compute' +# +# All the above parameter values will be used in the config file: n1kv.conf +# +# [*vteps_in_same_subnet*] +# (optional) +# The VXLAN tunnel interfaces created on VEM can belong to same IP-subnet. +# In such case, set this parameter to true. This results in below +# 'sysctl:ipv4' values to be modified. +# rp_filter (reverse path filtering) set to 2(Loose).Default is 1(Strict) +# arp_ignore (arp reply mode) set to 1:reply only if target ip matches +# that of incoming interface. Default is 0 +# arp_announce (arp announce mode) set to 1. Default is 0 +# Please refer Linux Documentation for detailed description +# http://lxr.free-electrons.com/source/Documentation/networking/ip-sysctl.txt +# +# If the tunnel interfaces are not in same subnet set this parameter to false. +# Note that setting to false causes no change in the sysctl settings and does +# not revert the changes made if it was originally set to true on a previous +# catalog run. +# +# Defaults to false +# +# [*n1kv_source*] +# (optional) +# n1kv_source ==> VEM package location. One of below +# A)URL of yum repository that hosts VEM package. +# B)VEM RPM/DPKG file name, If present locally in 'files' folder +# C)If not specified, assumes that VEM image is available in +# default enabled repositories. +# Defaults to empty +# +# [*n1kv_version*] +# (optional). Specify VEM package version to be installed. +# Not applicable if 'n1kv_source' is a file. (Option-B above) +# Defaults to 'present' +# +# [*package_ensure*] +# (optional) Ensure state for dependent packages: Openvswitch/libnl. +# Defaults to 'present'. +# +# [*enable*] +# (optional) Enable state for service. Defaults to 'true'. +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*portdb*] +# (optional) PortDB (ovs|vem) +# Defaults to ovs +# +# [*fastpath_flood*] +# (optional) Handle broadcast floods and unknown pkts in fastpath(KLM) +# Defaults to disable +# +class neutron::agents::n1kv_vem ( + $n1kv_vsm_ip = '127.0.0.1', + $n1kv_vsm_domain_id = 1000, + $host_mgmt_intf = 'eth1', + $uplink_profile = {}, + $vtep_config = {}, + $node_type = 'compute', + $vteps_in_same_subnet = false, + $n1kv_source = '', + $n1kv_version = 'present', + $package_ensure = 'present', + $enable = true, + $manage_service = true, + $portdb = 'ovs', + $fastpath_flood = 'disable' +) { + + include neutron::params + require vswitch::ovs + + Exec { path => [ '/bin/', '/sbin/' , '/usr/bin/', '/usr/sbin/' ] } + + if($::osfamily != 'Redhat') { + #current support exists for Redhat family. + #Support for Debian will be added soon. + fail("Unsupported osfamily ${::osfamily}") + } + + #Check source of n1kv-vem image:yum-repo (or) local file in 'files' directory + if $n1kv_source != '' { + if ($n1kv_source =~ /^http/) or ($n1kv_source =~ /^ftp/) { + $vemimage_uri = 'repo' + } else { + $vemimage_uri = 'file' + $vemtgtimg = "/var/n1kv/${n1kv_source}" + } + } else { + $vemimage_uri = 'unspec' + } + + + package { 'libnl': + ensure => $package_ensure, + name => $::neutron::params::libnl_package + } + + file { + '/etc/n1kv': + ensure => directory, + owner => 'root', + group => 'root', + mode => '0755'; + '/var/n1kv': + ensure => directory, + owner => 'root', + group => 'root', + mode => '0755', + } + + #specify template corresponding to 'n1kv.conf' + file {'/etc/n1kv/n1kv.conf': + ensure => present, + owner => 'root', + group => 'root', + mode => '0664', + content => template('neutron/n1kv.conf.erb'), + require => File['/etc/n1kv'], + } + + if $vemimage_uri == 'file' { + #specify location on target-host where image file will be downloaded to. + #Later vem package: 'nexus1000v' will be installed from this file. + file { $vemtgtimg: + owner => 'root', + group => 'root', + mode => '0664', + source => "puppet:///modules/neutron/${n1kv_source}", + require => File['/var/n1kv'], + } + package {'nexus1000v': + ensure => $n1kv_version, + provider => $::neutron::params::package_provider, + source => $vemtgtimg, + require => File[$vemtgtimg] + } + } else { + if $vemimage_uri == 'repo' { + #vem package: 'nexus1000v' will be downloaded and installed + #from below repo. + yumrepo { 'cisco-vem-repo': + baseurl => $n1kv_source, + descr => 'Repo for VEM Image', + enabled => 1, + gpgcheck => 1, + gpgkey => "${n1kv_source}/RPM-GPG-KEY" + #proxy => '_none_', + } + } + package {'nexus1000v': + ensure => $package_ensure + } + } + + if $manage_service { + if $enable { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + } + + service { 'nexus1000v': + ensure => $service_ensure, + } + + #Upon config change in 'n1kv.conf' execute below 'vemcmd reread config'. + #No need to restart service. + exec { 'vemcmd reread config': + subscribe => File['/etc/n1kv/n1kv.conf'], + refreshonly => true, + require => Service['nexus1000v'] + } + + if $vteps_in_same_subnet == true { + $my_sysctl_settings = { + 'net.ipv4.conf.default.rp_filter' => { value => 2 }, + 'net.ipv4.conf.all.rp_filter' => { value => 2 }, + 'net.ipv4.conf.default.arp_ignore' => { value => 1 }, + 'net.ipv4.conf.all.arp_ignore' => { value => 1 }, + 'net.ipv4.conf.all.arp_announce' => { value => 2 }, + 'net.ipv4.conf.default.arp_announce' => { value => 2 }, + } + create_resources(sysctl::value,$my_sysctl_settings) + } + + Package['libnl'] -> Package['nexus1000v'] + Service['openvswitch'] ~> Package['nexus1000v'] + File['/etc/n1kv/n1kv.conf'] -> Package['nexus1000v'] + Package['nexus1000v'] ~> Service['nexus1000v'] +} diff --git a/3rdparty/modules/neutron/manifests/agents/ovs.pp b/3rdparty/modules/neutron/manifests/agents/ovs.pp new file mode 100644 index 000000000..082a4b14c --- /dev/null +++ b/3rdparty/modules/neutron/manifests/agents/ovs.pp @@ -0,0 +1,161 @@ +# == Class: neutron::agents::ovs +# +# Setups OVS neutron agent. +# +# === Parameters +# +# [*firewall_driver*] +# (optional) Firewall driver for realizing neutron security group function. +# Defaults to 'neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver'. +# +class neutron::agents::ovs ( + $package_ensure = 'present', + $manage_service = true, + $enabled = true, + $bridge_uplinks = [], + $bridge_mappings = [], + $integration_bridge = 'br-int', + $enable_tunneling = false, + $tunnel_types = [], + $local_ip = false, + $tunnel_bridge = 'br-tun', + $vxlan_udp_port = 4789, + $polling_interval = 2, + $firewall_driver = 'neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver', + $veth_mtu = undef +) { + + include neutron::params + require vswitch::ovs + + if $enable_tunneling and ! $local_ip { + fail('Local ip for ovs agent must be set when tunneling is enabled') + } + + + if $enabled { + Neutron_config<||> ~> Service['neutron-plugin-ovs-service'] + Neutron_plugin_ovs<||> ~> Service['neutron-plugin-ovs-service'] + Neutron::Plugins::Ovs::Bridge<||> -> Service['neutron-plugin-ovs-service'] + Neutron::Plugins::Ovs::Port<||> -> Service['neutron-plugin-ovs-service'] + Vs_bridge<||> -> Service['neutron-plugin-ovs-service'] + } + + if ($bridge_mappings != []) { + # bridge_mappings are used to describe external networks that are + # *directly* attached to this machine. + # (This has nothing to do with VM-VM comms over neutron virtual networks.) + # Typically, the network node - running L3 agent - will want one external + # network (often this is on the control node) and the other nodes (all the + # compute nodes) will want none at all. The only other reason you will + # want to add networks here is if you're using provider networks, in which + # case you will name the network with bridge_mappings and add the server's + # interfaces that are attached to that network with bridge_uplinks. + # (The bridge names can be nearly anything, they just have to match between + # mappings and uplinks; they're what the OVS switches will get named.) + + # Set config for bridges that we're going to create + # The OVS neutron plugin will talk in terms of the networks in the bridge_mappings + $br_map_str = join($bridge_mappings, ',') + neutron_plugin_ovs { + 'OVS/bridge_mappings': value => $br_map_str; + } + neutron::plugins::ovs::bridge{ $bridge_mappings: } + neutron::plugins::ovs::port{ $bridge_uplinks: } + } + + neutron_plugin_ovs { + 'AGENT/polling_interval': value => $polling_interval; + 'OVS/integration_bridge': value => $integration_bridge; + } + + if ($firewall_driver) { + neutron_plugin_ovs { 'SECURITYGROUP/firewall_driver': + value => $firewall_driver + } + } else { + neutron_plugin_ovs { 'SECURITYGROUP/firewall_driver': ensure => absent } + } + + vs_bridge { $integration_bridge: + ensure => present, + } + + if $enable_tunneling { + vs_bridge { $tunnel_bridge: + ensure => present, + before => Service['neutron-plugin-ovs-service'], + } + neutron_plugin_ovs { + 'OVS/enable_tunneling': value => true; + 'OVS/tunnel_bridge': value => $tunnel_bridge; + 'OVS/local_ip': value => $local_ip; + } + + if size($tunnel_types) > 0 { + neutron_plugin_ovs { + 'agent/tunnel_types': value => join($tunnel_types, ','); + } + } + if 'vxlan' in $tunnel_types { + validate_vxlan_udp_port($vxlan_udp_port) + neutron_plugin_ovs { + 'agent/vxlan_udp_port': value => $vxlan_udp_port; + } + } + } else { + neutron_plugin_ovs { + 'OVS/enable_tunneling': value => false; + 'OVS/tunnel_bridge': ensure => absent; + 'OVS/local_ip': ensure => absent; + } + } + + + if $::neutron::params::ovs_agent_package { + Package['neutron-plugin-ovs-agent'] -> Neutron_plugin_ovs<||> + package { 'neutron-plugin-ovs-agent': + ensure => $package_ensure, + name => $::neutron::params::ovs_agent_package, + } + } else { + # Some platforms (RedHat) do not provide a separate + # neutron plugin ovs agent package. The configuration file for + # the ovs agent is provided by the neutron ovs plugin package. + Package['neutron-plugin-ovs'] -> Neutron_plugin_ovs<||> + Package['neutron-plugin-ovs'] -> Service['ovs-cleanup-service'] + + ensure_resource('package', 'neutron-plugin-ovs', { + ensure => $package_ensure, + name => $::neutron::params::ovs_server_package, + }) + } + + if $manage_service { + if $enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + } + + service { 'neutron-plugin-ovs-service': + ensure => $service_ensure, + name => $::neutron::params::ovs_agent_service, + enable => $enabled, + require => Class['neutron'], + } + + if $::neutron::params::ovs_cleanup_service { + service {'ovs-cleanup-service': + name => $::neutron::params::ovs_cleanup_service, + enable => $enabled, + } + } + + if $veth_mtu { + neutron_plugin_ovs { 'AGENT/veth_mtu': value => $veth_mtu } + } else { + neutron_plugin_ovs { 'AGENT/veth_mtu': ensure => absent } + } +} diff --git a/3rdparty/modules/neutron/manifests/agents/vpnaas.pp b/3rdparty/modules/neutron/manifests/agents/vpnaas.pp new file mode 100644 index 000000000..23cc307b0 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/agents/vpnaas.pp @@ -0,0 +1,118 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Class: neutron::agents:vpnaas +# +# Setups Neutron VPN agent. +# +# === Parameters +# +# [*package_ensure*] +# (optional) Ensure state for package. Defaults to 'present'. +# +# [*enabled*] +# (optional) Enable state for service. Defaults to 'true'. +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*vpn_device_driver*] +# (optional) Defaults to 'neutron.services.vpn.device_drivers.ipsec.OpenSwanDriver'. +# +# [*interface_driver*] +# (optional) Defaults to 'neutron.agent.linux.interface.OVSInterfaceDriver'. +# +# [*external_network_bridge] +# (optional) Defaults to undef +# +# [*ipsec_status_check_interval*] +# (optional) Status check interval. Defaults to '60'. +# +class neutron::agents::vpnaas ( + $package_ensure = present, + $enabled = true, + $manage_service = true, + $vpn_device_driver = 'neutron.services.vpn.device_drivers.ipsec.OpenSwanDriver', + $interface_driver = 'neutron.agent.linux.interface.OVSInterfaceDriver', + $external_network_bridge = undef, + $ipsec_status_check_interval = '60' +) { + + include neutron::params + + Neutron_config<||> ~> Service['neutron-vpnaas-service'] + Neutron_vpnaas_agent_config<||> ~> Service['neutron-vpnaas-service'] + + case $vpn_device_driver { + /\.OpenSwan/: { + Package['openswan'] -> Package<| title == 'neutron-vpnaas-agent' |> + package { 'openswan': + ensure => present, + name => $::neutron::params::openswan_package, + } + } + default: { + fail("Unsupported vpn_device_driver ${vpn_device_driver}") + } + } + + # The VPNaaS agent loads both neutron.ini and its own file. + # This only lists config specific to the agent. neutron.ini supplies + # the rest. + neutron_vpnaas_agent_config { + 'vpnagent/vpn_device_driver': value => $vpn_device_driver; + 'ipsec/ipsec_status_check_interval': value => $ipsec_status_check_interval; + 'DEFAULT/interface_driver': value => $interface_driver; + } + + if ($external_network_bridge) { + neutron_vpnaas_agent_config { + 'DEFAULT/external_network_bridge': value => $external_network_bridge; + } + } else { + neutron_vpnaas_agent_config { + 'DEFAULT/external_network_bridge': ensure => absent; + } + } + + if $::neutron::params::vpnaas_agent_package { + Package['neutron'] -> Package['neutron-vpnaas-agent'] + Package['neutron-vpnaas-agent'] -> Neutron_vpnaas_agent_config<||> + package { 'neutron-vpnaas-agent': + ensure => $package_ensure, + name => $::neutron::params::vpnaas_agent_package, + } + } else { + Package['neutron'] -> Neutron_vpnaas_agent_config<||> + } + + if $manage_service { + if $enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + } + + service { 'neutron-vpnaas-service': + ensure => $service_ensure, + name => $::neutron::params::vpnaas_agent_service, + enable => $enabled, + require => Class['neutron'], + } +} diff --git a/3rdparty/modules/neutron/manifests/client.pp b/3rdparty/modules/neutron/manifests/client.pp new file mode 100644 index 000000000..c6cf07a41 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/client.pp @@ -0,0 +1,22 @@ +# == Class: neutron::client +# +# Manages the neutron client package on systems +# +# === Parameters: +# +# [*package_ensure*] +# (optional) The state of the package +# Defaults to present +# +class neutron::client ( + $package_ensure = present +) { + + include neutron::params + + package { 'python-neutronclient': + ensure => $package_ensure, + name => $::neutron::params::client_package, + } + +} diff --git a/3rdparty/modules/neutron/manifests/config.pp b/3rdparty/modules/neutron/manifests/config.pp new file mode 100644 index 000000000..164ff0b45 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/config.pp @@ -0,0 +1,117 @@ +# == Class: neutron::config +# +# This class is used to manage arbitrary Neutron configurations. +# +# === Parameters +# +# [*xxx_config*] +# (optional) Allow configuration of arbitrary Neutron xxx specific configurations. +# The value is an hash of neutron_config resources. Example: +# server_config => +# { 'DEFAULT/foo' => { value => 'fooValue'}, +# 'DEFAULT/bar' => { value => 'barValue'} +# } +# +# NOTE: { 'DEFAULT/foo': value => 'fooValue'; 'DEFAULT/bar': value => 'barValue'} is invalid. +# +# In yaml format, Example: +# server_config: +# DEFAULT/foo: +# value: fooValue +# DEFAULT/bar: +# value: barValue +# +# [**server_config**] +# (optional) Manage configuration of neutron.conf +# +# [**api_config**] +# (optional) Manage configuration of api-paste.ini +# +# [**l3_agent_config**] +# (optional) Manage configuration of l3_agent.ini +# +# [**dhcp_agent_config**] +# (optional) Manage configuration of dhcp_agent.ini +# +# [**lbaas_agent_config**] +# (optional) Manage configuration of lbaas_agent.ini +# +# [**metadata_agent_config**] +# (optional) Manage configuration of metadata_agent.ini +# +# [**metering_agent_config**] +# (optional) Manage configuration of metering_agent.ini +# +# [**vpnaas_agent_config**] +# (optional) Manage configuration of vpn_agent.ini +# +# [**plugin_linuxbridge_config**] +# (optional) Manage configuration of linuxbridge_conf.ini +# +# [**plugin_cisco_db_conn_config**] +# (optional) Manage configuration of plugins/cisco/db_conn.ini +# +# [**plugin_cisco_config**] +# (optional) Manage configuration of cisco_plugins.ini +# +# [**plugin_midonet_config**] +# (optional) Manage configuration of plugins/midonet/midonet.ini +# +# [**plugin_ml2_config**] +# (optional) Manage configuration of ml2_conf.ini +# +# [**plugin_ovs_config**] +# (optional) Manage configuration of ovs_neutron_plugin.ini +# +# NOTE: The configuration MUST NOT be already handled by this module +# or Puppet catalog compilation will fail with duplicate resources. +# +class neutron::config ( + $server_config = {}, + $api_config = {}, + $l3_agent_config = {}, + $dhcp_agent_config = {}, + $lbaas_agent_config = {}, + $metadata_agent_config = {}, + $metering_agent_config = {}, + $vpnaas_agent_config = {}, + $plugin_linuxbridge_config = {}, + $plugin_cisco_db_conn_config = {}, + $plugin_cisco_l2network_config = {}, + $plugin_cisco_config = {}, + $plugin_midonet_config = {}, + $plugin_ml2_config = {}, + $plugin_ovs_config = {}, +) { + + validate_hash($server_config) + validate_hash($api_config) + validate_hash($l3_agent_config) + validate_hash($dhcp_agent_config) + validate_hash($lbaas_agent_config) + validate_hash($metadata_agent_config) + validate_hash($metering_agent_config) + validate_hash($vpnaas_agent_config) + validate_hash($plugin_linuxbridge_config) + validate_hash($plugin_cisco_db_conn_config) + validate_hash($plugin_cisco_l2network_config) + validate_hash($plugin_cisco_config) + validate_hash($plugin_midonet_config) + validate_hash($plugin_ml2_config) + validate_hash($plugin_ovs_config) + + create_resources('neutron_config', $server_config) + create_resources('neutron_api_config', $api_config) + create_resources('neutron_l3_agent_config', $l3_agent_config) + create_resources('neutron_dhcp_agent_config', $dhcp_agent_config) + create_resources('neutron_metadata_agent_config', $metadata_agent_config) + create_resources('neutron_metering_agent_config', $metering_agent_config) + create_resources('neutron_vpnaas_agent_config', $vpnaas_agent_config) + create_resources('neutron_plugin_linuxbridge', $plugin_linuxbridge_config) + create_resources('neutron_plugin_cisco_db_conn', $plugin_cisco_db_conn_config) + create_resources('neutron_plugin_cisco_l2network', $plugin_cisco_l2network_config) + create_resources('neutron_plugin_cisco', $plugin_cisco_config) + create_resources('neutron_plugin_midonet', $plugin_midonet_config) + create_resources('neutron_plugin_ml2', $plugin_ml2_config) + create_resources('neutron_plugin_ovs', $plugin_ovs_config) +} diff --git a/3rdparty/modules/neutron/manifests/db/mysql.pp b/3rdparty/modules/neutron/manifests/db/mysql.pp new file mode 100644 index 000000000..9808f75ad --- /dev/null +++ b/3rdparty/modules/neutron/manifests/db/mysql.pp @@ -0,0 +1,61 @@ +# The neutron::db::mysql class creates a MySQL database for neutron. +# It must be used on the MySQL server +# +# == Parameters +# +# [*password*] +# password to connect to the database. Mandatory. +# +# [*dbname*] +# name of the database. Optional. Defaults to neutron. +# +# [*user*] +# user to connect to the database. Optional. Defaults to neutron. +# +# [*host*] +# the default source host user is allowed to connect from. +# Optional. Defaults to 'localhost' +# +# [*allowed_hosts*] +# other hosts the user is allowd to connect from. +# Optional. Defaults to undef. +# +# [*charset*] +# the database charset. Optional. Defaults to 'utf8' +# +# [*collate*] +# the database collation. Optional. Defaults to 'utf8_general_ci' +# +# [*mysql_module*] +# (optional) Deprecated. Does nothing. +# +class neutron::db::mysql ( + $password, + $dbname = 'neutron', + $user = 'neutron', + $host = '127.0.0.1', + $allowed_hosts = undef, + $charset = 'utf8', + $collate = 'utf8_general_ci', + $cluster_id = 'localzone', + $mysql_module = undef, +) { + + if $mysql_module { + warning('The mysql_module parameter is deprecated. The latest 2.x mysql module will be used.') + } + + validate_string($password) + + + ::openstacklib::db::mysql { 'neutron': + user => $user, + password_hash => mysql_password($password), + dbname => $dbname, + host => $host, + charset => $charset, + collate => $collate, + allowed_hosts => $allowed_hosts, + } + ::Openstacklib::Db::Mysql['neutron'] ~> Service <| title == 'neutron-server' |> +} diff --git a/3rdparty/modules/neutron/manifests/init.pp b/3rdparty/modules/neutron/manifests/init.pp new file mode 100644 index 000000000..58e188ad1 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/init.pp @@ -0,0 +1,475 @@ +# == Class: neutron +# +# Installs the neutron package and configures +# /etc/neutron/neutron.conf +# +# === Parameters: +# +# [*enabled*] +# (required) Whether or not to enable the neutron service +# true/false +# +# [*package_ensure*] +# (optional) The state of the package +# Defaults to 'present' +# +# [*verbose*] +# (optional) Verbose logging +# Defaults to False +# +# [*debug*] +# (optional) Print debug messages in the logs +# Defaults to False +# +# [*bind_host*] +# (optional) The IP/interface to bind to +# Defaults to 0.0.0.0 (all interfaces) +# +# [*bind_port*] +# (optional) The port to use +# Defaults to 9696 +# +# [*core_plugin*] +# (optional) Neutron plugin provider +# Defaults to openvswitch +# Could be bigswitch, brocade, cisco, embrane, hyperv, linuxbridge, midonet, ml2, mlnx, nec, nicira, plumgrid, ryu +# +# [*service_plugins*] +# (optional) Advanced service modules. +# Could be an array that can have these elements: +# router, firewall, lbaas, vpnaas, metering +# Defaults to empty +# +# [*auth_strategy*] +# (optional) How to authenticate +# Defaults to 'keystone'. 'noauth' is the only other valid option +# +# [*base_mac*] +# (optional) The MAC address pattern to use. +# Defaults to fa:16:3e:00:00:00 +# +# [*mac_generation_retries*] +# (optional) How many times to try to generate a unique mac +# Defaults to 16 +# +# [*dhcp_lease_duration*] +# (optional) DHCP lease +# Defaults to 86400 seconds +# +# [*dhcp_agents_per_network*] +# (optional) Number of DHCP agents scheduled to host a network. +# This enables redundant DHCP agents for configured networks. +# Defaults to 1 +# +# [*network_device_mtu*] +# (optional) The MTU size for the interfaces managed by neutron +# Defaults to undef +# +# [*dhcp_agent_notification*] +# (optional) Allow sending resource operation notification to DHCP agent. +# Defaults to true +# +# [*allow_bulk*] +# (optional) Enable bulk crud operations +# Defaults to true +# +# [*allow_pagination*] +# (optional) Enable pagination +# Defaults to false +# +# [*allow_sorting*] +# (optional) Enable sorting +# Defaults to false +# +# [*allow_overlapping_ips*] +# (optional) Enables network namespaces +# Defaults to false +# +# [*api_extensions_path*] +# (optional) Specify additional paths for API extensions that the +# module in use needs to load. +# Defaults to undef +# +# [*report_interval*] +# (optional) Seconds between nodes reporting state to server; should be less than +# agent_down_time, best if it is half or less than agent_down_time. +# agent_down_time is a config for neutron-server, set by class neutron::server +# report_interval is a config for neutron agents, set by class neutron +# Defaults to: 30 +# +# [*control_exchange*] +# (optional) What RPC queue/exchange to use +# Defaults to neutron + +# [*rpc_backend*] +# (optional) what rpc/queuing service to use +# Defaults to impl_kombu (rabbitmq) +# +# [*rabbit_password*] +# [*rabbit_host*] +# [*rabbit_port*] +# [*rabbit_user*] +# (optional) Various rabbitmq settings +# +# [*rabbit_hosts*] +# (optional) array of rabbitmq servers for HA. +# A single IP address, such as a VIP, can be used for load-balancing +# multiple RabbitMQ Brokers. +# Defaults to false +# +# [*rabbit_use_ssl*] +# (optional) Connect over SSL for RabbitMQ +# Defaults to false +# +# [*kombu_ssl_ca_certs*] +# (optional) SSL certification authority file (valid only if SSL enabled). +# Defaults to undef +# +# [*kombu_ssl_certfile*] +# (optional) SSL cert file (valid only if SSL enabled). +# Defaults to undef +# +# [*kombu_ssl_keyfile*] +# (optional) SSL key file (valid only if SSL enabled). +# Defaults to undef +# +# [*kombu_ssl_version*] +# (optional) SSL version to use (valid only if SSL enabled). +# Valid values are TLSv1, SSLv23 and SSLv3. SSLv2 may be +# available on some distributions. +# Defaults to 'TLSv1' +# +# [*kombu_reconnect_delay*] +# (optional) The amount of time to wait before attempting to reconnect +# to MQ provider. This is used in some cases where you may need to wait +# for the provider to propery premote the master before attempting to +# reconnect. See https://review.openstack.org/#/c/76686 +# Defaults to '1.0' +# +# [*qpid_hostname*] +# [*qpid_port*] +# [*qpid_username*] +# [*qpid_password*] +# [*qpid_heartbeat*] +# [*qpid_protocol*] +# [*qpid_tcp_nodelay*] +# [*qpid_reconnect*] +# [*qpid_reconnect_timeout*] +# [*qpid_reconnect_limit*] +# [*qpid_reconnect_interval*] +# [*qpid_reconnect_interval_min*] +# [*qpid_reconnect_interval_max*] +# (optional) various QPID options +# +# [*use_ssl*] +# (optinal) Enable SSL on the API server +# Defaults to false, not set +# +# [*cert_file*] +# (optinal) certificate file to use when starting api server securely +# defaults to false, not set +# +# [*key_file*] +# (optional) Private key file to use when starting API server securely +# Defaults to false, not set +# +# [*ca_file*] +# (optional) CA certificate file to use to verify connecting clients +# Defaults to false, not set +# +# [*use_syslog*] +# (optional) Use syslog for logging +# Defaults to false +# +# [*log_facility*] +# (optional) Syslog facility to receive log lines +# Defaults to LOG_USER +# +# [*log_file*] +# (optional) Where to log +# Defaults to false +# +# [*log_dir*] +# (optional) Directory where logs should be stored +# If set to boolean false, it will not log to any directory +# Defaults to /var/log/neutron +# +class neutron ( + $enabled = true, + $package_ensure = 'present', + $verbose = false, + $debug = false, + $bind_host = '0.0.0.0', + $bind_port = '9696', + $core_plugin = 'openvswitch', + $service_plugins = undef, + $auth_strategy = 'keystone', + $base_mac = 'fa:16:3e:00:00:00', + $mac_generation_retries = 16, + $dhcp_lease_duration = 86400, + $dhcp_agents_per_network = 1, + $network_device_mtu = undef, + $dhcp_agent_notification = true, + $allow_bulk = true, + $allow_pagination = false, + $allow_sorting = false, + $allow_overlapping_ips = false, + $api_extensions_path = undef, + $root_helper = 'sudo neutron-rootwrap /etc/neutron/rootwrap.conf', + $report_interval = '30', + $control_exchange = 'neutron', + $rpc_backend = 'neutron.openstack.common.rpc.impl_kombu', + $rabbit_password = false, + $rabbit_host = 'localhost', + $rabbit_hosts = false, + $rabbit_port = '5672', + $rabbit_user = 'guest', + $rabbit_virtual_host = '/', + $rabbit_use_ssl = false, + $kombu_ssl_ca_certs = undef, + $kombu_ssl_certfile = undef, + $kombu_ssl_keyfile = undef, + $kombu_ssl_version = 'TLSv1', + $kombu_reconnect_delay = '1.0', + $qpid_hostname = 'localhost', + $qpid_port = '5672', + $qpid_username = 'guest', + $qpid_password = 'guest', + $qpid_heartbeat = 60, + $qpid_protocol = 'tcp', + $qpid_tcp_nodelay = true, + $qpid_reconnect = true, + $qpid_reconnect_timeout = 0, + $qpid_reconnect_limit = 0, + $qpid_reconnect_interval_min = 0, + $qpid_reconnect_interval_max = 0, + $qpid_reconnect_interval = 0, + $use_ssl = false, + $cert_file = false, + $key_file = false, + $ca_file = false, + $use_syslog = false, + $log_facility = 'LOG_USER', + $log_file = false, + $log_dir = '/var/log/neutron', +) { + + include neutron::params + + Package['neutron'] -> Neutron_config<||> + Package['neutron'] -> Nova_Admin_Tenant_Id_Setter<||> + + if $use_ssl { + if !$cert_file { + fail('The cert_file parameter is required when use_ssl is set to true') + } + if !$key_file { + fail('The key_file parameter is required when use_ssl is set to true') + } + } + + if $ca_file and !$use_ssl { + fail('The ca_file parameter requires that use_ssl to be set to true') + } + + if $kombu_ssl_ca_certs and !$rabbit_use_ssl { + fail('The kombu_ssl_ca_certs parameter requires rabbit_use_ssl to be set to true') + } + if $kombu_ssl_certfile and !$rabbit_use_ssl { + fail('The kombu_ssl_certfile parameter requires rabbit_use_ssl to be set to true') + } + if $kombu_ssl_keyfile and !$rabbit_use_ssl { + fail('The kombu_ssl_keyfile parameter requires rabbit_use_ssl to be set to true') + } + if ($kombu_ssl_certfile and !$kombu_ssl_keyfile) or ($kombu_ssl_keyfile and !$kombu_ssl_certfile) { + fail('The kombu_ssl_certfile and kombu_ssl_keyfile parameters must be used together') + } + + File { + require => Package['neutron'], + owner => 'root', + group => 'neutron', + mode => '0640', + } + + file { '/etc/neutron': + ensure => directory, + mode => '0750', + } + + file { '/etc/neutron/neutron.conf': } + + package { 'neutron': + ensure => $package_ensure, + name => $::neutron::params::package_name, + } + + neutron_config { + 'DEFAULT/verbose': value => $verbose; + 'DEFAULT/debug': value => $debug; + 'DEFAULT/bind_host': value => $bind_host; + 'DEFAULT/bind_port': value => $bind_port; + 'DEFAULT/auth_strategy': value => $auth_strategy; + 'DEFAULT/core_plugin': value => $core_plugin; + 'DEFAULT/base_mac': value => $base_mac; + 'DEFAULT/mac_generation_retries': value => $mac_generation_retries; + 'DEFAULT/dhcp_lease_duration': value => $dhcp_lease_duration; + 'DEFAULT/dhcp_agents_per_network': value => $dhcp_agents_per_network; + 'DEFAULT/dhcp_agent_notification': value => $dhcp_agent_notification; + 'DEFAULT/allow_bulk': value => $allow_bulk; + 'DEFAULT/allow_pagination': value => $allow_pagination; + 'DEFAULT/allow_sorting': value => $allow_sorting; + 'DEFAULT/allow_overlapping_ips': value => $allow_overlapping_ips; + 'DEFAULT/control_exchange': value => $control_exchange; + 'DEFAULT/rpc_backend': value => $rpc_backend; + 'DEFAULT/api_extensions_path': value => $api_extensions_path; + 'agent/root_helper': value => $root_helper; + 'agent/report_interval': value => $report_interval; + } + + if $log_file { + neutron_config { + 'DEFAULT/log_file': value => $log_file; + 'DEFAULT/log_dir': value => $log_dir; + } + } else { + if $log_dir { + neutron_config { + 'DEFAULT/log_dir': value => $log_dir; + 'DEFAULT/log_file': ensure => absent; + } + } else { + neutron_config { + 'DEFAULT/log_dir': ensure => absent; + 'DEFAULT/log_file': ensure => absent; + } + } + } + + if $network_device_mtu { + neutron_config { + 'DEFAULT/network_device_mtu': value => $network_device_mtu; + } + } else { + neutron_config { + 'DEFAULT/network_device_mtu': ensure => absent; + } + } + + + if $service_plugins { + if is_array($service_plugins) { + neutron_config { 'DEFAULT/service_plugins': value => join($service_plugins, ',') } + } else { + fail('service_plugins should be an array.') + } + } + + if $rpc_backend == 'neutron.openstack.common.rpc.impl_kombu' { + if ! $rabbit_password { + fail('When rpc_backend is rabbitmq, you must set rabbit password') + } + if $rabbit_hosts { + neutron_config { 'DEFAULT/rabbit_hosts': value => join($rabbit_hosts, ',') } + neutron_config { 'DEFAULT/rabbit_ha_queues': value => true } + } else { + neutron_config { 'DEFAULT/rabbit_host': value => $rabbit_host } + neutron_config { 'DEFAULT/rabbit_port': value => $rabbit_port } + neutron_config { 'DEFAULT/rabbit_hosts': value => "${rabbit_host}:${rabbit_port}" } + neutron_config { 'DEFAULT/rabbit_ha_queues': value => false } + } + + neutron_config { + 'DEFAULT/rabbit_userid': value => $rabbit_user; + 'DEFAULT/rabbit_password': value => $rabbit_password, secret => true; + 'DEFAULT/rabbit_virtual_host': value => $rabbit_virtual_host; + 'DEFAULT/rabbit_use_ssl': value => $rabbit_use_ssl; + 'DEFAULT/kombu_reconnect_delay': value => $kombu_reconnect_delay; + } + + if $rabbit_use_ssl { + + if $kombu_ssl_ca_certs { + neutron_config { 'DEFAULT/kombu_ssl_ca_certs': value => $kombu_ssl_ca_certs; } + } else { + neutron_config { 'DEFAULT/kombu_ssl_ca_certs': ensure => absent; } + } + + if $kombu_ssl_certfile or $kombu_ssl_keyfile { + neutron_config { + 'DEFAULT/kombu_ssl_certfile': value => $kombu_ssl_certfile; + 'DEFAULT/kombu_ssl_keyfile': value => $kombu_ssl_keyfile; + } + } else { + neutron_config { + 'DEFAULT/kombu_ssl_certfile': ensure => absent; + 'DEFAULT/kombu_ssl_keyfile': ensure => absent; + } + } + + if $kombu_ssl_version { + neutron_config { 'DEFAULT/kombu_ssl_version': value => $kombu_ssl_version; } + } else { + neutron_config { 'DEFAULT/kombu_ssl_version': ensure => absent; } + } + + } else { + neutron_config { + 'DEFAULT/kombu_ssl_ca_certs': ensure => absent; + 'DEFAULT/kombu_ssl_certfile': ensure => absent; + 'DEFAULT/kombu_ssl_keyfile': ensure => absent; + 'DEFAULT/kombu_ssl_version': ensure => absent; + } + } + + } + + if $rpc_backend == 'neutron.openstack.common.rpc.impl_qpid' { + neutron_config { + 'DEFAULT/qpid_hostname': value => $qpid_hostname; + 'DEFAULT/qpid_port': value => $qpid_port; + 'DEFAULT/qpid_username': value => $qpid_username; + 'DEFAULT/qpid_password': value => $qpid_password, secret => true; + 'DEFAULT/qpid_heartbeat': value => $qpid_heartbeat; + 'DEFAULT/qpid_protocol': value => $qpid_protocol; + 'DEFAULT/qpid_tcp_nodelay': value => $qpid_tcp_nodelay; + 'DEFAULT/qpid_reconnect': value => $qpid_reconnect; + 'DEFAULT/qpid_reconnect_timeout': value => $qpid_reconnect_timeout; + 'DEFAULT/qpid_reconnect_limit': value => $qpid_reconnect_limit; + 'DEFAULT/qpid_reconnect_interval_min': value => $qpid_reconnect_interval_min; + 'DEFAULT/qpid_reconnect_interval_max': value => $qpid_reconnect_interval_max; + 'DEFAULT/qpid_reconnect_interval': value => $qpid_reconnect_interval; + } + } + + # SSL Options + neutron_config { 'DEFAULT/use_ssl' : value => $use_ssl; } + if $use_ssl { + neutron_config { + 'DEFAULT/ssl_cert_file' : value => $cert_file; + 'DEFAULT/ssl_key_file' : value => $key_file; + } + if $ca_file { + neutron_config { 'DEFAULT/ssl_ca_file' : value => $ca_file; } + } else { + neutron_config { 'DEFAULT/ssl_ca_file' : ensure => absent; } + } + } else { + neutron_config { + 'DEFAULT/ssl_cert_file': ensure => absent; + 'DEFAULT/ssl_key_file': ensure => absent; + 'DEFAULT/ssl_ca_file': ensure => absent; + } + } + + if $use_syslog { + neutron_config { + 'DEFAULT/use_syslog': value => true; + 'DEFAULT/syslog_log_facility': value => $log_facility; + } + } else { + neutron_config { + 'DEFAULT/use_syslog': value => false; + } + } +} diff --git a/3rdparty/modules/neutron/manifests/keystone/auth.pp b/3rdparty/modules/neutron/manifests/keystone/auth.pp new file mode 100644 index 000000000..2bc061f42 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/keystone/auth.pp @@ -0,0 +1,130 @@ +# == Class: neutron::keystone::auth +# +# Configures Neutron user, service and endpoint in Keystone. +# +# === Parameters +# +# [*password*] +# (required) Password for Neutron user. +# +# [*auth_name*] +# Username for Neutron service. Defaults to 'neutron'. +# +# [*email*] +# Email for Neutron user. Defaults to 'neutron@localhost'. +# +# [*tenant*] +# Tenant for Neutron user. Defaults to 'services'. +# +# [*configure_endpoint*] +# Should Neutron endpoint be configured? Defaults to 'true'. +# +# [*configure_user*] +# Should the Neutron service user be configured? Defaults to 'true'. +# +# [*configure_user_role*] +# Should the admin role be configured for the service user? +# Defaults to 'true'. +# +# [*service_name*] +# Name of the service. Defaults to the value of auth_name. +# +# [*service_type*] +# Type of service. Defaults to 'network'. +# +# [*public_protocol*] +# Protocol for public endpoint. Defaults to 'http'. +# +# [*public_address*] +# Public address for endpoint. Defaults to '127.0.0.1'. +# +# [*admin_protocol*] +# Protocol for admin endpoint. Defaults to 'http'. +# +# [*admin_address*] +# Admin address for endpoint. Defaults to '127.0.0.1'. +# +# [*internal_protocol*] +# Protocol for internal endpoint. Defaults to 'http'. +# +# [*internal_address*] +# Internal address for endpoint. Defaults to '127.0.0.1'. +# +# [*port*] +# Port for endpoint. Defaults to '9696'. +# +# [*public_port*] +# Port for public endpoint. Defaults to $port. +# +# [*region*] +# Region for endpoint. Defaults to 'RegionOne'. +# +class neutron::keystone::auth ( + $password, + $auth_name = 'neutron', + $email = 'neutron@localhost', + $tenant = 'services', + $configure_endpoint = true, + $configure_user = true, + $configure_user_role = true, + $service_name = undef, + $service_type = 'network', + $public_protocol = 'http', + $public_address = '127.0.0.1', + $admin_protocol = 'http', + $admin_address = '127.0.0.1', + $internal_protocol = 'http', + $internal_address = '127.0.0.1', + $port = '9696', + $public_port = undef, + $region = 'RegionOne' +) { + + if $service_name == undef { + $real_service_name = $auth_name + } else { + $real_service_name = $service_name + } + + if ! $public_port { + $real_public_port = $port + } else { + $real_public_port = $public_port + } + + Keystone_endpoint["${region}/${real_service_name}"] ~> Service <| name == 'neutron-server' |> + + if $configure_user { + keystone_user { $auth_name: + ensure => present, + password => $password, + email => $email, + tenant => $tenant, + } + } + + if $configure_user_role { + Keystone_user_role["${auth_name}@${tenant}"] ~> Service <| name == 'neutron-server' |> + + keystone_user_role { "${auth_name}@${tenant}": + ensure => present, + roles => 'admin', + } + } + + keystone_service { $real_service_name: + ensure => present, + type => $service_type, + description => 'Neutron Networking Service', + } + + if $configure_endpoint { + keystone_endpoint { "${region}/${real_service_name}": + ensure => present, + public_url => "${public_protocol}://${public_address}:${real_public_port}/", + internal_url => "${internal_protocol}://${internal_address}:${port}/", + admin_url => "${admin_protocol}://${admin_address}:${port}/", + } + + } +} diff --git a/3rdparty/modules/neutron/manifests/params.pp b/3rdparty/modules/neutron/manifests/params.pp new file mode 100644 index 000000000..2aa221e91 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/params.pp @@ -0,0 +1,143 @@ +# +class neutron::params { + + if($::osfamily == 'Redhat') { + $nobody_user_group = 'nobody' + + $package_name = 'openstack-neutron' + $server_package = false + $server_service = 'neutron-server' + $client_package = 'python-neutronclient' + + $ml2_server_package = 'openstack-neutron-ml2' + + $ovs_agent_package = false + $ovs_agent_service = 'neutron-openvswitch-agent' + $ovs_server_package = 'openstack-neutron-openvswitch' + $ovs_cleanup_service = 'neutron-ovs-cleanup' + $ovs_package = 'openvswitch' + $libnl_package = 'libnl' + $package_provider = 'rpm' + + $linuxbridge_agent_package = false + $linuxbridge_agent_service = 'neutron-linuxbridge-agent' + $linuxbridge_server_package = 'openstack-neutron-linuxbridge' + $linuxbridge_config_file = '/etc/neutron/plugins/linuxbridge/linuxbridge_conf.ini' + + $sriov_nic_agent_service = 'neutron-sriov-nic-agent' + $sriov_nic_agent_package = 'openstack-neutron-sriov-nic-agent' + + $cisco_server_package = 'openstack-neutron-cisco' + $cisco_config_file = '/etc/neutron/plugins/cisco/cisco_plugins.ini' + $cisco_ml2_config_file = '/etc/neutron/plugins/ml2/ml2_conf_cisco.ini' + + $midonet_server_package = 'python-neutron-plugin-midonet' + $midonet_config_file = '/etc/neutron/plugins/midonet/midonet.ini' + + $nvp_server_package = 'openstack-neutron-nicira' + + $dhcp_agent_package = false + $dhcp_agent_service = 'neutron-dhcp-agent' + + $dnsmasq_packages = ['dnsmasq', 'dnsmasq-utils'] + + $lbaas_agent_package = false + $lbaas_agent_service = 'neutron-lbaas-agent' + + $haproxy_package = 'haproxy' + + $metering_agent_package = 'openstack-neutron-metering-agent' + $metering_agent_service = 'neutron-metering-agent' + + $vpnaas_agent_package = 'openstack-neutron-vpn-agent' + $vpnaas_agent_service = 'neutron-vpn-agent' + if $::operatingsystemrelease =~ /^7.*/ { + $openswan_package = 'libreswan' + } else { + $openswan_package = 'openswan' + } + + $l3_agent_package = false + $l3_agent_service = 'neutron-l3-agent' + + $metadata_agent_service = 'neutron-metadata-agent' + + $cliff_package = 'python-cliff' + + $kernel_headers = "linux-headers-${::kernelrelease}" + + } elsif($::osfamily == 'Debian') { + + $nobody_user_group = 'nogroup' + + $package_name = 'neutron-common' + $server_package = 'neutron-server' + $server_service = 'neutron-server' + $client_package = 'python-neutronclient' + + if $::operatingsystem == 'Ubuntu' { + $ml2_server_package = 'neutron-plugin-ml2' + } else { + $ml2_server_package = false + } + + $ovs_agent_package = 'neutron-plugin-openvswitch-agent' + $ovs_agent_service = 'neutron-plugin-openvswitch-agent' + $ovs_server_package = 'neutron-plugin-openvswitch' + $ovs_cleanup_service = false + $ovs_package = 'openvswitch-switch' + $libnl_package = 'libnl1' + $package_provider = 'dpkg' + + $linuxbridge_agent_package = 'neutron-plugin-linuxbridge-agent' + $linuxbridge_agent_service = 'neutron-plugin-linuxbridge-agent' + $linuxbridge_server_package = 'neutron-plugin-linuxbridge' + $linuxbridge_config_file = '/etc/neutron/plugins/linuxbridge/linuxbridge_conf.ini' + + $sriov_nic_agent_service = 'neutron-plugin-sriov-agent' + $sriov_nic_agent_package = 'neutron-plugin-sriov-agent' + + $cisco_server_package = 'neutron-plugin-cisco' + $cisco_config_file = '/etc/neutron/plugins/cisco/cisco_plugins.ini' + $cisco_ml2_config_file = '/etc/neutron/plugins/ml2/ml2_conf_cisco.ini' + + $midonet_server_package = 'python-neutron-plugin-midonet' + $midonet_config_file = '/etc/neutron/plugins/midonet/midonet.ini' + + $nvp_server_package = 'neutron-plugin-nicira' + + $dhcp_agent_package = 'neutron-dhcp-agent' + $dhcp_agent_service = 'neutron-dhcp-agent' + + $lbaas_agent_package = 'neutron-lbaas-agent' + $lbaas_agent_service = 'neutron-lbaas-agent' + + $haproxy_package = 'haproxy' + + $metering_agent_package = 'neutron-metering-agent' + $metering_agent_service = 'neutron-metering-agent' + + $vpnaas_agent_package = 'neutron-vpn-agent' + $vpnaas_agent_service = 'neutron-vpn-agent' + + $openswan_package = 'openswan' + + $metadata_agent_package = 'neutron-metadata-agent' + $metadata_agent_service = 'neutron-metadata-agent' + + $dnsmasq_packages = ['dnsmasq-base', 'dnsmasq-utils'] + + $isc_dhcp_packages = ['isc-dhcp-server'] + + $l3_agent_package = 'neutron-l3-agent' + $l3_agent_service = 'neutron-l3-agent' + + $cliff_package = 'python-cliff' + $kernel_headers = "linux-headers-${::kernelrelease}" + + } else { + + fail("Unsupported osfamily ${::osfamily}") + + } +} diff --git a/3rdparty/modules/neutron/manifests/plugins/cisco.pp b/3rdparty/modules/neutron/manifests/plugins/cisco.pp new file mode 100644 index 000000000..7ebea6ba6 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/plugins/cisco.pp @@ -0,0 +1,184 @@ + +# +# Configure the cisco neutron plugin +# More info available here: +# https://wiki.openstack.org/wiki/Cisco-neutron +# +# === Parameters +# +# [*database_pass*] +# The password that will be used to connect to the db +# +# [*keystone_password*] +# The password for the supplied username +# +# [*database_name*] +# The name of the db table to use +# Defaults to neutron +# +# [*database_user*] +# The user that will be used to connect to the db +# Defaults to neutron +# +# [*database_host*] +# The address or hostname of the database +# Defaults to 127.0.0.1 +# +# [*keystone_username*] +# The admin username for the plugin to use +# Defaults to neutron +# +# [*keystone_auth_url*] +# The url against which to authenticate +# Defaults to http://127.0.0.1:35357/v2.0/ +# +# [*keystone_tenant*] +# The tenant the supplied user has admin privs in +# Defaults to services +# +# [*vswitch_plugin*] +# (optional) The openvswitch plugin to use +# Defaults to ovs_neutron_plugin.OVSNeutronPluginV2 +# +# [*nexus_plugin*] +# (optional) The nexus plugin to use +# Defaults to undef. This will not set a nexus plugin to use +# Can be set to neutron.plugins.cisco.nexus.cisco_nexus_plugin_v2.NexusPlugin +# +# Other parameters are currently not used by the plugin and +# can be left unchanged, but in grizzly the plugin will fail +# to launch if they are not there. The config for Havana will +# move to a single config file and this will be simplified. + +class neutron::plugins::cisco( + $keystone_password, + $database_pass, + + # Database connection + $database_name = 'neutron', + $database_user = 'neutron', + $database_host = '127.0.0.1', + + # Keystone connection + $keystone_username = 'neutron', + $keystone_tenant = 'services', + $keystone_auth_url = 'http://127.0.0.1:35357/v2.0/', + + $vswitch_plugin = 'neutron.plugins.openvswitch.ovs_neutron_plugin.OVSNeutronPluginV2', + $nexus_plugin = undef, + + # Plugin minimum configuration + $vlan_start = '100', + $vlan_end = '3000', + $vlan_name_prefix = 'q-', + $model_class = 'neutron.plugins.cisco.models.virt_phy_sw_v2.VirtualPhysicalSwitchModelV2', + $max_ports = '100', + $max_port_profiles = '65568', + $manager_class = 'neutron.plugins.cisco.segmentation.l2network_vlan_mgr_v2.L2NetworkVLANMgr', + $max_networks = '65568', + $package_ensure = 'present' +) +{ + Neutron_plugin_cisco<||> ~> Service['neutron-server'] + Neutron_plugin_cisco_db_conn<||> ~> Service['neutron-server'] + Neutron_plugin_cisco_l2network<||> ~> Service['neutron-server'] + + ensure_resource('file', '/etc/neutron/plugins', { + ensure => directory, + owner => 'root', + group => 'neutron', + mode => '0640'} + ) + + ensure_resource('file', '/etc/neutron/plugins/cisco', { + ensure => directory, + owner => 'root', + group => 'neutron', + mode => '0640'} + ) + + # Ensure the neutron package is installed before config is set + # under both RHEL and Ubuntu + if ($::neutron::params::server_package) { + Package['neutron-server'] -> Neutron_plugin_cisco<||> + Package['neutron-server'] -> Neutron_plugin_cisco_db_conn<||> + Package['neutron-server'] -> Neutron_plugin_cisco_l2network<||> + } else { + Package['neutron'] -> Neutron_plugin_cisco<||> + Package['neutron'] -> Neutron_plugin_cisco_db_conn<||> + Package['neutron'] -> Neutron_plugin_cisco_l2network<||> + } + + if $::operatingsystem == 'Ubuntu' { + file_line { '/etc/default/neutron-server:NEUTRON_PLUGIN_CONFIG': + path => '/etc/default/neutron-server', + match => '^NEUTRON_PLUGIN_CONFIG=(.*)$', + line => "NEUTRON_PLUGIN_CONFIG=${::neutron::params::cisco_config_file}", + require => [ Package['neutron-server'], Package['neutron-plugin-cisco'] ], + notify => Service['neutron-server'], + } + } + + package { 'neutron-plugin-cisco': + ensure => $package_ensure, + name => $::neutron::params::cisco_server_package, + } + + + if $nexus_plugin { + neutron_plugin_cisco { + 'PLUGINS/nexus_plugin' : value => $nexus_plugin; + } + } + + if $vswitch_plugin { + neutron_plugin_cisco { + 'PLUGINS/vswitch_plugin' : value => $vswitch_plugin; + } + } + + # neutron-server will crash if the inventory section is empty. + # this is usually used for specifying which physical nexus + # devices are to be used. + neutron_plugin_cisco { + 'INVENTORY/dummy' : value => 'dummy'; + } + + neutron_plugin_cisco_db_conn { + 'DATABASE/name': value => $database_name; + 'DATABASE/user': value => $database_user; + 'DATABASE/pass': value => $database_pass; + 'DATABASE/host': value => $database_host; + } + + neutron_plugin_cisco_l2network { + 'VLANS/vlan_start': value => $vlan_start; + 'VLANS/vlan_end': value => $vlan_end; + 'VLANS/vlan_name_prefix': value => $vlan_name_prefix; + 'MODEL/model_class': value => $model_class; + 'PORTS/max_ports': value => $max_ports; + 'PORTPROFILES/max_port_profiles': value => $max_port_profiles; + 'NETWORKS/max_networks': value => $max_networks; + 'SEGMENTATION/manager_class': value => $manager_class; + } + + neutron_plugin_cisco_credentials { + 'keystone/username': value => $keystone_username; + 'keystone/password': value => $keystone_password, secret => true; + 'keystone/auth_url': value => $keystone_auth_url; + 'keystone/tenant' : value => $keystone_tenant; + } + + # In RH, this link is used to start Neutron process but in Debian, it's used only + # to manage database synchronization. + if defined(File['/etc/neutron/plugin.ini']) { + File <| path == '/etc/neutron/plugin.ini' |> { target => '/etc/neutron/plugins/cisco/cisco_plugins.ini' } + } + else { + file {'/etc/neutron/plugin.ini': + ensure => link, + target => '/etc/neutron/plugins/cisco/cisco_plugins.ini', + require => Package['neutron-plugin-cisco'], + } + } +} diff --git a/3rdparty/modules/neutron/manifests/plugins/linuxbridge.pp b/3rdparty/modules/neutron/manifests/plugins/linuxbridge.pp new file mode 100644 index 000000000..caf4696bc --- /dev/null +++ b/3rdparty/modules/neutron/manifests/plugins/linuxbridge.pp @@ -0,0 +1,73 @@ +# == Class: neutron::plugins::linuxbridge +# +# Setups linuxbridge plugin for neutron server. +# +# === Parameters +# +# [*sql_connection*] +# sql_connection is no longer configured in the plugin.ini. +# Use $connection in the nuetron::server class to configure the SQL +# connection string. +# +# [*network_vlan_ranges*] +# (required) Comma-separated list of [::] +# tuples enumerating ranges of VLAN IDs on named physical networks that are +# available for allocation. +# +# [*tenant_network_type*] +# (optional) Type of network to allocate for tenant networks. +# Defaults to 'vlan'. +# +# [*package_ensure*] +# (optional) Ensure state for package. Defaults to 'present'. +# +class neutron::plugins::linuxbridge ( + $sql_connection = false, + $network_vlan_ranges = 'physnet1:1000:2000', + $tenant_network_type = 'vlan', + $package_ensure = 'present' +) { + + include neutron::params + + Package['neutron'] -> Package['neutron-plugin-linuxbridge'] + Package['neutron-plugin-linuxbridge'] -> Neutron_plugin_linuxbridge<||> + Neutron_plugin_linuxbridge<||> ~> Service<| title == 'neutron-server' |> + Package['neutron-plugin-linuxbridge'] -> Service<| title == 'neutron-server' |> + + if $::operatingsystem == 'Ubuntu' { + file_line { '/etc/default/neutron-server:NEUTRON_PLUGIN_CONFIG': + path => '/etc/default/neutron-server', + match => '^NEUTRON_PLUGIN_CONFIG=(.*)$', + line => "NEUTRON_PLUGIN_CONFIG=${::neutron::params::linuxbridge_config_file}", + require => [ + Package['neutron-plugin-linuxbridge'], + Package['neutron-server'], + ], + notify => Service['neutron-server'], + } + } + + package { 'neutron-plugin-linuxbridge': + ensure => $package_ensure, + name => $::neutron::params::linuxbridge_server_package, + } + + if $sql_connection { + warning('sql_connection is deprecated for connection in the neutron::server class') + } + + neutron_plugin_linuxbridge { + 'VLANS/tenant_network_type': value => $tenant_network_type; + 'VLANS/network_vlan_ranges': value => $network_vlan_ranges; + } + + # In RH, this link is used to start Neutron process but in Debian, it's used only + # to manage database synchronization. + file {'/etc/neutron/plugin.ini': + ensure => link, + target => '/etc/neutron/plugins/linuxbridge/linuxbridge_conf.ini', + require => Package['neutron-plugin-linuxbridge'] + } + +} diff --git a/3rdparty/modules/neutron/manifests/plugins/midonet.pp b/3rdparty/modules/neutron/manifests/plugins/midonet.pp new file mode 100644 index 000000000..54b7c8f71 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/plugins/midonet.pp @@ -0,0 +1,144 @@ +# == Class: midonet::neutron_plugin +# +# Install and configure Midonet Neutron Plugin. Please note that this manifest +# does not install the 'python-neutron-midonet-plugin' package, it only +# configures Neutron to do so needed for this deployment. Check out the +# MidoNet module to do so. +# +# === Parameters +# +# [*midonet_api_ip*] +# IP address of the MidoNet api service +# [*midonet_api_port*] +# IP address of the MidoNet port service. MidoNet runs in a Tomcat, so 8080 +# is used by default. +# [*keystone_username*] +# Username from which midonet api will authenticate against Keystone (neutron +# service is desirable and defaulted) +# [*keystone_password*] +# Password from which midonet api will authenticate against Keystone +# [*keystone_tenant*] +# Tenant from which midonet api will authenticate against Keystone (services +# tenant is desirable and defaulted) +# [*sync_db*] +# Whether 'midonet-db-manage' should run to create and/or syncrhonize the database +# with MidoNet specific tables. Defaults to false +# +# === Examples +# +# An example call would be: +# +# class {'neutron:plugins::midonet': +# midonet_api_ip => '23.123.5.32', +# midonet_api_port => '8080', +# keystone_username => 'neutron', +# keystone_password => '32kjaxT0k3na', +# keystone_tenant => 'services', +# sync_db => true +# } +# +# You can alternatively use the Hiera's yaml style: +# neutron::plugin::midonet::midonet_api_ip: '23.213.5.32' +# neutron::plugin::midonet::port: '8080' +# neutron::plugin::midonet::keystone_username: 'neutron' +# neutron::plugin::midonet::keystone_password: '32.kjaxT0k3na' +# neutron::plugin::midonet::keystone_tenant: 'services' +# neutron::plugin::midonet::sync_db: true +# +# === Authors +# +# Midonet (http://MidoNet.org) +# +# === Copyright +# +# Copyright (c) 2015 Midokura SARL, All Rights Reserved. +# +# 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 neutron::plugins::midonet ( + $midonet_api_ip = '127.0.0.1', + $midonet_api_port = '8080', + $keystone_username = 'neutron', + $keystone_password = undef, + $keystone_tenant = 'services', + $sync_db = false +) { + + include ::neutron::params + + Neutron_plugin_midonet<||> ~> Service['neutron-server'] + + ensure_resource('file', '/etc/neutron/plugins/midonet', { + ensure => directory, + owner => 'root', + group => 'neutron', + mode => '0640'} + ) + + # Ensure the neutron package is installed before config is set + # under both RHEL and Ubuntu + if ($::neutron::params::server_package) { + Package['neutron-server'] -> Neutron_plugin_midonet<||> + } else { + Package['neutron'] -> Neutron_plugin_midonet<||> + } + + # Although this manifest does not install midonet plugin package because it + # is not available in common distro repos, this statement forces you to + # have an orchestrator/wrapper manifest that does that job. + Package[$::neutron::params::midonet_server_package] -> Neutron_plugin_midonet<||> + + neutron_plugin_midonet { + 'MIDONET/midonet_uri': value => "http://${midonet_api_ip}:${midonet_api_port}/midonet-api"; + 'MIDONET/username': value => $keystone_username; + 'MIDONET/password': value => $keystone_password, secret =>true; + 'MIDONET/project_id': value => $keystone_tenant; + } + + if $::osfamily == 'Debian' { + file_line { '/etc/default/neutron-server:NEUTRON_PLUGIN_CONFIG': + path => '/etc/default/neutron-server', + match => '^NEUTRON_PLUGIN_CONFIG=(.*)$', + line => "NEUTRON_PLUGIN_CONFIG=${::neutron::params::midonet_config_file}", + require => [ Package['neutron-server'], Package[$::neutron::params::midonet_server_package] ], + notify => Service['neutron-server'], + } + } + + # In RH, this link is used to start Neutron process but in Debian, it's used only + # to manage database synchronization. + if defined(File['/etc/neutron/plugin.ini']) { + File <| path == '/etc/neutron/plugin.ini' |> { target => $::neutron::params::midonet_config_file } + } + else { + file {'/etc/neutron/plugin.ini': + ensure => link, + target => $::neutron::params::midonet_config_file, + require => Package[$::neutron::params::midonet_server_package] + } + } + + if $sync_db { + + Package<| title == $::neutron::params::midonet_server_package |> ~> Exec['midonet-db-sync'] + + exec { 'midonet-db-sync': + command => 'midonet-db-manage --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugin.ini upgrade head', + path => '/usr/bin', + before => Service['neutron-server'], + subscribe => Neutron_config['database/connection'], + refreshonly => true + } + } +} + diff --git a/3rdparty/modules/neutron/manifests/plugins/ml2.pp b/3rdparty/modules/neutron/manifests/plugins/ml2.pp new file mode 100644 index 000000000..3c81794df --- /dev/null +++ b/3rdparty/modules/neutron/manifests/plugins/ml2.pp @@ -0,0 +1,182 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# Configure the neutron server to use the ML2 plugin. +# This configures the plugin for the API server, but does nothing +# about configuring the agents that must also run and share a config +# file with the OVS plugin if both are on the same machine. +# +# === Parameters +# +# [*type_drivers*] +# (optional) List of network type driver entrypoints to be loaded +# from the neutron.ml2.type_drivers namespace. +# Could be an array that can have these elements: +# local, flat, vlan, gre, vxlan +# Defaults to ['local', 'flat', 'vlan', 'gre', 'vxlan']. +# +# [*tenant_network_types*] +# (optional) Ordered list of network_types to allocate as tenant networks. +# The value 'local' is only useful for single-box testing +# but provides no connectivity between hosts. +# Should be an array that can have these elements: +# local, flat, vlan, gre, vxlan +# Defaults to ['local', 'flat', 'vlan', 'gre', 'vxlan']. +# +# [*mechanism_drivers*] +# (optional) An ordered list of networking mechanism driver +# entrypoints to be loaded from the neutron.ml2.mechanism_drivers namespace. +# Should be an array that can have these elements: +# logger, test, linuxbridge, openvswitch, hyperv, ncs, arista, cisco_nexus, +# l2population, sriovnicswitch +# Default to ['openvswitch', 'linuxbridge']. +# +# [*flat_networks*] +# (optional) List of physical_network names with which flat networks +# can be created. Use * to allow flat networks with arbitrary +# physical_network names. +# Should be an array. +# Default to *. +# +# [*network_vlan_ranges*] +# (optional) List of :: or +# specifying physical_network names +# usable for VLAN provider and tenant networks, as +# well as ranges of VLAN tags on each available for +# allocation to tenant networks. +# Should be an array with vlan_min = 1 & vlan_max = 4094 (IEEE 802.1Q) +# Default to empty. +# +# [*tunnel_id_ranges*] +# (optional) Comma-separated list of : tuples +# enumerating ranges of GRE tunnel IDs that are +# available for tenant network allocation +# Should be an array with tun_max +1 - tun_min > 1000000 +# Default to empty. +# +# [*vxlan_group*] +# (optional) Multicast group for VXLAN. +# Multicast group for VXLAN. If unset, disables VXLAN enable sending allocate +# broadcast traffic to this multicast group. When left unconfigured, will +# disable multicast VXLAN mode +# Should be an Multicast IP (v4 or v6) address. +# Default to 'None'. +# +# [*vni_ranges*] +# (optional) Comma-separated list of : tuples +# enumerating ranges of VXLAN VNI IDs that are +# available for tenant network allocation. +# Min value is 0 and Max value is 16777215. +# Default to empty. +# +# [*enable_security_group*] +# (optional) Controls if neutron security group is enabled or not. +# It should be false when you use nova security group. +# Defaults to true. +# +# [*supported_pci_vendor_devs*] +# (optional) Supported PCI vendor devices, defined by +# vendor_id:product_id according to the PCI ID +# Repository. Should be an array of devices. +# Defaults to ['15b3:1004', '8086:10ca'] (Intel & Mellanox SR-IOV capable NICs) +# +# [*sriov_agent_required*] +# (optional) SRIOV neutron agent is required for port binding. +# Only set to true if SRIOV network adapters support VF link state setting +# and if admin state management is desired. +# Defaults to false. +# + +class neutron::plugins::ml2 ( + $type_drivers = ['local', 'flat', 'vlan', 'gre', 'vxlan'], + $tenant_network_types = ['local', 'flat', 'vlan', 'gre', 'vxlan'], + $mechanism_drivers = ['openvswitch', 'linuxbridge'], + $flat_networks = ['*'], + $network_vlan_ranges = ['physnet1:1000:2999'], + $tunnel_id_ranges = ['20:100'], + $vxlan_group = '224.0.0.1', + $vni_ranges = ['10:100'], + $enable_security_group = true, + $package_ensure = 'present', + $supported_pci_vendor_devs = ['15b3:1004', '8086:10ca'], + $sriov_agent_required = false, +) { + + include neutron::params + + Neutron_plugin_ml2<||> ~> Service<| title == 'neutron-server' |> + + validate_array($mechanism_drivers) + if ! $mechanism_drivers { + warning('Without networking mechanism driver, ml2 will not communicate with L2 agents') + } + + if $::operatingsystem == 'Ubuntu' { + file_line { '/etc/default/neutron-server:NEUTRON_PLUGIN_CONFIG': + path => '/etc/default/neutron-server', + match => '^NEUTRON_PLUGIN_CONFIG=(.*)$', + line => 'NEUTRON_PLUGIN_CONFIG=/etc/neutron/plugin.ini', + require => File['/etc/neutron/plugin.ini'], + } + Package<| title == 'neutron-server' |> + -> File_line['/etc/default/neutron-server:NEUTRON_PLUGIN_CONFIG'] + ~> Service<| title == 'neutron-server' |> + } + + # In RH, the link is used to start Neutron process but in Debian, it's used only + # to manage database synchronization. + file {'/etc/neutron/plugin.ini': + ensure => link, + target => '/etc/neutron/plugins/ml2/ml2_conf.ini' + } + + # Some platforms do not have a dedicated ml2 plugin package + if $::neutron::params::ml2_server_package { + package { 'neutron-plugin-ml2': + ensure => $package_ensure, + name => $::neutron::params::ml2_server_package, + } + Package['neutron-plugin-ml2'] -> Neutron_plugin_ml2<||> + Package['neutron-plugin-ml2'] -> File['/etc/neutron/plugin.ini'] + } else { + Package <| title == 'neutron-server' |> -> Neutron_plugin_ml2<||> + Package['neutron'] -> File['/etc/neutron/plugin.ini'] + } + + neutron::plugins::ml2::type_driver { $type_drivers: + flat_networks => $flat_networks, + tunnel_id_ranges => $tunnel_id_ranges, + network_vlan_ranges => $network_vlan_ranges, + vni_ranges => $vni_ranges, + vxlan_group => $vxlan_group, + } + + neutron::plugins::ml2::mech_driver { $mechanism_drivers: + supported_pci_vendor_devs => $supported_pci_vendor_devs, + sriov_agent_required => $sriov_agent_required, + } + + neutron_plugin_ml2 { + 'ml2/type_drivers': value => join($type_drivers, ','); + 'ml2/tenant_network_types': value => join($tenant_network_types, ','); + 'ml2/mechanism_drivers': value => join($mechanism_drivers, ','); + 'securitygroup/enable_security_group': value => $enable_security_group; + } + + Neutron_plugin_ml2<||> ~> Exec<| title == 'neutron-db-sync' |> + +} diff --git a/3rdparty/modules/neutron/manifests/plugins/ml2/cisco/nexus.pp b/3rdparty/modules/neutron/manifests/plugins/ml2/cisco/nexus.pp new file mode 100644 index 000000000..ab034ac6a --- /dev/null +++ b/3rdparty/modules/neutron/manifests/plugins/ml2/cisco/nexus.pp @@ -0,0 +1,48 @@ +# +# Configure the Mech Driver for cisco neutron plugin +# More info available here: +# https://wiki.openstack.org/wiki/Neutron/ML2/MechCiscoNexus +# +# === Parameters +# +# [*neutron_config*] +# Neutron switch configuration for ml2_cisco_conf.ini +# Example nexus config format: +# { 'switch_hostname' => {'username' => 'admin', +# 'ssh_port' => 22, +# 'password' => "password", +# 'ip_address' => "172.18.117.28", +# 'servers' => { +# 'control01' => "portchannel:20", +# 'control02' => "portchannel:10" +# }}} +# + +class neutron::plugins::ml2::cisco::nexus ( + $nexus_config = undef, +) +{ + + if !$nexus_config { + fail('No nexus config specified') + } + + # For Ubuntu: This package is not available upstream + # Please use the source from: + # https://launchpad.net/~cisco-openstack/+archive/python-ncclient + # and install it manually + package { 'python-ncclient': + ensure => installed, + } ~> Service['neutron-server'] + + Neutron_plugin_ml2<||> -> + file { $::neutron::params::cisco_ml2_config_file: + owner => 'root', + group => 'root', + content => template('neutron/ml2_conf_cisco.ini.erb'), + } ~> Service['neutron-server'] + + create_resources(neutron::plugins::ml2::cisco::nexus_creds, $nexus_config) + +} + diff --git a/3rdparty/modules/neutron/manifests/plugins/ml2/cisco/nexus_creds.pp b/3rdparty/modules/neutron/manifests/plugins/ml2/cisco/nexus_creds.pp new file mode 100644 index 000000000..16c262cb0 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/plugins/ml2/cisco/nexus_creds.pp @@ -0,0 +1,31 @@ +# +# Configure the Mech Driver for cisco neutron plugin +# More info available here: +# https://wiki.openstack.org/wiki/Neutron/ML2/MechCiscoNexus +# +# +# neutron::plugins::ml2::cisco::nexus_creds used by +# neutron::plugins::ml2::cisco::nexus +# + +define neutron::plugins::ml2::cisco::nexus_creds( + $username, + $password, + $servers, + $ip_address, + $ssh_port +) { + + file {'/var/lib/neutron/.ssh': + ensure => directory, + owner => 'neutron', + require => Package['neutron-server'] + } + + exec {'nexus_creds': + unless => "/bin/cat /var/lib/neutron/.ssh/known_hosts | /bin/grep ${username}", + command => "/usr/bin/ssh-keyscan -t rsa ${ip_address} >> /var/lib/neutron/.ssh/known_hosts", + user => 'neutron', + require => [Package['neutron-server'], File['/var/lib/neutron/.ssh']] + } +} diff --git a/3rdparty/modules/neutron/manifests/plugins/ml2/mech_driver.pp b/3rdparty/modules/neutron/manifests/plugins/ml2/mech_driver.pp new file mode 100644 index 000000000..f2963cf7e --- /dev/null +++ b/3rdparty/modules/neutron/manifests/plugins/ml2/mech_driver.pp @@ -0,0 +1,31 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# neutron::plugins::ml2::mech_driver used by neutron::plugins::ml2 +# + +define neutron::plugins::ml2::mech_driver ( + $supported_pci_vendor_devs, + $sriov_agent_required, +){ + if ($name == 'sriovnicswitch') { + neutron_plugin_ml2 { + 'ml2_sriov/supported_pci_vendor_dev': value => join($supported_pci_vendor_devs, ','); + 'ml2_sriov/agent_required': value => $sriov_agent_required; + } + } +} diff --git a/3rdparty/modules/neutron/manifests/plugins/ml2/type_driver.pp b/3rdparty/modules/neutron/manifests/plugins/ml2/type_driver.pp new file mode 100644 index 000000000..af50157a9 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/plugins/ml2/type_driver.pp @@ -0,0 +1,90 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# neutron::plugins::ml2::type_driver used by neutron::plugins::ml2 +# + +define neutron::plugins::ml2::type_driver ( + $flat_networks, + $tunnel_id_ranges, + $network_vlan_ranges, + $vni_ranges, + $vxlan_group +){ + if ($name == 'flat') { + neutron_plugin_ml2 { + 'ml2_type_flat/flat_networks': value => join($flat_networks, ','); + } + } + elsif ($name == 'gre') { + # tunnel_id_ranges is required in gre + if ! $tunnel_id_ranges { + fail('when gre is part of type_drivers, tunnel_id_ranges should be given.') + } + + validate_tunnel_id_ranges($tunnel_id_ranges) + + neutron_plugin_ml2 { + 'ml2_type_gre/tunnel_id_ranges': value => join($tunnel_id_ranges, ','); + } + } + elsif ($name == 'vlan') { + # network_vlan_ranges is required in vlan + if ! $network_vlan_ranges { + fail('when vlan is part of type_drivers, network_vlan_ranges should be given.') + } + + validate_network_vlan_ranges($network_vlan_ranges) + + neutron_plugin_ml2 { + 'ml2_type_vlan/network_vlan_ranges': value => join($network_vlan_ranges, ','); + } + } + elsif ($name == 'vxlan') { + # vni_ranges and vxlan_group are required in vxlan + if (! $vni_ranges) or (! $vxlan_group) { + fail('when vxlan is part of type_drivers, vni_ranges and vxlan_group should be given.') + } + # test multicast ip address (ipv4 else ipv6): + case $vxlan_group { + /^2[\d.]+$/: { + case $vxlan_group { + /^(22[4-9]|23[0-9])\.(\d+)\.(\d+)\.(\d+)$/: { } + default: { } + } + } + /^ff[\d.]+$/: { } + default: { + fail("${vxlan_group} is not valid for vxlan_group.") + } + } + + validate_vni_ranges($vni_ranges) + + neutron_plugin_ml2 { + 'ml2_type_vxlan/vxlan_group': value => $vxlan_group; + 'ml2_type_vxlan/vni_ranges': value => join($vni_ranges, ','); + } + } + elsif ($name == 'local') { + warning('local type_driver is useful only for single-box, because it provides no connectivity between hosts') + } + else { + # detect an invalid type_drivers value + fail('type_driver unknown.') + } +} diff --git a/3rdparty/modules/neutron/manifests/plugins/nvp.pp b/3rdparty/modules/neutron/manifests/plugins/nvp.pp new file mode 100644 index 000000000..50d469f3f --- /dev/null +++ b/3rdparty/modules/neutron/manifests/plugins/nvp.pp @@ -0,0 +1,73 @@ +# +# Configure the Nicira NVP plugin for neutron. +# +# === Parameters +# +# [*nvp_controllers*] +# The password for connection to VMware vCenter server. +# +# [*nvp_user*] +# The user name for NVP controller. +# +# [*nvp_password*] +# The password for NVP controller +# +# [*default_tz_uuid*] +# UUID of the pre-existing default NVP Transport zone to be used for creating +# tunneled isolated "Neutron" networks. This option MUST be specified. +# +# [*default_l3_gw_service_uuid*] +# (Optional) UUID for the default l3 gateway service to use with this cluster. +# To be specified if planning to use logical routers with external gateways. +# Defaults to None. +# +class neutron::plugins::nvp ( + $default_tz_uuid, + $nvp_controllers, + $nvp_user, + $nvp_password, + $default_l3_gw_service_uuid = undef, + $package_ensure = 'present' +) { + + include neutron::params + + Package['neutron'] -> Package['neutron-plugin-nvp'] + Package['neutron-plugin-nvp'] -> Neutron_plugin_nvp<||> + Neutron_plugin_nvp<||> ~> Service<| title == 'neutron-server' |> + Package['neutron-plugin-nvp'] -> Service<| title == 'neutron-server' |> + + package { 'neutron-plugin-nvp': + ensure => $package_ensure, + name => $::neutron::params::nvp_server_package + } + + validate_array($nvp_controllers) + + neutron_plugin_nvp { + 'DEFAULT/default_tz_uuid': value => $default_tz_uuid; + 'DEFAULT/nvp_controllers': value => join($nvp_controllers, ','); + 'DEFAULT/nvp_user': value => $nvp_user; + 'DEFAULT/nvp_password': value => $nvp_password, secret => true; + 'nvp/metadata_mode': value => 'access_network'; + } + + if($default_l3_gw_service_uuid) { + neutron_plugin_nvp { + 'DEFAULT/default_l3_gw_service_uuid': value => $default_l3_gw_service_uuid; + } + } + + if $::neutron::core_plugin != 'neutron.plugins.nicira.NeutronPlugin.NvpPluginV2' { + fail('nvp plugin should be the core_plugin in neutron.conf') + } + + # In RH, this link is used to start Neutron process but in Debian, it's used only + # to manage database synchronization. + file {'/etc/neutron/plugin.ini': + ensure => link, + target => '/etc/neutron/plugins/nicira/nvp.ini', + require => Package['neutron-plugin-nvp'] + } + +} diff --git a/3rdparty/modules/neutron/manifests/plugins/ovs.pp b/3rdparty/modules/neutron/manifests/plugins/ovs.pp new file mode 100644 index 000000000..4c4be3504 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/plugins/ovs.pp @@ -0,0 +1,105 @@ +# Configure the neutron server to use the OVS plugin. +# This configures the plugin for the API server, but does nothing +# about configuring the agents that must also run and share a config +# file with the OVS plugin if both are on the same machine. +# +# === Parameters +# +class neutron::plugins::ovs ( + $package_ensure = 'present', + $sql_connection = false, + $sql_max_retries = false, + $sql_idle_timeout = false, + $reconnect_interval = false, + $tenant_network_type = 'vlan', + # NB: don't need tunnel ID range when using VLANs, + # *but* you do need the network vlan range regardless of type, + # because the list of networks there is still important + # even if the ranges aren't specified + # if type is vlan or flat, a default of physnet1:1000:2000 is used + # otherwise this will not be set by default. + $network_vlan_ranges = undef, + $tunnel_id_ranges = '1:1000', + $vxlan_udp_port = 4789 +) { + + include neutron::params + + Package['neutron'] -> Package['neutron-plugin-ovs'] + Package['neutron-plugin-ovs'] -> Neutron_plugin_ovs<||> + Neutron_plugin_ovs<||> ~> Service<| title == 'neutron-server' |> + Package['neutron-plugin-ovs'] -> Service<| title == 'neutron-server' |> + + if ! defined(Package['neutron-plugin-ovs']) { + package { 'neutron-plugin-ovs': + ensure => $package_ensure, + name => $::neutron::params::ovs_server_package, + } + } + + if $sql_connection { + warning('sql_connection is deprecated for connection in the neutron::server class') + } + + if $sql_max_retries { + warning('sql_max_retries is deprecated for max_retries in the neutron::server class') + } + + if $sql_idle_timeout { + warning('sql_idle_timeout is deprecated for idle_timeout in the neutron::server class') + } + + if $reconnect_interval { + warning('reconnect_interval is deprecated for retry_interval in the neutron::server class') + } + + neutron_plugin_ovs { + 'OVS/tenant_network_type': value => $tenant_network_type; + } + + if $tenant_network_type in ['gre', 'vxlan'] { + validate_tunnel_id_ranges($tunnel_id_ranges) + neutron_plugin_ovs { + # this is set by the plugin and the agent - since the plugin node has the agent installed + # we rely on it setting it. + # TODO(ijw): do something with a virtualised node + # 'OVS/enable_tunneling': value => 'True'; + 'OVS/tunnel_id_ranges': value => $tunnel_id_ranges; + 'OVS/tunnel_type': value => $tenant_network_type; + } + } + + validate_vxlan_udp_port($vxlan_udp_port) + neutron_plugin_ovs { 'OVS/vxlan_udp_port': value => $vxlan_udp_port; } + + if ! $network_vlan_ranges { + # If the user hasn't specified vlan_ranges, fail for the modes where + # it is required, otherwise keep it absent + if $tenant_network_type in ['vlan', 'flat'] { + fail('When using the vlan network type, network_vlan_ranges is required') + } else { + neutron_plugin_ovs { 'OVS/network_vlan_ranges': ensure => absent } + } + } else { + # This might be set by the user for the gre or vxlan case where + # provider networks are in use + if !is_array($network_vlan_ranges) { + $arr_network_vlan_ranges = strip(split($network_vlan_ranges, ',')) + } else { + $arr_network_vlan_ranges = $network_vlan_ranges + } + + validate_network_vlan_ranges($arr_network_vlan_ranges) + neutron_plugin_ovs { + 'OVS/network_vlan_ranges': value => join($arr_network_vlan_ranges, ','); + } + } + + # In RH, this link is used to start Neutron process but in Debian, it's used only + # to manage database synchronization. + file {'/etc/neutron/plugin.ini': + ensure => link, + target => '/etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini', + require => Package['neutron-plugin-ovs'] + } +} diff --git a/3rdparty/modules/neutron/manifests/plugins/ovs/bridge.pp b/3rdparty/modules/neutron/manifests/plugins/ovs/bridge.pp new file mode 100644 index 000000000..6de6ff683 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/plugins/ovs/bridge.pp @@ -0,0 +1,11 @@ +# +define neutron::plugins::ovs::bridge { + $mapping = split($name, ':') + $bridge = $mapping[1] + + vs_bridge {$bridge: + ensure => present, + external_ids => "bridge-id=${bridge}" + } +} + diff --git a/3rdparty/modules/neutron/manifests/plugins/ovs/port.pp b/3rdparty/modules/neutron/manifests/plugins/ovs/port.pp new file mode 100644 index 000000000..96b1c5cc8 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/plugins/ovs/port.pp @@ -0,0 +1,9 @@ +# +define neutron::plugins::ovs::port { + $mapping = split($name, ':') + vs_port {$mapping[1]: + ensure => present, + bridge => $mapping[0] + } +} + diff --git a/3rdparty/modules/neutron/manifests/policy.pp b/3rdparty/modules/neutron/manifests/policy.pp new file mode 100644 index 000000000..54a89989b --- /dev/null +++ b/3rdparty/modules/neutron/manifests/policy.pp @@ -0,0 +1,39 @@ +# == Class: neutron::policy +# +# Configure the neutron policies +# +# === Parameters +# +# [*policies*] +# (optional) Set of policies to configure for neutron +# Example : +# { +# 'neutron-context_is_admin' => { +# 'key' => 'context_is_admin', +# 'value' => 'true' +# }, +# 'neutron-default' => { +# 'key' => 'default', +# 'value' => 'rule:admin_or_owner' +# } +# } +# Defaults to empty hash. +# +# [*policy_path*] +# (optional) Path to the neutron policy.json file +# Defaults to /etc/neutron/policy.json +# +class neutron::policy ( + $policies = {}, + $policy_path = '/etc/neutron/policy.json', +) { + + validate_hash($policies) + + Openstacklib::Policy::Base { + file_path => $policy_path, + } + + create_resources('openstacklib::policy::base', $policies) + +} diff --git a/3rdparty/modules/neutron/manifests/quota.pp b/3rdparty/modules/neutron/manifests/quota.pp new file mode 100644 index 000000000..531214fa9 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/quota.pp @@ -0,0 +1,134 @@ +# == Class: neutron::quota +# +# Setups neutron quota. +# +# === Parameters +# +# [*default_quota*] +# (optional) Default number of resources allowed per tenant, +# minus for unlimited. Defaults to -1. +# +# [*quota_network*] +# (optional) Number of networks allowed per tenant, and minus means unlimited. +# Defaults to 10. +# +# [*quota_subnet*] +# (optional) Number of subnets allowed per tenant, and minus means unlimited. +# Defaults to 10. +# +# [*quota_port*] +# (optional) Number of ports allowed per tenant, and minus means unlimited. +# Defaults to 50. +# +# [*quota_router*] +# (optional) Number of routers allowed per tenant, and minus means unlimited. +# Requires L3 extension. Defaults to 10. +# +# [*quota_floatingip*] +# (optional) Number of floating IPs allowed per tenant, +# and minus means unlimited. Requires L3 extension. Defaults to 50. +# +# [*quota_security_group*] +# (optional) Number of security groups allowed per tenant, +# and minus means unlimited. Requires securitygroup extension. +# Defaults to 10. +# +# [*quota_security_group_rule*] +# (optional) Number of security rules allowed per tenant, +# and minus means unlimited. Requires securitygroup extension. +# Defaults to 100. +# +# [*quota_driver*] +# (optional) Default driver to use for quota checks. +# Defaults to 'neutron.db.quota_db.DbQuotaDriver'. +# +# [*quota_firewall*] +# (optional) Number of firewalls allowed per tenant, -1 for unlimited. +# Defaults to '1'. +# +# [*quota_firewall_policy*] +# (optional) Number of firewalls policies allowed per tenant, -1 for unlimited. +# Defaults to '1'. +# +# [*quota_firewall_rule*] +# (optional) Number of firewalls rules allowed per tenant, -1 for unlimited. +# Defaults to '-1'. +# +# [*quota_health_monitor*] +# (optional) Number of health monitors allowed per tenant. +# A negative value means unlimited. +# Defaults to '-1'. +# +# [*quota_items*] +# (optional) Resource name(s) that are supported in quota features. +# Defaults to 'network,subnet,port'. +# +# [*quota_member*] +# (optional) Number of pool members allowed per tenant. +# A negative value means unlimited +# Defaults to '-1'. +# +# [*quota_network_gateway*] +# (optional) Number of network gateways allowed per tenant, -1 for unlimited. +# Defaults to '5'. +# +# [*quota_packet_filter*] +# (optional) Number of packet_filters allowed per tenant, -1 for unlimited. +# Defaults to '100'. +# +# [*quota_pool*] +# (optional) Number of pools allowed per tenant. +# A negative value means unlimited. +# Defaults to '10'. +# +# [*quota_vip*] +# (optional) Number of vips allowed per tenant. +# A negative value means unlimited. +# Defaults to '10'. +# +class neutron::quota ( + $default_quota = -1, + $quota_network = 10, + $quota_subnet = 10, + $quota_port = 50, + # l3 extension + $quota_router = 10, + $quota_floatingip = 50, + # securitygroup extension + $quota_security_group = 10, + $quota_security_group_rule = 100, + $quota_driver = 'neutron.db.quota_db.DbQuotaDriver', + $quota_firewall = 1, + $quota_firewall_policy = 1, + $quota_firewall_rule = -1, + $quota_health_monitor = -1, + $quota_items = 'network,subnet,port', + $quota_member = -1, + $quota_network_gateway = 5, + $quota_packet_filter = 100, + $quota_pool = 10, + $quota_vip = 10 +) { + + neutron_config { + 'quotas/default_quota': value => $default_quota; + 'quotas/quota_network': value => $quota_network; + 'quotas/quota_subnet': value => $quota_subnet; + 'quotas/quota_port': value => $quota_port; + 'quotas/quota_router': value => $quota_router; + 'quotas/quota_floatingip': value => $quota_floatingip; + 'quotas/quota_security_group': value => $quota_security_group; + 'quotas/quota_security_group_rule': value => $quota_security_group_rule; + 'quotas/quota_driver': value => $quota_driver; + 'quotas/quota_firewall': value => $quota_firewall; + 'quotas/quota_firewall_policy': value => $quota_firewall_policy; + 'quotas/quota_firewall_rule': value => $quota_firewall_rule; + 'quotas/quota_health_monitor': value => $quota_health_monitor; + 'quotas/quota_items': value => $quota_items; + 'quotas/quota_member': value => $quota_member; + 'quotas/quota_network_gateway': value => $quota_network_gateway; + 'quotas/quota_packet_filter': value => $quota_packet_filter; + 'quotas/quota_pool': value => $quota_pool; + 'quotas/quota_vip': value => $quota_vip; + } +} diff --git a/3rdparty/modules/neutron/manifests/server.pp b/3rdparty/modules/neutron/manifests/server.pp new file mode 100644 index 000000000..2395c37fa --- /dev/null +++ b/3rdparty/modules/neutron/manifests/server.pp @@ -0,0 +1,448 @@ +# == Class: neutron::server +# +# Setup and configure the neutron API endpoint +# +# === Parameters +# +# [*package_ensure*] +# (optional) The state of the package +# Defaults to present +# +# [*enabled*] +# (optional) The state of the service +# Defaults to true +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*log_file*] +# REMOVED: Use log_file of neutron class instead. +# +# [*log_dir*] +# REMOVED: Use log_dir of neutron class instead. +# +# [*auth_password*] +# (optional) The password to use for authentication (keystone) +# Defaults to false. Set a value unless you are using noauth +# +# [*auth_type*] +# (optional) What auth system to use +# Defaults to 'keystone'. Can other be 'noauth' +# +# [*auth_host*] +# (optional) The keystone host +# Defaults to localhost +# +# [*auth_protocol*] +# (optional) The protocol used to access the auth host +# Defaults to http. +# +# [*auth_port*] +# (optional) The keystone auth port +# Defaults to 35357 +# +# [*auth_admin_prefix*] +# (optional) The admin_prefix used to admin endpoint of the auth host +# This allow admin auth URIs like http://auth_host:35357/keystone. +# (where '/keystone' is the admin prefix) +# Defaults to false for empty. If defined, should be a string with a leading '/' and no trailing '/'. +# +# [*auth_tenant*] +# (optional) The tenant of the auth user +# Defaults to services +# +# [*auth_user*] +# (optional) The name of the auth user +# Defaults to neutron +# +# [*auth_protocol*] +# (optional) The protocol to connect to keystone +# Defaults to http +# +# [*auth_uri*] +# (optional) Complete public Identity API endpoint. +# Defaults to: $auth_protocol://$auth_host:5000/ +# +# [*database_connection*] +# (optional) Connection url for the neutron database. +# (Defaults to 'sqlite:////var/lib/neutron/ovs.sqlite') +# +# [*sql_connection*] +# DEPRECATED: Use database_connection instead. +# +# [*connection*] +# DEPRECATED: Use database_connection instead. +# +# [*database_max_retries*] +# (optional) Maximum database connection retries during startup. +# (Defaults to 10) +# +# [*sql_max_retries*] +# DEPRECATED: Use database_max_retries instead. +# +# [*max_retries*] +# DEPRECATED: Use database_max_retries instead. +# +# [*database_idle_timeout*] +# (optional) Timeout before idle database connections are reaped. +# Deprecates sql_idle_timeout +# (Defaults to 3600) +# +# [*sql_idle_timeout*] +# DEPRECATED: Use database_idle_timeout instead. +# +# [*idle_timeout*] +# DEPRECATED: Use database_idle_timeout instead. +# +# [*database_retry_interval*] +# (optional) Interval between retries of opening a database connection. +# (Defaults to 10) +# +# [*sql_reconnect_interval*] +# DEPRECATED: Use database_retry_interval instead. +# +# [*retry_interval*] +# DEPRECATED: Use database_retry_interval instead. +# +# [*database_min_pool_size*] +# (optional) Minimum number of SQL connections to keep open in a pool. +# Defaults to: 1 +# +# [*database_max_pool_size*] +# (optional) Maximum number of SQL connections to keep open in a pool. +# Defaults to: 10 +# +# [*database_max_overflow*] +# (optional) If set, use this value for max_overflow with sqlalchemy. +# Defaults to: 20 +# +# [*sync_db*] +# (optional) Run neutron-db-manage on api nodes after installing the package. +# Defaults to false +# +# [*api_workers*] +# (optional) Number of separate worker processes to spawn. +# The default, count of machine's processors, runs the worker thread in the +# current process. +# Greater than 0 launches that number of child processes as workers. +# The parent process manages them. +# Defaults to: $::processorcount +# +# [*rpc_workers*] +# (optional) Number of separate RPC worker processes to spawn. +# The default, count of machine's processors, runs the worker thread in the +# current process. +# Greater than 0 launches that number of child processes as workers. +# The parent process manages them. +# Defaults to: $::processorcount +# +# [*agent_down_time*] +# (optional) Seconds to regard the agent as down; should be at least twice +# report_interval, to be sure the agent is down for good. +# agent_down_time is a config for neutron-server, set by class neutron::server +# report_interval is a config for neutron agents, set by class neutron +# Defaults to: 75 +# +# [*router_scheduler_driver*] +# (optional) Driver to use for scheduling router to a default L3 agent. Could be: +# neutron.scheduler.l3_agent_scheduler.ChanceScheduler to schedule a router in a random way +# neutron.scheduler.l3_agent_scheduler.LeastRoutersScheduler to allocate on an L3 agent with the least number of routers bound. +# Defaults to: neutron.scheduler.l3_agent_scheduler.ChanceScheduler +# +# [*mysql_module*] +# (optional) Deprecated. Does nothing. +# +# [*router_distributed*] +# (optional) Setting the "router_distributed" flag to "True" will default to the creation +# of distributed tenant routers. +# Also can be the type of the router on the create request (admin-only attribute). +# Defaults to false +# +# [*l3_ha*] +# (optional) Enable high availability for virtual routers. +# Defaults to false +# +# [*max_l3_agents_per_router*] +# (optional) Maximum number of l3 agents which a HA router will be scheduled on. If set to '0', a router will be scheduled on every agent. +# Defaults to '3' +# +# [*min_l3_agents_per_router*] +# (optional) Minimum number of l3 agents which a HA router will be scheduled on. +# Defaults to '2' +# +# [*l3_ha_net_cidr*] +# (optional) CIDR of the administrative network if HA mode is enabled. +# Defaults to '169.254.192.0/18' +# +class neutron::server ( + $package_ensure = 'present', + $enabled = true, + $manage_service = true, + $auth_password = false, + $auth_type = 'keystone', + $auth_host = 'localhost', + $auth_port = '35357', + $auth_admin_prefix = false, + $auth_tenant = 'services', + $auth_user = 'neutron', + $auth_protocol = 'http', + $auth_uri = false, + $database_connection = 'sqlite:////var/lib/neutron/ovs.sqlite', + $database_max_retries = 10, + $database_idle_timeout = 3600, + $database_retry_interval = 10, + $database_min_pool_size = 1, + $database_max_pool_size = 10, + $database_max_overflow = 20, + $sync_db = false, + $api_workers = $::processorcount, + $rpc_workers = $::processorcount, + $agent_down_time = '75', + $router_scheduler_driver = 'neutron.scheduler.l3_agent_scheduler.ChanceScheduler', + $router_distributed = false, + $l3_ha = false, + $max_l3_agents_per_router = 3, + $min_l3_agents_per_router = 2, + $l3_ha_net_cidr = '169.254.192.0/18', + # DEPRECATED PARAMETERS + $mysql_module = undef, + $sql_connection = undef, + $connection = undef, + $sql_max_retries = undef, + $max_retries = undef, + $sql_idle_timeout = undef, + $idle_timeout = undef, + $sql_reconnect_interval = undef, + $retry_interval = undef, + $log_dir = undef, + $log_file = undef, + $report_interval = undef, +) { + + include neutron::params + include neutron::policy + require keystone::python + + Nova_admin_tenant_id_setter<||> ~> Service['neutron-server'] + Neutron_config<||> ~> Service['neutron-server'] + Neutron_api_config<||> ~> Service['neutron-server'] + Class['neutron::policy'] ~> Service['neutron-server'] + + if $l3_ha { + if $min_l3_agents_per_router <= $max_l3_agents_per_router or $max_l3_agents_per_router == '0' { + neutron_config { + 'DEFAULT/l3_ha': value => true; + 'DEFAULT/max_l3_agents_per_router': value => $max_l3_agents_per_router; + 'DEFAULT/min_l3_agents_per_router': value => $min_l3_agents_per_router; + 'DEFAULT/l3_ha_net_cidr': value => $l3_ha_net_cidr; + } + } else { + fail('min_l3_agents_per_router should be less than or equal to max_l3_agents_per_router.') + } + } else { + neutron_config { + 'DEFAULT/l3_ha': value => false; + } + } + + if $mysql_module { + warning('The mysql_module parameter is deprecated. The latest 2.x mysql module will be used.') + } + + if $sql_connection { + warning('The sql_connection parameter is deprecated, use database_connection instead.') + $database_connection_real = $sql_connection + } elsif $connection { + warning('The connection parameter is deprecated, use database_connection instead.') + $database_connection_real = $connection + } else { + $database_connection_real = $database_connection + } + + if $sql_max_retries { + warning('The sql_max_retries parameter is deprecated, use database_max_retries instead.') + $database_max_retries_real = $sql_max_retries + } elsif $max_retries { + warning('The max_retries parameter is deprecated, use database_max_retries instead.') + $database_max_retries_real = $max_retries + } else { + $database_max_retries_real = $database_max_retries + } + + if $sql_idle_timeout { + warning('The sql_idle_timeout parameter is deprecated, use database_idle_timeout instead.') + $database_idle_timeout_real = $sql_idle_timeout + } elsif $idle_timeout { + warning('The dle_timeout parameter is deprecated, use database_idle_timeout instead.') + $database_idle_timeout_real = $idle_timeout + } else { + $database_idle_timeout_real = $database_idle_timeout + } + + if $sql_reconnect_interval { + warning('The sql_reconnect_interval parameter is deprecated, use database_retry_interval instead.') + $database_retry_interval_real = $sql_reconnect_interval + } elsif $retry_interval { + warning('The retry_interval parameter is deprecated, use database_retry_interval instead.') + $database_retry_interval_real = $retry_interval + } else { + $database_retry_interval_real = $database_retry_interval + } + + if $log_dir { + fail('The log_dir parameter is removed, use log_dir of neutron class instead.') + } + + if $log_file { + fail('The log_file parameter is removed, use log_file of neutron class instead.') + } + + if $report_interval { + fail('The report_interval is removed, use report_interval of neutron class instead.') + } + + validate_re($database_connection_real, '(sqlite|mysql|postgresql):\/\/(\S+:\S+@\S+\/\S+)?') + + case $database_connection_real { + /mysql:\/\/\S+:\S+@\S+\/\S+/: { + require 'mysql::bindings' + require 'mysql::bindings::python' + } + /postgresql:\/\/\S+:\S+@\S+\/\S+/: { + $backend_package = 'python-psycopg2' + } + /sqlite:\/\//: { + $backend_package = 'python-pysqlite2' + } + default: { + fail("Invalid database_connection parameter: ${database_connection_real}") + } + } + + if $sync_db { + if ($::neutron::params::server_package) { + # Debian platforms + Package<| title == 'neutron-server' |> ~> Exec['neutron-db-sync'] + } else { + # RH platforms + Package<| title == 'neutron' |> ~> Exec['neutron-db-sync'] + } + exec { 'neutron-db-sync': + command => 'neutron-db-manage --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugin.ini upgrade head', + path => '/usr/bin', + before => Service['neutron-server'], + require => Neutron_config['database/connection'], + refreshonly => true + } + Neutron_config<||> ~> Exec['neutron-db-sync'] + } + + neutron_config { + 'DEFAULT/api_workers': value => $api_workers; + 'DEFAULT/rpc_workers': value => $rpc_workers; + 'DEFAULT/agent_down_time': value => $agent_down_time; + 'DEFAULT/router_scheduler_driver': value => $router_scheduler_driver; + 'DEFAULT/router_distributed': value => $router_distributed; + 'database/connection': value => $database_connection_real, secret => true; + 'database/idle_timeout': value => $database_idle_timeout_real; + 'database/retry_interval': value => $database_retry_interval_real; + 'database/max_retries': value => $database_max_retries_real; + 'database/min_pool_size': value => $database_min_pool_size; + 'database/max_pool_size': value => $database_max_pool_size; + 'database/max_overflow': value => $database_max_overflow; + } + + if ($::neutron::params::server_package) { + Package['neutron-server'] -> Neutron_api_config<||> + Package['neutron-server'] -> Neutron_config<||> + Package['neutron-server'] -> Service['neutron-server'] + Package['neutron-server'] -> Class['neutron::policy'] + package { 'neutron-server': + ensure => $package_ensure, + name => $::neutron::params::server_package, + } + } else { + # Some platforms (RedHat) does not provide a neutron-server package. + # The neutron api config file is provided by the neutron package. + Package['neutron'] -> Class['neutron::policy'] + Package['neutron'] -> Neutron_api_config<||> + } + + if ($auth_type == 'keystone') { + + if ($auth_password == false) { + fail('$auth_password must be set when using keystone authentication.') + } else { + neutron_config { + 'keystone_authtoken/auth_host': value => $auth_host; + 'keystone_authtoken/auth_port': value => $auth_port; + 'keystone_authtoken/auth_protocol': value => $auth_protocol; + 'keystone_authtoken/admin_tenant_name': value => $auth_tenant; + 'keystone_authtoken/admin_user': value => $auth_user; + 'keystone_authtoken/admin_password': value => $auth_password, secret => true; + } + + neutron_api_config { + 'filter:authtoken/auth_host': value => $auth_host; + 'filter:authtoken/auth_port': value => $auth_port; + 'filter:authtoken/auth_protocol': value => $auth_protocol; + 'filter:authtoken/admin_tenant_name': value => $auth_tenant; + 'filter:authtoken/admin_user': value => $auth_user; + 'filter:authtoken/admin_password': value => $auth_password, secret => true; + } + + if $auth_admin_prefix { + validate_re($auth_admin_prefix, '^(/.+[^/])?$') + neutron_config { + 'keystone_authtoken/auth_admin_prefix': value => $auth_admin_prefix; + } + neutron_api_config { + 'filter:authtoken/auth_admin_prefix': value => $auth_admin_prefix; + } + } else { + neutron_config { + 'keystone_authtoken/auth_admin_prefix': ensure => absent; + } + neutron_api_config { + 'filter:authtoken/auth_admin_prefix': ensure => absent; + } + } + + if $auth_uri { + neutron_config { + 'keystone_authtoken/auth_uri': value => $auth_uri; + } + neutron_api_config { + 'filter:authtoken/auth_uri': value => $auth_uri; + } + } else { + neutron_config { + 'keystone_authtoken/auth_uri': value => "${auth_protocol}://${auth_host}:5000/"; + } + neutron_api_config { + 'filter:authtoken/auth_uri': value => "${auth_protocol}://${auth_host}:5000/"; + } + } + + } + + } + + if $manage_service { + if $enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + } + + service { 'neutron-server': + ensure => $service_ensure, + name => $::neutron::params::server_service, + enable => $enabled, + hasstatus => true, + hasrestart => true, + require => Class['neutron'], + } +} diff --git a/3rdparty/modules/neutron/manifests/server/notifications.pp b/3rdparty/modules/neutron/manifests/server/notifications.pp new file mode 100644 index 000000000..8cfb6d7fe --- /dev/null +++ b/3rdparty/modules/neutron/manifests/server/notifications.pp @@ -0,0 +1,112 @@ +# 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: neutron::server::notifications +# +# Configure Notification System Options +# +# === Parameters +# +# [*notify_nova_on_port_status_changes*] +# (optional) Send notification to nova when port status is active. +# Defaults to true +# +# [*notify_nova_on_port_data_changes*] +# (optional) Send notifications to nova when port data (fixed_ips/floatingips) +# change so nova can update its cache. +# Defaults to true +# +# [*send_events_interval*] +# (optional) Number of seconds between sending events to nova if there are +# any events to send. +# Defaults to '2' +# +# [*nova_url*] +# (optional) URL for connection to nova (Only supports one nova region +# currently). +# Defaults to 'http://127.0.0.1:8774/v2' +# +# [*nova_admin_auth_url*] +# (optional) Authorization URL for connection to nova in admin context. +# Defaults to 'http://127.0.0.1:35357/v2.0' +# +# [*nova_admin_username*] +# (optional) Username for connection to nova in admin context +# Defaults to 'nova' +# +# [*nova_admin_tenant_name*] +# (optional) The name of the admin nova tenant +# Defaults to 'services' +# +# [*nova_admin_tenant_id*] +# (optional) The UUID of the admin nova tenant. If provided this takes +# precedence over nova_admin_tenant_name. +# +# [*nova_admin_password*] +# (required) Password for connection to nova in admin context. +# +# [*nova_region_name*] +# (optional) Name of nova region to use. Useful if keystone manages more than +# one region. +# Defaults to 'RegionOne' +# + +class neutron::server::notifications ( + $notify_nova_on_port_status_changes = true, + $notify_nova_on_port_data_changes = true, + $send_events_interval = '2', + $nova_url = 'http://127.0.0.1:8774/v2', + $nova_admin_auth_url = 'http://127.0.0.1:35357/v2.0', + $nova_admin_username = 'nova', + $nova_admin_tenant_name = 'services', + $nova_admin_tenant_id = undef, + $nova_admin_password = false, + $nova_region_name = 'RegionOne', +) { + + # Depend on the specified keystone_user resource, if it exists. + Keystone_user <| title == 'nova' |> -> Class[neutron::server::notifications] + + if ! $nova_admin_password { + fail('nova_admin_password must be set.') + } + + if ! ( $nova_admin_tenant_id or $nova_admin_tenant_name ) { + fail('You must provide either nova_admin_tenant_name or nova_admin_tenant_id.') + } + + neutron_config { + 'DEFAULT/notify_nova_on_port_status_changes': value => $notify_nova_on_port_status_changes; + 'DEFAULT/notify_nova_on_port_data_changes': value => $notify_nova_on_port_data_changes; + 'DEFAULT/send_events_interval': value => $send_events_interval; + 'DEFAULT/nova_url': value => $nova_url; + 'DEFAULT/nova_admin_auth_url': value => $nova_admin_auth_url; + 'DEFAULT/nova_admin_username': value => $nova_admin_username; + 'DEFAULT/nova_admin_password': value => $nova_admin_password, secret => true; + 'DEFAULT/nova_region_name': value => $nova_region_name; + } + + if $nova_admin_tenant_id { + neutron_config { + 'DEFAULT/nova_admin_tenant_id': value => $nova_admin_tenant_id; + } + } else { + nova_admin_tenant_id_setter {'nova_admin_tenant_id': + ensure => present, + tenant_name => $nova_admin_tenant_name, + auth_url => $nova_admin_auth_url, + auth_username => $nova_admin_username, + auth_password => $nova_admin_password, + auth_tenant_name => $nova_admin_tenant_name, + } + } +} diff --git a/3rdparty/modules/neutron/manifests/services/fwaas.pp b/3rdparty/modules/neutron/manifests/services/fwaas.pp new file mode 100644 index 000000000..090b07970 --- /dev/null +++ b/3rdparty/modules/neutron/manifests/services/fwaas.pp @@ -0,0 +1,71 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# +# == Class: neutron::services::fwaas +# +# Configure the Firewall as a Service Neutron Plugin +# +# === Parameters: +# +# [*enabled*] +# (required) Whether or not to enable the FWaaS neutron plugin Service +# true/false +# +# [*driver*] +# (optional) FWaaS Driver to use +# Defaults to 'neutron.services.firewall.drivers.linux.iptables_fwaas.IptablesFwaasDriver' +# +# [*vpnaas_agent_package*] +# (optional) Use VPNaaS agent package instead of L3 agent package on debian platforms +# RedHat platforms won't take care of this parameter +# true/false +# Defaults to false +# + +class neutron::services::fwaas ( + $enabled = true, + $driver = 'neutron.services.firewall.drivers.linux.iptables_fwaas.IptablesFwaasDriver', + $vpnaas_agent_package = false +) { + + include neutron::params + + if ($::osfamily == 'Debian') { + # Debian platforms + if $vpnaas_agent_package { + ensure_resource( 'package', $::neutron::params::vpnaas_agent_package, + { 'ensure' => $neutron::package_ensure }) + Package[$::neutron::params::vpnaas_agent_package] -> Neutron_fwaas_service_config<||> + } + else { + ensure_resource( 'package', $::neutron::params::l3_agent_package, + { 'ensure' => $neutron::package_ensure }) + Package[$::neutron::params::l3_agent_package] -> Neutron_fwaas_service_config<||> + } + } elsif($::osfamily == 'Redhat') { + # RH platforms + ensure_resource( 'package', $::neutron::params::package_name, + { 'ensure' => $neutron::package_ensure }) + Package[$::neutron::params::package_name] -> Neutron_fwaas_service_config<||> + } + + neutron_fwaas_service_config { + 'fwaas/enabled': value => $enabled; + 'fwaas/driver': value => $driver; + } +} diff --git a/3rdparty/modules/neutron/metadata.json b/3rdparty/modules/neutron/metadata.json new file mode 100644 index 000000000..678031e55 --- /dev/null +++ b/3rdparty/modules/neutron/metadata.json @@ -0,0 +1,58 @@ +{ + "name": "stackforge-neutron", + "version": "5.1.0", + "author": "OpenStack Contributors", + "summary": "Puppet module for OpenStack Neutron", + "license": "Apache-2.0", + "source": "git://github.com/openstack/puppet-neutron.git", + "project_page": "https://launchpad.net/puppet-neutron", + "issues_url": "https://bugs.launchpad.net/puppet-neutron", + "dependencies": [ + {"name":"puppetlabs/inifile","version_requirement":">=1.0.0 <2.0.0"}, + {"name":"stackforge/keystone","version_requirement":">=5.0.0 <6.0.0"}, + {"name":"stackforge/nova","version_requirement":">=5.0.0 <6.0.0"}, + {"name":"puppetlabs/stdlib","version_requirement":">=4.0.0 <5.0.0"}, + {"name":"stackforge/vswitch","version_requirement":">=1.0.0 <2.0.0"}, + {"name":"duritong/sysctl","version_requirement":">=0.0.1 <1.0.0"}, + {"name":"stackforge/openstacklib","version_requirement":">=5.0.0 <6.0.0"} + ], + "requirements": [ + { + "name": "pe", + "version_requirement": "3.x" + }, + { + "name": "puppet", + "version_requirement": "3.x" + } + ], + "operatingsystem_support": [ + { + "operatingsystem": "Debian", + "operatingsystemrelease": [ + "7" + ] + }, + { + "operatingsystem": "Fedora", + "operatingsystemrelease": [ + "20" + ] + }, + { + "operatingsystem": "RedHat", + "operatingsystemrelease": [ + "6.5", + "7" + ] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": [ + "12.04", + "14.04" + ] + } + ], + "description": "Installs and configures OpenStack Neutron (Networking)." +} diff --git a/3rdparty/modules/neutron/spec/classes/neutron_agents_dhcp_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_agents_dhcp_spec.rb new file mode 100644 index 000000000..640d9318a --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_agents_dhcp_spec.rb @@ -0,0 +1,173 @@ +require 'spec_helper' + +describe 'neutron::agents::dhcp' do + + let :pre_condition do + "class { 'neutron': rabbit_password => 'passw0rd' }" + end + + let :params do + {} + end + + let :default_params do + { :package_ensure => 'present', + :enabled => true, + :debug => false, + :state_path => '/var/lib/neutron', + :resync_interval => 30, + :interface_driver => 'neutron.agent.linux.interface.OVSInterfaceDriver', + :dhcp_driver => 'neutron.agent.linux.dhcp.Dnsmasq', + :root_helper => 'sudo neutron-rootwrap /etc/neutron/rootwrap.conf', + :use_namespaces => true, + :dnsmasq_config_file => nil, + :dhcp_delete_namespaces => false, + :enable_isolated_metadata => false, + :enable_metadata_network => false } + end + + + shared_examples_for 'neutron dhcp agent' do + let :p do + default_params.merge(params) + end + + it { should contain_class('neutron::params') } + + it_configures 'dnsmasq dhcp_driver' + + it 'configures dhcp_agent.ini' do + should contain_neutron_dhcp_agent_config('DEFAULT/debug').with_value(p[:debug]); + should contain_neutron_dhcp_agent_config('DEFAULT/state_path').with_value(p[:state_path]); + should contain_neutron_dhcp_agent_config('DEFAULT/resync_interval').with_value(p[:resync_interval]); + should contain_neutron_dhcp_agent_config('DEFAULT/interface_driver').with_value(p[:interface_driver]); + should contain_neutron_dhcp_agent_config('DEFAULT/dhcp_driver').with_value(p[:dhcp_driver]); + should contain_neutron_dhcp_agent_config('DEFAULT/root_helper').with_value(p[:root_helper]); + should contain_neutron_dhcp_agent_config('DEFAULT/use_namespaces').with_value(p[:use_namespaces]); + should contain_neutron_dhcp_agent_config('DEFAULT/dhcp_delete_namespaces').with_value(p[:dhcp_delete_namespaces]); + should contain_neutron_dhcp_agent_config('DEFAULT/enable_isolated_metadata').with_value(p[:enable_isolated_metadata]); + should contain_neutron_dhcp_agent_config('DEFAULT/enable_metadata_network').with_value(p[:enable_metadata_network]); + end + + it 'installs neutron dhcp agent package' do + if platform_params.has_key?(:dhcp_agent_package) + should contain_package('neutron-dhcp-agent').with( + :name => platform_params[:dhcp_agent_package], + :ensure => p[:package_ensure] + ) + should contain_package('neutron').with_before(/Package\[neutron-dhcp-agent\]/) + should contain_package('neutron-dhcp-agent').with_before(/Neutron_dhcp_agent_config\[.+\]/) + should contain_package('neutron-dhcp-agent').with_before(/Neutron_config\[.+\]/) + else + should contain_package('neutron').with_before(/Neutron_dhcp_agent_config\[.+\]/) + end + end + + it 'configures neutron dhcp agent service' do + should contain_service('neutron-dhcp-service').with( + :name => platform_params[:dhcp_agent_service], + :enable => true, + :ensure => 'running', + :require => 'Class[Neutron]' + ) + end + + context 'with manage_service as false' do + before :each do + params.merge!(:manage_service => false) + end + it 'should not start/stop service' do + should contain_service('neutron-dhcp-service').without_ensure + end + end + + context 'when enabling isolated metadata only' do + before :each do + params.merge!(:enable_isolated_metadata => true, :enable_metadata_network => false) + end + it 'should enable isolated_metadata only' do + should contain_neutron_dhcp_agent_config('DEFAULT/enable_isolated_metadata').with_value('true'); + should contain_neutron_dhcp_agent_config('DEFAULT/enable_metadata_network').with_value('false'); + end + end + + context 'when enabling isolated metadata with metadata networks' do + before :each do + params.merge!(:enable_isolated_metadata => true, :enable_metadata_network => true) + end + it 'should enable both isolated_metadata and metadata_network' do + should contain_neutron_dhcp_agent_config('DEFAULT/enable_isolated_metadata').with_value('true'); + should contain_neutron_dhcp_agent_config('DEFAULT/enable_metadata_network').with_value('true'); + end + end + + context 'when enabling metadata networks without enabling isolated metadata' do + before :each do + params.merge!(:enable_isolated_metadata => false, :enable_metadata_network => true) + end + it 'should fails to configure metadata_network without isolated_metadata' do + expect { subject }.to raise_error(Puppet::Error, /enable_metadata_network to true requires enable_isolated_metadata also enabled./) + end + end + end + + shared_examples_for 'neutron dhcp agent with dnsmasq_config_file specified' do + before do + params.merge!( + :dnsmasq_config_file => '/foo' + ) + end + it 'configures dnsmasq_config_file' do + should contain_neutron_dhcp_agent_config('DEFAULT/dnsmasq_config_file').with_value(params[:dnsmasq_config_file]) + end + end + + shared_examples_for 'dnsmasq dhcp_driver' do + it 'installs dnsmasq packages' do + if platform_params.has_key?(:dhcp_agent_package) + should contain_package(platform_params[:dnsmasq_base_package]).with_before('Package[neutron-dhcp-agent]') + should contain_package(platform_params[:dnsmasq_utils_package]).with_before('Package[neutron-dhcp-agent]') + end + should contain_package(platform_params[:dnsmasq_base_package]).with( + :ensure => 'present', + :name => platform_params[:dnsmasq_base_package] + ) + should contain_package(platform_params[:dnsmasq_utils_package]).with( + :ensure => 'present', + :name => platform_params[:dnsmasq_utils_package] + ) + end + end + + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { :dnsmasq_base_package => 'dnsmasq-base', + :dnsmasq_utils_package => 'dnsmasq-utils', + :dhcp_agent_package => 'neutron-dhcp-agent', + :dhcp_agent_service => 'neutron-dhcp-agent' } + end + + it_configures 'neutron dhcp agent' + it_configures 'neutron dhcp agent with dnsmasq_config_file specified' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :dnsmasq_base_package => 'dnsmasq', + :dnsmasq_utils_package => 'dnsmasq-utils', + :dhcp_agent_service => 'neutron-dhcp-agent' } + end + + it_configures 'neutron dhcp agent' + it_configures 'neutron dhcp agent with dnsmasq_config_file specified' + end +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_agents_l3_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_agents_l3_spec.rb new file mode 100644 index 000000000..eb0a99040 --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_agents_l3_spec.rb @@ -0,0 +1,153 @@ +require 'spec_helper' + +describe 'neutron::agents::l3' do + + let :pre_condition do + "class { 'neutron': rabbit_password => 'passw0rd' }" + end + + let :default_params do + { :package_ensure => 'present', + :enabled => true, + :debug => false, + :external_network_bridge => 'br-ex', + :use_namespaces => true, + :interface_driver => 'neutron.agent.linux.interface.OVSInterfaceDriver', + :router_id => nil, + :gateway_external_network_id => nil, + :handle_internal_only_routers => true, + :metadata_port => '9697', + :send_arp_for_ha => '3', + :periodic_interval => '40', + :periodic_fuzzy_delay => '5', + :enable_metadata_proxy => true, + :network_device_mtu => nil, + :router_delete_namespaces => false, + :ha_enabled => false, + :ha_vrrp_auth_type => 'PASS', + :ha_vrrp_auth_password => nil, + :ha_vrrp_advert_int => '3', + :agent_mode => 'legacy', + :allow_automatic_l3agent_failover => false } + end + + let :params do + { } + end + + shared_examples_for 'neutron l3 agent' do + let :p do + default_params.merge(params) + end + + it { should contain_class('neutron::params') } + + it 'configures l3_agent.ini' do + should contain_neutron_l3_agent_config('DEFAULT/debug').with_value(p[:debug]) + should contain_neutron_l3_agent_config('DEFAULT/external_network_bridge').with_value(p[:external_network_bridge]) + should contain_neutron_l3_agent_config('DEFAULT/use_namespaces').with_value(p[:use_namespaces]) + should contain_neutron_l3_agent_config('DEFAULT/interface_driver').with_value(p[:interface_driver]) + should contain_neutron_l3_agent_config('DEFAULT/router_id').with_value(p[:router_id]) + should contain_neutron_l3_agent_config('DEFAULT/gateway_external_network_id').with_value(p[:gateway_external_network_id]) + should contain_neutron_l3_agent_config('DEFAULT/handle_internal_only_routers').with_value(p[:handle_internal_only_routers]) + should contain_neutron_l3_agent_config('DEFAULT/metadata_port').with_value(p[:metadata_port]) + should contain_neutron_l3_agent_config('DEFAULT/send_arp_for_ha').with_value(p[:send_arp_for_ha]) + should contain_neutron_l3_agent_config('DEFAULT/periodic_interval').with_value(p[:periodic_interval]) + should contain_neutron_l3_agent_config('DEFAULT/periodic_fuzzy_delay').with_value(p[:periodic_fuzzy_delay]) + should contain_neutron_l3_agent_config('DEFAULT/enable_metadata_proxy').with_value(p[:enable_metadata_proxy]) + should contain_neutron_l3_agent_config('DEFAULT/network_device_mtu').with_ensure('absent') + should contain_neutron_l3_agent_config('DEFAULT/router_delete_namespaces').with_value(p[:router_delete_namespaces]) + should contain_neutron_l3_agent_config('DEFAULT/allow_automatic_l3agent_failover').with_value(p[:allow_automatic_l3agent_failover]) + end + + it 'installs neutron l3 agent package' do + if platform_params.has_key?(:l3_agent_package) + should contain_package('neutron-l3').with( + :name => platform_params[:l3_agent_package], + :ensure => p[:package_ensure], + :require => 'Package[neutron]' + ) + should contain_package('neutron-l3').with_before(/Neutron_l3_agent_config\[.+\]/) + else + should contain_package('neutron').with_before(/Neutron_l3_agent_config\[.+\]/) + end + end + + it 'configures neutron l3 agent service' do + should contain_service('neutron-l3').with( + :name => platform_params[:l3_agent_service], + :enable => true, + :ensure => 'running', + :require => 'Class[Neutron]' + ) + end + + context 'with manage_service as false' do + before :each do + params.merge!(:manage_service => false) + end + it 'should not start/stop service' do + should contain_service('neutron-l3').without_ensure + end + end + + context 'with DVR' do + before :each do + params.merge!(:agent_mode => 'dvr') + end + it 'should enable DVR mode' do + should contain_neutron_l3_agent_config('DEFAULT/agent_mode').with_value(p[:agent_mode]) + end + end + + context 'with HA routers' do + before :each do + params.merge!(:ha_enabled => true, + :ha_vrrp_auth_password => 'secrete') + end + it 'should configure VRRP' do + should contain_neutron_l3_agent_config('DEFAULT/ha_vrrp_auth_type').with_value(p[:ha_vrrp_auth_type]) + should contain_neutron_l3_agent_config('DEFAULT/ha_vrrp_auth_password').with_value(p[:ha_vrrp_auth_password]) + should contain_neutron_l3_agent_config('DEFAULT/ha_vrrp_advert_int').with_value(p[:ha_vrrp_advert_int]) + end + end + end + + shared_examples_for 'neutron l3 agent with network_device_mtu specified' do + before do + params.merge!( + :network_device_mtu => 9999 + ) + end + it 'configures network_device_mtu' do + should contain_neutron_l3_agent_config('DEFAULT/network_device_mtu').with_value(params[:network_device_mtu]) + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { :l3_agent_package => 'neutron-l3-agent', + :l3_agent_service => 'neutron-l3-agent' } + end + + it_configures 'neutron l3 agent' + it_configures 'neutron l3 agent with network_device_mtu specified' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :l3_agent_service => 'neutron-l3-agent' } + end + + it_configures 'neutron l3 agent' + it_configures 'neutron l3 agent with network_device_mtu specified' + end +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_agents_lbaas_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_agents_lbaas_spec.rb new file mode 100644 index 000000000..7f67953ae --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_agents_lbaas_spec.rb @@ -0,0 +1,136 @@ +require 'spec_helper' + +describe 'neutron::agents::lbaas' do + + let :pre_condition do + "class { 'neutron': rabbit_password => 'passw0rd' }" + end + + let :params do + {} + end + + let :default_params do + { :package_ensure => 'present', + :enabled => true, + :debug => false, + :interface_driver => 'neutron.agent.linux.interface.OVSInterfaceDriver', + :device_driver => 'neutron.services.loadbalancer.drivers.haproxy.namespace_driver.HaproxyNSDriver', + :use_namespaces => true, + :manage_haproxy_package => true + } + end + + + shared_examples_for 'neutron lbaas agent' do + let :p do + default_params.merge(params) + end + + it { should contain_class('neutron::params') } + + it_configures 'haproxy lbaas_driver' + it_configures 'haproxy lbaas_driver without package' + + it 'configures lbaas_agent.ini' do + should contain_neutron_lbaas_agent_config('DEFAULT/debug').with_value(p[:debug]); + should contain_neutron_lbaas_agent_config('DEFAULT/interface_driver').with_value(p[:interface_driver]); + should contain_neutron_lbaas_agent_config('DEFAULT/device_driver').with_value(p[:device_driver]); + should contain_neutron_lbaas_agent_config('DEFAULT/use_namespaces').with_value(p[:use_namespaces]); + should contain_neutron_lbaas_agent_config('haproxy/user_group').with_value(platform_params[:nobody_user_group]); + end + + it 'installs neutron lbaas agent package' do + if platform_params.has_key?(:lbaas_agent_package) + should contain_package('neutron-lbaas-agent').with( + :name => platform_params[:lbaas_agent_package], + :ensure => p[:package_ensure] + ) + should contain_package('neutron').with_before(/Package\[neutron-lbaas-agent\]/) + should contain_package('neutron-lbaas-agent').with_before(/Neutron_lbaas_agent_config\[.+\]/) + should contain_package('neutron-lbaas-agent').with_before(/Neutron_config\[.+\]/) + else + should contain_package('neutron').with_before(/Neutron_lbaas_agent_config\[.+\]/) + end + end + + it 'configures neutron lbaas agent service' do + should contain_service('neutron-lbaas-service').with( + :name => platform_params[:lbaas_agent_service], + :enable => true, + :ensure => 'running', + :require => 'Class[Neutron]' + ) + end + + context 'with manage_service as false' do + before :each do + params.merge!(:manage_service => false) + end + it 'should not start/stop service' do + should contain_service('neutron-lbaas-service').without_ensure + end + end + end + + shared_examples_for 'haproxy lbaas_driver' do + it 'installs haproxy packages' do + if platform_params.has_key?(:lbaas_agent_package) + should contain_package(platform_params[:haproxy_package]).with_before('Package[neutron-lbaas-agent]') + end + should contain_package(platform_params[:haproxy_package]).with( + :ensure => 'present' + ) + end + end + + shared_examples_for 'haproxy lbaas_driver without package' do + let :pre_condition do + "package { 'haproxy': + ensure => 'present' + } + class { 'neutron': rabbit_password => 'passw0rd' }" + end + before do + params.merge!(:manage_haproxy_package => false) + end + it 'installs haproxy package via haproxy module' do + should contain_package(platform_params[:haproxy_package]).with( + :ensure => 'present' + ) + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian', + :concat_basedir => '/dne' + } + end + + let :platform_params do + { :haproxy_package => 'haproxy', + :lbaas_agent_package => 'neutron-lbaas-agent', + :nobody_user_group => 'nogroup', + :lbaas_agent_service => 'neutron-lbaas-agent' } + end + + it_configures 'neutron lbaas agent' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat', + :concat_basedir => '/dne' + } + end + + let :platform_params do + { :haproxy_package => 'haproxy', + :nobody_user_group => 'nobody', + :lbaas_agent_service => 'neutron-lbaas-agent' } + end + + it_configures 'neutron lbaas agent' + end +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_agents_linuxbridge_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_agents_linuxbridge_spec.rb new file mode 100644 index 000000000..53b5f9c07 --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_agents_linuxbridge_spec.rb @@ -0,0 +1,89 @@ +require 'spec_helper' + +describe 'neutron::agents::linuxbridge' do + + let :pre_condition do + "class { 'neutron': rabbit_password => 'passw0rd' }\n" + + "class { 'neutron::plugins::linuxbridge': }" + end + + let :params do + { :physical_interface_mappings => 'physnet:eth0', + :firewall_driver => 'neutron.agent.linux.iptables_firewall.IptablesFirewallDriver', + :package_ensure => 'present', + :enable => true + } + end + + shared_examples_for 'neutron linuxbridge agent' do + + it { should contain_class('neutron::params') } + + it 'configures neutron linuxbridge agent service' do + should contain_service('neutron-plugin-linuxbridge-service').with( + :ensure => 'running', + :name => platform_params[:linuxbridge_agent_service], + :enable => params[:enable] + ) + end + + context 'with manage_service as false' do + before :each do + params.merge!(:manage_service => false) + end + it 'should not start/stop service' do + should contain_service('neutron-plugin-linuxbridge-service').without_ensure + end + end + + it 'configures linuxbridge_conf.ini' do + should contain_neutron_plugin_linuxbridge('LINUX_BRIDGE/physical_interface_mappings').with( + :value => params[:physical_interface_mappings] + ) + should contain_neutron_plugin_linuxbridge('SECURITYGROUP/firewall_driver').with( + :value => params[:firewall_driver] + ) + end + end + + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { :linuxbridge_agent_package => 'neutron-plugin-linuxbridge-agent', + :linuxbridge_agent_service => 'neutron-plugin-linuxbridge-agent' } + end + + it_configures 'neutron linuxbridge agent' + + it 'installs neutron linuxbridge agent package' do + should contain_package('neutron-plugin-linuxbridge-agent').with( + :ensure => params[:package_ensure], + :name => platform_params[:linuxbridge_agent_package] + ) + end + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :linuxbridge_server_package => 'openstack-neutron-linuxbridge', + :linuxbridge_agent_service => 'neutron-linuxbridge-agent' } + end + + it_configures 'neutron linuxbridge agent' + + it 'installs neutron linuxbridge package' do + should contain_package('neutron-plugin-linuxbridge').with( + :ensure => params[:package_ensure], + :name => platform_params[:linuxbridge_server_package] + ) + end + end +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_agents_metadata_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_agents_metadata_spec.rb new file mode 100644 index 000000000..57f9a839e --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_agents_metadata_spec.rb @@ -0,0 +1,120 @@ +require 'spec_helper' + +describe 'neutron::agents::metadata' do + + let :pre_condition do + "class { 'neutron': rabbit_password => 'passw0rd' }" + end + + let :params do + { :package_ensure => 'present', + :debug => false, + :enabled => true, + :auth_url => 'http://localhost:35357/v2.0', + :auth_insecure => false, + :auth_region => 'RegionOne', + :auth_tenant => 'services', + :auth_user => 'neutron', + :auth_password => 'password', + :metadata_ip => '127.0.0.1', + :metadata_port => '8775', + :metadata_backlog => '4096', + :shared_secret => 'metadata-secret' + } + end + + shared_examples_for 'neutron metadata agent' do + + it { should contain_class('neutron::params') } + + it 'configures neutron metadata agent service' do + should contain_service('neutron-metadata').with( + :name => platform_params[:metadata_agent_service], + :enable => params[:enabled], + :ensure => 'running', + :require => 'Class[Neutron]' + ) + end + + context 'with manage_service as false' do + before :each do + params.merge!(:manage_service => false) + end + it 'should not start/stop service' do + should contain_service('neutron-metadata').without_ensure + end + end + + it 'configures metadata_agent.ini' do + should contain_neutron_metadata_agent_config('DEFAULT/debug').with(:value => params[:debug]) + should contain_neutron_metadata_agent_config('DEFAULT/auth_url').with(:value => params[:auth_url]) + should contain_neutron_metadata_agent_config('DEFAULT/auth_insecure').with(:value => params[:auth_insecure]) + should contain_neutron_metadata_agent_config('DEFAULT/auth_ca_cert').with_ensure('absent') + should contain_neutron_metadata_agent_config('DEFAULT/auth_region').with(:value => params[:auth_region]) + should contain_neutron_metadata_agent_config('DEFAULT/admin_tenant_name').with(:value => params[:auth_tenant]) + should contain_neutron_metadata_agent_config('DEFAULT/admin_user').with(:value => params[:auth_user]) + should contain_neutron_metadata_agent_config('DEFAULT/admin_password').with(:value => params[:auth_password]) + should contain_neutron_metadata_agent_config('DEFAULT/admin_password').with_secret( true ) + should contain_neutron_metadata_agent_config('DEFAULT/nova_metadata_ip').with(:value => params[:metadata_ip]) + should contain_neutron_metadata_agent_config('DEFAULT/nova_metadata_port').with(:value => params[:metadata_port]) + should contain_neutron_metadata_agent_config('DEFAULT/metadata_workers').with(:value => facts[:processorcount]) + should contain_neutron_metadata_agent_config('DEFAULT/metadata_backlog').with(:value => params[:metadata_backlog]) + should contain_neutron_metadata_agent_config('DEFAULT/metadata_proxy_shared_secret').with(:value => params[:shared_secret]) + should contain_neutron_metadata_agent_config('DEFAULT/cache_url').with(:value => 'memory://?default_ttl=5') + end + end + + shared_examples_for 'neutron metadata agent with auth_insecure and auth_ca_cert set' do + let :params do + { :auth_ca_cert => '/some/cert', + :auth_insecure => true, + :auth_password => 'blah', + :shared_secret => '42' + } + end + + it 'configures certificate' do + should contain_neutron_metadata_agent_config('DEFAULT/auth_ca_cert').with_value('/some/cert') + should contain_neutron_metadata_agent_config('DEFAULT/auth_insecure').with_value('true') + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian', + :processorcount => '2' } + end + + let :platform_params do + { :metadata_agent_package => 'neutron-metadata-agent', + :metadata_agent_service => 'neutron-metadata-agent' } + end + + it 'installs neutron metadata agent package' do + should contain_package('neutron-metadata').with( + :ensure => params[:package_ensure], + :name => platform_params[:metadata_agent_package] + ) + end + + it_configures 'neutron metadata agent' + it_configures 'neutron metadata agent with auth_insecure and auth_ca_cert set' + + end + + context 'on Red Hat platforms' do + let :facts do + { :osfamily => 'RedHat', + :processorcount => '2' } + end + + let :platform_params do + { :metadata_agent_service => 'neutron-metadata-agent' } + end + + it_configures 'neutron metadata agent' + it_configures 'neutron metadata agent with auth_insecure and auth_ca_cert set' + + end + +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_agents_metering_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_agents_metering_spec.rb new file mode 100644 index 000000000..03300f7d6 --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_agents_metering_spec.rb @@ -0,0 +1,120 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Unit tests for neutron::plugins::metering class +# + +require 'spec_helper' + +describe 'neutron::agents::metering' do + + let :pre_condition do + "class { 'neutron': + rabbit_password => 'passw0rd', + service_plugins => ['neutron.services.metering.metering_plugin.MeteringPlugin'] }" + end + + let :params do + {} + end + + let :default_params do + { :package_ensure => 'present', + :enabled => true, + :debug => false, + :interface_driver => 'neutron.agent.linux.interface.OVSInterfaceDriver', + :use_namespaces => true, + :measure_interval => '30', + :report_interval => '300' + } + end + + + shared_examples_for 'neutron metering agent' do + let :p do + default_params.merge(params) + end + + it { should contain_class('neutron::params') } + + it 'configures metering_agent.ini' do + should contain_neutron_metering_agent_config('DEFAULT/debug').with_value(p[:debug]); + should contain_neutron_metering_agent_config('DEFAULT/interface_driver').with_value(p[:interface_driver]); + should contain_neutron_metering_agent_config('DEFAULT/use_namespaces').with_value(p[:use_namespaces]); + should contain_neutron_metering_agent_config('DEFAULT/measure_interval').with_value(p[:measure_interval]); + should contain_neutron_metering_agent_config('DEFAULT/report_interval').with_value(p[:report_interval]); + end + + it 'installs neutron metering agent package' do + if platform_params.has_key?(:metering_agent_package) + should contain_package('neutron-metering-agent').with( + :name => platform_params[:metering_agent_package], + :ensure => p[:package_ensure] + ) + should contain_package('neutron').with_before(/Package\[neutron-metering-agent\]/) + should contain_package('neutron-metering-agent').with_before(/Neutron_metering_agent_config\[.+\]/) + should contain_package('neutron-metering-agent').with_before(/Neutron_config\[.+\]/) + else + should contain_package('neutron').with_before(/Neutron_metering_agent_config\[.+\]/) + end + end + + it 'configures neutron metering agent service' do + should contain_service('neutron-metering-service').with( + :name => platform_params[:metering_agent_service], + :enable => true, + :ensure => 'running', + :require => 'Class[Neutron]' + ) + end + + context 'with manage_service as false' do + before :each do + params.merge!(:manage_service => false) + end + it 'should not start/stop service' do + should contain_service('neutron-metering-service').without_ensure + end + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { :metering_agent_package => 'neutron-metering-agent', + :metering_agent_service => 'neutron-metering-agent' } + end + + it_configures 'neutron metering agent' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :metering_agent_package => 'openstack-neutron-metering-agent', + :metering_agent_service => 'neutron-metering-agent' } + end + + it_configures 'neutron metering agent' + end +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_agents_ml2_linuxbridge_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_agents_ml2_linuxbridge_spec.rb new file mode 100644 index 000000000..78d533dc4 --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_agents_ml2_linuxbridge_spec.rb @@ -0,0 +1,157 @@ +require 'spec_helper' + +describe 'neutron::agents::ml2::linuxbridge' do + + let :pre_condition do + "class { 'neutron': rabbit_password => 'passw0rd' }" + end + + let :default_params do + { :package_ensure => 'present', + :enabled => true, + :tunnel_types => [], + :local_ip => false, + :vxlan_group => '224.0.0.1', + :vxlan_ttl => false, + :vxlan_tos => false, + :polling_interval => 2, + :l2_population => false, + :physical_interface_mappings => [], + :firewall_driver => 'neutron.agent.linux.iptables_firewall.IptablesFirewallDriver' } + end + + let :params do + {} + end + + shared_examples_for 'neutron plugin linuxbridge agent with ml2 plugin' do + + context 'with default parameters' do + it { should contain_class('neutron::params') } + + it 'configures ml2_conf.ini' do + should contain_neutron_plugin_linuxbridge('agent/polling_interval').with_value(default_params[:polling_interval]) + should contain_neutron_plugin_linuxbridge('linux_bridge/physical_interface_mappings').with_value(default_params[:physical_interface_mappings].join(',')) + should contain_neutron_plugin_linuxbridge('securitygroup/firewall_driver').with_value(default_params[:firewall_driver]) + end + + it 'installs neutron linuxbridge agent package' do + if platform_params.has_key?(:linuxbridge_agent_package) + linuxbridge_agent_package = platform_params[:linuxbridge_agent_package] + else + linuxbridge_agent_package = platform_params[:linuxbridge_server_package] + end + + should contain_package('neutron-plugin-linuxbridge-agent').with( + :name => linuxbridge_agent_package, + :ensure => default_params[:package_ensure] + ) + + should contain_package('neutron-plugin-linuxbridge-agent').with_before(/Neutron_plugin_linuxbridge\[.+\]/) + end + + it 'configures neutron linuxbridge agent service' do + should contain_service('neutron-plugin-linuxbridge-agent').with( + :name => platform_params[:linuxbridge_agent_service], + :enable => true, + :ensure => 'running', + :require => 'Class[Neutron]' + ) + end + + it 'does not configre VXLAN tunneling' do + should contain_neutron_plugin_linuxbridge('vxlan/enable_vxlan').with_value(false) + should contain_neutron_plugin_linuxbridge('vxlan/local_ip').with_ensure('absent') + should contain_neutron_plugin_linuxbridge('vxlan/vxlan_group').with_ensure('absent') + should contain_neutron_plugin_linuxbridge('vxlan/l2_population').with_ensure('absent') + end + end + + context 'with VXLAN tunneling enabled' do + before do + params.merge!({ + :tunnel_types => ['vxlan'], + :local_ip => '192.168.0.10' + }) + end + + context 'when providing all parameters' do + it 'configures ml2_conf.ini' do + should contain_neutron_plugin_linuxbridge('vxlan/enable_vxlan').with_value(true) + should contain_neutron_plugin_linuxbridge('vxlan/local_ip').with_value(params[:local_ip]) + should contain_neutron_plugin_linuxbridge('vxlan/vxlan_group').with_value(default_params[:vxlan_group]) + should contain_neutron_plugin_linuxbridge('vxlan/vxlan_ttl').with_ensure('absent') + should contain_neutron_plugin_linuxbridge('vxlan/vxlan_tos').with_ensure('absent') + should contain_neutron_plugin_linuxbridge('vxlan/l2_population').with_value(default_params[:l2_population]) + end + end + + context 'when not providing or overriding some parameters' do + before do + params.merge!({ + :vxlan_group => '224.0.0.2', + :vxlan_ttl => 10, + :vxlan_tos => 2, + :l2_population => true, + }) + end + + it 'configures ml2_conf.ini' do + should contain_neutron_plugin_linuxbridge('vxlan/enable_vxlan').with_value(true) + should contain_neutron_plugin_linuxbridge('vxlan/local_ip').with_value(params[:local_ip]) + should contain_neutron_plugin_linuxbridge('vxlan/vxlan_group').with_value(params[:vxlan_group]) + should contain_neutron_plugin_linuxbridge('vxlan/vxlan_ttl').with_value(params[:vxlan_ttl]) + should contain_neutron_plugin_linuxbridge('vxlan/vxlan_tos').with_value(params[:vxlan_tos]) + should contain_neutron_plugin_linuxbridge('vxlan/l2_population').with_value(params[:l2_population]) + end + end + end + + context 'when providing the physical_interface_mappings parameter' do + before do + params.merge!(:physical_interface_mappings => ['physnet0:eth0', 'physnet1:eth1']) + end + + it 'configures physical interface mappings' do + should contain_neutron_plugin_linuxbridge('linux_bridge/physical_interface_mappings').with_value( + params[:physical_interface_mappings].join(',') + ) + end + end + + context 'with firewall_driver parameter set to false' do + before :each do + params.merge!(:firewall_driver => false) + end + it 'removes firewall driver configuration' do + should contain_neutron_plugin_linuxbridge('securitygroup/firewall_driver').with_ensure('absent') + end + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { :linuxbridge_agent_package => 'neutron-plugin-linuxbridge-agent', + :linuxbridge_agent_service => 'neutron-plugin-linuxbridge-agent' } + end + + it_configures 'neutron plugin linuxbridge agent with ml2 plugin' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :linuxbridge_server_package => 'openstack-neutron-linuxbridge', + :linuxbridge_agent_service => 'neutron-linuxbridge-agent' } + end + + it_configures 'neutron plugin linuxbridge agent with ml2 plugin' + end +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_agents_ml2_ovs_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_agents_ml2_ovs_spec.rb new file mode 100644 index 000000000..a09963a28 --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_agents_ml2_ovs_spec.rb @@ -0,0 +1,220 @@ +require 'spec_helper' + +describe 'neutron::agents::ml2::ovs' do + + let :pre_condition do + "class { 'neutron': rabbit_password => 'passw0rd' }" + end + + let :default_params do + { :package_ensure => 'present', + :enabled => true, + :bridge_uplinks => [], + :bridge_mappings => [], + :integration_bridge => 'br-int', + :enable_tunneling => false, + :local_ip => false, + :tunnel_bridge => 'br-tun', + :polling_interval => 2, + :l2_population => false, + :arp_responder => false, + :enable_distributed_routing => false, + :firewall_driver => 'neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver' } + end + + let :params do + {} + end + + shared_examples_for 'neutron plugin ovs agent with ml2 plugin' do + let :p do + default_params.merge(params) + end + + it { should contain_class('neutron::params') } + + it 'configures ovs_neutron_plugin.ini' do + should contain_neutron_plugin_ml2('agent/polling_interval').with_value(p[:polling_interval]) + should contain_neutron_plugin_ml2('agent/l2_population').with_value(p[:l2_population]) + should contain_neutron_plugin_ml2('agent/arp_responder').with_value(p[:arp_responder]) + should contain_neutron_plugin_ml2('ovs/integration_bridge').with_value(p[:integration_bridge]) + should contain_neutron_plugin_ml2('securitygroup/firewall_driver').\ + with_value(p[:firewall_driver]) + should contain_neutron_plugin_ml2('ovs/enable_tunneling').with_value(false) + should contain_neutron_plugin_ml2('ovs/tunnel_bridge').with_ensure('absent') + should contain_neutron_plugin_ml2('ovs/local_ip').with_ensure('absent') + end + + it 'configures vs_bridge' do + should contain_vs_bridge(p[:integration_bridge]).with( + :ensure => 'present', + :before => 'Service[neutron-ovs-agent-service]' + ) + should_not contain_vs_brige(p[:integration_bridge]) + end + + it 'installs neutron ovs agent package' do + if platform_params.has_key?(:ovs_agent_package) + should contain_package('neutron-ovs-agent').with( + :name => platform_params[:ovs_agent_package], + :ensure => p[:package_ensure] + ) + should contain_package('neutron-ovs-agent').with_before(/Neutron_plugin_ml2\[.+\]/) + else + end + end + + it 'configures neutron ovs agent service' do + should contain_service('neutron-ovs-agent-service').with( + :name => platform_params[:ovs_agent_service], + :enable => true, + :ensure => 'running', + :require => 'Class[Neutron]' + ) + end + + context 'when supplying a firewall driver' do + before :each do + params.merge!(:firewall_driver => false) + end + it 'should configure firewall driver' do + should contain_neutron_plugin_ml2('securitygroup/firewall_driver').with_ensure('absent') + end + end + + context 'when enabling ARP responder' do + before :each do + params.merge!(:arp_responder => true) + end + it 'should enable ARP responder' do + should contain_neutron_plugin_ml2('agent/arp_responder').with_value(true) + end + end + + context 'when enabling DVR' do + before :each do + params.merge!(:enable_distributed_routing => true, + :l2_population => true ) + end + it 'should enable DVR' do + should contain_neutron_plugin_ml2('agent/enable_distributed_routing').with_value(true) + end + end + + context 'when supplying bridge mappings for provider networks' do + before :each do + params.merge!(:bridge_uplinks => ['br-ex:eth2'],:bridge_mappings => ['default:br-ex']) + end + + it 'configures bridge mappings' do + should contain_neutron_plugin_ml2('ovs/bridge_mappings') + end + + it 'should configure bridge mappings' do + should contain_neutron__plugins__ovs__bridge(params[:bridge_mappings].join(',')).with( + :before => 'Service[neutron-ovs-agent-service]' + ) + end + + it 'should configure bridge uplinks' do + should contain_neutron__plugins__ovs__port(params[:bridge_uplinks].join(',')).with( + :before => 'Service[neutron-ovs-agent-service]' + ) + end + end + + context 'when enabling tunneling' do + context 'without local ip address' do + before :each do + params.merge!(:enable_tunneling => true) + end + it 'should fail' do + expect do + subject + end.to raise_error(Puppet::Error, /Local ip for ovs agent must be set when tunneling is enabled/) + end + end + context 'with default params' do + before :each do + params.merge!(:enable_tunneling => true, :local_ip => '127.0.0.1' ) + end + it 'should configure ovs for tunneling' do + should contain_neutron_plugin_ml2('ovs/enable_tunneling').with_value(true) + should contain_neutron_plugin_ml2('ovs/tunnel_bridge').with_value(default_params[:tunnel_bridge]) + should contain_neutron_plugin_ml2('ovs/local_ip').with_value('127.0.0.1') + should contain_vs_bridge(default_params[:tunnel_bridge]).with( + :ensure => 'present', + :before => 'Service[neutron-ovs-agent-service]' + ) + end + end + + context 'with vxlan tunneling' do + before :each do + params.merge!(:enable_tunneling => true, + :local_ip => '127.0.0.1', + :tunnel_types => ['vxlan'], + :vxlan_udp_port => '4789') + end + + it 'should perform vxlan network configuration' do + should contain_neutron_plugin_ml2('agent/tunnel_types').with_value(params[:tunnel_types]) + should contain_neutron_plugin_ml2('agent/vxlan_udp_port').with_value(params[:vxlan_udp_port]) + end + end + + context 'when l2 population is disabled and DVR enabled' do + before :each do + params.merge!(:enable_distributed_routing => true, + :l2_population => false ) + end + it 'should fail' do + expect do + subject + end.to raise_error(Puppet::Error, /L2 population must be enabled when DVR is enabled/) + end + end + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { :ovs_agent_package => 'neutron-plugin-openvswitch-agent', + :ovs_agent_service => 'neutron-plugin-openvswitch-agent' } + end + + it_configures 'neutron plugin ovs agent with ml2 plugin' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :ovs_cleanup_service => 'neutron-ovs-cleanup', + :ovs_agent_service => 'neutron-openvswitch-agent' } + end + + it_configures 'neutron plugin ovs agent with ml2 plugin' + + it 'configures neutron ovs cleanup service' do + should contain_service('ovs-cleanup-service').with( + :name => platform_params[:ovs_cleanup_service], + :enable => true + ) + should contain_package('neutron-ovs-agent').with_before(/Service\[ovs-cleanup-service\]/) + end + + it 'links from ovs config to plugin config' do + should contain_file('/etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini').with( + :ensure => 'link', + :target => '/etc/neutron/plugins/ml2/ml2_conf.ini' + ) + end + end +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_agents_ml2_sriov_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_agents_ml2_sriov_spec.rb new file mode 100644 index 000000000..d61ed0294 --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_agents_ml2_sriov_spec.rb @@ -0,0 +1,90 @@ +require 'spec_helper' + +describe 'neutron::agents::ml2::sriov' do + + let :pre_condition do + "class { 'neutron': rabbit_password => 'passw0rd' }" + end + + let :default_params do + { :package_ensure => 'present', + :enabled => true, + :physical_device_mappings => [], + :exclude_devices => [], + :polling_interval => 2, + } + end + + let :params do + {} + end + + shared_examples_for 'neutron sriov-nic agent with ml2 plugin' do + let :p do + default_params.merge(params) + end + + it { should contain_class('neutron::params') } + + it 'configures ovs_neutron_plugin.ini' do + should contain_neutron_plugin_ml2('sriov_nic/polling_interval').with_value(p[:polling_interval]) + should contain_neutron_plugin_ml2('sriov_nic/exclude_devices').with_value(p[:exclude_devices].join(',')) + should contain_neutron_plugin_ml2('sriov_nic/physical_device_mappings').with_value(p[:physical_device_mappings].join(',')) + end + + it 'installs neutron sriov-nic agent package' do + should contain_package('neutron-sriov-nic-agent').with( + :name => platform_params[:sriov_nic_agent_package], + :ensure => p[:package_ensure] + ) + should contain_package('neutron-sriov-nic-agent').with_before(/Neutron_plugin_ml2\[.+\]/) + end + + it 'configures neutron ovs agent service' do + should contain_service('neutron-sriov-nic-agent-service').with( + :name => platform_params[:sriov_nic_agent_service], + :enable => true, + :ensure => 'running', + :require => 'Class[Neutron]' + ) + end + + context 'when supplying device mapping' do + before :each do + params.merge!(:physical_device_mappings => ['physnet1:eth1'], + :exclude_devices => ['physnet1:eth2']) + end + + it 'configures physical device mappings with exclusion' do + should contain_neutron_plugin_ml2('sriov_nic/exclude_devices').with_value(['physnet1:eth2']) + should contain_neutron_plugin_ml2('sriov_nic/physical_device_mappings').with_value(['physnet1:eth1']) + end + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { :sriov_nic_agent_package => 'neutron-plugin-sriov-agent', + :sriov_nic_agent_service => 'neutron-plugin-sriov-agent' } + end + + it_configures 'neutron sriov-nic agent with ml2 plugin' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :sriov_nic_agent_package => 'openstack-neutron-sriov-nic-agent', + :sriov_nic_agent_service => 'neutron-sriov-nic-agent' } + end + + it_configures 'neutron sriov-nic agent with ml2 plugin' + end +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_agents_n1kv_vem_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_agents_n1kv_vem_spec.rb new file mode 100644 index 000000000..4eeee17e6 --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_agents_n1kv_vem_spec.rb @@ -0,0 +1,215 @@ +require 'spec_helper' + +describe 'neutron::agents::n1kv_vem' do + + let :facts do + { :osfamily => 'RedHat' } + end + + it 'should have a n1kv-vem config file' do + should contain_file('/etc/n1kv/n1kv.conf').with( + :ensure => 'present', + :owner => 'root', + :group => 'root', + :mode => '0664' + ) + end + + it 'install n1kv-vem' do + should contain_package('libnl').with_before('Package[nexus1000v]') + should contain_service('openvswitch').with_notify('Package[nexus1000v]') + should contain_package('nexus1000v').with_notify('Service[nexus1000v]') + should contain_service('nexus1000v').with_ensure('running') + end + + context 'with local file vem rpm' do + let :params do + { + :n1kv_source => 'vem.rpm' + } + end + + it 'verify dependency' do + should contain_package('nexus1000v').with_source('/var/n1kv/vem.rpm') + should contain_file('/var/n1kv/vem.rpm').that_requires('File[/var/n1kv]') + should contain_file('/var/n1kv/vem.rpm').with( + :owner => 'root', + :group => 'root', + :mode => '0664' + ) + end + end + + context 'remote vem rpm' do + let :params do + { + :n1kv_source => 'http://www.cisco.com/repo' + } + end + + it 'verify dependency' do + should contain_package('nexus1000v').without_source + should contain_yumrepo('cisco-vem-repo').with( + :baseurl => 'http://www.cisco.com/repo', + :enabled => 1 + ) + end + end + + it 'execute reread config upon config change' do + should contain_exec('vemcmd reread config') \ + .that_subscribes_to('File[/etc/n1kv/n1kv.conf]') + end + + context 'verify n1kv.conf default' do + let :params do + { + :n1kv_vsm_ip => '9.0.0.1', + :n1kv_vsm_domain_id => 900, + :host_mgmt_intf => 'eth9', + :portdb => 'ovs', + :fastpath_flood => 'disable' + } + end + it do + should contain_file('/etc/n1kv/n1kv.conf') \ + .with_content(/^l3control-ipaddr 9.0.0.1/) + should contain_file('/etc/n1kv/n1kv.conf') \ + .with_content(/^switch-domain 900/) + should contain_file('/etc/n1kv/n1kv.conf') \ + .with_content(/^host-mgmt-intf eth9/) + should contain_file('/etc/n1kv/n1kv.conf') \ + .with_content(/^portdb ovs/) + should contain_file('/etc/n1kv/n1kv.conf') \ + .without_content(/^phys/) + should contain_file('/etc/n1kv/n1kv.conf') \ + .without_content(/^virt/) + should contain_file('/etc/n1kv/n1kv.conf') \ + .with_content(/^node-type compute/) + should contain_file('/etc/n1kv/n1kv.conf') \ + .with_content(/^fastpath-flood disable/) + end + end + + context 'verify node_type' do + let :params do + { + :node_type => 'network', + } + end + it do + should contain_file('/etc/n1kv/n1kv.conf') \ + .with_content(/^node-type network/) + should contain_file('/etc/n1kv/n1kv.conf') \ + .without_content(/^node-type compute/) + end + end + + context 'verify portdb' do + let :params do + { + :portdb => 'vem', + } + end + it do + should contain_file('/etc/n1kv/n1kv.conf') \ + .with_content(/^portdb vem/) + should contain_file('/etc/n1kv/n1kv.conf') \ + .without_content(/^portdb ovs/) + end + end + + context 'verify fastpath_flood' do + let :params do + { + :fastpath_flood => 'enable', + } + end + it do + should contain_file('/etc/n1kv/n1kv.conf') \ + .with_content(/^fastpath-flood enable/) + should contain_file('/etc/n1kv/n1kv.conf') \ + .without_content(/^fastpath-flood disable/) + end + end + + context 'verify n1kv.conf with uplinks' do + let :params do + { + :uplink_profile => { 'eth1' => 'prof1', + 'eth2' => 'prof2' + } + } + end + it do + should contain_file('/etc/n1kv/n1kv.conf') \ + .with_content(/^phys eth1 profile prof1/) + should contain_file('/etc/n1kv/n1kv.conf') \ + .with_content(/^phys eth2 profile prof2/) + end + + end + + context 'verify n1kv.conf with vtep info' do + let :params do + { + :vtep_config => { 'vtep1' => { 'profile' => 'profint', + 'ipmode' => 'dhcp' + }, + 'vtep2' => { 'profile' => 'profint', + 'ipmode' => 'static', + 'ipaddress' => '192.168.1.1', + 'netmask' => '255.255.255.0' + } + } + } + end + it do + should contain_file('/etc/n1kv/n1kv.conf') \ + .with_content(/^virt vtep1 profile profint mode dhcp/) + should contain_file('/etc/n1kv/n1kv.conf') \ + .with_content(/^virt vtep2 profile profint mode static/) + end + + end + + context 'with manage_service as false' do + let :params do + { + :manage_service => false + } + end + it 'should not start/stop service' do + should contain_service('nexus1000v').without_ensure + end + end + + context 'with manage_service true and enable_service false' do + let :params do + { + :manage_service => true, + :enable => false + } + end + it 'should stop service' do + should contain_service('nexus1000v').with_ensure('stopped') + end + end + + context 'verify sysctl setting with vteps_in_same_subnet true' do + let :params do + { + :vteps_in_same_subnet => true + } + end + it do + should contain_sysctl__value('net.ipv4.conf.default.rp_filter').with_value('2') + should contain_sysctl__value('net.ipv4.conf.all.rp_filter').with_value('2') + should contain_sysctl__value('net.ipv4.conf.default.arp_ignore').with_value('1') + should contain_sysctl__value('net.ipv4.conf.all.arp_ignore').with_value('1') + should contain_sysctl__value('net.ipv4.conf.all.arp_announce').with_value('2') + should contain_sysctl__value('net.ipv4.conf.default.arp_announce').with_value('2') + end + end + +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_agents_ovs_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_agents_ovs_spec.rb new file mode 100644 index 000000000..dd9090b07 --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_agents_ovs_spec.rb @@ -0,0 +1,200 @@ +require 'spec_helper' + +describe 'neutron::agents::ovs' do + + let :pre_condition do + "class { 'neutron': rabbit_password => 'passw0rd' }\n" + + "class { 'neutron::plugins::ovs': network_vlan_ranges => 'physnet1:1000:2000' }" + end + + let :default_params do + { :package_ensure => 'present', + :manage_service => true, + :enabled => true, + :bridge_uplinks => [], + :bridge_mappings => [], + :integration_bridge => 'br-int', + :enable_tunneling => false, + :local_ip => false, + :tunnel_bridge => 'br-tun', + :polling_interval => 2, + :firewall_driver => 'neutron.agent.linux.iptables_firewall.OVSHybridIptablesFirewallDriver', + :veth_mtu => '' + } + end + + let :params do + {} + end + + shared_examples_for 'neutron plugin ovs agent' do + let :p do + default_params.merge(params) + end + + it { should contain_class('neutron::params') } + + it 'configures ovs_neutron_plugin.ini' do + should contain_neutron_plugin_ovs('AGENT/polling_interval').with_value(p[:polling_interval]) + should contain_neutron_plugin_ovs('OVS/integration_bridge').with_value(p[:integration_bridge]) + should contain_neutron_plugin_ovs('SECURITYGROUP/firewall_driver').\ + with_value(p[:firewall_driver]) + should contain_neutron_plugin_ovs('OVS/enable_tunneling').with_value(false) + should contain_neutron_plugin_ovs('OVS/tunnel_bridge').with_ensure('absent') + should contain_neutron_plugin_ovs('OVS/local_ip').with_ensure('absent') + should contain_neutron_plugin_ovs('AGENT/veth_mtu').with_ensure('absent') + end + + it 'configures vs_bridge' do + should contain_vs_bridge(p[:integration_bridge]).with_ensure('present') + end + + it 'installs neutron ovs agent package' do + if platform_params.has_key?(:ovs_agent_package) + should contain_package('neutron-plugin-ovs-agent').with( + :name => platform_params[:ovs_agent_package], + :ensure => p[:package_ensure] + ) + should contain_package('neutron-plugin-ovs-agent').with_before(/Neutron_plugin_ovs\[.+\]/) + else + should contain_package('neutron-plugin-ovs').with_before(/Neutron_plugin_ovs\[.+\]/) + end + end + + it 'configures neutron ovs agent service' do + should contain_service('neutron-plugin-ovs-service').with( + :name => platform_params[:ovs_agent_service], + :enable => true, + :ensure => 'running', + :require => 'Class[Neutron]' + ) + end + + context 'with veth_mtu set' do + before :each do + params.merge(:veth_mtu => '9000') + end + + it 'should set the veth_mtu on the ovs agent' do + should contain_neutron_plugin_ovs('AGENT/veth_mtu').with_value(params[:veth_mtu]) + end + end + + context 'when not installing ovs agent package' do + before :each do + params.merge!(:package_ensure => 'absent') + end + it 'uninstalls neutron ovs agent package' do + if platform_params.has_key?(:ovs_agent_package) + should contain_package('neutron-plugin-ovs-agent').with( + :name => platform_params[:ovs_agent_package], + :ensure => p[:package_ensure] + ) + end + end + end + + context 'when supplying a firewall driver' do + before :each do + params.merge!(:firewall_driver => false) + end + it 'should configure firewall driver' do + should contain_neutron_plugin_ovs('SECURITYGROUP/firewall_driver').with_ensure('absent') + end + end + + context 'when supplying bridge mappings for provider networks' do + before :each do + params.merge!(:bridge_uplinks => ['br-ex:eth2'],:bridge_mappings => ['default:br-ex']) + end + + it 'configures bridge mappings' do + should contain_neutron_plugin_ovs('OVS/bridge_mappings') + end + + it 'should configure bridge mappings' do + should contain_neutron__plugins__ovs__bridge(params[:bridge_mappings].join(',')).with( + :before => 'Service[neutron-plugin-ovs-service]' + ) + end + + it 'should configure bridge uplinks' do + should contain_neutron__plugins__ovs__port(params[:bridge_uplinks].join(',')).with( + :before => 'Service[neutron-plugin-ovs-service]' + ) + end + end + + context 'when enabling tunneling' do + context 'without local ip address' do + before :each do + params.merge!(:enable_tunneling => true) + end + it 'should fail' do + expect do + subject + end.to raise_error(Puppet::Error, /Local ip for ovs agent must be set when tunneling is enabled/) + end + end + context 'with default params' do + before :each do + params.merge!(:enable_tunneling => true, :local_ip => '127.0.0.1' ) + end + it 'should configure ovs for tunneling' do + should contain_neutron_plugin_ovs('OVS/enable_tunneling').with_value(true) + should contain_neutron_plugin_ovs('OVS/tunnel_bridge').with_value(default_params[:tunnel_bridge]) + should contain_neutron_plugin_ovs('OVS/local_ip').with_value('127.0.0.1') + should contain_vs_bridge(default_params[:tunnel_bridge]).with_ensure('present') + end + end + + context 'with vxlan tunneling' do + before :each do + params.merge!(:enable_tunneling => true, + :local_ip => '127.0.0.1', + :tunnel_types => ['vxlan'], + :vxlan_udp_port => '4789') + end + + it 'should perform vxlan network configuration' do + should contain_neutron_plugin_ovs('agent/tunnel_types').with_value(params[:tunnel_types]) + should contain_neutron_plugin_ovs('agent/vxlan_udp_port').with_value(params[:vxlan_udp_port]) + end + end + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { :ovs_agent_package => 'neutron-plugin-openvswitch-agent', + :ovs_agent_service => 'neutron-plugin-openvswitch-agent' } + end + + it_configures 'neutron plugin ovs agent' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :ovs_cleanup_service => 'neutron-ovs-cleanup', + :ovs_agent_service => 'neutron-openvswitch-agent' } + end + + it_configures 'neutron plugin ovs agent' + it 'configures neutron ovs cleanup service' do + should contain_service('ovs-cleanup-service').with( + :name => platform_params[:ovs_cleanup_service], + :enable => true + ) + should contain_package('neutron-plugin-ovs').with_before(/Service\[ovs-cleanup-service\]/) + end + + end +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_agents_vpnaas_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_agents_vpnaas_spec.rb new file mode 100644 index 000000000..8ecf1ff60 --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_agents_vpnaas_spec.rb @@ -0,0 +1,160 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Unit tests for neutron::agents::vpnaas class +# + +require 'spec_helper' + +describe 'neutron::agents::vpnaas' do + + let :pre_condition do + "class { 'neutron': rabbit_password => 'passw0rd' }" + end + + let :params do + {} + end + + let :default_params do + { :package_ensure => 'present', + :enabled => true, + :vpn_device_driver => 'neutron.services.vpn.device_drivers.ipsec.OpenSwanDriver', + :interface_driver => 'neutron.agent.linux.interface.OVSInterfaceDriver', + :ipsec_status_check_interval => '60' + } + end + + + shared_examples_for 'neutron vpnaas agent' do + let :p do + default_params.merge(params) + end + + it { should contain_class('neutron::params') } + + it_configures 'openswan vpnaas_driver' + + it 'configures vpnaas_agent.ini' do + should contain_neutron_vpnaas_agent_config('vpnagent/vpn_device_driver').with_value(p[:vpn_device_driver]); + should contain_neutron_vpnaas_agent_config('ipsec/ipsec_status_check_interval').with_value(p[:ipsec_status_check_interval]); + should contain_neutron_vpnaas_agent_config('DEFAULT/interface_driver').with_value(p[:interface_driver]); + should contain_neutron_vpnaas_agent_config('DEFAULT/external_network_bridge').with_ensure('absent'); + end + + context 'with external_network_bridge as br-ex' do + before do + params.merge!( + :external_network_bridge => 'br-ex' + ) + end + + it 'configures vpnaas_agent.ini' do + should contain_neutron_vpnaas_agent_config('DEFAULT/external_network_bridge').with_value(p[:external_network_bridge]); + end + end + + it 'installs neutron vpnaas agent package' do + if platform_params.has_key?(:vpnaas_agent_package) + should contain_package('neutron-vpnaas-agent').with( + :name => platform_params[:vpnaas_agent_package], + :ensure => p[:package_ensure] + ) + should contain_package('neutron').with_before(/Package\[neutron-vpnaas-agent\]/) + should contain_package('neutron-vpnaas-agent').with_before(/Neutron_vpnaas_agent_config\[.+\]/) + else + should contain_package('neutron').with_before(/Neutron_vpnaas_agent_config\[.+\]/) + end + end + + it 'configures neutron vpnaas agent service' do + should contain_service('neutron-vpnaas-service').with( + :name => platform_params[:vpnaas_agent_service], + :enable => true, + :ensure => 'running', + :require => 'Class[Neutron]' + ) + end + + context 'with manage_service as false' do + before :each do + params.merge!(:manage_service => false) + end + it 'should not start/stop service' do + should contain_service('neutron-vpnaas-service').without_ensure + end + end + end + + shared_examples_for 'openswan vpnaas_driver' do + it 'installs openswan packages' do + if platform_params.has_key?(:vpnaas_agent_package) + should contain_package('openswan').with_before('Package[neutron-vpnaas-agent]') + end + should contain_package('openswan').with( + :ensure => 'present', + :name => platform_params[:openswan_package] + ) + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { :openswan_package => 'openswan', + :vpnaas_agent_package => 'neutron-vpn-agent', + :vpnaas_agent_service => 'neutron-vpn-agent' } + end + + it_configures 'neutron vpnaas agent' + end + + context 'on RedHat 6 platforms' do + let :facts do + { :osfamily => 'RedHat', + :operatingsystemrelease => '6.5', + :operatingsystemmajrelease => 6 } + end + + let :platform_params do + { :openswan_package => 'openswan', + :vpnaas_agent_package => 'openstack-neutron-vpn-agent', + :vpnaas_agent_service => 'neutron-vpn-agent'} + end + + it_configures 'neutron vpnaas agent' + end + + context 'on RedHat 7 platforms' do + let :facts do + { :osfamily => 'RedHat', + :operatingsystemrelease => '7.1.2', + :operatingsystemmajrelease => 7 } + end + + let :platform_params do + { :openswan_package => 'libreswan', + :vpnaas_agent_package => 'openstack-neutron-vpn-agent', + :vpnaas_agent_service => 'neutron-vpn-agent'} + end + + it_configures 'neutron vpnaas agent' + end +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_client_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_client_spec.rb new file mode 100644 index 000000000..8d6239f95 --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_client_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' + +describe 'neutron::client' do + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it { should contain_class('neutron::client') } + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it { should contain_class('neutron::client') } + end +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_db_mysql_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_db_mysql_spec.rb new file mode 100644 index 000000000..559a7fd4b --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_db_mysql_spec.rb @@ -0,0 +1,76 @@ +require 'spec_helper' + +describe 'neutron::db::mysql' do + + let :pre_condition do + 'include mysql::server' + end + + let :params do + { :password => 'passw0rd', + } + end + let :facts do + { :osfamily => 'Debian' } + end + + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it { should contain_openstacklib__db__mysql('neutron').with( + :user => 'neutron', + :password_hash => '*74B1C21ACE0C2D6B0678A5E503D2A60E8F9651A3', + :host => '127.0.0.1', + :charset => 'utf8', + :collate => 'utf8_general_ci', + ) } + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it { should contain_openstacklib__db__mysql('neutron').with( + :user => 'neutron', + :password_hash => '*74B1C21ACE0C2D6B0678A5E503D2A60E8F9651A3', + :host => '127.0.0.1', + :charset => 'utf8', + :collate => 'utf8_general_ci', + ) } + end + + describe "overriding allowed_hosts param to array" do + let :params do + { + :password => 'neutronpass', + :allowed_hosts => ['127.0.0.1','%'] + } + end + + end + + describe "overriding allowed_hosts param to string" do + let :params do + { + :password => 'neutronpass2', + :allowed_hosts => '192.168.1.1' + } + end + + end + + describe "overriding allowed_hosts param equals to host param " do + let :params do + { + :password => 'neutronpass2', + :allowed_hosts => '127.0.0.1' + } + end + + end +end + diff --git a/3rdparty/modules/neutron/spec/classes/neutron_init_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_init_spec.rb new file mode 100644 index 000000000..8a475da96 --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_init_spec.rb @@ -0,0 +1,425 @@ +require 'spec_helper' + +describe 'neutron' do + + let :params do + { :package_ensure => 'present', + :verbose => false, + :debug => false, + :core_plugin => 'linuxbridge', + :rabbit_host => '127.0.0.1', + :rabbit_port => 5672, + :rabbit_hosts => false, + :rabbit_user => 'guest', + :rabbit_password => 'guest', + :rabbit_virtual_host => '/', + :kombu_reconnect_delay => '1.0', + :log_dir => '/var/log/neutron', + :report_interval => '30', + } + end + + shared_examples_for 'neutron' do + + context 'and if rabbit_host parameter is provided' do + it_configures 'a neutron base installation' + end + + context 'and if rabbit_hosts parameter is provided' do + before do + params.delete(:rabbit_host) + params.delete(:rabbit_port) + end + + context 'with one server' do + before { params.merge!( :rabbit_hosts => ['127.0.0.1:5672'] ) } + it_configures 'a neutron base installation' + it_configures 'rabbit HA with a single virtual host' + end + + context 'with multiple servers' do + before { params.merge!( :rabbit_hosts => ['rabbit1:5672', 'rabbit2:5672'] ) } + it_configures 'a neutron base installation' + it_configures 'rabbit HA with multiple hosts' + end + + it 'configures logging' do + should contain_neutron_config('DEFAULT/log_file').with_ensure('absent') + should contain_neutron_config('DEFAULT/log_dir').with_value(params[:log_dir]) + end + + end + + it_configures 'with SSL enabled with kombu' + it_configures 'with SSL enabled without kombu' + it_configures 'with SSL disabled' + it_configures 'with SSL wrongly configured' + it_configures 'with SSL and kombu wrongly configured' + it_configures 'with SSL socket options set' + it_configures 'with SSL socket options set with wrong parameters' + it_configures 'with SSL socket options set to false' + it_configures 'with syslog disabled' + it_configures 'with syslog enabled' + it_configures 'with syslog enabled and custom settings' + it_configures 'with log_file specified' + it_configures 'with logging disabled' + it_configures 'without service_plugins' + it_configures 'with service_plugins' + end + + shared_examples_for 'a neutron base installation' do + + it { should contain_class('neutron::params') } + + it 'configures neutron configuration folder' do + should contain_file('/etc/neutron/').with( + :ensure => 'directory', + :owner => 'root', + :group => 'neutron', + :mode => '0750', + :require => 'Package[neutron]' + ) + end + + it 'configures neutron configuration file' do + should contain_file('/etc/neutron/neutron.conf').with( + :owner => 'root', + :group => 'neutron', + :mode => '0640', + :require => 'Package[neutron]' + ) + end + + it 'installs neutron package' do + should contain_package('neutron').with( + :ensure => 'present', + :name => platform_params[:common_package_name] + ) + end + + it 'configures credentials for rabbit' do + should contain_neutron_config('DEFAULT/rabbit_userid').with_value( params[:rabbit_user] ) + should contain_neutron_config('DEFAULT/rabbit_password').with_value( params[:rabbit_password] ) + should contain_neutron_config('DEFAULT/rabbit_password').with_secret( true ) + should contain_neutron_config('DEFAULT/rabbit_virtual_host').with_value( params[:rabbit_virtual_host] ) + should contain_neutron_config('DEFAULT/kombu_reconnect_delay').with_value( params[:kombu_reconnect_delay] ) + end + + it 'configures neutron.conf' do + should contain_neutron_config('DEFAULT/verbose').with_value( params[:verbose] ) + should contain_neutron_config('DEFAULT/bind_host').with_value('0.0.0.0') + should contain_neutron_config('DEFAULT/bind_port').with_value('9696') + should contain_neutron_config('DEFAULT/auth_strategy').with_value('keystone') + should contain_neutron_config('DEFAULT/core_plugin').with_value( params[:core_plugin] ) + should contain_neutron_config('DEFAULT/base_mac').with_value('fa:16:3e:00:00:00') + should contain_neutron_config('DEFAULT/mac_generation_retries').with_value(16) + should contain_neutron_config('DEFAULT/dhcp_lease_duration').with_value(86400) + should contain_neutron_config('DEFAULT/dhcp_agents_per_network').with_value(1) + should contain_neutron_config('DEFAULT/network_device_mtu').with_ensure('absent') + should contain_neutron_config('DEFAULT/dhcp_agent_notification').with_value(true) + should contain_neutron_config('DEFAULT/allow_bulk').with_value(true) + should contain_neutron_config('DEFAULT/allow_pagination').with_value(false) + should contain_neutron_config('DEFAULT/allow_sorting').with_value(false) + should contain_neutron_config('DEFAULT/allow_overlapping_ips').with_value(false) + should contain_neutron_config('DEFAULT/api_extensions_path').with_value(nil) + should contain_neutron_config('DEFAULT/control_exchange').with_value('neutron') + should contain_neutron_config('agent/root_helper').with_value('sudo neutron-rootwrap /etc/neutron/rootwrap.conf') + should contain_neutron_config('agent/report_interval').with_value('30') + end + end + + shared_examples_for 'rabbit HA with a single virtual host' do + it 'in neutron.conf' do + should_not contain_neutron_config('DEFAULT/rabbit_host') + should_not contain_neutron_config('DEFAULT/rabbit_port') + should contain_neutron_config('DEFAULT/rabbit_hosts').with_value( params[:rabbit_hosts] ) + should contain_neutron_config('DEFAULT/rabbit_ha_queues').with_value(true) + end + end + + shared_examples_for 'rabbit HA with multiple hosts' do + it 'in neutron.conf' do + should_not contain_neutron_config('DEFAULT/rabbit_host') + should_not contain_neutron_config('DEFAULT/rabbit_port') + should contain_neutron_config('DEFAULT/rabbit_hosts').with_value( params[:rabbit_hosts].join(',') ) + should contain_neutron_config('DEFAULT/rabbit_ha_queues').with_value(true) + end + end + + shared_examples_for 'with SSL socket options set' do + before do + params.merge!( + :use_ssl => true, + :cert_file => '/path/to/cert', + :key_file => '/path/to/key', + :ca_file => '/path/to/ca' + ) + end + + it { should contain_neutron_config('DEFAULT/use_ssl').with_value('true') } + it { should contain_neutron_config('DEFAULT/ssl_cert_file').with_value('/path/to/cert') } + it { should contain_neutron_config('DEFAULT/ssl_key_file').with_value('/path/to/key') } + it { should contain_neutron_config('DEFAULT/ssl_ca_file').with_value('/path/to/ca') } + end + + shared_examples_for 'with SSL socket options set with wrong parameters' do + before do + params.merge!( + :use_ssl => true, + :key_file => '/path/to/key', + :ca_file => '/path/to/ca' + ) + end + + it_raises 'a Puppet::Error', /The cert_file parameter is required when use_ssl is set to true/ + end + + shared_examples_for 'with SSL socket options set to false' do + before do + params.merge!( + :use_ssl => false, + :cert_file => false, + :key_file => false, + :ca_file => false + ) + end + + it { should contain_neutron_config('DEFAULT/use_ssl').with_value('false') } + it { should contain_neutron_config('DEFAULT/ssl_cert_file').with_ensure('absent') } + it { should contain_neutron_config('DEFAULT/ssl_key_file').with_ensure('absent') } + it { should contain_neutron_config('DEFAULT/ssl_ca_file').with_ensure('absent') } + end + + shared_examples_for 'with SSL socket options set and no ca_file' do + before do + params.merge!( + :use_ssl => true, + :cert_file => '/path/to/cert', + :key_file => '/path/to/key' + ) + end + + it { should contain_neutron_config('DEFAULT/use_ssl').with_value('true') } + it { should contain_neutron_config('DEFAULT/ssl_cert_file').with_value('/path/to/cert') } + it { should contain_neutron_config('DEFAULT/ssl_key_file').with_value('/path/to/key') } + it { should contain_neutron_config('DEFAULT/ssl_ca_file').with_ensure('absent') } + end + + shared_examples_for 'with SSL socket options disabled with ca_file' do + before do + params.merge!( + :use_ssl => false, + :ca_file => '/path/to/ca' + ) + end + + it_raises 'a Puppet::Error', /The ca_file parameter requires that use_ssl to be set to true/ + end + + shared_examples_for 'with syslog disabled' do + it { should contain_neutron_config('DEFAULT/use_syslog').with_value(false) } + end + + shared_examples_for 'with SSL enabled with kombu' do + before do + params.merge!( + :rabbit_use_ssl => true, + :kombu_ssl_ca_certs => '/path/to/ssl/ca/certs', + :kombu_ssl_certfile => '/path/to/ssl/cert/file', + :kombu_ssl_keyfile => '/path/to/ssl/keyfile', + :kombu_ssl_version => 'TLSv1' + ) + end + + it do + should contain_neutron_config('DEFAULT/rabbit_use_ssl').with_value('true') + should contain_neutron_config('DEFAULT/kombu_ssl_ca_certs').with_value('/path/to/ssl/ca/certs') + should contain_neutron_config('DEFAULT/kombu_ssl_certfile').with_value('/path/to/ssl/cert/file') + should contain_neutron_config('DEFAULT/kombu_ssl_keyfile').with_value('/path/to/ssl/keyfile') + should contain_neutron_config('DEFAULT/kombu_ssl_version').with_value('TLSv1') + end + end + + shared_examples_for 'with SSL enabled without kombu' do + before do + params.merge!( + :rabbit_use_ssl => true + ) + end + + it do + should contain_neutron_config('DEFAULT/rabbit_use_ssl').with_value('true') + should contain_neutron_config('DEFAULT/kombu_ssl_ca_certs').with_ensure('absent') + should contain_neutron_config('DEFAULT/kombu_ssl_certfile').with_ensure('absent') + should contain_neutron_config('DEFAULT/kombu_ssl_keyfile').with_ensure('absent') + should contain_neutron_config('DEFAULT/kombu_ssl_version').with_value('TLSv1') + end + end + + shared_examples_for 'with SSL disabled' do + before do + params.merge!( + :rabbit_use_ssl => false, + :kombu_ssl_version => 'TLSv1' + ) + end + + it do + should contain_neutron_config('DEFAULT/rabbit_use_ssl').with_value('false') + should contain_neutron_config('DEFAULT/kombu_ssl_ca_certs').with_ensure('absent') + should contain_neutron_config('DEFAULT/kombu_ssl_certfile').with_ensure('absent') + should contain_neutron_config('DEFAULT/kombu_ssl_keyfile').with_ensure('absent') + should contain_neutron_config('DEFAULT/kombu_ssl_version').with_ensure('absent') + end + end + + shared_examples_for 'with SSL wrongly configured' do + before do + params.merge!( + :rabbit_use_ssl => false + ) + end + + context 'with SSL disabled' do + + context 'with kombu_ssl_ca_certs parameter' do + before { params.merge!(:kombu_ssl_ca_certs => '/path/to/ssl/ca/certs') } + it_raises 'a Puppet::Error', /The kombu_ssl_ca_certs parameter requires rabbit_use_ssl to be set to true/ + end + + context 'with kombu_ssl_certfile parameter' do + before { params.merge!(:kombu_ssl_certfile => '/path/to/ssl/cert/file') } + it_raises 'a Puppet::Error', /The kombu_ssl_certfile parameter requires rabbit_use_ssl to be set to true/ + end + + context 'with kombu_ssl_keyfile parameter' do + before { params.merge!(:kombu_ssl_keyfile => '/path/to/ssl/keyfile') } + it_raises 'a Puppet::Error', /The kombu_ssl_keyfile parameter requires rabbit_use_ssl to be set to true/ + end + end + + end + + shared_examples_for 'with SSL and kombu wrongly configured' do + before do + params.merge!( + :rabbit_use_ssl => true, + :kombu_ssl_certfile => '/path/to/ssl/cert/file', + :kombu_ssl_keyfile => '/path/to/ssl/keyfile' + ) + end + + context 'without required parameters' do + + context 'without kombu_ssl_keyfile parameter' do + before { params.delete(:kombu_ssl_keyfile) } + it_raises 'a Puppet::Error', /The kombu_ssl_certfile and kombu_ssl_keyfile parameters must be used together/ + end + end + + end + + shared_examples_for 'with syslog enabled' do + before do + params.merge!( + :use_syslog => 'true' + ) + end + + it do + should contain_neutron_config('DEFAULT/use_syslog').with_value(true) + should contain_neutron_config('DEFAULT/syslog_log_facility').with_value('LOG_USER') + end + end + + shared_examples_for 'with syslog enabled and custom settings' do + before do + params.merge!( + :use_syslog => 'true', + :log_facility => 'LOG_LOCAL0' + ) + end + + it do + should contain_neutron_config('DEFAULT/use_syslog').with_value(true) + should contain_neutron_config('DEFAULT/syslog_log_facility').with_value('LOG_LOCAL0') + end + end + + shared_examples_for 'with log_file specified' do + before do + params.merge!( + :log_file => '/var/log/neutron/server.log', + :log_dir => '/tmp/log/neutron' + ) + end + it 'configures logging' do + should contain_neutron_config('DEFAULT/log_file').with_value(params[:log_file]) + should contain_neutron_config('DEFAULT/log_dir').with_value(params[:log_dir]) + end + end + + shared_examples_for 'with logging disabled' do + before { params.merge!( + :log_file => false, + :log_dir => false + )} + it { + should contain_neutron_config('DEFAULT/log_file').with_ensure('absent') + should contain_neutron_config('DEFAULT/log_dir').with_ensure('absent') + } + end + + shared_examples_for 'without service_plugins' do + it { should_not contain_neutron_config('DEFAULT/service_plugins') } + end + + shared_examples_for 'with service_plugins' do + before do + params.merge!( + :service_plugins => ['router','firewall','lbaas','vpnaas','metering'] + ) + end + + it do + should contain_neutron_config('DEFAULT/service_plugins').with_value('router,firewall,lbaas,vpnaas,metering') + end + + end + + shared_examples_for 'with network_device_mtu defined' do + before do + params.merge!( + :network_device_mtu => 9000 + ) + end + + it do + should contina_neutron_config('DEFAULT/network_device_mtu').with_value(params[:newtork_device_mtu]) + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { :common_package_name => 'neutron-common' } + end + + it_configures 'neutron' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :common_package_name => 'openstack-neutron' } + end + + it_configures 'neutron' + end +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_keystone_auth_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_keystone_auth_spec.rb new file mode 100644 index 000000000..db2ed2bea --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_keystone_auth_spec.rb @@ -0,0 +1,178 @@ +require 'spec_helper' + +describe 'neutron::keystone::auth' do + + describe 'with default class parameters' do + let :params do + { + :password => 'neutron_password', + :tenant => 'foobar' + } + end + + it { should contain_keystone_user('neutron').with( + :ensure => 'present', + :password => 'neutron_password', + :tenant => 'foobar' + ) } + + it { should contain_keystone_user_role('neutron@foobar').with( + :ensure => 'present', + :roles => 'admin' + )} + + it { should contain_keystone_service('neutron').with( + :ensure => 'present', + :type => 'network', + :description => 'Neutron Networking Service' + ) } + + it { should contain_keystone_endpoint('RegionOne/neutron').with( + :ensure => 'present', + :public_url => "http://127.0.0.1:9696/", + :admin_url => "http://127.0.0.1:9696/", + :internal_url => "http://127.0.0.1:9696/" + ) } + + end + + describe 'when configuring neutron-server' do + let :pre_condition do + "class { 'neutron::server': auth_password => 'test' }" + end + + let :facts do + { :osfamily => 'Debian' } + end + + let :params do + { + :password => 'neutron_password', + :tenant => 'foobar' + } + end + + it { should contain_keystone_endpoint('RegionOne/neutron').with_notify('Service[neutron-server]') } + end + + describe 'when overriding public_protocol, public_port and public address' do + + let :params do + { + :password => 'neutron_password', + :public_protocol => 'https', + :public_port => '80', + :public_address => '10.10.10.10', + :port => '81', + :internal_address => '10.10.10.11', + :admin_address => '10.10.10.12' + } + end + + it { should contain_keystone_endpoint('RegionOne/neutron').with( + :ensure => 'present', + :public_url => "https://10.10.10.10:80/", + :internal_url => "http://10.10.10.11:81/", + :admin_url => "http://10.10.10.12:81/" + ) } + + end + + describe 'when overriding admin_protocol and internal_protocol' do + + let :params do + { + :password => 'neutron_password', + :admin_protocol => 'https', + :internal_protocol => 'https', + } + end + + it { should contain_keystone_endpoint('RegionOne/neutron').with( + :ensure => 'present', + :public_url => "http://127.0.0.1:9696/", + :admin_url => "https://127.0.0.1:9696/", + :internal_url => "https://127.0.0.1:9696/" + ) } + + end + + describe 'when overriding auth name' do + + let :params do + { + :password => 'foo', + :auth_name => 'neutrony' + } + end + + it { should contain_keystone_user('neutrony') } + + it { should contain_keystone_user_role('neutrony@services') } + + it { should contain_keystone_service('neutrony') } + + it { should contain_keystone_endpoint('RegionOne/neutrony') } + + end + + describe 'when overriding service name' do + + let :params do + { + :service_name => 'neutron_service', + :password => 'neutron_password' + } + end + + it { should contain_keystone_user('neutron') } + it { should contain_keystone_user_role('neutron@services') } + it { should contain_keystone_service('neutron_service') } + it { should contain_keystone_endpoint('RegionOne/neutron_service') } + + end + + describe 'when disabling user configuration' do + + let :params do + { + :password => 'neutron_password', + :configure_user => false + } + end + + it { should_not contain_keystone_user('neutron') } + + it { should contain_keystone_user_role('neutron@services') } + + it { should contain_keystone_service('neutron').with( + :ensure => 'present', + :type => 'network', + :description => 'Neutron Networking Service' + ) } + + end + + describe 'when disabling user and user role configuration' do + + let :params do + { + :password => 'neutron_password', + :configure_user => false, + :configure_user_role => false + } + end + + it { should_not contain_keystone_user('neutron') } + + it { should_not contain_keystone_user_role('neutron@services') } + + it { should contain_keystone_service('neutron').with( + :ensure => 'present', + :type => 'network', + :description => 'Neutron Networking Service' + ) } + + end + +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_plugins_cisco_ml2_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_plugins_cisco_ml2_spec.rb new file mode 100644 index 000000000..7fd3d4a12 --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_plugins_cisco_ml2_spec.rb @@ -0,0 +1,62 @@ +# +# Unit tests for neutron::plugins::ml2 class +# + +require 'spec_helper' + +describe 'neutron::plugins::ml2::cisco::nexus' do + + let :pre_condition do + "class { 'neutron::server': auth_password => 'password'} + class { 'neutron': + rabbit_password => 'passw0rd', + core_plugin => 'neutron.plugins.ml2.plugin.Ml2Plugin' }" + end + + let :default_params do + { + :nexus_config => nil + } + end + + let :params do + {} + end + + let :facts do + { :osfamily => 'Debian' } + end + + context 'fail when missing nexus_config' do + it 'should fails to configure cisco nexus driver' do + expect { subject }.to raise_error(Puppet::Error, /No nexus config specified/) + end + end + + context 'when using cisco' do + let (:nexus_config) do + { 'cvf2leaff2' => {'username' => 'prad', + "ssh_port" => 22, + "password" => "password", + "ip_address" => "172.18.117.28", + "servers" => { + "control02" => "portchannel:20", + "control01" => "portchannel:10" + } + } + } + end + + before :each do + params.merge!(:nexus_config => nexus_config ) + end + + it 'installs ncclient package' do + should contain_package('python-ncclient').with( + :ensure => 'installed' + ) + end + + end + +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_plugins_cisco_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_plugins_cisco_spec.rb new file mode 100644 index 000000000..2e8ac5ff1 --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_plugins_cisco_spec.rb @@ -0,0 +1,172 @@ +require 'spec_helper' + +describe 'neutron::plugins::cisco' do + + let :pre_condition do + "class { 'neutron::server': auth_password => 'password'} + class { 'neutron': rabbit_password => 'passw0rd' }" + end + + let :params do + { :keystone_username => 'neutron', + :keystone_password => 'neutron_pass', + :keystone_auth_url => 'http://127.0.0.1:35357/v2.0/', + :keystone_tenant => 'tenant', + + :database_name => 'neutron', + :database_pass => 'dbpass', + :database_host => 'localhost', + :database_user => 'neutron'} + end + + let :params_default do + { + :vswitch_plugin => 'neutron.plugins.openvswitch.ovs_neutron_plugin.OVSNeutronPluginV2', + :vlan_start => '100', + :vlan_end => '3000', + :vlan_name_prefix => 'q-', + :model_class => 'neutron.plugins.cisco.models.virt_phy_sw_v2.VirtualPhysicalSwitchModelV2', + :max_ports => '100', + :max_port_profiles => '65568', + :max_networks => '65568', + :manager_class => 'neutron.plugins.cisco.segmentation.l2network_vlan_mgr_v2.L2NetworkVLANMgr' + } + end + + shared_examples_for 'default cisco plugin' do + + before do + params.merge!(params_default) + end + + it 'should create plugin symbolic link' do + should contain_file('/etc/neutron/plugin.ini').with( + :ensure => 'link', + :target => '/etc/neutron/plugins/cisco/cisco_plugins.ini', + :require => 'Package[neutron-plugin-cisco]' + ) + end + + it 'should have a plugin config folder' do + should contain_file('/etc/neutron/plugins').with( + :ensure => 'directory', + :owner => 'root', + :group => 'neutron', + :mode => '0640' + ) + end + + it 'should have a cisco plugin config folder' do + should contain_file('/etc/neutron/plugins/cisco').with( + :ensure => 'directory', + :owner => 'root', + :group => 'neutron', + :mode => '0640' + ) + end + + it 'should perform default l2 configuration' do + should contain_neutron_plugin_cisco_l2network('VLANS/vlan_start').\ + with_value(params[:vlan_start]) + should contain_neutron_plugin_cisco_l2network('VLANS/vlan_end').\ + with_value(params[:vlan_end]) + should contain_neutron_plugin_cisco_l2network('VLANS/vlan_name_prefix').\ + with_value(params[:vlan_name_prefix]) + should contain_neutron_plugin_cisco_l2network('MODEL/model_class').\ + with_value(params[:model_class]) + should contain_neutron_plugin_cisco_l2network('PORTS/max_ports').\ + with_value(params[:max_ports]) + should contain_neutron_plugin_cisco_l2network('PORTPROFILES/max_port_profiles').\ + with_value(params[:max_port_profiles]) + should contain_neutron_plugin_cisco_l2network('NETWORKS/max_networks').\ + with_value(params[:max_networks]) + should contain_neutron_plugin_cisco_l2network('SEGMENTATION/manager_class').\ + with_value(params[:manager_class]) + end + + it 'should create a dummy inventory item' do + should contain_neutron_plugin_cisco('INVENTORY/dummy').\ + with_value('dummy') + end + + it 'should configure the db connection' do + should contain_neutron_plugin_cisco_db_conn('DATABASE/name').\ + with_value(params[:database_name]) + should contain_neutron_plugin_cisco_db_conn('DATABASE/user').\ + with_value(params[:database_user]) + should contain_neutron_plugin_cisco_db_conn('DATABASE/pass').\ + with_value(params[:database_pass]) + should contain_neutron_plugin_cisco_db_conn('DATABASE/host').\ + with_value(params[:database_host]) + end + + it 'should configure the admin credentials' do + should contain_neutron_plugin_cisco_credentials('keystone/username').\ + with_value(params[:keystone_username]) + should contain_neutron_plugin_cisco_credentials('keystone/password').\ + with_value(params[:keystone_password]) + should contain_neutron_plugin_cisco_credentials('keystone/password').with_secret( true ) + should contain_neutron_plugin_cisco_credentials('keystone/auth_url').\ + with_value(params[:keystone_auth_url]) + should contain_neutron_plugin_cisco_credentials('keystone/tenant').\ + with_value(params[:keystone_tenant]) + end + + it 'should perform vswitch plugin configuration' do + should contain_neutron_plugin_cisco('PLUGINS/vswitch_plugin').\ + with_value('neutron.plugins.openvswitch.ovs_neutron_plugin.OVSNeutronPluginV2') + end + + describe 'with nexus plugin' do + before do + params.merge!(:nexus_plugin => 'neutron.plugins.cisco.nexus.cisco_nexus_plugin_v2.NexusPlugin') + end + + it 'should perform nexus plugin configuration' do + should contain_neutron_plugin_cisco('PLUGINS/nexus_plugin').\ + with_value('neutron.plugins.cisco.nexus.cisco_nexus_plugin_v2.NexusPlugin') + end + end + + end + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + context 'on Ubuntu operating systems' do + before do + facts.merge!({:operatingsystem => 'Ubuntu'}) + end + + it 'configures /etc/default/neutron-server' do + should contain_file_line('/etc/default/neutron-server:NEUTRON_PLUGIN_CONFIG').with( + :path => '/etc/default/neutron-server', + :match => '^NEUTRON_PLUGIN_CONFIG=(.*)$', + :line => 'NEUTRON_PLUGIN_CONFIG=/etc/neutron/plugins/cisco/cisco_plugins.ini', + :require => ['Package[neutron-server]', 'Package[neutron-plugin-cisco]'], + :notify => 'Service[neutron-server]' + ) + end + it_configures 'default cisco plugin' + end + + context 'on Debian operating systems' do + before do + facts.merge!({:operatingsystem => 'Debian'}) + end + + it_configures 'default cisco plugin' + end + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'default cisco plugin' + + end + +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_plugins_linuxbridge_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_plugins_linuxbridge_spec.rb new file mode 100644 index 000000000..c27aab8c0 --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_plugins_linuxbridge_spec.rb @@ -0,0 +1,92 @@ +require 'spec_helper' + +describe 'neutron::plugins::linuxbridge' do + + let :pre_condition do + "class { 'neutron': rabbit_password => 'passw0rd' }" + end + + let :params do + { :sql_connection => false, + :network_vlan_ranges => 'physnet0:100:109', + :tenant_network_type => 'vlan', + :package_ensure => 'installed' + } + end + + shared_examples_for 'neutron linuxbridge plugin' do + + it { should contain_class('neutron::params') } + + it 'installs neutron linuxbridge plugin package' do + should contain_package('neutron-plugin-linuxbridge').with( + :ensure => params[:package_ensure], + :name => platform_params[:linuxbridge_plugin_package] + ) + end + + it 'configures linuxbridge_conf.ini' do + should contain_neutron_plugin_linuxbridge('VLANS/tenant_network_type').with( + :value => params[:tenant_network_type] + ) + should contain_neutron_plugin_linuxbridge('VLANS/network_vlan_ranges').with( + :value => params[:network_vlan_ranges] + ) + end + + it 'should create plugin symbolic link' do + should contain_file('/etc/neutron/plugin.ini').with( + :ensure => 'link', + :target => '/etc/neutron/plugins/linuxbridge/linuxbridge_conf.ini', + :require => 'Package[neutron-plugin-linuxbridge]' + ) + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { :linuxbridge_plugin_package => 'neutron-plugin-linuxbridge' } + end + + context 'on Ubuntu operating systems' do + before do + facts.merge!({:operatingsystem => 'Ubuntu'}) + end + + it 'configures /etc/default/neutron-server' do + should contain_file_line('/etc/default/neutron-server:NEUTRON_PLUGIN_CONFIG').with( + :path => '/etc/default/neutron-server', + :match => '^NEUTRON_PLUGIN_CONFIG=(.*)$', + :line => 'NEUTRON_PLUGIN_CONFIG=/etc/neutron/plugins/linuxbridge/linuxbridge_conf.ini', + :require => ['Package[neutron-plugin-linuxbridge]', 'Package[neutron-server]'], + :notify => 'Service[neutron-server]' + ) + end + it_configures 'neutron linuxbridge plugin' + end + + context 'on Debian operating systems' do + before do + facts.merge!({:operatingsystem => 'Debian'}) + end + + it_configures 'neutron linuxbridge plugin' + end + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :linuxbridge_plugin_package => 'openstack-neutron-linuxbridge' } + end + + it_configures 'neutron linuxbridge plugin' + end +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_plugins_midonet_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_plugins_midonet_spec.rb new file mode 100644 index 000000000..197da93ed --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_plugins_midonet_spec.rb @@ -0,0 +1,71 @@ +require 'spec_helper' + +describe 'neutron::plugins::midonet' do + + let :pre_condition do + "class { 'neutron::server': auth_password => 'password' } + class { 'neutron': rabbit_password => 'passw0rd' } + package { 'python-neutron-plugin-midonet': }" + end + + let :default_params do + { + :midonet_api_ip => '127.0.0.1', + :midonet_api_port => '8080', + :keystone_username => 'neutron', + :keystone_password => 'test_midonet', + :keystone_tenant => 'services' + } + end + + shared_examples_for 'neutron midonet plugin' do + + let :params do + {} + end + + before do + params.merge!(default_params) + end + + it 'should create plugin symbolic link' do + should contain_file('/etc/neutron/plugin.ini').with( + :ensure => 'link', + :target => '/etc/neutron/plugins/midonet/midonet.ini', + :require => 'Package[python-neutron-plugin-midonet]') + end + + it 'should perform default configuration of' do + midonet_uri = "http://" + params[:midonet_api_ip] + ":" + params[:midonet_api_port] + "/midonet-api"; + should contain_neutron_plugin_midonet('MIDONET/midonet_uri').with_value(midonet_uri) + should contain_neutron_plugin_midonet('MIDONET/username').with_value(params[:keystone_username]) + should contain_neutron_plugin_midonet('MIDONET/password').with_value(params[:keystone_password]) + should contain_neutron_plugin_midonet('MIDONET/project_id').with_value(params[:keystone_tenant]) + end + + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian'} + end + it 'configures /etc/default/neutron-server' do + should contain_file_line('/etc/default/neutron-server:NEUTRON_PLUGIN_CONFIG').with( + :path => '/etc/default/neutron-server', + :match => '^NEUTRON_PLUGIN_CONFIG=(.*)$', + :line => 'NEUTRON_PLUGIN_CONFIG=/etc/neutron/plugins/midonet/midonet.ini', + :require => ['Package[neutron-server]', 'Package[python-neutron-plugin-midonet]'], + :notify => 'Service[neutron-server]' + ) + end + it_configures 'neutron midonet plugin' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat'} + end + it_configures 'neutron midonet plugin' + end + +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_plugins_ml2_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_plugins_ml2_spec.rb new file mode 100644 index 000000000..daa87392d --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_plugins_ml2_spec.rb @@ -0,0 +1,254 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Unit tests for neutron::plugins::ml2 class +# + +require 'spec_helper' + +describe 'neutron::plugins::ml2' do + + let :pre_condition do + "class { 'neutron': + rabbit_password => 'passw0rd', + core_plugin => 'neutron.plugins.ml2.plugin.Ml2Plugin' }" + end + + let :default_params do + { :type_drivers => ['local', 'flat', 'vlan', 'gre', 'vxlan'], + :tenant_network_types => ['local', 'flat', 'vlan', 'gre', 'vxlan'], + :mechanism_drivers => ['openvswitch', 'linuxbridge'], + :flat_networks => ['*'], + :network_vlan_ranges => ['10:50'], + :tunnel_id_ranges => ['20:100'], + :vxlan_group => '224.0.0.1', + :vni_ranges => ['10:100'], + :package_ensure => 'present' } + end + + let :params do + {} + end + + shared_examples_for 'neutron plugin ml2' do + let :p do + default_params.merge(params) + end + + it { should contain_class('neutron::params') } + + it 'configures neutron.conf' do + should contain_neutron_config('DEFAULT/core_plugin').with_value('neutron.plugins.ml2.plugin.Ml2Plugin') + end + + it 'configures ml2_conf.ini' do + should contain_neutron_plugin_ml2('ml2/type_drivers').with_value(p[:type_drivers].join(',')) + should contain_neutron_plugin_ml2('ml2/tenant_network_types').with_value(p[:tenant_network_types].join(',')) + should contain_neutron_plugin_ml2('ml2/mechanism_drivers').with_value(p[:mechanism_drivers].join(',')) + end + + it 'creates plugin symbolic link' do + should contain_file('/etc/neutron/plugin.ini').with( + :ensure => 'link', + :target => '/etc/neutron/plugins/ml2/ml2_conf.ini' + ) + end + + it 'installs ml2 package (if any)' do + if platform_params.has_key?(:ml2_server_package) + should contain_package('neutron-plugin-ml2').with( + :name => platform_params[:ml2_server_package], + :ensure => p[:package_ensure] + ) + should contain_package('neutron-plugin-ml2').with_before(/Neutron_plugin_ml2\[.+\]/) + end + end + + context 'configure ml2 with bad driver value' do + before :each do + params.merge!(:type_drivers => ['foobar']) + end + it 'fails to configure ml2 because foobar is not a valid driver' do + expect { subject }.to raise_error(Puppet::Error, /type_driver unknown./) + end + end + + context 'when using flat driver' do + before :each do + params.merge!(:flat_networks => ['eth1', 'eth2']) + end + it 'configures flat_networks' do + should contain_neutron_plugin_ml2('ml2_type_flat/flat_networks').with_value(p[:flat_networks].join(',')) + end + end + + context 'when using gre driver with valid values' do + before :each do + params.merge!(:tunnel_id_ranges => ['0:20', '40:60']) + end + it 'configures gre_networks with valid ranges' do + should contain_neutron_plugin_ml2('ml2_type_gre/tunnel_id_ranges').with_value(p[:tunnel_id_ranges].join(',')) + end + end + + context 'when using gre driver with invalid values' do + before :each do + params.merge!(:tunnel_id_ranges => ['0:20', '40:100000000']) + end + it 'fails to configure gre_networks because of too big range' do + expect { subject }.to raise_error(Puppet::Error, /tunnel id ranges are to large./) + end + end + + context 'when using vlan driver with valid values' do + before :each do + params.merge!(:network_vlan_ranges => ['1:20', '400:4094']) + end + it 'configures vlan_networks with 1:20 and 400:4094 VLAN ranges' do + should contain_neutron_plugin_ml2('ml2_type_vlan/network_vlan_ranges').with_value(p[:network_vlan_ranges].join(',')) + end + end + + context 'when using vlan driver with invalid vlan id' do + before :each do + params.merge!(:network_vlan_ranges => ['1:20', '400:4099']) + end + it 'fails to configure vlan_networks because of 400:4099 VLAN range' do + expect { subject }.to raise_error(Puppet::Error, /vlan id are invalid./) + end + end + + context 'when using vlan driver with invalid vlan range' do + before :each do + params.merge!(:network_vlan_ranges => ['2938:1']) + end + it 'fails to configure network_vlan_ranges with 2938:1 range' do + expect { subject }.to raise_error(Puppet::Error, /vlan ranges are invalid./) + end + end + + context 'when using vxlan driver with valid values' do + before :each do + params.merge!(:vni_ranges => ['40:300', '500:1000'], :vxlan_group => '224.1.1.1') + end + it 'configures vxlan_networks with 224.1.1.1 vxlan group' do + should contain_neutron_plugin_ml2('ml2_type_vxlan/vni_ranges').with_value(p[:vni_ranges].join(',')) + should contain_neutron_plugin_ml2('ml2_type_vxlan/vxlan_group').with_value(p[:vxlan_group]) + end + end + + context 'when using vxlan driver with invalid vxlan group' do + before :each do + params.merge!(:vxlan_group => '192.1.1.1') + end + it 'fails to configure vxlan_group with 192.1.1.1 vxlan group' do + expect { subject }.to raise_error(Puppet::Error, /is not valid for vxlan_group./) + end + end + + context 'when using vxlan driver with invalid vni_range' do + before :each do + params.merge!(:vni_ranges => ['2938:1']) + end + it 'fails to configure vni_ranges with 2938:1 range' do + expect { subject }.to raise_error(Puppet::Error, /vni ranges are invalid./) + end + end + + context 'when overriding package ensure state' do + before :each do + params.merge!(:package_ensure => 'latest') + end + it 'overrides package ensure state (if possible)' do + if platform_params.has_key?(:ml2_server_package) + should contain_package('neutron-plugin-ml2').with( + :name => platform_params[:ml2_server_package], + :ensure => params[:package_ensure] + ) + end + end + end + + context 'when running sriov mechanism driver' do + before :each do + params.merge!( + :mechanism_drivers => ['openvswitch', 'sriovnicswitch'], + :sriov_agent_required => true, + ) + end + it 'configures sriov mechanism driver with agent_enabled' do + should contain_neutron_plugin_ml2('ml2_sriov/supported_pci_vendor_dev').with_value(['15b3:1004,8086:10ca']) + should contain_neutron_plugin_ml2('ml2_sriov/agent_required').with_value('true') + end + end + + context 'on Ubuntu operating systems' do + before do + facts.merge!({:operatingsystem => 'Ubuntu'}) + end + + it 'configures /etc/default/neutron-server' do + should contain_file_line('/etc/default/neutron-server:NEUTRON_PLUGIN_CONFIG').with( + :path => '/etc/default/neutron-server', + :match => '^NEUTRON_PLUGIN_CONFIG=(.*)$', + :line => 'NEUTRON_PLUGIN_CONFIG=/etc/neutron/plugin.ini', + :require => ['File[/etc/neutron/plugin.ini]'] + ) + end + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + {} + end + + context 'on Ubuntu operating systems' do + before do + facts.merge!({:operatingsystem => 'Ubuntu'}) + platform_params.merge!(:ml2_server_package => 'neutron-plugin-ml2') + end + + it_configures 'neutron plugin ml2' + end + + context 'on non-Ubuntu operating systems' do + before do + facts.merge!({:operatingsystem => 'Debian'}) + end + + it_configures 'neutron plugin ml2' + end + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :ml2_server_package => 'openstack-neutron-ml2' } + end + + it_configures 'neutron plugin ml2' + end + +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_plugins_nvp_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_plugins_nvp_spec.rb new file mode 100644 index 000000000..444d1ff65 --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_plugins_nvp_spec.rb @@ -0,0 +1,113 @@ +require 'spec_helper' + +describe 'neutron::plugins::nvp' do + + let :pre_condition do + "class { 'neutron': + rabbit_password => 'passw0rd', + core_plugin => 'neutron.plugins.nicira.NeutronPlugin.NvpPluginV2' }" + end + + let :default_params do + { + :metadata_mode => 'access_network', + :package_ensure => 'present'} + end + + let :params do + { + :default_tz_uuid => '0344130f-1add-4e86-b36e-ad1c44fe40dc', + :nvp_controllers => %w(10.0.0.1 10.0.0.2), + :nvp_user => 'admin', + :nvp_password => 'password'} + end + + let :optional_params do + {:default_l3_gw_service_uuid => '0344130f-1add-4e86-b36e-ad1c44fe40dc'} + end + + shared_examples_for 'neutron plugin nvp' do + let :p do + default_params.merge(params) + end + + it { should contain_class('neutron::params') } + + it 'should have' do + should contain_package('neutron-plugin-nvp').with( + :name => platform_params[:nvp_server_package], + :ensure => p[:package_ensure] + ) + end + + it 'should configure neutron.conf' do + should contain_neutron_config('DEFAULT/core_plugin').with_value('neutron.plugins.nicira.NeutronPlugin.NvpPluginV2') + end + + it 'should create plugin symbolic link' do + should contain_file('/etc/neutron/plugin.ini').with( + :ensure => 'link', + :target => '/etc/neutron/plugins/nicira/nvp.ini', + :require => 'Package[neutron-plugin-nvp]' + ) + end + + it 'should configure nvp.ini' do + should contain_neutron_plugin_nvp('DEFAULT/default_tz_uuid').with_value(p[:default_tz_uuid]) + should contain_neutron_plugin_nvp('nvp/metadata_mode').with_value(p[:metadata_mode]) + should contain_neutron_plugin_nvp('DEFAULT/nvp_controllers').with_value(p[:nvp_controllers].join(',')) + should contain_neutron_plugin_nvp('DEFAULT/nvp_user').with_value(p[:nvp_user]) + should contain_neutron_plugin_nvp('DEFAULT/nvp_password').with_value(p[:nvp_password]) + should contain_neutron_plugin_nvp('DEFAULT/nvp_password').with_secret( true ) + should_not contain_neutron_plugin_nvp('DEFAULT/default_l3_gw_service_uuid').with_value(p[:default_l3_gw_service_uuid]) + end + + context 'configure nvp with optional params' do + before :each do + params.merge!(optional_params) + end + + it 'should configure nvp.ini' do + should contain_neutron_plugin_nvp('DEFAULT/default_l3_gw_service_uuid').with_value(params[:default_l3_gw_service_uuid]) + end + end + + context 'configure nvp with wrong core_plugin configure' do + let :pre_condition do + "class { 'neutron': + rabbit_password => 'passw0rd', + core_plugin => 'foo' }" + end + it 'should fail to configure nvp because core_plugin should contain NvpPluginV2 class' do + expect { subject }.to raise_error(Puppet::Error, /nvp plugin should be the core_plugin in neutron.conf/) + end + end + end + + begin + context 'on Debian platforms' do + let :facts do + {:osfamily => 'Debian'} + end + + let :platform_params do + { :nvp_server_package => 'neutron-plugin-nicira' } + end + + it_configures 'neutron plugin nvp' + end + + context 'on RedHat platforms' do + let :facts do + {:osfamily => 'RedHat'} + end + + let :platform_params do + { :nvp_server_package => 'openstack-neutron-nicira' } + end + + it_configures 'neutron plugin nvp' + end + end + +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_plugins_ovs_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_plugins_ovs_spec.rb new file mode 100644 index 000000000..4def5d900 --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_plugins_ovs_spec.rb @@ -0,0 +1,214 @@ +require 'spec_helper' + +describe 'neutron::plugins::ovs' do + + let :pre_condition do + "class { 'neutron': rabbit_password => 'passw0rd' }" + end + + let :default_params do + { + :package_ensure => 'present', + :sql_connection => false, + :sql_max_retries => false, + :sql_idle_timeout => false, + :reconnect_interval => false, + :tunnel_id_ranges => '1:1000', + :network_vlan_ranges => 'physnet1:1000:2000' + } + end + + let :params do + { } + end + + shared_examples_for 'neutron ovs plugin' do + before do + params.merge!(default_params) { |key, v1, v2| v1 } + end + + let :params do + { :tenant_network_type => 'vlan' } + end + + it 'should create plugin symbolic link' do + should contain_file('/etc/neutron/plugin.ini').with( + :ensure => 'link', + :target => '/etc/neutron/plugins/openvswitch/ovs_neutron_plugin.ini', + :require => 'Package[neutron-plugin-ovs]' + ) + end + + it 'should perform default configuration of' do + should contain_neutron_plugin_ovs('OVS/tenant_network_type').with_value(params[:tenant_network_type]) + should contain_package('neutron-plugin-ovs').with( + :name => platform_params[:ovs_server_package], + :ensure => params[:package_ensure] + ) + should_not contain_class('vswitch::ovs') + end + + context 'with vlan mode' do + let :params do + { :tenant_network_type => 'vlan' } + end + + it 'should perform vlan network configuration' do + should contain_neutron_plugin_ovs('OVS/tenant_network_type').with_value(params[:tenant_network_type]) + should contain_neutron_plugin_ovs('OVS/network_vlan_ranges').with_value(params[:network_vlan_ranges]) + end + end + + context 'with gre tunneling' do + let :params do + { :tenant_network_type => 'gre', :tunnel_id_ranges => '1:1000'} + end + + before do + params.delete(:network_vlan_ranges) + end + + it 'should perform gre network configuration' do + should contain_neutron_plugin_ovs('OVS/tenant_network_type').with_value(params[:tenant_network_type]) + should contain_neutron_plugin_ovs('OVS/tunnel_id_ranges').with_value(params[:tunnel_id_ranges]) + should contain_neutron_plugin_ovs('OVS/network_vlan_ranges').with_ensure('absent') + end + end + + context 'with gre tunneling and provider networks' do + let :params do + { :tenant_network_type => 'gre', + :network_vlan_ranges => 'physnet1:1000:2000', + :tunnel_id_ranges => '1:1000'} + end + + it 'should perform gre network configuration' do + should contain_neutron_plugin_ovs('OVS/network_vlan_ranges').with_value(params[:network_vlan_ranges]) + should contain_neutron_plugin_ovs('OVS/tenant_network_type').with_value(params[:tenant_network_type]) + should contain_neutron_plugin_ovs('OVS/tunnel_id_ranges').with_value(params[:tunnel_id_ranges]) + end + end + + context 'with vxlan tunneling' do + let :params do + { :tenant_network_type => 'vxlan', + :vxlan_udp_port => '4789'} + end + + before do + params.delete(:network_vlan_ranges) + end + + it 'should perform vxlan network configuration' do + should contain_neutron_plugin_ovs('OVS/tenant_network_type').with_value(params[:tenant_network_type]) + should contain_neutron_plugin_ovs('OVS/vxlan_udp_port').with_value(params[:vxlan_udp_port]) + should contain_neutron_plugin_ovs('OVS/network_vlan_ranges').with_ensure('absent') + end + end + + context 'with vxlan tunnelling using bad vxlan_udp_port' do + let :params do + { :tenant_network_type => 'vxlan', + :vxlan_udp_port => '1',} + end + + it 'should fail if invalid port is passed' do + expect { subject }.to raise_error(Puppet::Error, /vxlan udp port is invalid./) + end + end + + context 'with vxlan tunnelling using bad tunnel_id_ranges' do + let :params do + { :tenant_network_type => 'vxlan', + :tunnel_id_ranges => '100:9',} + end + + it 'should fail if invalid id range is passed' do + expect { subject }.to raise_error(Puppet::Error, /tunnel id ranges are invalid./) + end + end + + context 'with vxlan tunneling and provider networks using bad network_vlan_ranges' do + let :params do + { :tenant_network_type => 'vxlan', + :network_vlan_ranges => 'physnet1:200:1'} + end + + it 'should fail if invalid vlan range is passed' do + expect { subject }.to raise_error(Puppet::Error, /network vlan ranges are invalid./) + end + end + + context 'with vxlan tunneling using bad multiple network_vlan_ranges' do + let :params do + { :tenant_network_type => 'vxlan', + :network_vlan_ranges => ['physnet1:0:100', 'physnet2:1000:1']} + end + + it 'should fail if invalid network vlan range is passed' do + expect { subject }.to raise_error(Puppet::Error, /network vlan ranges are invalid/) + end + end + + context 'with vxlan tunneling and provider networks' do + let :params do + { :tenant_network_type => 'vxlan', + :network_vlan_ranges => 'physnet1:1000:2000'} + end + + it 'should perform vxlan network configuration' do + should contain_neutron_plugin_ovs('OVS/network_vlan_ranges').with_value(params[:network_vlan_ranges]) + should contain_neutron_plugin_ovs('OVS/tenant_network_type').with_value(params[:tenant_network_type]) + end + end + + context 'with a flat network' do + let :params do + { :tenant_network_type => 'flat'} + end + it { should contain_neutron_plugin_ovs('OVS/network_vlan_ranges').with_value(params[:network_vlan_ranges]) } + end + + context 'with comma separated vlan ranges' do + let :params do + { :network_vlan_ranges => 'physint1:1000:2000,physext1:100:200' } + end + it { should contain_neutron_plugin_ovs('OVS/network_vlan_ranges').with_value(params[:network_vlan_ranges]) } + end + + context 'with vlan ranges in array' do + let :params do + { :network_vlan_ranges => ['physint1:1000:2000', 'physext1:100:200'] } + end + it { should contain_neutron_plugin_ovs('OVS/network_vlan_ranges').with_value(params[:network_vlan_ranges].join(',')) } + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { :ovs_server_package => 'neutron-plugin-openvswitch' } + end + + it_configures 'neutron ovs plugin' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :params do + { :network_vlan_ranges => 'physnet1:1000:2000' } + end + + let :platform_params do + { :ovs_server_package => 'openstack-neutron-openvswitch' } + end + + it_configures 'neutron ovs plugin' + end +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_policy_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_policy_spec.rb new file mode 100644 index 000000000..b485a9e55 --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_policy_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +describe 'neutron::policy' do + + shared_examples_for 'neutron policies' do + let :params do + { + :policy_path => '/etc/neutron/policy.json', + :policies => { + 'context_is_admin' => { + 'key' => 'context_is_admin', + 'value' => 'foo:bar' + } + } + } + end + + it 'set up the policies' do + should contain_openstacklib__policy__base('context_is_admin').with({ + :key => 'context_is_admin', + :value => 'foo:bar' + }) + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'neutron policies' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'neutron policies' + end +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_quota_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_quota_spec.rb new file mode 100644 index 000000000..ce2829b4a --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_quota_spec.rb @@ -0,0 +1,72 @@ +require 'spec_helper' + +describe 'neutron::quota' do + + let :params do + {} + end + + let :default_params do + { :default_quota => -1, + :quota_network => 10, + :quota_subnet => 10, + :quota_port => 50, + :quota_router => 10, + :quota_floatingip => 50, + :quota_security_group => 10, + :quota_security_group_rule => 100, + :quota_driver => 'neutron.db.quota_db.DbQuotaDriver', + :quota_firewall => 1, + :quota_firewall_policy => 1, + :quota_firewall_rule => -1, + :quota_health_monitor => -1, + :quota_items => 'network,subnet,port', + :quota_member => -1, + :quota_network_gateway => 5, + :quota_packet_filter => 100, + :quota_pool => 10, + :quota_vip => 10 } + end + + shared_examples_for 'neutron quota' do + let :params_hash do + default_params.merge(params) + end + + it 'configures quota in neutron.conf' do + params_hash.each_pair do |config,value| + should contain_neutron_config("quotas/#{config}").with_value( value ) + end + end + end + + context 'with default parameters' do + it_configures 'neutron quota' + end + + context 'with provided parameters' do + before do + params.merge!({ + :quota_network => 20, + :quota_subnet => 20, + :quota_port => 100, + :quota_router => 20, + :quota_floatingip => 100, + :quota_security_group => 20, + :quota_security_group_rule => 200, + :quota_firewall => 1, + :quota_firewall_policy => 1, + :quota_firewall_rule => -1, + :quota_health_monitor => -1, + :quota_items => 'network,subnet,port', + :quota_member => -1, + :quota_network_gateway => 5, + :quota_packet_filter => 100, + :quota_pool => 10, + :quota_vip => 10 + }) + end + + it_configures 'neutron quota' + end +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_server_notifications_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_server_notifications_spec.rb new file mode 100644 index 000000000..3bc4768e7 --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_server_notifications_spec.rb @@ -0,0 +1,152 @@ +# 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 neutron::server::notifications class +# + +require 'spec_helper' + +describe 'neutron::server::notifications' do + let :pre_condition do + 'define keystone_user ($name) {}' + end + + let :default_params do + { + :notify_nova_on_port_status_changes => true, + :notify_nova_on_port_data_changes => true, + :send_events_interval => '2', + :nova_url => 'http://127.0.0.1:8774/v2', + :nova_admin_auth_url => 'http://127.0.0.1:35357/v2.0', + :nova_admin_username => 'nova', + :nova_admin_tenant_name => 'services', + :nova_region_name => 'RegionOne' + } + end + + let :params do + { + :nova_admin_password => 'secrete', + :nova_admin_tenant_id => 'UUID' + } + end + + shared_examples_for 'neutron server notifications' do + let :p do + default_params.merge(params) + end + + it 'configure neutron.conf' do + should contain_neutron_config('DEFAULT/notify_nova_on_port_status_changes').with_value(true) + should contain_neutron_config('DEFAULT/notify_nova_on_port_data_changes').with_value(true) + should contain_neutron_config('DEFAULT/send_events_interval').with_value('2') + should contain_neutron_config('DEFAULT/nova_url').with_value('http://127.0.0.1:8774/v2') + should contain_neutron_config('DEFAULT/nova_admin_auth_url').with_value('http://127.0.0.1:35357/v2.0') + should contain_neutron_config('DEFAULT/nova_admin_username').with_value('nova') + should contain_neutron_config('DEFAULT/nova_admin_password').with_value('secrete') + should contain_neutron_config('DEFAULT/nova_admin_password').with_secret( true ) + should contain_neutron_config('DEFAULT/nova_region_name').with_value('RegionOne') + should contain_neutron_config('DEFAULT/nova_admin_tenant_id').with_value('UUID') + end + + context 'when overriding parameters' do + before :each do + params.merge!( + :notify_nova_on_port_status_changes => false, + :notify_nova_on_port_data_changes => false, + :send_events_interval => '10', + :nova_url => 'http://nova:8774/v3', + :nova_admin_auth_url => 'http://keystone:35357/v2.0', + :nova_admin_username => 'joe', + :nova_region_name => 'MyRegion', + :nova_admin_tenant_id => 'UUID2' + ) + end + it 'should configure neutron server with overrided parameters' do + should contain_neutron_config('DEFAULT/notify_nova_on_port_status_changes').with_value(false) + should contain_neutron_config('DEFAULT/notify_nova_on_port_data_changes').with_value(false) + should contain_neutron_config('DEFAULT/send_events_interval').with_value('10') + should contain_neutron_config('DEFAULT/nova_url').with_value('http://nova:8774/v3') + should contain_neutron_config('DEFAULT/nova_admin_auth_url').with_value('http://keystone:35357/v2.0') + should contain_neutron_config('DEFAULT/nova_admin_username').with_value('joe') + should contain_neutron_config('DEFAULT/nova_admin_password').with_value('secrete') + should contain_neutron_config('DEFAULT/nova_admin_password').with_secret( true ) + should contain_neutron_config('DEFAULT/nova_region_name').with_value('MyRegion') + should contain_neutron_config('DEFAULT/nova_admin_tenant_id').with_value('UUID2') + end + end + + context 'when no nova_admin_password is specified' do + before :each do + params.merge!(:nova_admin_password => '') + end + it 'should fail to configure neutron server' do + expect { subject }.to raise_error(Puppet::Error, /nova_admin_password must be set./) + end + end + + context 'when no nova_admin_tenant_id and nova_admin_tenant_name specified' do + before :each do + params.merge!( + :nova_admin_tenant_id => '', + :nova_admin_tenant_name => '' + ) + end + it 'should fail to configure neutron server' do + expect { subject }.to raise_error(Puppet::Error, /You must provide either nova_admin_tenant_name or nova_admin_tenant_id./) + end + end + + context 'when providing a tenant name' do + before :each do + params.merge!( + :nova_admin_tenant_id => '', + :nova_admin_tenant_name => 'services' + ) + end + it 'should configure nova admin tenant id' do + should contain_nova_admin_tenant_id_setter('nova_admin_tenant_id').with( + :ensure => 'present', + :tenant_name => 'services', + :auth_url => 'http://127.0.0.1:35357/v2.0', + :auth_password => 'secrete', + :auth_tenant_name => 'services' + ) + end + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + {} + end + + it_configures 'neutron server notifications' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + {} + end + + it_configures 'neutron server notifications' + end + +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_server_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_server_spec.rb new file mode 100644 index 000000000..1664ce684 --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_server_spec.rb @@ -0,0 +1,344 @@ +require 'spec_helper' + +describe 'neutron::server' do + + let :pre_condition do + "class { 'neutron': rabbit_password => 'passw0rd' }" + end + + let :params do + { :auth_password => 'passw0rd', + :auth_user => 'neutron' } + end + + let :default_params do + { :package_ensure => 'present', + :enabled => true, + :auth_type => 'keystone', + :auth_host => 'localhost', + :auth_port => '35357', + :auth_tenant => 'services', + :auth_user => 'neutron', + :database_connection => 'sqlite:////var/lib/neutron/ovs.sqlite', + :database_max_retries => '10', + :database_idle_timeout => '3600', + :database_retry_interval => '10', + :database_min_pool_size => '1', + :database_max_pool_size => '10', + :database_max_overflow => '20', + :sync_db => false, + :agent_down_time => '75', + :router_scheduler_driver => 'neutron.scheduler.l3_agent_scheduler.ChanceScheduler', + :router_distributed => false, + :l3_ha => false, + :max_l3_agents_per_router => '3', + :min_l3_agents_per_router => '2', + :l3_ha_net_cidr => '169.254.192.0/18' + } + end + + shared_examples_for 'a neutron server' do + let :p do + default_params.merge(params) + end + + it 'should perform default database configuration of' do + should contain_neutron_config('database/connection').with_value(p[:database_connection]) + should contain_neutron_config('database/connection').with_secret( true ) + should contain_neutron_config('database/max_retries').with_value(p[:database_max_retries]) + should contain_neutron_config('database/idle_timeout').with_value(p[:database_idle_timeout]) + should contain_neutron_config('database/retry_interval').with_value(p[:database_retry_interval]) + should contain_neutron_config('database/min_pool_size').with_value(p[:database_min_pool_size]) + should contain_neutron_config('database/max_pool_size').with_value(p[:database_max_pool_size]) + should contain_neutron_config('database/max_overflow').with_value(p[:database_max_overflow]) + end + + it { should contain_class('neutron::params') } + it { should contain_class('neutron::policy') } + + it 'configures authentication middleware' do + should contain_neutron_api_config('filter:authtoken/auth_host').with_value(p[:auth_host]); + should contain_neutron_api_config('filter:authtoken/auth_port').with_value(p[:auth_port]); + should contain_neutron_api_config('filter:authtoken/admin_tenant_name').with_value(p[:auth_tenant]); + should contain_neutron_api_config('filter:authtoken/admin_user').with_value(p[:auth_user]); + should contain_neutron_api_config('filter:authtoken/admin_password').with_value(p[:auth_password]); + should contain_neutron_api_config('filter:authtoken/admin_password').with_secret( true ) + should contain_neutron_api_config('filter:authtoken/auth_admin_prefix').with(:ensure => 'absent') + should contain_neutron_api_config('filter:authtoken/auth_uri').with_value("http://localhost:5000/"); + end + + it 'installs neutron server package' do + if platform_params.has_key?(:server_package) + should contain_package('neutron-server').with( + :name => platform_params[:server_package], + :ensure => p[:package_ensure] + ) + should contain_package('neutron-server').with_before(/Neutron_api_config\[.+\]/) + should contain_package('neutron-server').with_before(/Neutron_config\[.+\]/) + should contain_package('neutron-server').with_before(/Service\[neutron-server\]/) + else + should contain_package('neutron').with_before(/Neutron_api_config\[.+\]/) + end + end + + it 'configures neutron server service' do + should contain_service('neutron-server').with( + :name => platform_params[:server_service], + :enable => true, + :ensure => 'running', + :require => 'Class[Neutron]' + ) + should_not contain_exec('neutron-db-sync') + should contain_neutron_api_config('filter:authtoken/auth_admin_prefix').with( + :ensure => 'absent' + ) + should contain_neutron_config('DEFAULT/api_workers').with_value(facts[:processorcount]) + should contain_neutron_config('DEFAULT/rpc_workers').with_value(facts[:processorcount]) + should contain_neutron_config('DEFAULT/agent_down_time').with_value(p[:agent_down_time]) + should contain_neutron_config('DEFAULT/router_scheduler_driver').with_value(p[:router_scheduler_driver]) + end + + context 'with manage_service as false' do + before :each do + params.merge!(:manage_service => false) + end + it 'should not start/stop service' do + should contain_service('neutron-server').without_ensure + end + end + + context 'with DVR enabled' do + before :each do + params.merge!(:router_distributed => true) + end + it 'should enable DVR' do + should contain_neutron_config('DEFAULT/router_distributed').with_value(true) + end + end + + context 'with HA routers enabled' do + before :each do + params.merge!(:l3_ha => true) + end + it 'should enable HA routers' do + should contain_neutron_config('DEFAULT/l3_ha').with_value(true) + should contain_neutron_config('DEFAULT/max_l3_agents_per_router').with_value('3') + should contain_neutron_config('DEFAULT/min_l3_agents_per_router').with_value('2') + should contain_neutron_config('DEFAULT/l3_ha_net_cidr').with_value('169.254.192.0/18') + end + end + + context 'with HA routers disabled' do + before :each do + params.merge!(:l3_ha => false) + end + it 'should disable HA routers' do + should contain_neutron_config('DEFAULT/l3_ha').with_value(false) + end + end + + context 'with HA routers enabled with unlimited l3 agents per router' do + before :each do + params.merge!(:l3_ha => true, + :max_l3_agents_per_router => '0' ) + end + it 'should enable HA routers' do + should contain_neutron_config('DEFAULT/max_l3_agents_per_router').with_value('0') + end + end + + context 'with HA routers enabled and wrong parameters' do + before :each do + params.merge!(:l3_ha => true, + :max_l3_agents_per_router => '2', + :min_l3_agents_per_router => '3' ) + end + it 'should fail to configure HA routerd' do + expect { subject }.to raise_error(Puppet::Error, /min_l3_agents_per_router should be less than or equal to max_l3_agents_per_router./) + end + end + end + + shared_examples_for 'a neutron server with auth_admin_prefix set' do + [ '/keystone', '/keystone/admin', '' ].each do |auth_admin_prefix| + describe "with keystone_auth_admin_prefix containing incorrect value #{auth_admin_prefix}" do + before do + params.merge!({ + :auth_admin_prefix => auth_admin_prefix, + }) + end + it do + should contain_neutron_api_config('filter:authtoken/auth_admin_prefix').with( + :value => params[:auth_admin_prefix] + ) + end + end + end + end + + shared_examples_for 'a neutron server with some incorrect auth_admin_prefix set' do + [ '/keystone/', 'keystone/', 'keystone' ].each do |auth_admin_prefix| + describe "with keystone_auth_admin_prefix containing incorrect value #{auth_admin_prefix}" do + before do + params.merge!({ + :auth_admin_prefix => auth_admin_prefix, + }) + end + it do + expect { + should contain_neutron_api_config('filter:authtoken/auth_admin_prefix') + }.to raise_error(Puppet::Error, /validate_re\(\): "#{auth_admin_prefix}" does not match/) + end + end + end + end + + shared_examples_for 'a neutron server with broken authentication' do + before do + params.delete(:auth_password) + end + it_raises 'a Puppet::Error', /auth_password must be set/ + end + + shared_examples_for 'a neutron server with removed log_dir parameter' do + before { params.merge!({ :log_dir => '/var/log/neutron' })} + it_raises 'a Puppet::Error', /log_dir parameter is removed/ + end + + shared_examples_for 'a neutron server with removed log_file parameter' do + before { params.merge!({ :log_file => '/var/log/neutron/blah.log' })} + it_raises 'a Puppet::Error', /log_file parameter is removed/ + end + + shared_examples_for 'a neutron server without database synchronization' do + before do + params.merge!( + :sync_db => true + ) + end + it 'should exec neutron-db-sync' do + should contain_exec('neutron-db-sync').with( + :command => 'neutron-db-manage --config-file /etc/neutron/neutron.conf --config-file /etc/neutron/plugin.ini upgrade head', + :path => '/usr/bin', + :before => 'Service[neutron-server]', + :require => 'Neutron_config[database/connection]', + :refreshonly => true + ) + end + end + + shared_examples_for 'a neutron server with deprecated parameters' do + + context 'first generation' do + before do + params.merge!({ + :sql_connection => 'sqlite:////var/lib/neutron/ovs-deprecated_parameter.sqlite', + :database_connection => 'sqlite:////var/lib/neutron/ovs-IGNORED_parameter.sqlite', + :sql_max_retries => 20, + :database_max_retries => 90, + :sql_idle_timeout => 21, + :database_idle_timeout => 91, + :sql_reconnect_interval => 22, + :database_retry_interval => 92, + }) + end + + it 'configures database connection with deprecated parameters' do + should contain_neutron_config('database/connection').with_value(params[:sql_connection]) + should contain_neutron_config('database/max_retries').with_value(params[:sql_max_retries]) + should contain_neutron_config('database/idle_timeout').with_value(params[:sql_idle_timeout]) + should contain_neutron_config('database/retry_interval').with_value(params[:sql_reconnect_interval]) + end + end + + context 'second generation' do + before do + params.merge!({ + :connection => 'sqlite:////var/lib/neutron/ovs-deprecated_parameter.sqlite', + :database_connection => 'sqlite:////var/lib/neutron/ovs-IGNORED_parameter.sqlite', + :max_retries => 20, + :database_max_retries => 90, + :idle_timeout => 21, + :database_idle_timeout => 91, + :retry_interval => 22, + :database_retry_interval => 92, + }) + end + + it 'configures database connection with deprecated parameters' do + should contain_neutron_config('database/connection').with_value(params[:connection]) + should contain_neutron_config('database/max_retries').with_value(params[:max_retries]) + should contain_neutron_config('database/idle_timeout').with_value(params[:idle_timeout]) + should contain_neutron_config('database/retry_interval').with_value(params[:retry_interval]) + end + end + end + + shared_examples_for 'a neutron server with database_connection specified' do + before do + params.merge!( + :database_connection => 'sqlite:////var/lib/neutron/ovs-TEST_parameter.sqlite' + ) + end + it 'configures database connection' do + should contain_neutron_config('database/connection').with_value(params[:database_connection]) + end + end + + describe "with custom keystone auth_uri" do + let :facts do + { :osfamily => 'RedHat' } + end + before do + params.merge!({ + :auth_uri => 'https://foo.bar:1234/', + }) + end + it 'configures auth_uri' do + should contain_neutron_api_config('filter:authtoken/auth_uri').with_value("https://foo.bar:1234/"); + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian', + :processorcount => '2' } + end + + let :platform_params do + { :server_package => 'neutron-server', + :server_service => 'neutron-server' } + end + + it_configures 'a neutron server' + it_configures 'a neutron server with broken authentication' + it_configures 'a neutron server with auth_admin_prefix set' + it_configures 'a neutron server with some incorrect auth_admin_prefix set' + it_configures 'a neutron server with deprecated parameters' + it_configures 'a neutron server with database_connection specified' + it_configures 'a neutron server without database synchronization' + it_configures 'a neutron server with removed log_file parameter' + it_configures 'a neutron server with removed log_dir parameter' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat', + :processorcount => '2' } + end + + let :platform_params do + { :server_service => 'neutron-server' } + end + + it_configures 'a neutron server' + it_configures 'a neutron server with broken authentication' + it_configures 'a neutron server with auth_admin_prefix set' + it_configures 'a neutron server with some incorrect auth_admin_prefix set' + it_configures 'a neutron server with deprecated parameters' + it_configures 'a neutron server with database_connection specified' + it_configures 'a neutron server without database synchronization' + it_configures 'a neutron server with removed log_file parameter' + it_configures 'a neutron server with removed log_dir parameter' + end +end diff --git a/3rdparty/modules/neutron/spec/classes/neutron_services_fwaas_spec.rb b/3rdparty/modules/neutron/spec/classes/neutron_services_fwaas_spec.rb new file mode 100644 index 000000000..03841913d --- /dev/null +++ b/3rdparty/modules/neutron/spec/classes/neutron_services_fwaas_spec.rb @@ -0,0 +1,100 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Unit tests for neutron::services::fwaas class +# + +require 'spec_helper' + +describe 'neutron::services::fwaas' do + let :pre_condition do + "class { 'neutron': rabbit_password => 'passw0rd' }" + end + + let :params do + {} + end + + let :default_params do + { :driver => 'neutron.services.firewall.drivers.linux.iptables_fwaas.IptablesFwaasDriver', + :enabled => true, + :vpnaas_agent_package => false } + end + + shared_examples_for 'neutron fwaas service plugin' do + let :params_hash do + default_params.merge(params) + end + + it 'configures driver in fwaas_driver.ini' do + should contain_neutron_fwaas_service_config('fwaas/driver').with_value('neutron.services.firewall.drivers.linux.iptables_fwaas.IptablesFwaasDriver') + should contain_neutron_fwaas_service_config('fwaas/enabled').with_value('true') + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { :l3_agent_package => 'neutron-l3-agent', + :vpnaas_agent_package => 'neutron-vpn-agent'} + end + + it_configures 'neutron fwaas service plugin' + + it 'installs neutron l3 agent package' do + should contain_package('neutron-l3-agent').with_ensure('present') + end + end + + context 'on Debian platforms with VPNaaS' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { :l3_agent_package => 'neutron-l3-agent', + :vpnaas_agent_package => 'neutron-vpn-agent' } + end + + let :params do + { :vpnaas_agent_package => true } + end + + it_configures 'neutron fwaas service plugin' + + it 'installs neutron vpnaas agent package' do + should contain_package('neutron-vpn-agent').with_ensure('present') + end + end + + context 'on Red Hat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :package_name => 'openstack-neutron' } + end + + it_configures 'neutron fwaas service plugin' + + end + +end diff --git a/3rdparty/modules/neutron/spec/shared_examples.rb b/3rdparty/modules/neutron/spec/shared_examples.rb new file mode 100644 index 000000000..d92156a36 --- /dev/null +++ b/3rdparty/modules/neutron/spec/shared_examples.rb @@ -0,0 +1,5 @@ +shared_examples_for "a Puppet::Error" do |description| + it "with message matching #{description.inspect}" do + expect { should have_class_count(1) }.to raise_error(Puppet::Error, description) + end +end diff --git a/3rdparty/modules/neutron/spec/spec_helper.rb b/3rdparty/modules/neutron/spec/spec_helper.rb new file mode 100644 index 000000000..a21fd4305 --- /dev/null +++ b/3rdparty/modules/neutron/spec/spec_helper.rb @@ -0,0 +1,13 @@ +require 'puppetlabs_spec_helper/module_spec_helper' +require 'shared_examples' +require 'webmock/rspec' +require 'json' + +fixture_path = File.expand_path(File.join(__FILE__, '..', 'fixtures')) + +RSpec.configure do |c| + c.alias_it_should_behave_like_to :it_configures, 'configures' + c.alias_it_should_behave_like_to :it_raises, 'raises' + c.module_path = File.join(fixture_path, 'modules') + c.manifest_dir = File.join(fixture_path, 'manifests') +end diff --git a/3rdparty/modules/neutron/spec/unit/provider/neutron_l3_ovs_bridge/neutron_spec.rb b/3rdparty/modules/neutron/spec/unit/provider/neutron_l3_ovs_bridge/neutron_spec.rb new file mode 100644 index 000000000..e2f3ef27a --- /dev/null +++ b/3rdparty/modules/neutron/spec/unit/provider/neutron_l3_ovs_bridge/neutron_spec.rb @@ -0,0 +1,52 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/neutron_l3_ovs_bridge/neutron' + +provider_class = Puppet::Type.type(:neutron_l3_ovs_bridge).provider(:neutron) + +describe provider_class do + + let :resource do + Puppet::Type::Neutron_l3_ovs_bridge.new( + :name => 'br-ex', + :subnet_name => 'subnet1' + ) + end + + let :provider do + provider_class.new(resource) + end + + + describe 'when retrieving bridge ip addresses' do + + it 'should return an empty array for no matches' do + provider.expects(:ip).returns('') + provider.bridge_ip_addresses.should eql [] + end + + it 'should return an array of addresses if matches are found' do + output = <<-EOT +122: br-ex: mtu 1500 qdisc noqueue state UNKNOWN + link/ether d2:95:15:80:b5:4f brd ff:ff:ff:ff:ff:ff + inet 172.24.4.225/28 scope global br-ex + inet6 fe80::d095:15ff:fe80:b54f/64 scope link + valid_lft forever preferred_lft forever +EOT + provider.expects(:ip).returns(output) + provider.bridge_ip_addresses.should eql ['172.24.4.225/28'] + end + + end + + describe 'when checking if the l3 bridge exists' do + + it 'should return true if the gateway ip is present' do + provider.expects(:bridge_ip_addresses).returns(['a']) + provider.expects(:gateway_ip).returns('a') + provider.exists?.should eql true + end + + end + +end diff --git a/3rdparty/modules/neutron/spec/unit/provider/neutron_network/neutron_spec.rb b/3rdparty/modules/neutron/spec/unit/provider/neutron_network/neutron_spec.rb new file mode 100644 index 000000000..974a7057b --- /dev/null +++ b/3rdparty/modules/neutron/spec/unit/provider/neutron_network/neutron_spec.rb @@ -0,0 +1,71 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/neutron_network/neutron' + +provider_class = Puppet::Type.type(:neutron_network).provider(:neutron) + +describe provider_class do + + let :net_name do + 'net1' + end + + let :net_attrs do + { + :name => net_name, + :ensure => 'present', + :admin_state_up => 'True', + :router_external => 'False', + :shared => 'False', + :tenant_id => '', + } + end + + describe 'when updating a network' do + let :resource do + Puppet::Type::Neutron_network.new(net_attrs) + end + + let :provider do + provider_class.new(resource) + end + + it 'should call net-update to change admin_state_up' do + provider.expects(:auth_neutron).with('net-update', + '--admin_state_up=False', + net_name) + provider.admin_state_up=('False') + end + + it 'should call net-update to change shared' do + provider.expects(:auth_neutron).with('net-update', + '--shared=True', + net_name) + provider.shared=('True') + end + + it 'should call net-update to change router_external' do + provider.expects(:auth_neutron).with('net-update', + '--router:external=False', + net_name) + provider.router_external=('False') + end + + it 'should call net-update to change router_external' do + provider.expects(:auth_neutron).with('net-update', + '--router:external', + net_name) + provider.router_external=('True') + end + + [:provider_network_type, :provider_physical_network, :provider_segmentation_id].each do |attr| + it "should fail when #{attr.to_s} is update " do + expect do + provider.send("#{attr}=", 'foo') + end.to raise_error(Puppet::Error, /does not support being updated/) + end + end + + end + +end diff --git a/3rdparty/modules/neutron/spec/unit/provider/neutron_router/neutron_spec.rb b/3rdparty/modules/neutron/spec/unit/provider/neutron_router/neutron_spec.rb new file mode 100644 index 000000000..8a2ba4a63 --- /dev/null +++ b/3rdparty/modules/neutron/spec/unit/provider/neutron_router/neutron_spec.rb @@ -0,0 +1,53 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/neutron_router/neutron' + +provider_class = Puppet::Type.type(:neutron_router).provider(:neutron) + +describe provider_class do + + let :router_name do + 'router1' + end + + let :router_attrs do + { + :name => router_name, + :ensure => 'present', + :admin_state_up => 'True', + :tenant_id => '', + } + end + + describe 'when updating a router' do + let :resource do + Puppet::Type::Neutron_router.new(router_attrs) + end + + let :provider do + provider_class.new(resource) + end + + it 'should call router-update to change admin_state_up' do + provider.expects(:auth_neutron).with('router-update', + '--admin-state-up=False', + router_name) + provider.admin_state_up=('False') + end + + it 'should call router-gateway-clear for an empty network name' do + provider.expects(:auth_neutron).with('router-gateway-clear', + router_name) + provider.gateway_network_name=('') + end + + it 'should call router-gateway-set to configure an external network' do + provider.expects(:auth_neutron).with('router-gateway-set', + router_name, + 'net1') + provider.gateway_network_name=('net1') + end + + end + +end diff --git a/3rdparty/modules/neutron/spec/unit/provider/neutron_router_interface/neutron_spec.rb b/3rdparty/modules/neutron/spec/unit/provider/neutron_router_interface/neutron_spec.rb new file mode 100644 index 000000000..1678e19bc --- /dev/null +++ b/3rdparty/modules/neutron/spec/unit/provider/neutron_router_interface/neutron_spec.rb @@ -0,0 +1,36 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/neutron_router_interface/neutron' + +provider_class = Puppet::Type.type(:neutron_router_interface). + provider(:neutron) + +describe provider_class do + + let :interface_attrs do + { + :name => 'router:subnet', + :ensure => 'present', + } + end + + describe 'when accessing attributes of an interface' do + let :resource do + Puppet::Type::Neutron_router_interface.new(interface_attrs) + end + + let :provider do + provider_class.new(resource) + end + + it 'should return the correct router name' do + provider.router_name.should eql('router') + end + + it 'should return the correct subnet name' do + provider.subnet_name.should eql('subnet') + end + + end + +end diff --git a/3rdparty/modules/neutron/spec/unit/provider/neutron_spec.rb b/3rdparty/modules/neutron/spec/unit/provider/neutron_spec.rb new file mode 100644 index 000000000..fed14ece2 --- /dev/null +++ b/3rdparty/modules/neutron/spec/unit/provider/neutron_spec.rb @@ -0,0 +1,246 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/neutron' +require 'tempfile' + +describe Puppet::Provider::Neutron do + + def klass + described_class + end + + let :credential_hash do + { + 'auth_host' => '192.168.56.210', + 'auth_port' => '35357', + 'auth_protocol' => 'https', + 'admin_tenant_name' => 'admin_tenant', + 'admin_user' => 'admin', + 'admin_password' => 'password', + } + end + + let :auth_endpoint do + 'https://192.168.56.210:35357/v2.0/' + end + + let :credential_error do + /Neutron types will not work/ + end + + let :exec_error do + /Neutron or Keystone API is not avalaible/ + end + + after :each do + klass.reset + end + + describe 'when determining credentials' do + + it 'should fail if config is empty' do + conf = {} + klass.expects(:neutron_conf).returns(conf) + expect do + klass.neutron_credentials + end.to raise_error(Puppet::Error, credential_error) + end + + it 'should fail if config does not have keystone_authtoken section.' do + conf = {'foo' => 'bar'} + klass.expects(:neutron_conf).returns(conf) + expect do + klass.neutron_credentials + end.to raise_error(Puppet::Error, credential_error) + end + + it 'should fail if config does not contain all auth params' do + conf = {'keystone_authtoken' => {'invalid_value' => 'foo'}} + klass.expects(:neutron_conf).returns(conf) + expect do + klass.neutron_credentials + end.to raise_error(Puppet::Error, credential_error) + end + + it 'should use specified host/port/protocol in the auth endpoint' do + conf = {'keystone_authtoken' => credential_hash} + klass.expects(:neutron_conf).returns(conf) + klass.get_auth_endpoint.should == auth_endpoint + end + + it 'should find region_name if specified' do + conf = { + 'keystone_authtoken' => credential_hash, + 'DEFAULT' => { 'nova_region_name' => 'REGION_NAME' } + } + klass.expects(:neutron_conf).returns(conf) + klass.neutron_credentials['nova_region_name'] == 'REGION_NAME' + end + + end + + describe 'when invoking the neutron cli' do + + it 'should set auth credentials in the environment' do + authenv = { + :OS_AUTH_URL => auth_endpoint, + :OS_USERNAME => credential_hash['admin_user'], + :OS_TENANT_NAME => credential_hash['admin_tenant_name'], + :OS_PASSWORD => credential_hash['admin_password'], + } + klass.expects(:get_neutron_credentials).with().returns(credential_hash) + klass.expects(:withenv).with(authenv) + klass.auth_neutron('test_retries') + end + + it 'should set region in the environment if needed' do + authenv = { + :OS_AUTH_URL => auth_endpoint, + :OS_USERNAME => credential_hash['admin_user'], + :OS_TENANT_NAME => credential_hash['admin_tenant_name'], + :OS_PASSWORD => credential_hash['admin_password'], + :OS_REGION_NAME => 'REGION_NAME', + } + + cred_hash = credential_hash.merge({'nova_region_name' => 'REGION_NAME'}) + klass.expects(:get_neutron_credentials).with().returns(cred_hash) + klass.expects(:withenv).with(authenv) + klass.auth_neutron('test_retries') + end + + ['[Errno 111] Connection refused', + '400-{\'message\': \'\'}', + '(HTTP 400)', + '503 Service Unavailable', + '504 Gateway Time-out', + 'Maximum attempts reached', + 'Unauthorized: bad credentials', + 'Max retries exceeded'].reverse.each do |valid_message| + it "should retry when neutron cli returns with error #{valid_message}" do + klass.expects(:get_neutron_credentials).with().returns({}) + klass.expects(:sleep).with(2).returns(nil) + klass.expects(:neutron).twice.with(['test_retries']).raises( + Puppet::ExecutionFailure, valid_message).then.returns('') + klass.auth_neutron('test_retries') + end + end + + end + + describe 'when listing neutron resources' do + + it 'should exclude the column header' do + output = <<-EOT + id + net1 + net2 + EOT + klass.expects(:auth_neutron).returns(output) + result = klass.list_neutron_resources('foo') + result.should eql(['net1', 'net2']) + end + + it 'should return empty list when there are no neutron resources' do + output = <<-EOT + EOT + klass.stubs(:auth_neutron).returns(output) + result = klass.list_neutron_resources('foo') + result.should eql([]) + end + + it 'should fail if resources list is nil' do + klass.stubs(:auth_neutron).returns(nil) + expect do + klass.list_neutron_resources('foo') + end.to raise_error(Puppet::Error, exec_error) + end + + end + + describe 'when retrieving attributes for neutron resources' do + + it 'should parse single-valued attributes into a key-value pair' do + klass.expects(:auth_neutron).returns('admin_state_up="True"') + result = klass.get_neutron_resource_attrs('foo', 'id') + result.should eql({"admin_state_up" => 'True'}) + end + + it 'should parse multi-valued attributes into a key-list pair' do + output = <<-EOT +subnets="subnet1 +subnet2 +subnet3" + EOT + klass.expects(:auth_neutron).returns(output) + result = klass.get_neutron_resource_attrs('foo', 'id') + result.should eql({"subnets" => ['subnet1', 'subnet2', 'subnet3']}) + end + + end + + describe 'when listing router ports' do + + let :router do + 'router1' + end + + it 'should handle an empty port list' do + klass.expects(:auth_neutron).with('router-port-list', + '--format=csv', + router) + result = klass.list_router_ports(router) + result.should eql([]) + end + + it 'should handle several ports' do + output = <<-EOT +"id","name","mac_address","fixed_ips" +"1345e576-a21f-4c2e-b24a-b245639852ab","","fa:16:3e:e3:e6:38","{""subnet_id"": ""839a1d2d-2c6e-44fb-9a2b-9b011dce8c2f"", ""ip_address"": ""10.0.0.1""}" +"de0dc526-02b2-467c-9832-2c3dc69ac2b4","","fa:16:3e:f6:b5:72","{""subnet_id"": ""e4db0abd-276a-4f69-92ea-8b9e4eacfd43"", ""ip_address"": ""172.24.4.226""}" + EOT + expected = + [{ "fixed_ips"=> + "{\"subnet_id\": \"839a1d2d-2c6e-44fb-9a2b-9b011dce8c2f\", \ +\"ip_address\": \"10.0.0.1\"}", + "name"=>"", + "subnet_id"=>"839a1d2d-2c6e-44fb-9a2b-9b011dce8c2f", + "id"=>"1345e576-a21f-4c2e-b24a-b245639852ab", + "mac_address"=>"fa:16:3e:e3:e6:38"}, + {"fixed_ips"=> + "{\"subnet_id\": \"e4db0abd-276a-4f69-92ea-8b9e4eacfd43\", \ +\"ip_address\": \"172.24.4.226\"}", + "name"=>"", + "subnet_id"=>"e4db0abd-276a-4f69-92ea-8b9e4eacfd43", + "id"=>"de0dc526-02b2-467c-9832-2c3dc69ac2b4", + "mac_address"=>"fa:16:3e:f6:b5:72"}] + klass.expects(:auth_neutron). + with('router-port-list', '--format=csv', router). + returns(output) + result = klass.list_router_ports(router) + result.should eql(expected) + end + + end + + describe 'when parsing creation output' do + + it 'should parse valid output into a hash' do + data = <<-EOT +Created a new network: +admin_state_up="True" +id="5f9cbed2-d31c-4e9c-be92-87229acb3f69" +name="foo" +tenant_id="3056a91768d948d399f1d79051a7f221" + EOT + expected = { + 'admin_state_up' => 'True', + 'id' => '5f9cbed2-d31c-4e9c-be92-87229acb3f69', + 'name' => 'foo', + 'tenant_id' => '3056a91768d948d399f1d79051a7f221', + } + klass.parse_creation_output(data).should == expected + end + + end + +end diff --git a/3rdparty/modules/neutron/spec/unit/provider/neutron_subnet/neutron_spec.rb b/3rdparty/modules/neutron/spec/unit/provider/neutron_subnet/neutron_spec.rb new file mode 100644 index 000000000..ed49cd664 --- /dev/null +++ b/3rdparty/modules/neutron/spec/unit/provider/neutron_subnet/neutron_spec.rb @@ -0,0 +1,107 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/neutron_subnet/neutron' + +provider_class = Puppet::Type.type(:neutron_subnet).provider(:neutron) + +describe provider_class do + + let :subnet_name do + 'net1' + end + + let :subnet_attrs do + { + :name => subnet_name, + :ensure => 'present', + :cidr => '10.0.0.0/24', + :ip_version => '4', + :gateway_ip => '10.0.0.1', + :enable_dhcp => 'False', + :network_name => 'net1', + :tenant_id => '', + :allocation_pools => 'start=7.0.0.1,end=7.0.0.10', + :dns_nameservers => '8.8.8.8', + :host_routes => 'destination=12.0.0.0/24,nexthop=10.0.0.1', + } + end + + describe 'when updating a subnet' do + let :resource do + Puppet::Type::Neutron_subnet.new(subnet_attrs) + end + + let :provider do + provider_class.new(resource) + end + + it 'should call subnet-update to change gateway_ip' do + provider.expects(:auth_neutron).with('subnet-update', + '--gateway-ip=10.0.0.2', + subnet_name) + provider.gateway_ip=('10.0.0.2') + end + + it 'should call subnet-update to remove gateway_ip with empty string' do + provider.expects(:auth_neutron).with('subnet-update', + '--no-gateway', + subnet_name) + provider.gateway_ip=('') + end + + it 'should call subnet-update to change enable_dhcp' do + provider.expects(:auth_neutron).with('subnet-update', + '--enable-dhcp', + subnet_name) + provider.enable_dhcp=('True') + end + + it 'should call subnet-update to change dns_nameservers' do + provider.expects(:auth_neutron).with('subnet-update', + [subnet_name, + '--dns-nameservers', + 'list=true', + '9.9.9.9']) + provider.dns_nameservers=(['9.9.9.9']) + end + + it 'should call subnet-update to change host_routes' do + provider.expects(:auth_neutron).with('subnet-update', + [subnet_name, + '--host-routes', + 'type=dict', + 'list=true', + 'destination=12.0.0.0/24,nexthop=10.0.0.2']) + provider.host_routes=(['destination=12.0.0.0/24,nexthop=10.0.0.2']) + end + + it 'should not update if dns_nameservers are empty' do + provider.dns_nameservers=('') + end + + it 'should not update if host_routes are empty' do + provider.host_routes=('') + end + end + + describe 'when updating a subnet (reverse)' do + let :subnet_attrs_mod do + subnet_attrs.merge!({:enable_dhcp => 'True'}) + end + let :resource do + Puppet::Type::Neutron_subnet.new(subnet_attrs_mod) + end + + let :provider do + provider_class.new(resource) + end + + + it 'should call subnet-update to change enable_dhcp' do + provider.expects(:auth_neutron).with('subnet-update', + '--disable-dhcp', + subnet_name) + provider.enable_dhcp=('False') + end + end +end diff --git a/3rdparty/modules/neutron/spec/unit/provider/nova_admin_tenant_id_setter/neutron_spec.rb b/3rdparty/modules/neutron/spec/unit/provider/nova_admin_tenant_id_setter/neutron_spec.rb new file mode 100644 index 000000000..feb6c1864 --- /dev/null +++ b/3rdparty/modules/neutron/spec/unit/provider/nova_admin_tenant_id_setter/neutron_spec.rb @@ -0,0 +1,212 @@ +require 'spec_helper' +require 'puppet' +require 'puppet/type/nova_admin_tenant_id_setter' + +provider_class = Puppet::Type.type(:nova_admin_tenant_id_setter).provider(:ruby) + +# used to simulate an authentication response from Keystone +# (POST v2.0/tokens) +auth_response = { + 'access' => { + 'token' => { + 'id' => 'TOKEN', + } + } +} + +# used to simulate a response to GET v2.0/tenants +tenants_response = { + 'tenants' => [ + { + 'name' => 'services', + 'id' => 'UUID_SERVICES' + }, + { + 'name' => 'multiple_matches_tenant', + 'id' => 'UUID1' + }, + { + 'name' => 'multiple_matches_tenant', + 'id' => 'UUID2' + }, + ] +} + +# Stub for ini_setting resource +Puppet::Type.newtype(:ini_setting) do +end + +# Stub for ini_setting provider +Puppet::Type.newtype(:ini_setting).provide(:ruby) do + def create + end +end + +describe 'Puppet::Type.type(:nova_admin_tenant_id_setter)' do + let :params do + { + :name => 'nova_admin_tenant_id', + :tenant_name => 'services', + :auth_username => 'nova', + :auth_password => 'secret', + :auth_tenant_name => 'admin', + :auth_url => 'http://127.0.0.1:35357/v2.0', + } + end + + it 'should have a non-nil provider' do + expect(provider_class).not_to be_nil + end + + context 'when url is correct' do + before :each do + stub_request(:post, "http://127.0.0.1:35357/v2.0/tokens"). + to_return(:status => 200, + :body => auth_response.to_json, + :headers => {}) + stub_request(:get, "http://127.0.0.1:35357/v2.0/tenants"). + with(:headers => {'X-Auth-Token'=>'TOKEN'}). + to_return(:status => 200, + :body => tenants_response.to_json, + :headers => {}) + end + + it 'should create a resource' do + resource = Puppet::Type::Nova_admin_tenant_id_setter.new(params) + provider = provider_class.new(resource) + expect(provider.exists?).to be_false + expect(provider.create).to be_nil + end + + context 'when tenant id already set' do + it 'should create a resource, with exists? true' do + mock = { 'DEFAULT' => { 'nova_admin_tenant_id' => 'UUID_SERVICES' } } + Puppet::Util::IniConfig::File.expects(:new).returns(mock) + mock.expects(:read).with('/etc/neutron/neutron.conf') + + resource = Puppet::Type::Nova_admin_tenant_id_setter.new(params) + provider = provider_class.new(resource) + expect(provider.exists?).to be_true + expect(provider.create).to be_nil + end + end + end + + # What happens if we ask for a tenant that does not exist? + context 'when tenant cannot be found' do + before :each do + stub_request(:post, "http://127.0.0.1:35357/v2.0/tokens"). + to_return(:status => 200, + :body => auth_response.to_json, + :headers => {}) + stub_request(:get, "http://127.0.0.1:35357/v2.0/tenants"). + with(:headers => {'X-Auth-Token'=>'TOKEN'}). + to_return(:status => 200, + :body => tenants_response.to_json, + :headers => {}) + + params.merge!(:tenant_name => 'bad_tenant_name') + end + + it 'should receive an api error' do + resource = Puppet::Type::Nova_admin_tenant_id_setter.new(params) + provider = provider_class.new(resource) + expect(provider.exists?).to be_false + expect { provider.create }.to raise_error KeystoneAPIError, /Unable to find matching tenant/ + end + end + + # What happens if we ask for a tenant name that results in multiple + # matches? + context 'when there are multiple matching tenants' do + before :each do + stub_request(:post, "http://127.0.0.1:35357/v2.0/tokens"). + to_return(:status => 200, + :body => auth_response.to_json, + :headers => {}) + stub_request(:get, "http://127.0.0.1:35357/v2.0/tenants"). + with(:headers => {'X-Auth-Token'=>'TOKEN'}). + to_return(:status => 200, + :body => tenants_response.to_json, + :headers => {}) + + params.merge!(:tenant_name => 'multiple_matches_tenant') + end + + it 'should receive an api error' do + resource = Puppet::Type::Nova_admin_tenant_id_setter.new(params) + provider = provider_class.new(resource) + expect(provider.exists?).to be_false + expect { provider.create }.to raise_error KeystoneAPIError, /Found multiple matches for tenant name/ + end + end + + # What happens if we pass a bad password? + context 'when password is incorrect' do + before :each do + stub_request(:post, "http://127.0.0.1:35357/v2.0/tokens"). + to_return(:status => 401, + :body => auth_response.to_json, + :headers => {}) + end + + it 'should receive an authentication error' do + resource = Puppet::Type::Nova_admin_tenant_id_setter.new(params) + provider = provider_class.new(resource) + expect(provider.exists?).to be_false + expect { provider.create }.to raise_error KeystoneAPIError + end + end + + # What happens if the server is not listening? + context 'when keystone server is unavailable' do + before :each do + stub_request(:post, "http://127.0.0.1:35357/v2.0/tokens").to_raise Errno::ECONNREFUSED + end + + it 'should receive a connection error' do + resource = Puppet::Type::Nova_admin_tenant_id_setter.new(params) + provider = provider_class.new(resource) + expect(provider.exists?).to be_false + expect { provider.create }.to raise_error KeystoneConnectionError + end + end + + # What happens if we mistype the hostname? + context 'when keystone server is unknown' do + before :each do + stub_request(:post, "http://127.0.0.1:35357/v2.0/tokens").to_raise SocketError, 'getaddrinfo: Name or service not known' + end + + it 'should receive a connection error' do + resource = Puppet::Type::Nova_admin_tenant_id_setter.new(params) + provider = provider_class.new(resource) + expect(provider.exists?).to be_false + expect { provider.create }.to raise_error KeystoneConnectionError + end + end + + context 'when using secure keystone endpoint' do + before :each do + params.merge!(:auth_url => "https://127.0.0.1:35357/v2.0") + stub_request(:post, "https://127.0.0.1:35357/v2.0/tokens"). + to_return(:status => 200, + :body => auth_response.to_json, + :headers => {}) + stub_request(:get, "https://127.0.0.1:35357/v2.0/tenants"). + with(:headers => {'X-Auth-Token'=>'TOKEN'}). + to_return(:status => 200, + :body => tenants_response.to_json, + :headers => {}) + end + + it 'should create a resource' do + resource = Puppet::Type::Nova_admin_tenant_id_setter.new(params) + provider = provider_class.new(resource) + expect(provider.exists?).to be_false + expect(provider.create).to be_nil + end + end + +end + diff --git a/3rdparty/modules/neutron/templates/ml2_conf_cisco.ini.erb b/3rdparty/modules/neutron/templates/ml2_conf_cisco.ini.erb new file mode 100644 index 000000000..cb880d9d7 --- /dev/null +++ b/3rdparty/modules/neutron/templates/ml2_conf_cisco.ini.erb @@ -0,0 +1,59 @@ +[ml2_cisco] + +# (StrOpt) A short prefix to prepend to the VLAN number when creating a +# VLAN interface. For example, if an interface is being created for +# VLAN 2001 it will be named 'q-2001' using the default prefix. +# +# vlan_name_prefix = q- +# Example: vlan_name_prefix = vnet- + +# (BoolOpt) A flag to enable round robin scheduling of routers for SVI. +# svi_round_robin = False + +# +# (StrOpt) The name of the physical_network managed via the Cisco Nexus Switch. +# This string value must be present in the ml2_conf.ini network_vlan_ranges +# variable. +# +# managed_physical_network = +# Example: managed_physical_network = physnet1 + +# Cisco Nexus Switch configurations. +# Each switch to be managed by Openstack Neutron must be configured here. +# +# Cisco Nexus Switch Format. +# [ml2_mech_cisco_nexus:] +# = (1) +# ssh_port= (2) +# username= (3) +# password= (4) +# +# (1) For each host connected to a port on the switch, specify the hostname +# and the Nexus physical port (interface) it is connected to. +# Valid intf_type's are 'ethernet' and 'port-channel'. +# The default setting for is 'ethernet' and need not be +# added to this setting. +# (2) The TCP port for connecting via SSH to manage the switch. This is +# port number 22 unless the switch has been configured otherwise. +# (3) The username for logging into the switch to manage it. +# (4) The password for logging into the switch to manage it. +# +# Example: +# [ml2_mech_cisco_nexus:1.1.1.1] +# compute1=1/1 +# compute2=ethernet:1/2 +# compute3=port-channel:1 +# ssh_port=22 +# username=admin +# password=mySecretPassword + +<% nexus_config.each do |switch_hostname, switch_data| %> +[ML2_MECH_CISCO_NEXUS:<%= switch_data['ip_address'] %>] +<%- switch_data['servers'].each do|host_name, port| -%> +<%=host_name-%>=<%= port %> +<%- end -%> +ssh_port=<%= switch_data['ssh_port'] %> +username=<%= switch_data['username'] %> +password=<%= switch_data['password'] %> +<% end %> + diff --git a/3rdparty/modules/neutron/templates/n1kv.conf.erb b/3rdparty/modules/neutron/templates/n1kv.conf.erb new file mode 100644 index 000000000..dd9409432 --- /dev/null +++ b/3rdparty/modules/neutron/templates/n1kv.conf.erb @@ -0,0 +1,169 @@ +# This is the N1KV VEM configuration file. +# file contains all the configuration parameters for VEM operation. +# Please find below a brief explanation of these parameters and their meaning. +# Optional Parameters and Default Values of parameters are explicitly stated. +# Note: +# a)Mandatory parameters are needed for proper VEM operation. +# N1KV DP/DPA should start even if these are not specified. +# But there will be functional impact. For eg: in VSM connectivity +# b)For any updates to parameters to take effect, you just need to execute +# 'vemcmd reread config'. Its the least-disruptive way for changes to +# take effect. However for certain params, n1kv service need to be restarted. +# These parameter are stated explictly (restart_on_modify: YES). +# + +# +# +# +# TAG: switch-domain +# Description: +# Optional: No +# Default: 1000 +# restart_on_modify: No +switch-domain <%= @n1kv_vsm_domain_id %> + +# TAG: l3control-ipaddr +# Description: IP Address of VSM Mgmt I/F +# Optional: No +# Default: 127.0.0.1 +# restart_on_modify: No +l3control-ipaddr <%= @n1kv_vsm_ip %> + +# TAG: host-mgmt-intf +# Description: Management interface of the Host +# Optional: No (on N1KV, we need this +# for Host Identification on VSM). +# Default: lo +# restart_on_modify: Yes +host-mgmt-intf <%= @host_mgmt_intf %> + +# +# Description: Port-Profile mapping for all VEM managed Interfaces. +# Optional: Yes +# restart_on_modify: No +# +# Note: Do not specify Host Management Interface here. +# We do yet support System Ports (Ports which need to be up all time: Post Reboot/VEM Upgrade). +# +# Format for physical ports: +# phys profile +#phys eth1 profile sys-uplink +#phys eth2 profile uplink2 + +<% @uplink_profile.each do |port, profile| -%> +phys <%= port%> profile <%= profile%> +<% end -%> + +# Format for non-vm virt ports. For instance: VTEP ports. +# virt profile [mode static|dhcp] [address ] +# [netmask ] [mac ] +# [] -->indicates optional parameters. +#Eg: +#virt vtep3 profile profint mode dhcp +#virt vtep1 profile profint mode dhcp mac 00:11:22:33:44:55 +#virt vtep2 profile profint mode static address 192.168.2.91 netmask 255.255.255.0 +#virt vtep2 profile profint mode static address 192.168.2.91 netmask 255.255.255.0 mac 00:22:22:33:44:55 + +<% @vtep_config.each do |port, params| -%> +<% if params['ipmode'] == 'dhcp' -%> +virt <%= port%> profile <%= params['profile']%> mode dhcp +<% else-%> +virt <%= port%> profile <%= params['profile']%> mode static address <%= params['ipaddress']%> netmask <%= params['netmask']%> +<% end -%> +<% end -%> + +# TAG: uvem-ovs-brname +# Description: Default Open VSwitch Bridge Name +# Optional: YES. +# Default: n1kvdvs +# restart_on_modify: Yes +# Format: +# uvem-ovs-brname n1kvdvs +uvem-ovs-brname br-int + +# TAG: portdb +# Description: PortDB (ovs|vem) +# Optional: YES. +# Default: ovs +# restart_on_modify: Yes +# Format: +# portdb vem +portdb <%= @portdb %> + +# TAG: node-type +# Description: Type of Node: 'compute' (or) 'neutron' +# Optional: YES. +# Default: compute +# restart_on_modify: No +# Format: +# node-type compute +node-type <%= @node_type %> + +# The below parameters are not commonly modified. +# +# +# +# Description: System Port Profiles. +# Optional: Yes (If there are no System Interfaces: Mgmt I/F etc) +# restart_on_modify: No +# +#Trunk Profile Format +#profile trunk +#profile native-vlan +#profile mtu +# +#Access Profile +#profile access +#profile mtu + +# TAG: dp-np-threads +# Description: Number of datapath threads to process normal priority packets +# Optional: YES +# Default: 4 +# restart_on_modify: Yes +# Format: dp-np-threads <1..32> + +# TAG: dp-lp-threads +# Description: Number of datapath threads to process low priority packets +# Optional: YES +# Default: 1 +# restart_on_modify: Yes +# Format: dp-lp-threads <1..32> + +# TAG: dp-hp-threads +# Description: Number of datapath threads to process high priority packets +# Optional: YES +# Default: 1 +# restart_on_modify: Yes +# Format: dp-hp-threads <1..32> + +# TAG: dp-thread-sockets +# Description: Number of packet sockets each datapath thread creates +# Optional: YES +# Default: 1 +# restart_on_modify: Yes +# Format: dp-thread-sockets <1..16> + +# TAG: dp-thread-socket-rbuflen +# Description: Receive buffer length of each packet socket +# Optional: YES +# Default: 8 MBytes +# restart_on_modify: Yes +# Format: dp-thread-socket-rbuflen <0..255> +# Note: 0 - use system default + +# TAG: dp-thread-socket-rrnglen +# Description: Rx-ring length of each packet socket +# Optional: YES +# Default: 4096 +# restart_on_modify: Yes +# Format: dp-thread-socket-rrnglen <0..16384> +# Note: 0 - disables memory map I/O + +# TAG: fastpath-flood +# Description: Enable flood of broadcast and unknown pkts in KLM +# Optional: YES +# Default: disable +# restart_on_modify: Yes +# Format: fastpath-flood +fastpath-flood <%= @fastpath_flood %> diff --git a/3rdparty/modules/nova/Gemfile b/3rdparty/modules/nova/Gemfile new file mode 100644 index 000000000..5596f3405 --- /dev/null +++ b/3rdparty/modules/nova/Gemfile @@ -0,0 +1,20 @@ +source 'https://rubygems.org' + +group :development, :test do + gem 'puppetlabs_spec_helper', :require => false + gem 'metadata-json-lint' + gem 'puppet-lint', '~> 0.3.2' + gem 'rake', '10.1.1' + gem 'rspec-puppet', '~> 1.0.1', :require => false + gem 'rspec', '< 2.99' + gem 'json' + gem 'webmock' +end + +if puppetversion = ENV['PUPPET_GEM_VERSION'] + gem 'puppet', puppetversion, :require => false +else + gem 'puppet', :require => false +end + +# vim:ft=ruby diff --git a/3rdparty/modules/nova/LICENSE b/3rdparty/modules/nova/LICENSE new file mode 100644 index 000000000..8d968b6cb --- /dev/null +++ b/3rdparty/modules/nova/LICENSE @@ -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. diff --git a/3rdparty/modules/nova/README.md b/3rdparty/modules/nova/README.md new file mode 100644 index 000000000..be6105773 --- /dev/null +++ b/3rdparty/modules/nova/README.md @@ -0,0 +1,256 @@ +nova +==== + +5.1.0 - 2014.2 - Juno + +#### Table of Contents + +1. [Overview - What is the nova module?](#overview) +2. [Module Description - What does the module do?](#module-description) +3. [Setup - The basics of getting started with nova](#setup) +4. [Implementation - An under-the-hood peek at what the module is doing](#implementation) +5. [Limitations - OS compatibility, etc.](#limitations) +6. [Development - Guide for contributing to the module](#development) +7. [Contributors - Those with commits](#contributors) +8. [Release Notes - Notes on the most recent updates to the module](#release-notes) + +Overview +-------- + +The nova module is a part of [Stackforge](https://github.com/stackforge), an effort by the Openstack infrastructure team to provide continuous integration testing and code review for Openstack and Openstack community projects not part of the core software. The module its self is used to flexibly configure and manage the compute service for Openstack. + +Module Description +------------------ + +The nova module is a thorough attempt to make Puppet capable of managing the entirety of nova. This includes manifests to provision such things as keystone endpoints, RPC configurations specific to nova, and database connections. Types are shipped as part of the nova module to assist in manipulation of configuration files. + +This module is tested in combination with other modules needed to build and leverage an entire Openstack software stack. These modules can be found, all pulled together in the [openstack module](https://github.com/stackforge/puppet-openstack). + +Setup +----- + +**What the nova module affects:** + +* nova, the compute service for Openstack. + +### Installing nova + + example% puppet module install puppetlabs/nova + +### Beginning with nova + +To utilize the nova module's functionality you will need to declare multiple resources. The following is a modified excerpt from the [openstack module](https://github.com/stackforge/puppet-openstack). This is not an exhaustive list of all the components needed, we recommend you consult and understand the [openstack module](https://github.com/stackforge/puppet-openstack) and the [core openstack](http://docs.openstack.org) documentation. + +```puppet +class { 'nova': + database_connection => 'mysql://nova:a_big_secret@127.0.0.1/nova?charset=utf8', + rabbit_userid => 'nova', + rabbit_password => 'an_even_bigger_secret', + image_service => 'nova.image.glance.GlanceImageService', + glance_api_servers => 'localhost:9292', + verbose => false, + rabbit_host => '127.0.0.1', +} + +class { 'nova::compute': + enabled => true, + vnc_enabled => true, +} + +class { 'nova::compute::libvirt': + migration_support => true, +} +``` + +Implementation +-------------- + +### nova + +nova is a combination of Puppet manifest and ruby code to delivery configuration and extra functionality through types and providers. + +Limitations +----------- + +* Supports libvirt, xenserver and vmware compute drivers. +* Tested on EL and Debian derivatives. + +Development +----------- + +Developer documentation for the entire puppet-openstack project. + +* https://wiki.openstack.org/wiki/Puppet-openstack#Developer_documentation + +Contributors +------------ + +* https://github.com/stackforge/puppet-nova/graphs/contributors + +Release Notes +------------- + +**5.1.0** + +* move setting of novncproxy_base_url +* Added parameters for availability zones configuration +* crontab: ensure nova-common is installed before +* Correct docs on format for nova::policy data +* Allow libvirt secret key setting from param +* Fix behaviour of 'set-secret-value virsh' exec +* MySQL: change default MySQL collate to utf8_general_ci +* Pin puppetlabs-concat to 1.2.1 in fixtures +* Make group on /var/log/nova OS specific +* IPv6 support for migration check. +* Database: add slave_connection support +* Correct references to ::nova::rabbit_* variables +* Add optional network_api_class parameter to nova::network::neutron class +* Add Nova Aggregate support +* rpc_backend: simplify parameters +* supporting lxc cpu mode Fixing the default cpu_mode from None to none +* virsh returns a list of secret uuids, not keyring names +* Pin fixtures for stables branches +* Add serialproxy configuration +* Switch to TLSv1 as SSLv3 is considered insecure and is disabled by default +* Disable file injection when using RBD as compute ephemeral storage +* Add PCI Passthrough/SR-IOV support +* Add Ironic support into nova puppet modules +* spec: pin rspec-puppet to 1.0.1 +* Correct section for cell_type nova.conf parameter +* crontab: ensure the script is run with shell +* Configure database parameters on the right nodes + +**5.0.0** + +* Stable Juno release +* Added tags to all nova packages +* Added parameter dhcp_domain to nova class +* Updated the [glance] and [neutron] section parameters for Juno +* Fixed potential duplicate declaration errors for sysctl::value in nova::network +* Fixed dependency cycle in nova::migration::libvirt +* Updated the libvirtd init script path for Debian +* Added parameters for nova service validation to nova::api +* Added nova::policy to control policy.json +* Fixed the rabbit_virtual_host default in nova::cells +* Bumped stdlib dependency to >=4.0.0 +* Added force_raw_images parameter to nova::compute class +* Replaced usage of the keyword type with the string 'type' since type is a reserved keyword in puppet 3.7 +* Added parameter ec2_workers to nova::api +* Fixed bug in usage of --vlan versus --vlan_start in nova_network provider +* Added parameter rabbit_ha_queues to nova class +* Added parameter pool to nova_floating type +* Added parameters to control whether to configure keystone users +* Added nova::cron::archive_deleted_rows class to create a crontab for archiving deleted database rows +* Changed the keystone_service to only be configured if the endpoint is to be configured +* Added parameter keystone_ec2_url to nova::api +* Added the ability to override the keystone service name in ceilometer::keystone::auth +* Removed dynamic scoping of File resources in nova class +* Add parameter workers to in nova::conductor and deprecate conductor_workers in nova::api +* Update nova quota parameters for Juno +* Migrated the ceilometer::db::mysql class to use openstacklib::db::mysql and deprecated the mysql_module parameter +* Removed deprecation notice for sectionless nova_config names +* Added parameter vnc_keymap in nova::compute +* Added parameter osapi_v3 to nova::api + +**4.2.0** + +* Added option to configure libvirt service name via class parameters +* Added support for multiple SSL APIs +* Added option to configure os_region_name in the nova config +* Corrected resource dependencies on the nova user +* Fixed os version fact comparison for RedHat-based operating systems + for specifying service provider +* Fixed ssl parameter requirements when using kombu and rabbit +* Added class for extended logging options + +**4.1.0** + +* Added API v3 endpoint support. +* Added configuration of rbd keyring name. +* Added support for run Nova SSL endpoints. +* Updated RabbitMQ dependency. +* Updated mysql charset to UTF8. +* Pinned major gems. + +**4.0.0** + +* Stable Icehouse release. +* Added support for RHEL 7. +* Added support for metadata and conductor workers. +* Added support for vif_plugging parameters. +* Added support for puppetlabs-mysql 2.2 and greater. +* Added support for instance_usage_audit parameters. +* Added support to manage the nova uid/gid for NFS live migration.. +* Added nova::config to handle additional custom options. +* Added support to disable installation of nova utilities. +* Added support for durable RabbitMQ queues. +* Added SSL support for RabbitMQ. +* Added support for nova-objectstore bind address. +* Updated support for notification parameters. +* Fixed packaging bugs. +* Fixed report_interval configuration. +* Fixed file location for nova compute rbd secret. + +**3.2.1** + +* Fixed consoleauth/spice resource duplication on Red Hat systems. + +**3.2.0** + +* Replace pip with native package manager for VMWare. +* Deprecated logdir parameter in favor of log_dir. +* Allows log_dir to be set to false in order to disable file logging. +* Enables libvirt at boot. +* Adds RBD backend support for VM image storage. +* Parameterizes libvirt cpu_mode and disk_cachemodes. +* Adds support for https auth endpoints. +* Adds ability to disable installation of nova utilities. + +**3.1.0** + +* Minor release for OpenStack Havana. +* Add libguestfs-tools package to nova utilities. +* Fixed vncproxy package naming for Ubuntu. +* Fixed libvirt configuration. + +**3.0.0** + +* Major release for OpenStack Havana. +* Removed api-paste.ini configuration. +* Adds support for live migrations with using the libvirt Nova driver. +* Fixed bug to ensure keystone endpoint is set before service is started. +* Fixed nova-spiceproxy support on Ubuntu. +* Added support for VMWareVCDriver. + +**2.2.0** + +* Added a check to install bridge-utils only if needed. +* Added syslog support. +* Added installation of pm-utils for VM power management support. +* Fixed cinder include dependency bug. +* Various bug and lint fixes. + +**2.1.0** + +* Added support for X-Forwarded-For HTTP Headers. +* Added html5 spice support. +* Added config drive support. +* Added RabbitMQ clustering support. +* Added memcached support. +* Added SQL idle timeout support. +* Fixed allowed_hosts/database connection bug. +* Pinned RabbitMQ and database module versions. + +**2.0.0** + +* Upstream is now part of stackforge. +* The ini_file type is now used by nova_config. +* Support for nova-conductor added. +* Networks can now be labeled by Class['nova::manage::network']. +* The Apache Qpid message broker is available as an RPC backend. +* Further compatibility fixes for RHEL and its derivatives. +* Postgres support added. +* Adjustments to help in supporting the still in development neutron module. +* Config changes can be hidden from Puppet logs. +* Move from deprecated rabbit_notifier to rpc_notifier. +* Various cleanups and bug fixes. diff --git a/3rdparty/modules/nova/Rakefile b/3rdparty/modules/nova/Rakefile new file mode 100644 index 000000000..56dc07de3 --- /dev/null +++ b/3rdparty/modules/nova/Rakefile @@ -0,0 +1,7 @@ +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' + +PuppetLint.configuration.fail_on_warnings = true +PuppetLint.configuration.send('disable_80chars') +PuppetLint.configuration.send('disable_class_parameter_defaults') +PuppetLint.configuration.send('disable_class_inherits_from_params_class') diff --git a/3rdparty/modules/nova/checksums.json b/3rdparty/modules/nova/checksums.json new file mode 100644 index 000000000..79c6eeb95 --- /dev/null +++ b/3rdparty/modules/nova/checksums.json @@ -0,0 +1,125 @@ +{ + "Gemfile": "e1ed0a5421e2d306100a77b815d5f57c", + "LICENSE": "0e5ccf641e613489e66aa98271dbe798", + "README.md": "4fd410cf17ac4dc6c4a22fcdbb0058b4", + "Rakefile": "e64db1215b97906c4b9d4b4074a581e6", + "examples/nova_with_pacemaker.pp": "bd002b354a6c028b706b8a4c32fe8c6b", + "lib/puppet/parser/functions/check_array_of_hash.rb": "cd3d7fa9f2e89890632854382bb19025", + "lib/puppet/provider/nova.rb": "c57bee05fe29ff9bcbcad28a45f4f5ae", + "lib/puppet/provider/nova_admin/nova_manage.rb": "c0978afcbe3dac5ebd57d4dbb354bde0", + "lib/puppet/provider/nova_aggregate/nova.rb": "c64e0e5a640d6654e5b7908f1dcb8d0b", + "lib/puppet/provider/nova_cells/nova_manage.rb": "f13e6122f9993e8e07d2ecaebb1aeaa7", + "lib/puppet/provider/nova_config/ini_setting.rb": "43f0f135b3257e9cdfd99c13f1d0a1be", + "lib/puppet/provider/nova_floating/nova_manage.rb": "bacf66dc2516b1129979f221ad0e4122", + "lib/puppet/provider/nova_network/nova_manage.rb": "b0f1e1e1ea626fde6fac42b78363dcdc", + "lib/puppet/provider/nova_paste_api_ini/ini_setting.rb": "126127f9e096b1da9184c1dd617bd766", + "lib/puppet/provider/nova_project/nova_manage.rb": "ce8d1b84545b9f9b6c5904b25997a7a0", + "lib/puppet/type/nova_admin.rb": "4c9c145848c936a67585f5d42e805f9b", + "lib/puppet/type/nova_aggregate.rb": "e6b557bb076b98dce24bd0f3394c71b5", + "lib/puppet/type/nova_cells.rb": "5a1faf29b22aec1a0956900616f713c6", + "lib/puppet/type/nova_config.rb": "272e491c14010e88ce52bdced6e1e076", + "lib/puppet/type/nova_floating.rb": "df1e413f5240f04132e126bb40ad0266", + "lib/puppet/type/nova_network.rb": "55336d8b66c3757353a9239199a7afdb", + "lib/puppet/type/nova_paste_api_ini.rb": "6e14d1afcaf1000624459e9654c51937", + "lib/puppet/type/nova_project.rb": "e75354751a78bf2a395529eb10a8835f", + "manifests/api.pp": "0ec2d326f6afca80dd637381d0aa1873", + "manifests/cells.pp": "ec50a40b6034f9869ed133263968f5fe", + "manifests/cert.pp": "6a2c00959867d249a3f7533234d66960", + "manifests/client.pp": "d7f64f8db3567c83fc05f4e5e295ba2d", + "manifests/compute/ironic.pp": "f336093bb3b41126f8014e7d585f60ef", + "manifests/compute/libvirt.pp": "d76c9a8a9f39c61b6a882e17f870e0ec", + "manifests/compute/neutron.pp": "8a39e023da8bdcf8c7a39e9812ea537a", + "manifests/compute/rbd.pp": "ac9ab907b4d24a3d692240cb6e0af622", + "manifests/compute/serial.pp": "8c9028f12279c679583e7748ccde7b95", + "manifests/compute/spice.pp": "acbd57e2b8c5f40b33a9f3908bde59b5", + "manifests/compute/vmware.pp": "ae6765771b6905879b8be734e48672e3", + "manifests/compute/xenserver.pp": "e29a9f556799b20fbde9c5f19fdaa549", + "manifests/compute.pp": "eee75cb5537400348310442a628bfb17", + "manifests/conductor.pp": "ea7f8da7ffc8a7e499cfc67cdfa1b03b", + "manifests/config.pp": "46f3b0492f1c1844aaef8155cc41d2cf", + "manifests/consoleauth.pp": "d9e236858fb865213881dd53173ab557", + "manifests/cron/archive_deleted_rows.pp": "5e5a48e1b9ceda65fa8a4690945fadb6", + "manifests/db/mysql.pp": "4af1e7c841293b1e33757f7ffc605e98", + "manifests/db/postgresql.pp": "f81497c8baefd1f51359b067f39b5f81", + "manifests/db.pp": "bdf4e08a454478059bf7ac8ae7f5aa52", + "manifests/generic_service.pp": "0776fb0024acbe774e4492614965c194", + "manifests/init.pp": "ab63c201d4fd0e34096fba3c81e9d93b", + "manifests/keystone/auth.pp": "86ba5c3b54cedb9f2e781e07a5899d22", + "manifests/logging.pp": "e1d49d8f23b1009feaa401e069c838a8", + "manifests/manage/cells.pp": "d08662fd0a54f5ee37487bb534f13222", + "manifests/manage/floating.pp": "b7b477a087a0e98f5c47729159f19af3", + "manifests/manage/network.pp": "221da8a02e1e0cad769da42731e6c6aa", + "manifests/migration/libvirt.pp": "aa34ed55d3284a25be49a7fb0dcdc316", + "manifests/network/bridge.pp": "55f2fa5c658a4c0f11b88434972fc7f8", + "manifests/network/flat.pp": "38d3c53d0cc7cc56b949cf6f5703ea1f", + "manifests/network/flatdhcp.pp": "65ccf050719fe3e6c02a5019c9328706", + "manifests/network/neutron.pp": "846dd944a333de839d69eca59bce9424", + "manifests/network/vlan.pp": "b3f7d3e25d6db5eac469d78a5ff98080", + "manifests/network.pp": "1ff7cb6595cf7d2ea03384df79256d12", + "manifests/objectstore.pp": "4c007ef221f3021122778c9a805b181d", + "manifests/params.pp": "4cbd6a75db1b61776b54c6e0442de5c2", + "manifests/policy.pp": "66ad9d6e0487a2801fa69d4f576c44a2", + "manifests/qpid.pp": "04e9e8b65ac6028be6e4c2b16dba56a0", + "manifests/quota.pp": "68f3f707568097f3e5152aeb78d3cff3", + "manifests/rabbitmq.pp": "4e691a52b428c7af23dca81c393093d4", + "manifests/scheduler/filter.pp": "dbf08de636ce0a6e80d7424697458ac5", + "manifests/scheduler.pp": "944b76c325d168125d1d578212b3a6a0", + "manifests/serialproxy.pp": "31f0e714c1ce04486dd5ceca2dc49aea", + "manifests/spicehtml5proxy.pp": "f76827ae2c523d5d47c60ce2c592d397", + "manifests/utilities.pp": "3013aba97b4d7b3ddf003446b54e7613", + "manifests/vncproxy/common.pp": "5a4b15a5668606c86ba583a9ff2081b8", + "manifests/vncproxy.pp": "afa3a537b3e82f7f139a6fb163fcdbda", + "metadata.json": "86fb230baf268b6d2634ebbbb3a1b6f8", + "spec/classes/nova_api_spec.rb": "99bbd4f7daebd731ce66fe22ff213511", + "spec/classes/nova_cells_spec.rb": "7d643cebeec701414e690f58d23d78e9", + "spec/classes/nova_cert_spec.rb": "1ba485e28f18dfebc3646ed9cec361dd", + "spec/classes/nova_client_spec.rb": "1cc88936f0152a85117597b9422d5d9d", + "spec/classes/nova_compute_ironic_spec.rb": "99d04e982dc8d98acc426831bb5cfed8", + "spec/classes/nova_compute_libvirt_spec.rb": "297524cda212106b969f68d833b0f7c8", + "spec/classes/nova_compute_neutron_spec.rb": "0f8ec8ec80a650bd647144b9efb29d5d", + "spec/classes/nova_compute_rbd_spec.rb": "51739311a4b992cedc430eabece0f48d", + "spec/classes/nova_compute_serial_spec.rb": "c1a5bdba679c14e33c3e7e1336f829a4", + "spec/classes/nova_compute_spec.rb": "5ecbe51a4e949154ebf0b05255f2f2e3", + "spec/classes/nova_compute_spice_spec.rb": "ad75cf60a3846a7d84300c3e07f36d92", + "spec/classes/nova_compute_vmware_spec.rb": "b410f91b33f0e9c5cbd7724d1899e98c", + "spec/classes/nova_compute_xenserver_spec.rb": "67bb9f28fdf68342817252b99356aad4", + "spec/classes/nova_conductor_spec.rb": "0befb1db4e63fa5034f2b990fc56923e", + "spec/classes/nova_config_spec.rb": "a2f2bf1410abd5e6ef95d8b71296ae88", + "spec/classes/nova_consoleauth_spec.rb": "3504ec1c1645eb58ac7029d4ed02258e", + "spec/classes/nova_cron_archive_deleted_rows_spec.rb": "a0d9d071c2d794713b972668c68ccfb9", + "spec/classes/nova_db_mysql_spec.rb": "4afa967968f365c50165320be83e47a1", + "spec/classes/nova_db_postgresql_spec.rb": "cd675cba47b392909822b8c85095a32f", + "spec/classes/nova_db_spec.rb": "79eeab03a69601946decc423b8d17e85", + "spec/classes/nova_init_spec.rb": "28b52bd0b2d04557912a06f9cd636bbe", + "spec/classes/nova_keystone_endpoint_spec.rb": "15fa525219387829f88a180648cb245e", + "spec/classes/nova_logging_spec.rb": "a0bd152a7c45335818acf90e51e3cd83", + "spec/classes/nova_migration_libvirt_spec.rb": "b00828381677b56b55b96ab9f8b77c02", + "spec/classes/nova_network_flat_spec.rb": "d11d3f5b7bc37c4dd84996fe3fa1f1c7", + "spec/classes/nova_network_flatdhcp_spec.rb": "256108ee1246f1670519f020899641e3", + "spec/classes/nova_network_neutron_spec.rb": "1288eb269449779a1d5b44dc81ae80e9", + "spec/classes/nova_network_spec.rb": "42308e8f655ac902357482c90190497d", + "spec/classes/nova_network_vlan_spec.rb": "6a00e700aec28b87b18669e95affef34", + "spec/classes/nova_objectstore_spec.rb": "f2a901630c9428a6c5db2e0412a15c86", + "spec/classes/nova_policy_spec.rb": "46a27309fca2c316ca8a86db44fc7163", + "spec/classes/nova_qpid_spec.rb": "ce8c0194c3407d04cb62cca293b457a3", + "spec/classes/nova_quota_spec.rb": "93920167e88e7f7c1ce47c632235588f", + "spec/classes/nova_rabbitmq_spec.rb": "7a3cbb62a6a9fd58fad44b5e2446dc66", + "spec/classes/nova_scheduler_filter_spec.rb": "03586bfcb54a3481d27792db532c2410", + "spec/classes/nova_scheduler_spec.rb": "568f47b45ddbbe7bee53d0cfa672ea87", + "spec/classes/nova_serial_proxy_spec.rb": "2052489f19db9fecbcbf8914bcd0ba5d", + "spec/classes/nova_spicehtml5_proxy_spec.rb": "66c5401610a671297c0724ed24e3832e", + "spec/classes/nova_utilities_spec.rb": "8d7cf85391c883551f84d91b3d4779b5", + "spec/classes/nova_vnc_proxy_spec.rb": "08c3f312dcc40045d198d8eb99dc8409", + "spec/defines/nova_generic_service_spec.rb": "0006c4e1ad2b7ec97e26c97951ed12ba", + "spec/defines/nova_manage_networks_spec.rb": "0987f213d16bfd924d79e112fb285dec", + "spec/fixtures/manifests/site.pp": "4a5324f0a1c271a43c2e0a6251853012", + "spec/hosts/test-001_spec.rb": "a3621f1f165b91cbd84f5c26341971d7", + "spec/shared_examples.rb": "e578ec13d6482780cab97d3624f33d88", + "spec/spec_helper.rb": "41d71ed92d01bb23d52397572e9b24bb", + "spec/type/nova_aggregate_spec.rb": "02d61b6c0c711ed738861d2593a30a3e", + "spec/unit/provider/nova_config/ini_setting_spec.rb": "5b1b30930662f3eb9dd876f73f0111ba", + "spec/unit/provider/nova_spec.rb": "779166eaad29ad7f2d40e844a3e825dc", + "spec/unit/type/nova_config_spec.rb": "27ecce4b96b0790e044c61025fc4328b", + "spec/unit/type/nova_network_spec.rb": "655aaeb25fd65c8a94bbe8b5a56637d5", + "templates/secret.xml-compute.erb": "b36b866969c86c182c67ab85feec1755" +} \ No newline at end of file diff --git a/3rdparty/modules/nova/examples/nova_with_pacemaker.pp b/3rdparty/modules/nova/examples/nova_with_pacemaker.pp new file mode 100644 index 000000000..0e2833cc3 --- /dev/null +++ b/3rdparty/modules/nova/examples/nova_with_pacemaker.pp @@ -0,0 +1,55 @@ +# Example: managing nova compute controller services with pacemaker +# +# By setting enabled to false, these services will not be started at boot. By setting +# manage_service to false, puppet will not kill these services on every run. This +# allows the Pacemaker resource manager to dynamically determine on which node each +# service should run. +# +# The puppet commands below would ideally be applied to at least three nodes. +# +# Note that nova-api and nova-novncproxy are associated with the virtual IP address as +# they are called from external services. The remaining services connect to the +# database and/or message broker independently. +# +# Example pacemaker resource configuration commands (configured once per cluster): +# +# sudo pcs resource create nova_vip ocf:heartbeat:IPaddr2 params ip=192.0.2.3 \ +# cidr_netmask=24 op monitor interval=10s +# +# sudo pcs resource create nova_api_service lsb:openstack-nova-api +# sudo pcs resource create nova_conductor_service lsb:openstack-nova-conductor +# sudo pcs resource create nova_consoleauth_service lsb:openstack-nova-consoleauth +# sudo pcs resource create nova_novncproxy_service lsb:openstack-nova-novncproxy +# sudo pcs resource create nova_scheduler_service lsb:openstack-nova-scheduler +# +# sudo pcs constraint colocation add nova_api_service with nova_vip +# sudo pcs constraint colocation add nova_novncproxy_service with nova_vip + +class { 'nova': } + +class { 'nova::api': + enabled => false, + manage_service => false, + admin_password => 'PASSWORD', +} + +class { 'nova::conductor': + enabled => false, + manage_service => false, +} + +class { 'nova::consoleauth': + enabled => false, + manage_service => false, +} + +class { 'nova::scheduler': + enabled => false, + manage_service => false, +} + +class { 'nova::vncproxy': + enabled => false, + manage_service => false, +} + diff --git a/3rdparty/modules/nova/lib/puppet/parser/functions/check_array_of_hash.rb b/3rdparty/modules/nova/lib/puppet/parser/functions/check_array_of_hash.rb new file mode 100644 index 000000000..be75db296 --- /dev/null +++ b/3rdparty/modules/nova/lib/puppet/parser/functions/check_array_of_hash.rb @@ -0,0 +1,27 @@ +require 'json' + +def array_of_hash?(list) + return false unless !list.empty? && list.class == Array + list.each do |e| + return false unless e.class == Hash + end + true +end + +module Puppet::Parser::Functions + newfunction(:check_array_of_hash, :arity =>1, :type => :rvalue, :doc => "Check + input String is a valid Array of Hash in JSON style") do |arg| + if arg[0].class == String + begin + list = JSON.load(arg[0].gsub("'","\"")) + rescue JSON::ParserError + raise Puppet::ParseError, "Syntax error: #{arg[0]} is invalid" + else + return arg[0] if array_of_hash?(list) + end + else + raise Puppet::ParseError, "Syntax error: #{arg[0]} is not a String" + end + return '' + end +end diff --git a/3rdparty/modules/nova/lib/puppet/provider/nova.rb b/3rdparty/modules/nova/lib/puppet/provider/nova.rb new file mode 100644 index 000000000..ca7bb0181 --- /dev/null +++ b/3rdparty/modules/nova/lib/puppet/provider/nova.rb @@ -0,0 +1,199 @@ +# Run test ie with: rspec spec/unit/provider/nova_spec.rb + +require 'puppet/util/inifile' + +class Puppet::Provider::Nova < Puppet::Provider + + def self.conf_filename + '/etc/nova/nova.conf' + end + + def self.withenv(hash, &block) + saved = ENV.to_hash + hash.each do |name, val| + ENV[name.to_s] = val + end + + yield + ensure + ENV.clear + saved.each do |name, val| + ENV[name] = val + end + end + + def self.nova_conf + return @nova_conf if @nova_conf + @nova_conf = Puppet::Util::IniConfig::File.new + @nova_conf.read(conf_filename) + @nova_conf + end + + def self.nova_credentials + @nova_credentials ||= get_nova_credentials + end + + def nova_credentials + self.class.nova_credentials + end + + def self.get_nova_credentials + #needed keys for authentication + auth_keys = ['auth_host', 'auth_port', 'auth_protocol', + 'admin_tenant_name', 'admin_user', 'admin_password'] + conf = nova_conf + if conf and conf['keystone_authtoken'] and + auth_keys.all?{|k| !conf['keystone_authtoken'][k].nil?} + return Hash[ auth_keys.map \ + { |k| [k, conf['keystone_authtoken'][k].strip] } ] + else + raise(Puppet::Error, "File: #{conf_filename} does not contain all " + + "required sections. Nova types will not work if nova is not " + + "correctly configured.") + end + end + + def self.get_auth_endpoint + q = nova_credentials + "#{q['auth_protocol']}://#{q['auth_host']}:#{q['auth_port']}/v2.0/" + end + + def self.auth_endpoint + @auth_endpoint ||= get_auth_endpoint + end + + def self.auth_nova(*args) + q = nova_credentials + authenv = { + :OS_AUTH_URL => self.auth_endpoint, + :OS_USERNAME => q['admin_user'], + :OS_TENANT_NAME => q['admin_tenant_name'], + :OS_PASSWORD => q['admin_password'] + } + begin + withenv authenv do + nova(args) + end + rescue Exception => e + if (e.message =~ /\[Errno 111\] Connection refused/) or + (e.message =~ /\(HTTP 400\)/) + sleep 10 + withenv authenv do + nova(args) + end + else + raise(e) + end + end + end + + def auth_nova(*args) + self.class.auth_nova(args) + end + + def self.reset + @nova_conf = nil + @nova_credentials = nil + end + + def self.str2hash(s) + #parse string + if s.include? "=" + k, v = s.split("=", 2) + return {k.gsub(/'/, "") => v.gsub(/'/, "")} + else + return s.gsub(/'/, "") + end + end + + def self.str2list(s) + #parse string + if s.include? "," + if s.include? "=" + new = {} + else + new = [] + end + s.split(",").each do |el| + ret = str2hash(el.strip()) + if s.include? "=" + new.update(ret) + else + new.push(ret) + end + end + return new + else + return str2hash(s.strip()) + end + end + + def self.cliout2list(output) + #don't proceed with empty output + if output.empty? + return [] + end + lines = [] + output.each_line do |line| + #ignore lines starting with '+' + if not line.match("^\\+") + #split line at '|' and remove useless information + line = line.gsub(/^\| /, "").gsub(/ \|$/, "").gsub(/[\n]+/, "") + line = line.split("|").map do |el| + el.strip().gsub(/^-$/, "") + end + #check every element for list + line = line.map do |el| + el = str2list(el) + end + lines.push(line) + end + end + #create a list of hashes and return the list + hash_list = [] + header = lines[0] + lines[1..-1].each do |line| + hash_list.push(Hash[header.zip(line)]) + end + return hash_list + end + + def self.nova_aggregate_resources_ids + #produce a list of hashes with Id=>Name pairs + lines = [] + #run command + cmd_output = auth_nova("aggregate-list") + #parse output + hash_list = cliout2list(cmd_output) + #only interessted in Id and Name + hash_list.map{ |e| e.delete("Availability Zone")} + hash_list.map{ |e| e['Id'] = e['Id'].to_i} + return hash_list + end + + def self.nova_aggregate_resources_get_name_by_id(name) + #find the id by the given name + nova_aggregate_resources_ids.each do |entry| + if entry["Name"] == name + return entry["Id"] + end + end + #name not found + return nil + end + + def self.nova_aggregate_resources_attr(id) + #run command to get details for given Id + cmd_output = auth_nova("aggregate-details", id) + list = cliout2list(cmd_output)[0] + if ! list["Hosts"].is_a?(Array) + if list["Hosts"] == "" + list["Hosts"] = [] + else + list["Hosts"] = [ list["Hosts"] ] + end + end + return list + end + +end diff --git a/3rdparty/modules/nova/lib/puppet/provider/nova_admin/nova_manage.rb b/3rdparty/modules/nova/lib/puppet/provider/nova_admin/nova_manage.rb new file mode 100644 index 000000000..6dd4cb47c --- /dev/null +++ b/3rdparty/modules/nova/lib/puppet/provider/nova_admin/nova_manage.rb @@ -0,0 +1,20 @@ +Puppet::Type.type(:nova_admin).provide(:nova_manage) do + + desc "Manage nova admin user" + + optional_commands :nova_manage => 'nova-manage' + + def exists? + nova_manage("user", "list").match(/^#{resource[:name]}$/) + end + + def create + nova_manage("user", "admin", resource[:name]) + end + + def destroy + nova_manage("user", "delete", resource[:name]) + end + +end + diff --git a/3rdparty/modules/nova/lib/puppet/provider/nova_aggregate/nova.rb b/3rdparty/modules/nova/lib/puppet/provider/nova_aggregate/nova.rb new file mode 100644 index 000000000..cad8a67e3 --- /dev/null +++ b/3rdparty/modules/nova/lib/puppet/provider/nova_aggregate/nova.rb @@ -0,0 +1,157 @@ +require File.join(File.dirname(__FILE__), '..','..','..', + 'puppet/provider/nova') + +Puppet::Type.type(:nova_aggregate).provide( + :nova, + :parent => Puppet::Provider::Nova +) do + + desc "Manage nova aggregations" + + commands :nova => 'nova' + + mk_resource_methods + + def self.instances + nova_aggregate_resources_ids().collect do |el| + attrs = nova_aggregate_resources_attr(el['Id']) + new( + :ensure => :present, + :name => attrs['Name'], + :id => attrs['Id'], + :availability_zone => attrs['Availability Zone'], + :metadata => attrs['Metadata'], + :hosts => attrs['Hosts'] + ) + end + end + + def self.prefetch(resources) + instances_ = instances + resources.keys.each do |name| + if provider = instances_.find{ |instance| instance.name == name } + resources[name].provider = provider + end + end + end + + def exists? + @property_hash[:ensure] == :present + end + + def destroy + #delete hosts first + if not @property_hash[:hosts].nil? + @property_hash[:hosts].each do |h| + auth_nova("aggregate-remove-host", name, h) + end + end + #now delete aggregate + auth_nova("aggregate-delete", name) + @property_hash[:ensure] = :absent + end + + def create + extras = Array.new + #check for availability zone + if not @resource[:availability_zone].nil? and not @resource[:availability_zone].empty? + extras << "#{@resource[:availability_zone]}" + end + #run the command + result = auth_nova("aggregate-create", resource[:name], extras) + + #get Id by Name + id = self.class.nova_aggregate_resources_get_name_by_id(resource[:name]) + + @property_hash = { + :ensure => :present, + :name => resource[:name], + :id => id, + :availability_zone => resource[:availability_zone] + } + + #add metadata + if not @resource[:metadata].nil? and not @resource[:metadata].empty? + @resource[:metadata].each do |key, value| + set_metadata_helper(id, key, value) + end + @property_hash[:metadata] = resource[:metadata] + end + + #add hosts - This throws an error if the host is already attached to another aggregate! + if not @resource[:hosts].nil? and not @resource[:hosts].empty? + @resource[:hosts].each do |host| + auth_nova("aggregate-add-host", id, "#{host}") + end + @property_hash[:hosts] = resource[:hosts] + end + end + + def hosts=(val) + #get current hosts + id = self.class.nova_aggregate_resources_get_name_by_id(name) + attrs = self.class.nova_aggregate_resources_attr(id) + #remove all hosts which are not in new value list + attrs['Hosts'].each do |h| + if not val.include? h + auth_nova("aggregate-remove-host", id, "#{h}") + end + end + + #add hosts from the value list + val.each do |h| + if not attrs['Hosts'].include? h + auth_nova("aggregate-add-host", id, "#{h}") + end + end + end + + def set_metadata_helper(agg_id, key, value) + auth_nova("aggregate-set-metadata", agg_id, "#{key}=#{value}") + end + + def metadata + #get current metadata + id = self.class.nova_aggregate_resources_get_name_by_id(name) + attrs = self.class.nova_aggregate_resources_attr(id) + #just ignore the availability_zone. that's handled directly by nova + attrs['Metadata'].delete('availability_zone') + return attrs['Metadata'] + end + + def metadata=(val) + #get current metadata + id = self.class.nova_aggregate_resources_get_name_by_id(name) + attrs = self.class.nova_aggregate_resources_attr(id) + #get keys which are in current metadata but not in val. Make sure it has data first! + if attrs['Metadata'].length > 0 + obsolete_keys = attrs['Metadata'].keys - val.keys + end + # clear obsolete keys. If there are any! + if obsolete_keys + obsolete_keys.each do |key| + if not key.include? 'availability_zone' + auth_nova("aggregate-set-metadata", id, "#{key}") + end + end + #handle keys (with obsolete keys) + new_keys = val.keys - obsolete_keys + else + #handle keys (without obsolete keys) + new_keys = val.keys + end + #set new metadata if value changed + new_keys.each do |key| + if val[key] != attrs['Metadata'][key.to_s] + value = val[key] + set_metadata_helper(id, key, value) + end + end + end + + def availability_zone=(val) + id = self.class.nova_aggregate_resources_get_name_by_id(name) + auth_nova("aggregate-set-metadata", id, "availability_zone=#{val}") + end + +end diff --git a/3rdparty/modules/nova/lib/puppet/provider/nova_cells/nova_manage.rb b/3rdparty/modules/nova/lib/puppet/provider/nova_cells/nova_manage.rb new file mode 100644 index 000000000..84051f16b --- /dev/null +++ b/3rdparty/modules/nova/lib/puppet/provider/nova_cells/nova_manage.rb @@ -0,0 +1,87 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# François Charlier +# +# 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. +# +# +# nova_cells provider +# + +Puppet::Type.type(:nova_cells).provide(:nova_manage) do + + desc "Manage nova cells" + + optional_commands :nova_manage => 'nova-manage' + + def self.instances + begin + cells_list = nova_manage("cell", "list") + rescue Exception => e + if e.message =~ /No cells defined/ + return [] + else + raise(e) + end + end + cells_list.split("\n")[1..-1].collect do |net| + if net =~ /^(\S+)\s+(\S+)/ + new(:name => $2 ) + end + end.compact + end + + + def create + optional_opts = [] + { + :name => '--name', + :cell_type => '--cell_type', + :rabbit_username => '--username', + :rabbit_password => '--password', + :rabbit_hosts => '--hostname', + :rabbit_port => '--port', + :rabbit_virtual_host => '--virtual_host', + :weight_offset => '--woffset', + :weight_scale => '--wscale' + + }.each do |param, opt| + if resource[param] + optional_opts.push(opt).push(resource[param]) + end + end + + nova_manage('cell', 'create', + optional_opts + ) + end + + def exists? + begin + cells_list = nova_manage("cell", "list") + return cells_list.split("\n")[1..-1].detect do |n| + n =~ /^(\S+)\s+(#{resource[:cells].split('/').first})/ + end + rescue + return false + end + end + + + def destroy + nova_manage("cell", "delete", resource[:name]) + end + +end diff --git a/3rdparty/modules/nova/lib/puppet/provider/nova_config/ini_setting.rb b/3rdparty/modules/nova/lib/puppet/provider/nova_config/ini_setting.rb new file mode 100644 index 000000000..85b90a723 --- /dev/null +++ b/3rdparty/modules/nova/lib/puppet/provider/nova_config/ini_setting.rb @@ -0,0 +1,32 @@ +Puppet::Type.type(:nova_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + # the setting is always default + # this if for backwards compat with the old puppet providers for nova_config + def section + resource[:name].split('/', 2)[0] + end + + # assumes that the name was the setting + # this is to maintain backwards compat with the the older + # stuff + def setting + resource[:name].split('/', 2)[1] + end + + def separator + '=' + end + + def self.file_path + '/etc/nova/nova.conf' + end + + # this needs to be removed. This has been replaced with the class method + def file_path + self.class.file_path + end + +end diff --git a/3rdparty/modules/nova/lib/puppet/provider/nova_floating/nova_manage.rb b/3rdparty/modules/nova/lib/puppet/provider/nova_floating/nova_manage.rb new file mode 100644 index 000000000..de3d71b67 --- /dev/null +++ b/3rdparty/modules/nova/lib/puppet/provider/nova_floating/nova_manage.rb @@ -0,0 +1,23 @@ +Puppet::Type.type(:nova_floating).provide(:nova_manage) do + + desc "Manage nova floating" + + optional_commands :nova_manage => 'nova-manage' + + def exists? + # Calculate num quads to grab for prefix + mask=resource[:network].sub(/.*\/([0-9][0-9]?)/, '\1').to_i + num_quads = 4 - mask / 8 + prefix=resource[:network].sub(/(\.[0-9]{1,3}){#{num_quads}}(\/[0-9]{1,2})?$/, '') + "." + return nova_manage("floating", "list").match(/#{prefix}/) + end + + def create + nova_manage("floating", "create", '--pool', resource[:pool], resource[:network]) + end + + def destroy + nova_manage("floating", "delete", resource[:network]) + end + +end diff --git a/3rdparty/modules/nova/lib/puppet/provider/nova_network/nova_manage.rb b/3rdparty/modules/nova/lib/puppet/provider/nova_network/nova_manage.rb new file mode 100644 index 000000000..6da03a39d --- /dev/null +++ b/3rdparty/modules/nova/lib/puppet/provider/nova_network/nova_manage.rb @@ -0,0 +1,66 @@ +Puppet::Type.type(:nova_network).provide(:nova_manage) do + + desc "Manage nova network" + + optional_commands :nova_manage => 'nova-manage' + + # I need to setup caching and what-not to make this lookup performance not suck + def self.instances + begin + network_list = nova_manage("network", "list") + rescue Exception => e + if e.message =~ /No networks defined/ + return [] + else + raise(e) + end + end + network_list.split("\n")[1..-1].collect do |net| + if net =~ /^(\S+)\s+(\S+)/ + new(:name => $2 ) + end + end.compact + end + + def create + optional_opts = [] + { + # this needs to be converted from a project name to an id + :project => '--project_id', + :dns2 => '--dns2', + :gateway => '--gateway', + :bridge => '--bridge', + :vlan_start => '--vlan_start' + }.each do |param, opt| + if resource[param] + optional_opts.push(opt).push(resource[param]) + end + end + + nova_manage('network', 'create', + resource[:label], + resource[:name], + resource[:num_networks], + resource[:network_size], + optional_opts + ) + end + + def exists? + begin + network_list = nova_manage("network", "list") + return network_list.split("\n")[1..-1].detect do |n| + # TODO - this does not take the CIDR into accont. Does it matter? + n =~ /^(\S+)\s+(#{resource[:network].split('/').first})/ + end + rescue + return false + end + end + + + def destroy + nova_manage("network", "delete", resource[:network]) + end + +end diff --git a/3rdparty/modules/nova/lib/puppet/provider/nova_paste_api_ini/ini_setting.rb b/3rdparty/modules/nova/lib/puppet/provider/nova_paste_api_ini/ini_setting.rb new file mode 100644 index 000000000..339d32af0 --- /dev/null +++ b/3rdparty/modules/nova/lib/puppet/provider/nova_paste_api_ini/ini_setting.rb @@ -0,0 +1,27 @@ +Puppet::Type.type(:nova_paste_api_ini).provide( + :ini_setting, + :parent => Puppet::Type.type(:ini_setting).provider(:ruby) +) do + + def section + resource[:name].split('/', 2).first + end + + def setting + resource[:name].split('/', 2).last + end + + def separator + '=' + end + + def self.file_path + '/etc/nova/api-paste.ini' + end + + # this needs to be removed. This has been replaced with the class method + def file_path + self.class.file_path + end + +end diff --git a/3rdparty/modules/nova/lib/puppet/provider/nova_project/nova_manage.rb b/3rdparty/modules/nova/lib/puppet/provider/nova_project/nova_manage.rb new file mode 100644 index 000000000..31a818f72 --- /dev/null +++ b/3rdparty/modules/nova/lib/puppet/provider/nova_project/nova_manage.rb @@ -0,0 +1,19 @@ +Puppet::Type.type(:nova_project).provide(:nova_manage) do + + desc "Manage nova project" + + optional_commands :nova_manage => 'nova-manage' + + def exists? + nova_manage("project", "list").match(/^#{resource[:name]}$/) + end + + def create + nova_manage("project", "create", resource[:name], resource[:owner]) + end + + def destroy + nova_manage("project", "delete", resource[:name]) + end + +end diff --git a/3rdparty/modules/nova/lib/puppet/type/nova_admin.rb b/3rdparty/modules/nova/lib/puppet/type/nova_admin.rb new file mode 100644 index 000000000..2df9210bf --- /dev/null +++ b/3rdparty/modules/nova/lib/puppet/type/nova_admin.rb @@ -0,0 +1,11 @@ +Puppet::Type.newtype(:nova_admin) do + + @doc = "Manage creation/deletion of nova admin users." + + ensurable + + newparam(:name, :namevar => true) do + desc "The name of the admins." + end + +end diff --git a/3rdparty/modules/nova/lib/puppet/type/nova_aggregate.rb b/3rdparty/modules/nova/lib/puppet/type/nova_aggregate.rb new file mode 100644 index 000000000..ccc6b9c5e --- /dev/null +++ b/3rdparty/modules/nova/lib/puppet/type/nova_aggregate.rb @@ -0,0 +1,110 @@ +# -*- coding: utf-8 -*- +# +# Copyright (C) 2014 Deutsche Telekom AG +# +# Author: Thomas Bechtold +# +# 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. +# +# nova_aggregate type +# +# == Parameters +# [*name*] +# Name for the new aggregate +# Required +# +# [*availability_zone*] +# The availability zone. ie "zone1" +# Optional +# +# [*metadata*] +# String with key/value pairs. ie "key=value,key=value" +# Optional +# +# [*hosts*] +# A comma seperated list with hosts or a single host. ie "host1,host2" +# Optional +# + +require 'puppet' + +Puppet::Type.newtype(:nova_aggregate) do + + @doc = "Manage creation of nova aggregations." + + ensurable + + autorequire(:nova_config) do + ['auth_host', 'auth_port', 'auth_protocol', 'admin_tenant_name', 'admin_user', 'admin_password'] + end + + newparam(:name, :namevar => true) do + desc 'Name for the new aggregate' + validate do |value| + if not value.is_a? String + raise ArgumentError, "name parameter must be a String" + end + unless value =~ /[a-z0-9]+/ + raise ArgumentError, "#{value} is not a valid name" + end + end + end + + newproperty(:id) do + desc 'The unique Id of the aggregate' + validate do |v| + raise ArgumentError, 'This is a read only property' + end + end + + newproperty(:availability_zone) do + desc 'The availability zone of the aggregate' + validate do |value| + if not value.is_a? String + raise ArgumentError, "availability zone must be a String" + end + end + end + + newproperty(:metadata) do + desc 'The metadata of the aggregate' + #convert DSL/string form to internal form which is a single hash + munge do |value| + internal = Hash.new + value.split(",").map{|el| el.strip()}.each do |pair| + key, value = pair.split("=", 2) + internal[key.strip()] = value.strip() + end + return internal + end + + validate do |value| + value.split(",").each do |kv| + raise ArgumentError, "Key/value pairs must be separated by an =" unless value.include?("=") + end + end + end + + newproperty(:hosts) do + desc 'Single host or comma seperated list of hosts' + #convert DSL/string form to internal form + munge do |value| + return value.split(",").map{|el| el.strip()} + end + end + + validate do + raise ArgumentError, 'Name type must be set' unless self[:name] + end + +end diff --git a/3rdparty/modules/nova/lib/puppet/type/nova_cells.rb b/3rdparty/modules/nova/lib/puppet/type/nova_cells.rb new file mode 100644 index 000000000..77098f1e9 --- /dev/null +++ b/3rdparty/modules/nova/lib/puppet/type/nova_cells.rb @@ -0,0 +1,115 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# François Charlier +# +# 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. +# +# +# nova_cells type +# +# == Parameters +# [*name*] +# Name for the new cell +# Optional +# +# [*cell_type*] +# Whether the cell is a 'parent' or 'child' +# Required +# +# [*rabbit_username*] +# Username for the message broker in this cell +# Optional +# +# [*rabbit_password*] +# Password for the message broker in this cell +# Optional +# +# [*rabbit_hosts*] +# Address of the message broker in this cell +# Optional +# +# [*rabbit_port*] +# Port number of the message broker in this cell +# Optional +# +# [*rabbit_virtual_host*] +# The virtual host of the message broker in this cell +# Optional +# +# [*weight_offset*] +# It might be used by some cell scheduling code in the future +# Optional +# +# [*weight_scale*] +# It might be used by some cell scheduling code in the future +# Optional +# + +Puppet::Type.newtype(:nova_cells) do + + @doc = "Manage creation/deletion of nova cells." + + ensurable + + newparam(:name) do + desc "Name for the new cell" + defaultto "api" + end + + newparam(:cell_type) do + desc 'Whether the cell is a parent or child' + end + + newparam(:rabbit_username) do + desc 'Username for the message broker in this cell' + defaultto "guest" + end + + newparam(:rabbit_password) do + desc 'Password for the message broker in this cell' + defaultto "guest" + end + + newparam(:rabbit_port) do + desc 'Port number for the message broker in this cell' + defaultto "5672" + end + + newparam(:rabbit_hosts) do + desc 'Address of the message broker in this cell' + defaultto "localhost" + end + + newparam(:rabbit_virtual_host) do + desc 'The virtual host of the message broker in this cell' + defaultto "/" + end + + newparam(:weight_offset) do + desc 'It might be used by some cell scheduling code in the future' + defaultto "1.0" + end + + newparam(:weight_scale) do + desc 'It might be used by some cell scheduling code in the future' + defaultto "1.0" + end + + + validate do + raise(Puppet::Error, 'Cell type must be set') unless self[:cell_type] + end + +end diff --git a/3rdparty/modules/nova/lib/puppet/type/nova_config.rb b/3rdparty/modules/nova/lib/puppet/type/nova_config.rb new file mode 100644 index 000000000..007546dee --- /dev/null +++ b/3rdparty/modules/nova/lib/puppet/type/nova_config.rb @@ -0,0 +1,42 @@ +Puppet::Type.newtype(:nova_config) do + + ensurable + + newparam(:name, :namevar => true) do + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + newvalues(/^[\S ]*$/) + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end +end diff --git a/3rdparty/modules/nova/lib/puppet/type/nova_floating.rb b/3rdparty/modules/nova/lib/puppet/type/nova_floating.rb new file mode 100644 index 000000000..6da29ecce --- /dev/null +++ b/3rdparty/modules/nova/lib/puppet/type/nova_floating.rb @@ -0,0 +1,18 @@ +Puppet::Type.newtype(:nova_floating) do + + @doc = "Manage creation/deletion of nova floating ip ranges. " + + ensurable + + newparam(:network, :namevar => true) do + desc "Network (ie, 192.168.1.0/24 or 192.168.1.128/25 etc.)" + newvalues(/^[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\/[0-9]{1,2}$/) + end + + newparam(:pool) do + desc "Floating IP pool name. Default: 'nova'" + defaultto :nova + newvalues(/^.{1,255}$/) + end + +end diff --git a/3rdparty/modules/nova/lib/puppet/type/nova_network.rb b/3rdparty/modules/nova/lib/puppet/type/nova_network.rb new file mode 100644 index 000000000..3a750e02e --- /dev/null +++ b/3rdparty/modules/nova/lib/puppet/type/nova_network.rb @@ -0,0 +1,51 @@ +Puppet::Type.newtype(:nova_network) do + + @doc = "Manage creation/deletion of nova networks. During creation, network + CIDR and netmask will be calculated automatically" + + ensurable + + # there are concerns about determining uniqiueness of network + # segments b/c it is actually the combination of network/prefix + # that determine uniqueness + newparam(:network, :namevar => true) do + desc "IPv4 Network (ie, 192.168.1.0/24)" + newvalues(/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(\d|[1-2]\d|3[0-2]))$/) + end + + newparam(:label) do + desc "The Nova network label" + defaultto "novanetwork" + end + + newparam(:num_networks) do + desc 'Number of networks to create' + defaultto(1) + end + + newparam(:bridge) do + desc 'bridge to use for flat network' + end + + newparam(:project) do + desc 'project that the network is associated with' + end + + newparam(:gateway) do + end + + newparam(:dns2) do + end + + newparam(:vlan_start) do + end + + newparam(:network_size) do + defaultto('256') + end + + validate do + raise(Puppet::Error, 'Label must be set') unless self[:label] + end + +end diff --git a/3rdparty/modules/nova/lib/puppet/type/nova_paste_api_ini.rb b/3rdparty/modules/nova/lib/puppet/type/nova_paste_api_ini.rb new file mode 100644 index 000000000..095fa210c --- /dev/null +++ b/3rdparty/modules/nova/lib/puppet/type/nova_paste_api_ini.rb @@ -0,0 +1,43 @@ +Puppet::Type.newtype(:nova_paste_api_ini) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from nova/paste-api.ini' + newvalues(/\S+\/\S+/) + end + + newproperty(:value) do + desc 'The value of the setting to be defined.' + munge do |value| + value = value.to_s.strip + value.capitalize! if value =~ /^(true|false)$/i + value + end + + def is_to_s( currentvalue ) + if resource.secret? + return '[old secret redacted]' + else + return currentvalue + end + end + + def should_to_s( newvalue ) + if resource.secret? + return '[new secret redacted]' + else + return newvalue + end + end + end + + newparam(:secret, :boolean => true) do + desc 'Whether to hide the value from Puppet logs. Defaults to `false`.' + + newvalues(:true, :false) + + defaultto false + end + +end diff --git a/3rdparty/modules/nova/lib/puppet/type/nova_project.rb b/3rdparty/modules/nova/lib/puppet/type/nova_project.rb new file mode 100644 index 000000000..f538d2e2c --- /dev/null +++ b/3rdparty/modules/nova/lib/puppet/type/nova_project.rb @@ -0,0 +1,21 @@ +Puppet::Type.newtype(:nova_project) do + + @doc = "Manage creation/deletion of nova projects." + + ensurable + + newparam(:name, :namevar => true) do + desc "The name of the project." + end + + newparam(:owner) do + desc "Owner of this project. *This is only set on project creation*" + end + + # newproperty(:owner) - this needs to be a property + + autorequire(:nova_admin) do + [self[:owner]] + end + +end diff --git a/3rdparty/modules/nova/manifests/api.pp b/3rdparty/modules/nova/manifests/api.pp new file mode 100644 index 000000000..76056b9c2 --- /dev/null +++ b/3rdparty/modules/nova/manifests/api.pp @@ -0,0 +1,361 @@ +# == Class: nova::api +# +# Setup and configure the Nova API endpoint +# +# === Parameters +# +# [*admin_password*] +# (required) The password to set for the nova admin user in keystone +# +# [*enabled*] +# (optional) Whether the nova api service will be run +# Defaults to false +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*ensure_package*] +# (optional) Whether the nova api package will be installed +# Defaults to 'present' +# +# [*auth_strategy*] +# (DEPRECATED) Does nothing and will be removed in Icehouse +# Defaults to false +# +# [*auth_host*] +# (optional) The IP of the server running keystone +# Defaults to '127.0.0.1' +# +# [*auth_port*] +# (optional) The port to use when authenticating against Keystone +# Defaults to 35357 +# +# [*auth_protocol*] +# (optional) The protocol to use when authenticating against Keystone +# Defaults to 'http' +# +# [*auth_uri*] +# (optional) The uri of a Keystone service to authenticate against +# Defaults to false +# +# [*auth_admin_prefix*] +# (optional) Prefix to prepend at the beginning of the keystone path +# Defaults to false +# +# [*auth_version*] +# (optional) API version of the admin Identity API endpoint +# for example, use 'v3.0' for the keystone version 3.0 api +# Defaults to false +# +# [*admin_tenant_name*] +# (optional) The name of the tenant to create in keystone for use by the nova services +# Defaults to 'services' +# +# [*admin_user*] +# (optional) The name of the user to create in keystone for use by the nova services +# Defaults to 'nova' +# +# [*api_bind_address*] +# (optional) IP address for nova-api server to listen +# Defaults to '0.0.0.0' +# +# [*metadata_listen*] +# (optional) IP address for metadata server to listen +# Defaults to '0.0.0.0' +# +# [*enabled_apis*] +# (optional) A comma separated list of apis to enable +# Defaults to 'ec2,osapi_compute,metadata' +# +# [*keystone_ec2_url*] +# (optional) The keystone url where nova should send requests for ec2tokens +# Defaults to false +# +# [*volume_api_class*] +# (optional) The name of the class that nova will use to access volumes. Cinder is the only option. +# Defaults to 'nova.volume.cinder.API' +# +# [*use_forwarded_for*] +# (optional) Treat X-Forwarded-For as the canonical remote address. Only +# enable this if you have a sanitizing proxy. +# Defaults to false +# +# [*osapi_compute_workers*] +# (optional) Number of workers for OpenStack API service +# Defaults to $::processorcount +# +# [*ec2_workers*] +# (optional) Number of workers for EC2 service +# Defaults to $::processorcount +# +# [*metadata_workers*] +# (optional) Number of workers for metadata service +# Defaults to $::processorcount +# +# [*conductor_workers*] +# (optional) DEPRECATED. Use workers parameter of nova::conductor +# Class instead. +# Defaults to undef +# +# [*sync_db*] +# (optional) Run nova-manage db sync on api nodes after installing the package. +# Defaults to true +# +# [*neutron_metadata_proxy_shared_secret*] +# (optional) Shared secret to validate proxies Neutron metadata requests +# Defaults to undef +# +# [*pci_alias*] +# (optional) Pci passthrough for controller: +# Defaults to undef +# Example +# "[ {'vendor_id':'1234', 'product_id':'5678', 'name':'default'}, {...} ]" +# +# [*ratelimits*] +# (optional) A string that is a semicolon-separated list of 5-tuples. +# See http://docs.openstack.org/trunk/config-reference/content/configuring-compute-API.html +# Example: '(POST, "*", .*, 10, MINUTE);(POST, "*/servers", ^/servers, 50, DAY);(PUT, "*", .*, 10, MINUTE)' +# Defaults to undef +# +# [*ratelimits_factory*] +# (optional) The rate limiting factory to use +# Defaults to 'nova.api.openstack.compute.limits:RateLimitingMiddleware.factory' +# +# [*osapi_v3*] +# (optional) Enable or not Nova API v3 +# Defaults to false +# +# [*validate*] +# (optional) Whether to validate the service is working after any service refreshes +# Defaults to false +# +# [*validation_options*] +# (optional) Service validation options +# Should be a hash of options defined in openstacklib::service_validation +# If empty, defaults values are taken from openstacklib function. +# Default command list nova flavors. +# Require validate set at True. +# Example: +# nova::api::validation_options: +# nova-api: +# command: check_nova.py +# path: /usr/bin:/bin:/usr/sbin:/sbin +# provider: shell +# tries: 5 +# try_sleep: 10 +# Defaults to {} +# +class nova::api( + $admin_password, + $enabled = false, + $manage_service = true, + $ensure_package = 'present', + $auth_strategy = undef, + $auth_host = '127.0.0.1', + $auth_port = 35357, + $auth_protocol = 'http', + $auth_uri = false, + $auth_admin_prefix = false, + $auth_version = false, + $admin_tenant_name = 'services', + $admin_user = 'nova', + $api_bind_address = '0.0.0.0', + $metadata_listen = '0.0.0.0', + $enabled_apis = 'ec2,osapi_compute,metadata', + $keystone_ec2_url = false, + $volume_api_class = 'nova.volume.cinder.API', + $use_forwarded_for = false, + $osapi_compute_workers = $::processorcount, + $ec2_workers = $::processorcount, + $metadata_workers = $::processorcount, + $sync_db = true, + $neutron_metadata_proxy_shared_secret = undef, + $osapi_v3 = false, + $pci_alias = undef, + $ratelimits = undef, + $ratelimits_factory = + 'nova.api.openstack.compute.limits:RateLimitingMiddleware.factory', + $validate = false, + $validation_options = {}, + # DEPRECATED PARAMETER + $workers = undef, + $conductor_workers = undef, +) { + + include nova::db + include nova::params + include nova::policy + require keystone::python + include cinder::client + + Package<| title == 'nova-api' |> -> Nova_paste_api_ini<| |> + + Package<| title == 'nova-common' |> -> Class['nova::api'] + Package<| title == 'nova-common' |> -> Class['nova::policy'] + + Nova_paste_api_ini<| |> ~> Exec['post-nova_config'] + + Nova_paste_api_ini<| |> ~> Service['nova-api'] + Class['nova::policy'] ~> Service['nova-api'] + + if $auth_strategy { + warning('The auth_strategy parameter is deprecated and has no effect.') + } + + if $workers { + warning('The workers parameter is deprecated, use osapi_compute_workers instead.') + $osapi_compute_workers_real = $workers + } else { + $osapi_compute_workers_real = $osapi_compute_workers + } + + if $conductor_workers { + warning('The conductor_workers parameter is deprecated and has no effect. Use workers parameter of nova::conductor class instead.') + } + + nova::generic_service { 'api': + enabled => $enabled, + manage_service => $manage_service, + ensure_package => $ensure_package, + package_name => $::nova::params::api_package_name, + service_name => $::nova::params::api_service_name, + subscribe => Class['cinder::client'], + } + + nova_config { + 'DEFAULT/enabled_apis': value => $enabled_apis; + 'DEFAULT/volume_api_class': value => $volume_api_class; + 'DEFAULT/ec2_listen': value => $api_bind_address; + 'DEFAULT/osapi_compute_listen': value => $api_bind_address; + 'DEFAULT/metadata_listen': value => $metadata_listen; + 'DEFAULT/osapi_volume_listen': value => $api_bind_address; + 'DEFAULT/osapi_compute_workers': value => $osapi_compute_workers_real; + 'DEFAULT/ec2_workers': value => $ec2_workers; + 'DEFAULT/metadata_workers': value => $metadata_workers; + 'DEFAULT/use_forwarded_for': value => $use_forwarded_for; + 'osapi_v3/enabled': value => $osapi_v3; + } + + if ($neutron_metadata_proxy_shared_secret){ + nova_config { + 'neutron/service_metadata_proxy': value => true; + 'neutron/metadata_proxy_shared_secret': + value => $neutron_metadata_proxy_shared_secret; + } + } else { + nova_config { + 'neutron/service_metadata_proxy': value => false; + 'neutron/metadata_proxy_shared_secret': ensure => absent; + } + } + + if $auth_uri { + $auth_uri_real = $auth_uri + } else { + $auth_uri_real = "${auth_protocol}://${auth_host}:5000/" + } + nova_config { 'keystone_authtoken/auth_uri': value => $auth_uri_real; } + + if $auth_version { + nova_config { 'keystone_authtoken/auth_version': value => $auth_version; } + } else { + nova_config { 'keystone_authtoken/auth_version': ensure => absent; } + } + + nova_config { + 'keystone_authtoken/auth_host': value => $auth_host; + 'keystone_authtoken/auth_port': value => $auth_port; + 'keystone_authtoken/auth_protocol': value => $auth_protocol; + 'keystone_authtoken/admin_tenant_name': value => $admin_tenant_name; + 'keystone_authtoken/admin_user': value => $admin_user; + 'keystone_authtoken/admin_password': value => $admin_password, secret => true; + } + + if $auth_admin_prefix { + validate_re($auth_admin_prefix, '^(/.+[^/])?$') + nova_config { + 'keystone_authtoken/auth_admin_prefix': value => $auth_admin_prefix; + } + } else { + nova_config { + 'keystone_authtoken/auth_admin_prefix': ensure => absent; + } + } + + if $keystone_ec2_url { + nova_config { + 'DEFAULT/keystone_ec2_url': value => $keystone_ec2_url; + } + } else { + nova_config { + 'DEFAULT/keystone_ec2_url': ensure => absent; + } + } + + if 'occiapi' in $enabled_apis { + if !defined(Package['python-pip']) { + package { 'python-pip': + ensure => latest, + } + } + if !defined(Package['pyssf']) { + package { 'pyssf': + ensure => latest, + provider => pip, + require => Package['python-pip'] + } + } + package { 'openstackocci': + ensure => latest, + provider => 'pip', + require => Package['python-pip'], + } + } + + if ($ratelimits != undef) { + nova_paste_api_ini { + 'filter:ratelimit/paste.filter_factory': value => $ratelimits_factory; + 'filter:ratelimit/limits': value => $ratelimits; + } + } + + # Added arg and if statement prevents this from being run + # where db is not active i.e. the compute + if $sync_db { + Package<| title == 'nova-api' |> -> Exec['nova-db-sync'] + exec { 'nova-db-sync': + command => '/usr/bin/nova-manage db sync', + refreshonly => true, + subscribe => Exec['post-nova_config'], + } + } + + # Remove auth configuration from api-paste.ini + nova_paste_api_ini { + 'filter:authtoken/auth_uri': ensure => absent; + 'filter:authtoken/auth_host': ensure => absent; + 'filter:authtoken/auth_port': ensure => absent; + 'filter:authtoken/auth_protocol': ensure => absent; + 'filter:authtoken/admin_tenant_name': ensure => absent; + 'filter:authtoken/admin_user': ensure => absent; + 'filter:authtoken/admin_password': ensure => absent; + 'filter:authtoken/auth_admin_prefix': ensure => absent; + } + + if $pci_alias { + nova_config { + 'DEFAULT/pci_alias': value => check_array_of_hash($pci_alias); + } + } + + if $validate { + $defaults = { + 'nova-api' => { + 'command' => "nova --os-auth-url ${auth_uri_real} --os-tenant-name ${admin_tenant_name} --os-username ${admin_user} --os-password ${admin_password} flavor-list", + } + } + $validation_options_hash = merge ($defaults, $validation_options) + create_resources('openstacklib::service_validation', $validation_options_hash, {'subscribe' => 'Service[nova-api]'}) + } +} diff --git a/3rdparty/modules/nova/manifests/cells.pp b/3rdparty/modules/nova/manifests/cells.pp new file mode 100644 index 000000000..da66c01d5 --- /dev/null +++ b/3rdparty/modules/nova/manifests/cells.pp @@ -0,0 +1,245 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# François Charlier +# +# 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. +# +# The nova::cells class installs the Nova Cells +# +# == Parameters +# [*enabled*] +# Use Nova Cells or not +# Defaults to 'False' +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*create_cells*] +# Create cells with nova-manage +# Defaults to 'True' +# +# [*driver*] +# Cells communication driver to use +# Defaults to 'nova.cells.rpc_driver.CellsRPCDriver' +# +# [*instance_updated_at_threshold*] +# Number of seconds after an instance was updated or deleted to continue to update cells +# Defaults to '3600' +# +# [*max_hop_count*] +# Maximum number of hops for cells routing +# Defaults to '10' +# +# [*scheduler*] +# Cells scheduler to use +# Defaults to 'nova.cells.scheduler.CellsScheduler' +# +# [*instance_update_num_instances*] +# Number of instances to update per periodic task run +# Defaults to '1' +# +# [*manager*] +# Number of instances to update per periodic task run +# Defaults to 'nova.cells.manager.CellsManager' +# +# [*cell_name*] +# name of this cell +# Defaults to 'nova' +# +# [*cell_parent_name*] +# * If a child cell, this is the name of the 'parent' cell. +# * If a parent cell, should be left to undef. +# +# [*capabilities*] +# Key/Multi-value list with the capabilities of the cell +# Defaults to 'hypervisor=xenserver;kvm,os=linux;windows' +# +# [*call_timeout*] +# Seconds to wait for response from a call to a cell +# Defaults to '60' +# +# [*reserve_percent*] +# Percentage of cell capacity to hold in reserve. Affects both memory and disk utilization +# Defaults to '10.0' +# +# [*cell_type*] +# Type of cell: parent or child +# Defaults to 'None' +# +# [*mute_child_interval*] +# Number of seconds after which a lack of capability and +# capacity updates signals the child cell is to be treated as a mute +# Defaults to '300' +# +# [*bandwidth_update_interval*] +# Seconds between bandwidth updates for cells +# Defaults to '600' +# +# [*rpc_driver_queue_base*] +# Base queue name to use when communicating between cells +# Various topics by message type will be appended to this +# Defaults to 'cells.intercell' +# +# [*scheduler_filter_classes*] +# Filter classes the cells scheduler should use +# Defaults to 'nova.cells.filters.all_filters' +# +# [*scheduler_weight_classes*] +# Weigher classes the cells scheduler should use +# Defaults to 'nova.cells.weights.all_weighers' +# +# [*scheduler_retries*] +# How many retries when no cells are available +# Defaults to '10' +# +# [*scheduler_retry_delay*] +# How often to retry in seconds when no cells are available +# Defaults to '2' +# +# [*db_check_interval*] +# Seconds between getting fresh cell info from db +# Defaults to '60' +# +# [*mute_weight_multiplier*] +# Multiplier used to weigh mute children (The value should be negative) +# Defaults to '-10.0' +# +# [*mute_weight_value*] +# Weight value assigned to mute children (The value should be positive) +# Defaults to '1000.0' +# +# [*ram_weight_multiplier*] +# Multiplier used for weighing ram. Negative numbers mean to stack vs spread +# Defaults to '10.0' +# +# [*weight_offset*] +# It might be used by some cell scheduling code in the future +# Defaults to '1.0' +# +# [*weight_scale*] +# It might be used by some cell scheduling code in the future +# Defaults to '1.0' +# + +class nova::cells ( + $bandwidth_update_interval = '600', + $call_timeout = '60', + $capabilities = ['hypervisor=xenserver;kvm','os=linux;windows'], + $cell_name = 'nova', + $cell_type = undef, + $cell_parent_name = undef, + $create_cells = true, + $db_check_interval = '60', + $driver = 'nova.cells.rpc_driver.CellsRPCDriver', + $enabled = false, + $ensure_package = 'present', + $instance_updated_at_threshold = '3600', + $instance_update_num_instances = '1', + $manage_service = true, + $manager = 'nova.cells.manager.CellsManager', + $max_hop_count = '10', + $mute_child_interval = '300', + $mute_weight_multiplier = '-10.0', + $mute_weight_value = '1000.0', + $ram_weight_multiplier = '10.0', + $reserve_percent = '10.0', + $rpc_driver_queue_base = 'cells.intercell', + $scheduler_filter_classes = 'nova.cells.filters.all_filters', + $scheduler = 'nova.cells.scheduler.CellsScheduler', + $scheduler_retries = '10', + $scheduler_retry_delay = '2', + $scheduler_weight_classes = 'nova.cells.weights.all_weighers', + $weight_offset = '1.0', + $weight_scale = '1.0' +) { + + include nova::params + + case $cell_type { + 'parent': { + nova_config { 'DEFAULT/compute_api_class': value => 'nova.compute.cells_api.ComputeCellsAPI' } + nova_config { 'cells/cell_type': value => 'api' } + } + 'child': { + nova_config { 'DEFAULT/quota_driver': value => 'nova.quota.NoopQuotaDriver' } + nova_config { 'cells/cell_type': value => 'compute' } + } + default: { fail("Unsupported cell_type parameter value: '${cell_type}'. Should be 'parent' or 'child'.") } + } + + nova_config { + 'cells/bandwidth_update_interval': value => $bandwidth_update_interval; + 'cells/call_timeout': value => $call_timeout; + 'cells/capabilities': value => join($capabilities, ','); + 'cells/db_check_interval': value => $db_check_interval; + 'cells/driver': value => $driver; + 'cells/enable': value => $enabled; + 'cells/instance_updated_at_threshold': value => $instance_updated_at_threshold; + 'cells/instance_update_num_instances': value => $instance_update_num_instances; + 'cells/manager': value => $manager; + 'cells/max_hop_count': value => $max_hop_count; + 'cells/mute_child_interval': value => $mute_child_interval; + 'cells/mute_weight_multiplier': value => $mute_weight_multiplier; + 'cells/mute_weight_value': value => $mute_weight_value; + 'cells/name': value => $cell_name; + 'cells/ram_weight_multiplier': value => $ram_weight_multiplier; + 'cells/reserve_percent': value => $reserve_percent; + 'cells/rpc_driver_queue_base': value => $rpc_driver_queue_base; + 'cells/scheduler_filter_classes': value => $scheduler_filter_classes; + 'cells/scheduler_retries': value => $scheduler_retries; + 'cells/scheduler_retry_delay': value => $scheduler_retry_delay; + 'cells/scheduler': value => $scheduler; + 'cells/scheduler_weight_classes': value => $scheduler_weight_classes; + } + + nova::generic_service { 'cells': + enabled => $enabled, + manage_service => $manage_service, + package_name => $::nova::params::cells_package_name, + service_name => $::nova::params::cells_service_name, + ensure_package => $ensure_package, + } + + if $create_cells { + @@nova::manage::cells { $cell_name: + cell_type => $cell_type, + cell_parent_name => $cell_parent_name, + rabbit_username => $::nova::rabbit_userid, + rabbit_password => $::nova::rabbit_password, + rabbit_hosts => $::nova::rabbit_hosts, + rabbit_port => $::nova::rabbit_port, + rabbit_virtual_host => $::nova::rabbit_virtual_host, + weight_offset => $weight_offset, + weight_scale => $weight_scale, + before => Service['cells'] + } + + case $cell_type { + 'parent': { + # A parent cell must declare its child cell(s) + Nova::Manage::Cells <<| cell_parent_name == $cell_parent_name and cell_type == 'child' |>> + } + 'child': { + # A child cell must declare its parent cell + Nova::Manage::Cells <<| name == $cell_parent_name and cell_type == 'parent' |>> + } + default: { + fail("Invalid cell_type parameter value: ${cell_type}") + } + } + } + +} diff --git a/3rdparty/modules/nova/manifests/cert.pp b/3rdparty/modules/nova/manifests/cert.pp new file mode 100644 index 000000000..4e276a167 --- /dev/null +++ b/3rdparty/modules/nova/manifests/cert.pp @@ -0,0 +1,35 @@ +# == Class: nova::cert +# +# Installs nova cert package and service +# +# === Parameters: +# +# [*enabled*] +# (optional) Whether or not to enable the nova cert service +# Defaults to false +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*ensure_package*] +# (optional) The state to set for the nova-cert package +# Defaults to 'present' +# +class nova::cert( + $enabled = false, + $manage_service = true, + $ensure_package = 'present' +) { + + include nova::params + + nova::generic_service { 'cert': + enabled => $enabled, + manage_service => $manage_service, + package_name => $::nova::params::cert_package_name, + service_name => $::nova::params::cert_service_name, + ensure_package => $ensure_package, + } + +} diff --git a/3rdparty/modules/nova/manifests/client.pp b/3rdparty/modules/nova/manifests/client.pp new file mode 100644 index 000000000..35748c095 --- /dev/null +++ b/3rdparty/modules/nova/manifests/client.pp @@ -0,0 +1,20 @@ +# == Class nova::client +# +# installs nova client +# +# === Parameters: +# +# [*ensure*] +# (optional) The state for the nova client package +# Defaults to 'present' +# +class nova::client( + $ensure = 'present' +) { + + package { 'python-novaclient': + ensure => $ensure, + tag => ['openstack', 'nova'], + } + +} diff --git a/3rdparty/modules/nova/manifests/compute.pp b/3rdparty/modules/nova/manifests/compute.pp new file mode 100644 index 000000000..4afe43ec7 --- /dev/null +++ b/3rdparty/modules/nova/manifests/compute.pp @@ -0,0 +1,222 @@ +# == Class: nova::compute +# +# Installs the nova-compute service +# +# === Parameters: +# +# [*enabled*] +# (optional) Whether to enable the nova-compute service +# Defaults to false +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*ensure_package*] +# (optional) The state for the nova-compute package +# Defaults to 'present' +# +# [*vnc_enabled*] +# (optional) Whether to use a VNC proxy +# Defaults to true +# +# [*vncserver_proxyclient_address*] +# (optional) The IP address of the server running the VNC proxy client +# Defaults to '127.0.0.1' +# +# [*vncproxy_host*] +# (optional) The host of the VNC proxy server +# Defaults to false +# +# [*vncproxy_protocol*] +# (optional) The protocol to communicate with the VNC proxy server +# Defaults to 'http' +# +# [*vncproxy_port*] +# (optional) The port to communicate with the VNC proxy server +# Defaults to '6080' +# +# [*vncproxy_path*] +# (optional) The path at the end of the uri for communication with the VNC proxy server +# Defaults to '/vnc_auto.html' +# +# [*vnc_keymap*] +# (optional) The keymap to use with VNC (ls -alh /usr/share/qemu/keymaps to list available keymaps) +# Defaults to 'en-us' +# +# [*force_config_drive*] +# (optional) Whether to force the config drive to be attached to all VMs +# Defaults to false +# +# [*virtio_nic*] +# (optional) Whether to use virtio for the nic driver of VMs +# Defaults to false +# +# [*neutron_enabled*] +# (optional) Whether to use Neutron for networking of VMs +# Defaults to true +# +# [*network_device_mtu*] +# (optional) The MTU size for the interfaces managed by nova +# Defaults to undef +# +# [*instance_usage_audit*] +# (optional) Generate periodic compute.instance.exists notifications. +# Defaults to false +# +# [*instance_usage_audit_period*] +# (optional) Time period to generate instance usages for. +# Time period must be hour, day, month or year +# Defaults to 'month' +# +# [*force_raw_images*] +# (optional) Force backing images to raw format. +# Defaults to true +# +# [*reserved_host_memory*] +# Reserved host memory +# The amount of memory in MB reserved for the host. +# Defaults to '512' +# +# [*compute_manager*] +# Compute manager +# The driver that will manage the running instances. +# Defaults to nova.compute.manager.ComputeManager +# +# [*pci_passthrough_whitelist*] +# (optional) Pci passthrough hash in format of: +# Defaults to undef +# Example +# "[ { 'vendor_id':'1234','product_id':'5678' }, +# { 'vendor_id':'4321','product_id':'8765','physical_network':'default' } ] " +# +# [*default_availability_zone*] +# (optional) Default compute node availability zone. +# Defaults to nova +# +# [*default_schedule_zone*] +# (optional) Availability zone to use when user doesn't specify one. +# Defaults to undef +# +# [*internal_service_availability_zone*] +# (optional) The availability zone to show internal services under. +# Defaults to internal +# +class nova::compute ( + $enabled = false, + $manage_service = true, + $ensure_package = 'present', + $vnc_enabled = true, + $vncserver_proxyclient_address = '127.0.0.1', + $vncproxy_host = false, + $vncproxy_protocol = 'http', + $vncproxy_port = '6080', + $vncproxy_path = '/vnc_auto.html', + $vnc_keymap = 'en-us', + $force_config_drive = false, + $virtio_nic = false, + $neutron_enabled = true, + $network_device_mtu = undef, + $instance_usage_audit = false, + $instance_usage_audit_period = 'month', + $force_raw_images = true, + $reserved_host_memory = '512', + $compute_manager = 'nova.compute.manager.ComputeManager', + $pci_passthrough = undef, + $default_availability_zone = 'nova', + $default_schedule_zone = undef, + $internal_service_availability_zone = 'internal', +) { + + include nova::params + + nova_config { + 'DEFAULT/reserved_host_memory_mb': value => $reserved_host_memory; + 'DEFAULT/compute_manager': value => $compute_manager; + } + + if ($vnc_enabled) { + include ::nova::vncproxy::common + } + + nova_config { + 'DEFAULT/vnc_enabled': value => $vnc_enabled; + 'DEFAULT/vncserver_proxyclient_address': value => $vncserver_proxyclient_address; + 'DEFAULT/vnc_keymap': value => $vnc_keymap; + } + + if $neutron_enabled != true { + # Install bridge-utils if we use nova-network + package { 'bridge-utils': + ensure => present, + before => Nova::Generic_service['compute'], + } + } + + nova::generic_service { 'compute': + enabled => $enabled, + manage_service => $manage_service, + package_name => $::nova::params::compute_package_name, + service_name => $::nova::params::compute_service_name, + ensure_package => $ensure_package, + before => Exec['networking-refresh'] + } + + if $force_config_drive { + nova_config { 'DEFAULT/force_config_drive': value => true } + } else { + nova_config { 'DEFAULT/force_config_drive': ensure => absent } + } + + if $virtio_nic { + # Enable the virtio network card for instances + nova_config { 'DEFAULT/libvirt_use_virtio_for_bridges': value => true } + } + + if $network_device_mtu { + nova_config { + 'DEFAULT/network_device_mtu': value => $network_device_mtu; + } + } else { + nova_config { + 'DEFAULT/network_device_mtu': ensure => absent; + } + } + + if $instance_usage_audit and $instance_usage_audit_period in ['hour', 'day', 'month', 'year'] { + nova_config { + 'DEFAULT/instance_usage_audit': value => $instance_usage_audit; + 'DEFAULT/instance_usage_audit_period': value => $instance_usage_audit_period; + } + } else { + nova_config { + 'DEFAULT/instance_usage_audit': ensure => absent; + 'DEFAULT/instance_usage_audit_period': ensure => absent; + } + } + + package { 'pm-utils': + ensure => present, + } + + nova_config { + 'DEFAULT/force_raw_images': value => $force_raw_images; + } + + if ($pci_passthrough) { + nova_config { + 'DEFAULT/pci_passthrough_whitelist': value => check_array_of_hash($pci_passthrough); + } + } + + nova_config { + 'DEFAULT/default_availability_zone': value => $default_availability_zone; + 'DEFAULT/internal_service_availability_zone': value => $internal_service_availability_zone; + } + + if $default_schedule_zone { + nova_config { + 'DEFAULT/default_schedule_zone': value => $default_schedule_zone; + } + } +} diff --git a/3rdparty/modules/nova/manifests/compute/ironic.pp b/3rdparty/modules/nova/manifests/compute/ironic.pp new file mode 100644 index 000000000..2924a029f --- /dev/null +++ b/3rdparty/modules/nova/manifests/compute/ironic.pp @@ -0,0 +1,49 @@ +# == Class: nova::compute::ironic +# +# Configures Nova compute service to use Ironic. +# +# === Parameters: +# +# [*admin_user*] +# Admin username +# The admin username for Ironic to connect to Nova. +# Defaults to 'admin' +# +# [*admin_passwd*] +# Admin password +# The admin password for Ironic to connect to Nova. +# Defaults to 'ironic' +# +# [*admin_url*] +# Admin url +# The address of the Keystone api endpoint. +# Defaults to 'http://127.0.0.1:35357/v2.0' +# +# [*admin_tenant_name*] +# Admin tenant name +# The Ironic Keystone tenant name. +# Defaults to 'services' +# +# [*api_endpoint*] +# Api endpoint +# The url for Ironic api endpoint. +# Defaults to 'http://127.0.0.1:6385/v1' +# + +class nova::compute::ironic ( + $admin_user = 'admin', + $admin_passwd = 'ironic', + $admin_url = 'http://127.0.0.1:35357/v2.0', + $admin_tenant_name = 'services', + $api_endpoint = 'http://127.0.0.1:6385/v1', +) { + + nova_config { + 'ironic/admin_username': value => $admin_user; + 'ironic/admin_password': value => $admin_passwd; + 'ironic/admin_url': value => $admin_url; + 'ironic/admin_tenant_name': value => $admin_tenant_name; + 'ironic/api_endpoint': value => $api_endpoint; + 'DEFAULT/compute_driver': value => 'nova.virt.ironic.IronicDriver'; + } +} diff --git a/3rdparty/modules/nova/manifests/compute/libvirt.pp b/3rdparty/modules/nova/manifests/compute/libvirt.pp new file mode 100644 index 000000000..7d37c6f9d --- /dev/null +++ b/3rdparty/modules/nova/manifests/compute/libvirt.pp @@ -0,0 +1,224 @@ +# == Class: nova::compute::libvirt +# +# Install and manage nova-compute guests managed +# by libvirt +# +# === Parameters: +# +# [*libvirt_virt_type*] +# (optional) Libvirt domain type. Options are: kvm, lxc, qemu, uml, xen +# Replaces libvirt_type +# Defaults to 'kvm' +# +# [*vncserver_listen*] +# (optional) IP address on which instance vncservers should listen +# Defaults to '127.0.0.1' +# +# [*migration_support*] +# (optional) Whether to support virtual machine migration +# Defaults to false +# +# [*libvirt_cpu_mode*] +# (optional) The libvirt CPU mode to configure. Possible values +# include custom, host-model, none, host-passthrough. +# Defaults to 'host-model' if libvirt_virt_type is set to either +# kvm or qemu, otherwise defaults to 'none'. +# +# [*libvirt_disk_cachemodes*] +# (optional) A list of cachemodes for different disk types, e.g. +# ["file=directsync", "block=none"] +# If an empty list is specified, the disk_cachemodes directive +# will be removed from nova.conf completely. +# Defaults to an empty list +# +# [*libvirt_inject_password*] +# (optional) Inject the admin password at boot time, without an agent. +# Defaults to false +# +# [*libvirt_inject_key*] +# (optional) Inject the ssh public key at boot time. +# Defaults to false +# +# [*libvirt_inject_partition*] +# (optional) The partition to inject to : -2 => disable, -1 => inspect +# (libguestfs only), 0 => not partitioned, >0 => partition +# number (integer value) +# Defaults to -2 +# +# [*remove_unused_base_images*] +# (optional) Should unused base images be removed? +# If undef is specified, remove the line in nova.conf +# otherwise, use a boolean to remove or not the base images. +# Defaults to undef +# +# [*remove_unused_kernels*] +# (optional) Should unused kernel images be removed? +# This is only safe to enable if all compute nodes +# have been updated to support this option. +# If undef is specified, remove the line in nova.conf +# otherwise, use a boolean to remove or not the kernels. +# Defaults to undef +# +# [*remove_unused_resized_minimum_age_seconds*] +# (optional) Unused resized base images younger +# than this will not be removed +# If undef is specified, remove the line in nova.conf +# otherwise, use a integer or a string to define after +# how many seconds it will be removed. +# Defaults to undef +# +# [*remove_unused_original_minimum_age_seconds*] +# (optional) Unused unresized base images younger +# than this will not be removed +# If undef is specified, remove the line in nova.conf +# otherwise, use a integer or a string to define after +# how many seconds it will be removed. +# Defaults to undef +# +# [*libvirt_service_name*] +# (optional) libvirt service name. +# Defaults to $::nova::params::libvirt_service_name +# +class nova::compute::libvirt ( + $libvirt_virt_type = 'kvm', + $vncserver_listen = '127.0.0.1', + $migration_support = false, + $libvirt_cpu_mode = false, + $libvirt_disk_cachemodes = [], + $libvirt_inject_password = false, + $libvirt_inject_key = false, + $libvirt_inject_partition = -2, + $remove_unused_base_images = undef, + $remove_unused_kernels = undef, + $remove_unused_resized_minimum_age_seconds = undef, + $remove_unused_original_minimum_age_seconds = undef, + $libvirt_service_name = $::nova::params::libvirt_service_name, + # DEPRECATED PARAMETER + $libvirt_type = false +) inherits nova::params { + + include nova::params + + Service['libvirt'] -> Service['nova-compute'] + + if $libvirt_type { + warning ('The libvirt_type parameter is deprecated, use libvirt_virt_type instead.') + $libvirt_virt_type_real = $libvirt_type + } else { + $libvirt_virt_type_real = $libvirt_virt_type + } + + # libvirt_cpu_mode has different defaults depending on hypervisor. + if !$libvirt_cpu_mode { + case $libvirt_virt_type_real { + 'kvm','qemu': { + $libvirt_cpu_mode_real = 'host-model' + } + default: { + $libvirt_cpu_mode_real = 'none' + } + } + } else { + $libvirt_cpu_mode_real = $libvirt_cpu_mode + } + + if($::osfamily == 'Debian') { + package { "nova-compute-${libvirt_virt_type_real}": + ensure => present, + before => Package['nova-compute'], + require => Package['nova-common'], + tag => ['openstack', 'nova'], + } + } + + if($::osfamily == 'RedHat' and $::operatingsystem != 'Fedora') { + service { 'messagebus': + ensure => running, + enable => true, + provider => $::nova::params::special_service_provider, + } + Package['libvirt'] -> Service['messagebus'] -> Service['libvirt'] + + } + + if $migration_support { + if $vncserver_listen != '0.0.0.0' and $vncserver_listen != '::0' { + fail('For migration support to work, you MUST set vncserver_listen to \'0.0.0.0\' or \'::0\'') + } else { + class { 'nova::migration::libvirt': } + } + } + + package { 'libvirt': + ensure => present, + name => $::nova::params::libvirt_package_name, + } + + service { 'libvirt' : + ensure => running, + enable => true, + name => $libvirt_service_name, + provider => $::nova::params::special_service_provider, + require => Package['libvirt'], + } + + nova_config { + 'DEFAULT/compute_driver': value => 'libvirt.LibvirtDriver'; + 'DEFAULT/vncserver_listen': value => $vncserver_listen; + 'libvirt/virt_type': value => $libvirt_virt_type_real; + 'libvirt/cpu_mode': value => $libvirt_cpu_mode_real; + 'libvirt/inject_password': value => $libvirt_inject_password; + 'libvirt/inject_key': value => $libvirt_inject_key; + 'libvirt/inject_partition': value => $libvirt_inject_partition; + } + + if size($libvirt_disk_cachemodes) > 0 { + nova_config { + 'libvirt/disk_cachemodes': value => join($libvirt_disk_cachemodes, ','); + } + } else { + nova_config { + 'libvirt/disk_cachemodes': ensure => absent; + } + } + + if $remove_unused_kernels != undef { + nova_config { + 'libvirt/remove_unused_kernels': value => $remove_unused_kernels; + } + } else { + nova_config { + 'libvirt/remove_unused_kernels': ensure => absent; + } + } + + if $remove_unused_resized_minimum_age_seconds != undef { + nova_config { + 'libvirt/remove_unused_resized_minimum_age_seconds': value => $remove_unused_resized_minimum_age_seconds; + } + } else { + nova_config { + 'libvirt/remove_unused_resized_minimum_age_seconds': ensure => absent; + } + } + + if $remove_unused_base_images != undef { + nova_config { + 'DEFAULT/remove_unused_base_images': value => $remove_unused_base_images; + } + } else { + nova_config { + 'DEFAULT/remove_unused_base_images': ensure => absent; + } + } + + if $remove_unused_original_minimum_age_seconds != undef { + nova_config { + 'DEFAULT/remove_unused_original_minimum_age_seconds': value => $remove_unused_original_minimum_age_seconds; + } + } else { + nova_config { + 'DEFAULT/remove_unused_original_minimum_age_seconds': ensure => absent; + } + } +} diff --git a/3rdparty/modules/nova/manifests/compute/neutron.pp b/3rdparty/modules/nova/manifests/compute/neutron.pp new file mode 100644 index 000000000..91ee91cfc --- /dev/null +++ b/3rdparty/modules/nova/manifests/compute/neutron.pp @@ -0,0 +1,47 @@ +# == Class: nova::compute::neutron +# +# Manage the network driver to use for compute guests +# This will use virtio for VM guests and the +# specified driver for the VIF +# +# === Parameters +# +# [*libvirt_vif_driver*] +# (optional) The libvirt VIF driver to configure the VIFs. +# Defaults to 'nova.virt.libvirt.vif.LibvirtGenericVIFDriver'. +# +# [*force_snat_range*] +# (optional) Force SNAT rule to specified network for nova-network +# Default to 0.0.0.0/0 +# Due to architecture constraints in nova_config, it's not possible to setup +# more than one SNAT rule though initial parameter is MultiStrOpt +class nova::compute::neutron ( + $libvirt_vif_driver = 'nova.virt.libvirt.vif.LibvirtGenericVIFDriver', + $force_snat_range = '0.0.0.0/0', +) { + + if $libvirt_vif_driver == 'nova.virt.libvirt.vif.LibvirtOpenVswitchDriver' { + fail('nova.virt.libvirt.vif.LibvirtOpenVswitchDriver as vif_driver is removed from Icehouse') + } + + nova_config { + 'libvirt/vif_driver': value => $libvirt_vif_driver; + } + + if $libvirt_vif_driver == 'nova.virt.libvirt.vif.LibvirtGenericVIFDriver' and $force_snat_range { + # Validate ip and mask for force_snat_range + $force_snat_range_array = split($force_snat_range, '/') + if is_ip_address($force_snat_range_array[0]) and is_integer($force_snat_range_array[1]) { + nova_config { + 'DEFAULT/force_snat_range': value => $force_snat_range; + } + } else { + fail('force_snat_range should be IPv4 or IPv6 CIDR notation') + } + } else { + nova_config { + 'DEFAULT/force_snat_range': ensure => absent; + } + } + +} diff --git a/3rdparty/modules/nova/manifests/compute/rbd.pp b/3rdparty/modules/nova/manifests/compute/rbd.pp new file mode 100644 index 000000000..9bb0dceaf --- /dev/null +++ b/3rdparty/modules/nova/manifests/compute/rbd.pp @@ -0,0 +1,99 @@ +# +# Copyright (C) 2014 OpenStack Fondation +# +# Author: Emilien Macchi +# Donald Talton +# +# 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: nova::compute::rbd +# +# Configure nova-compute to store virtual machines on RBD +# +# === Parameters +# +# [*libvirt_images_rbd_pool*] +# (optional) The RADOS pool in which rbd volumes are stored. +# Defaults to 'rbd'. +# +# [*libvirt_images_rbd_ceph_conf*] +# (optional) The path to the ceph configuration file to use. +# Defaults to '/etc/ceph/ceph.conf'. +# +# [*libvirt_rbd_user*] +# (Required) The RADOS client name for accessing rbd volumes. +# +# [*libvirt_rbd_secret_uuid*] +# (optional) The libvirt uuid of the secret for the rbd_user. +# Required to use cephx. +# Default to false. +# +# [*libvirt_rbd_secret_key*] +# (optional) The cephx key to use as key for the libvirt secret, +# it must be base64 encoded; when not provided this key will be +# requested to the ceph cluster, which assumes the node is +# provided of the client.admin keyring as well. +# Default to undef. +# +# [*rbd_keyring*] +# (optional) The keyring name to use when retrieving the RBD secret +# Default to 'client.nova' +# + +class nova::compute::rbd ( + $libvirt_rbd_user, + $libvirt_rbd_secret_uuid = false, + $libvirt_rbd_secret_key = undef, + $libvirt_images_rbd_pool = 'rbd', + $libvirt_images_rbd_ceph_conf = '/etc/ceph/ceph.conf', + $rbd_keyring = 'client.nova', +) { + + include nova::params + + nova_config { + 'libvirt/images_type': value => 'rbd'; + 'libvirt/images_rbd_pool': value => $libvirt_images_rbd_pool; + 'libvirt/images_rbd_ceph_conf': value => $libvirt_images_rbd_ceph_conf; + 'libvirt/rbd_user': value => $libvirt_rbd_user; + } + + if $libvirt_rbd_secret_uuid { + nova_config { + 'libvirt/rbd_secret_uuid': value => $libvirt_rbd_secret_uuid; + } + + file { '/etc/nova/secret.xml': + content => template('nova/secret.xml-compute.erb') + } + + exec { 'get-or-set virsh secret': + command => '/usr/bin/virsh secret-define --file /etc/nova/secret.xml | /usr/bin/awk \'{print $2}\' | sed \'/^$/d\' > /etc/nova/virsh.secret', + creates => '/etc/nova/virsh.secret', + require => File['/etc/nova/secret.xml'] + } + + if $libvirt_rbd_secret_key { + $libvirt_key = $libvirt_rbd_secret_key + } else { + $libvirt_key = "$(ceph auth get-key ${rbd_keyring})" + } + exec { 'set-secret-value virsh': + command => "/usr/bin/virsh secret-set-value --secret ${libvirt_rbd_secret_uuid} --base64 ${libvirt_key}", + unless => "/usr/bin/virsh secret-get-value ${libvirt_rbd_secret_uuid}", + require => Exec['get-or-set virsh secret'] + } + + } + +} diff --git a/3rdparty/modules/nova/manifests/compute/serial.pp b/3rdparty/modules/nova/manifests/compute/serial.pp new file mode 100644 index 000000000..00173e230 --- /dev/null +++ b/3rdparty/modules/nova/manifests/compute/serial.pp @@ -0,0 +1,40 @@ +# == Class: nova::compute::serial +# +# Configures nova serial console +# +# === Parameters: +# +# [*port_range] +# (optional) Range of TCP ports to use for serial ports on compute hosts +# Defaults to 10000:20000 +# +# [*base_url*] +# (optional) URL that gets passed to the clients +# Defaults to 'ws://127.0.0.1:6083/' +# +# [*listen] +# IP address on which instance serial console should listen +# Defaults to 127.0.0.1 +# +# [*proxyclient_address*] +# The address to which proxy clients (like nova-serialproxy) +# should connect (string value) +# Defaults to 127.0.0.1 + + +class nova::compute::serial( + $port_range = '10000:20000', + $base_url = 'ws://127.0.0.1:6083/', + $listen = '127.0.0.1', + $proxyclient_address = '127.0.0.1', +) { + + + nova_config { + 'serial_console/enabled': value => true; + 'serial_console/port_range': value => $port_range; + 'serial_console/base_url': value => $base_url; + 'serial_console/listen': value => $listen; + 'serial_console/proxyclient_address': value => $proxyclient_address; + } +} diff --git a/3rdparty/modules/nova/manifests/compute/spice.pp b/3rdparty/modules/nova/manifests/compute/spice.pp new file mode 100644 index 000000000..b6cf09f0e --- /dev/null +++ b/3rdparty/modules/nova/manifests/compute/spice.pp @@ -0,0 +1,65 @@ +# == Class: nova::compute::spice +# +# Configure spice on the compute side +# +# === Parameters: +# +# [*agent_enabled*] +# (optional) enable spice guest agent support +# Defaults to true +# +# [*server_listen*] +# (optional) IP address on which instance spice servers should listen +# Defaults to undef +# +# [*server_proxyclient_address*] +# (optional) Management IP Address on which instance spiceservers will +# listen on the compute host. +# Defaults to '127.0.0.1' +# +# [*keymap*] +# (optional) keymap for spice +# Defaults to 'en-us' +# +# [*proxy_host*] +# (optional) Host for the html5 console proxy +# Defaults to false +# +# [*proxy_port*] +# (optional) Port for the html5 console proxy +# Defaults to '6082' +# +# [*proxy_protocol*] +# (optional) Protocol for the html5 console proxy +# Defaults to 'http' +# +# [*proxy_path*] +# (optional) Path of the spice html file for the html5 console proxy +# Defaults to '/spice_auto.html' +# +class nova::compute::spice( + $agent_enabled = true, + $server_listen = undef, + $server_proxyclient_address = '127.0.0.1', + $keymap = 'en-us', + $proxy_host = false, + $proxy_protocol = 'http', + $proxy_port = '6082', + $proxy_path = '/spice_auto.html' +) { + + if $proxy_host { + $html5proxy_base_url = "${proxy_protocol}://${proxy_host}:${proxy_port}${proxy_path}" + nova_config { + 'spice/html5proxy_base_url': value => $html5proxy_base_url; + } + } + + nova_config { + 'spice/enabled': value => true; + 'spice/agent_enabled': value => $agent_enabled; + 'spice/server_listen': value => $server_listen; + 'spice/server_proxyclient_address': value => $server_proxyclient_address; + 'spice/keymap': value => $keymap; + } +} diff --git a/3rdparty/modules/nova/manifests/compute/vmware.pp b/3rdparty/modules/nova/manifests/compute/vmware.pp new file mode 100644 index 000000000..5432e5bcf --- /dev/null +++ b/3rdparty/modules/nova/manifests/compute/vmware.pp @@ -0,0 +1,80 @@ +# +# Configure the VMware compute driver for nova. +# +# === Parameters +# +# [*host_ip*] +# The IP address of the VMware vCenter server. +# +# [*host_username*] +# The username for connection to VMware vCenter server. +# +# [*host_password*] +# The password for connection to VMware vCenter server. +# +# [*cluster_name*] +# The name of a vCenter cluster compute resource. +# +# [*api_retry_count*] +# (optional) The number of times we retry on failures, +# e.g., socket error, etc. +# Defaults to 5. +# +# [*maximum_objects*] +# (optional) The maximum number of ObjectContent data objects that should +# be returned in a single result. A positive value will cause +# the operation to suspend the retrieval when the count of +# objects reaches the specified maximum. The server may still +# limit the count to something less than the configured value. +# Any remaining objects may be retrieved with additional requests. +# Defaults to 100. +# +# [*task_poll_interval*] +# (optional) The interval in seconds used for polling of remote tasks. +# Defaults to 5.0 +# +# [*use_linked_clone*] +# (optional) Whether to use linked clone strategy while creating VM's. +# Defaults to true. +# +# [*wsdl_location*] +# (optional) VIM Service WSDL Location e.g +# http:///vimService.wsdl. Optional over-ride to +# default location for bug work-arounds. +# Defaults to None. +# + +class nova::compute::vmware( + $host_ip, + $host_username, + $host_password, + $cluster_name, + $api_retry_count=5, + $maximum_objects=100, + $task_poll_interval=5.0, + $use_linked_clone=true, + $wsdl_location=undef +) { + + nova_config { + 'DEFAULT/compute_driver': value => 'vmwareapi.VMwareVCDriver'; + 'VMWARE/host_ip': value => $host_ip; + 'VMWARE/host_username': value => $host_username; + 'VMWARE/host_password': value => $host_password; + 'VMWARE/cluster_name': value => $cluster_name; + 'VMWARE/api_retry_count' : value => $api_retry_count; + 'VMWARE/maximum_objects' : value => $maximum_objects; + 'VMWARE/task_poll_interval' : value => $task_poll_interval; + 'VMWARE/use_linked_clone': value => $use_linked_clone; + } + + if $wsdl_location { + nova_config { + 'VMWARE/wsdl_location' : value => $wsdl_location; + } + } + + package { 'python-suds': + ensure => present + } +} diff --git a/3rdparty/modules/nova/manifests/compute/xenserver.pp b/3rdparty/modules/nova/manifests/compute/xenserver.pp new file mode 100644 index 000000000..f28c0b486 --- /dev/null +++ b/3rdparty/modules/nova/manifests/compute/xenserver.pp @@ -0,0 +1,44 @@ +# == Class: nova::compute::xenserver +# +# Configures nova-compute to manage xen guests +# +# === Parameters: +# +# [*xenapi_connection_url*] +# (required) URL for connection to XenServer/Xen Cloud Platform. +# +# [*xenapi_connection_username*] +# (required) Username for connection to XenServer/Xen Cloud Platform +# +# [*xenapi_connection_password*] +# (required) Password for connection to XenServer/Xen Cloud Platform +# +# [*xenapi_inject_image*] +# (optional) This parameter was removed in Diablo and does nothing. +# Defaults to false +# +class nova::compute::xenserver( + $xenapi_connection_url, + $xenapi_connection_username, + $xenapi_connection_password, + $xenapi_inject_image=false +) { + + nova_config { + 'DEFAULT/compute_driver': value => 'xenapi.XenAPIDriver'; + 'DEFAULT/connection_type': value => 'xenapi'; + 'DEFAULT/xenapi_connection_url': value => $xenapi_connection_url; + 'DEFAULT/xenapi_connection_username': value => $xenapi_connection_username; + 'DEFAULT/xenapi_connection_password': value => $xenapi_connection_password; + 'DEFAULT/xenapi_inject_image': value => $xenapi_inject_image; + } + + ensure_packages(['python-pip']) + + package { 'xenapi': + ensure => present, + provider => pip + } + + Package['python-pip'] -> Package['xenapi'] +} diff --git a/3rdparty/modules/nova/manifests/conductor.pp b/3rdparty/modules/nova/manifests/conductor.pp new file mode 100644 index 000000000..dbc91464e --- /dev/null +++ b/3rdparty/modules/nova/manifests/conductor.pp @@ -0,0 +1,46 @@ +# == Class: nova::conductor +# +# Manages nova conductor package and service +# +# === Parameters: +# +# [*enabled*] +# (optional) Whether to enable the nova-conductor service +# Defaults to false +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*ensure_package*] +# (optional) The state of the nova conductor package +# Defaults to 'present' +# +# [*workers*] +# (optional) Number of workers for OpenStack Conductor service +# Defaults to undef (i.e. parameter will not be present) +# +class nova::conductor( + $enabled = false, + $manage_service = true, + $ensure_package = 'present', + $workers = undef, +) { + + include nova::db + include nova::params + + nova::generic_service { 'conductor': + enabled => $enabled, + manage_service => $manage_service, + package_name => $::nova::params::conductor_package_name, + service_name => $::nova::params::conductor_service_name, + ensure_package => $ensure_package, + } + + if $workers { + nova_config { + 'conductor/workers': value => $workers; + } + } +} diff --git a/3rdparty/modules/nova/manifests/config.pp b/3rdparty/modules/nova/manifests/config.pp new file mode 100644 index 000000000..3f0bc2131 --- /dev/null +++ b/3rdparty/modules/nova/manifests/config.pp @@ -0,0 +1,33 @@ +# == Class: nova::config +# +# This class is used to manage arbitrary Nova configurations. +# +# === Parameters +# +# [*nova_config*] +# (optional) Allow configuration of arbitrary Nova configurations. +# The value is an hash of nova_config resources. Example: +# { 'DEFAULT/foo' => { value => 'fooValue'}, +# 'DEFAULT/bar' => { value => 'barValue'} +# } +# In yaml format, Example: +# nova_config: +# DEFAULT/foo: +# value: fooValue +# DEFAULT/bar: +# value: barValue +# +# NOTE: The configuration MUST NOT be already handled by this module +# or Puppet catalog compilation will fail with duplicate resources. +# +class nova::config ( + $nova_config = {}, + $nova_paste_api_ini = {}, +) { + + validate_hash($nova_config) + validate_hash($nova_paste_api_ini) + + create_resources('nova_config', $nova_config) + create_resources('nova_paste_api_ini', $nova_paste_api_ini) +} diff --git a/3rdparty/modules/nova/manifests/consoleauth.pp b/3rdparty/modules/nova/manifests/consoleauth.pp new file mode 100644 index 000000000..4813b36b6 --- /dev/null +++ b/3rdparty/modules/nova/manifests/consoleauth.pp @@ -0,0 +1,39 @@ +# == Class: nova::consoleauth +# +# Installs and configures consoleauth service +# +# The consoleauth service is required for vncproxy auth +# for Horizon +# +# === Parameters +# +# [*enabled*] +# (optional) Whether the nova consoleauth service will be run +# Defaults to false +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*ensure_package*] +# (optional) Whether the nova consoleauth package will be installed +# Defaults to 'present' +# +class nova::consoleauth( + $enabled = false, + $manage_service = true, + $ensure_package = 'present' +) { + + include nova::params + + nova::generic_service { 'consoleauth': + enabled => $enabled, + manage_service => $manage_service, + package_name => $::nova::params::consoleauth_package_name, + service_name => $::nova::params::consoleauth_service_name, + ensure_package => $ensure_package, + require => Package['nova-common'], + } + +} diff --git a/3rdparty/modules/nova/manifests/cron/archive_deleted_rows.pp b/3rdparty/modules/nova/manifests/cron/archive_deleted_rows.pp new file mode 100644 index 000000000..b8335462e --- /dev/null +++ b/3rdparty/modules/nova/manifests/cron/archive_deleted_rows.pp @@ -0,0 +1,69 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Class: nova::cron::archive_deleted_rows +# +# Move deleted instances to another table that you don't have to backup +# unless you have data retention policies. +# +# === Parameters +# +# [*minute*] +# (optional) Defaults to '1'. +# +# [*hour*] +# (optional) Defaults to '0'. +# +# [*monthday*] +# (optional) Defaults to '*'. +# +# [*month*] +# (optional) Defaults to '*'. +# +# [*weekday*] +# (optional) Defaults to '*'. +# +# [*max_rows*] +# (optional) Maximum number of deleted rows to archive. +# Defaults to '100'. +# +# [*user*] +# (optional) User with access to nova files. +# Defaults to 'nova'. +# +class nova::cron::archive_deleted_rows ( + $minute = 1, + $hour = 0, + $monthday = '*', + $month = '*', + $weekday = '*', + $max_rows = '100', + $user = 'nova', +) { + + cron { 'nova-manage db archive_deleted_rows': + command => "nova-manage db archive_deleted_rows --max_rows ${max_rows} >>/var/log/nova/nova-rowsflush.log 2>&1", + environment => 'PATH=/bin:/usr/bin:/usr/sbin SHELL=/bin/sh', + user => $user, + minute => $minute, + hour => $hour, + monthday => $monthday, + month => $month, + weekday => $weekday, + require => Package['nova-common'], + } +} diff --git a/3rdparty/modules/nova/manifests/db.pp b/3rdparty/modules/nova/manifests/db.pp new file mode 100644 index 000000000..850b9254e --- /dev/null +++ b/3rdparty/modules/nova/manifests/db.pp @@ -0,0 +1,71 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Class: nova::db +# Configures the nova database. +# +# == Parameters +# +# [*database_connection*] +# (optional) Connection url to connect to nova database. +# Defaults to undef +# +# [*slave_connection*] +# (optional) Connection url to connect to nova slave database (read-only). +# Defaults to undef +# +# [*database_idle_timeout*] +# (optional) Timeout before idle db connections are reaped. +# Defaults to undef +# +class nova::db ( + $database_connection = undef, + $slave_connection = undef, + $database_idle_timeout = undef, +) { + + $database_connection_real = pick($database_connection, $::nova::database_connection, false) + $slave_connection_real = pick($slave_connection, $::nova::slave_connection, false) + $database_idle_timeout_real = pick($database_idle_timeout, $::nova::database_idle_timeout, false) + + if $database_connection_real { + if($database_connection_real =~ /mysql:\/\/\S+:\S+@\S+\/\S+/) { + require 'mysql::bindings' + require 'mysql::bindings::python' + } elsif($database_connection_real =~ /postgresql:\/\/\S+:\S+@\S+\/\S+/) { + + } elsif($database_connection_real =~ /sqlite:\/\//) { + + } else { + fail("Invalid db connection ${database_connection_real}") + } + nova_config { + 'database/connection': value => $database_connection_real, secret => true; + 'database/idle_timeout': value => $database_idle_timeout_real; + } + if $slave_connection_real { + nova_config { + 'database/slave_connection': value => $slave_connection_real, secret => true; + } + } else { + nova_config { + 'database/slave_connection': ensure => absent; + } + } + } + +} diff --git a/3rdparty/modules/nova/manifests/db/mysql.pp b/3rdparty/modules/nova/manifests/db/mysql.pp new file mode 100644 index 000000000..f1aa16c51 --- /dev/null +++ b/3rdparty/modules/nova/manifests/db/mysql.pp @@ -0,0 +1,72 @@ +# == Class: nova::db::mysql +# +# Class that configures mysql for nova +# +# === Parameters: +# +# [*password*] +# Password to use for the nova user +# +# [*dbname*] +# (optional) The name of the database +# Defaults to 'nova' +# +# [*user*] +# (optional) The mysql user to create +# Defaults to 'nova' +# +# [*host*] +# (optional) The IP address of the mysql server +# Defaults to '127.0.0.1' +# +# [*charset*] +# (optional) The charset to use for the nova database +# Defaults to 'utf8' +# +# [*collate*] +# (optional) The collate to use for the nova database +# Defaults to 'utf8_general_ci' +# +# [*allowed_hosts*] +# (optional) Additional hosts that are allowed to access this DB +# Defaults to undef +# +# [*cluster_id*] +# (optional) Deprecated. Does nothing +# Defaults to 'localzone' +# +# [*mysql_module*] +# (optional) Deprecated. Does nothing. +# +class nova::db::mysql( + $password, + $dbname = 'nova', + $user = 'nova', + $host = '127.0.0.1', + $charset = 'utf8', + $collate = 'utf8_general_ci', + $allowed_hosts = undef, + $mysql_module = undef, + $cluster_id = undef +) { + + if $cluster_id { + warning('The cluster_id parameter is deprecated and has no effect.') + } + + if $mysql_module { + warning('The mysql_module parameter is deprecated. The latest 2.x mysql module will be used.') + } + + ::openstacklib::db::mysql { 'nova': + user => $user, + password_hash => mysql_password($password), + dbname => $dbname, + host => $host, + charset => $charset, + collate => $collate, + allowed_hosts => $allowed_hosts, + } + + ::Openstacklib::Db::Mysql['nova'] ~> Exec<| title == 'nova-db-sync' |> +} diff --git a/3rdparty/modules/nova/manifests/db/postgresql.pp b/3rdparty/modules/nova/manifests/db/postgresql.pp new file mode 100644 index 000000000..e6b7a49c9 --- /dev/null +++ b/3rdparty/modules/nova/manifests/db/postgresql.pp @@ -0,0 +1,36 @@ +# == Class: nova::db::postgresql +# +# Class that configures postgresql for nova +# Requires the Puppetlabs postgresql module. +# +# === Parameters: +# +# [*password*] +# Password to use to connect to postgresql +# +# [*dbname*] +# (optional) Name of the database to create for nova +# Defaults to 'nova' +# +# [*user*] +# (optional) Name of the user to connect to postgresql +# Defaults to 'nova' +# +class nova::db::postgresql( + $password, + $dbname = 'nova', + $user = 'nova' +) { + + require 'postgresql::python' + + Postgresql::Db[$dbname] -> Anchor<| title == 'nova-start' |> + Postgresql::Db[$dbname] ~> Exec<| title == 'nova-db-sync' |> + Package['python-psycopg2'] -> Exec<| title == 'nova-db-sync' |> + + postgresql::db { $dbname: + user => $user, + password => $password, + } + +} diff --git a/3rdparty/modules/nova/manifests/generic_service.pp b/3rdparty/modules/nova/manifests/generic_service.pp new file mode 100644 index 000000000..3328ba5f7 --- /dev/null +++ b/3rdparty/modules/nova/manifests/generic_service.pp @@ -0,0 +1,62 @@ +# == Define: nova::generic_service +# +# This defined type implements basic nova services. +# It is introduced to attempt to consolidate +# common code. +# +# It also allows users to specify ad-hoc services +# as needed +# +# This define creates a service resource with title nova-${name} and +# conditionally creates a package resource with title nova-${name} +# +define nova::generic_service( + $package_name, + $service_name, + $enabled = false, + $manage_service = true, + $ensure_package = 'present' +) { + + include nova::params + + $nova_title = "nova-${name}" + # ensure that the service is only started after + # all nova config entries have been set + Exec['post-nova_config'] ~> Service<| title == $nova_title |> + # ensure that the service has only been started + # after the initial db sync + Exec<| title == 'nova-db-sync' |> ~> Service<| title == $nova_title |> + + + # I need to mark that ths package should be + # installed before nova_config + if ($package_name) { + if !defined(Package[$package_name]) { + package { $nova_title: + ensure => $ensure_package, + name => $package_name, + notify => Service[$nova_title], + tag => ['openstack', 'nova'], + } + } + } + + if $service_name { + if $manage_service { + if $enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + } + + service { $nova_title: + ensure => $service_ensure, + name => $service_name, + enable => $enabled, + hasstatus => true, + require => [Package['nova-common'], Package[$package_name]], + } + } +} diff --git a/3rdparty/modules/nova/manifests/init.pp b/3rdparty/modules/nova/manifests/init.pp new file mode 100644 index 000000000..d5488a152 --- /dev/null +++ b/3rdparty/modules/nova/manifests/init.pp @@ -0,0 +1,726 @@ +# == Class: nova +# +# This class is used to specify configuration parameters that are common +# across all nova services. +# +# === Parameters: +# +# [*ensure_package*] +# (optional) The state of nova packages +# Defaults to 'present' +# +# [*nova_cluster_id*] +# (optional) Deprecated. This parameter does nothing and will be removed. +# Defaults to 'localcluster' +# +# [*sql_connection*] +# (optional) Deprecated. Use database_connection instead. +# Defaults to false +# +# [*sql_idle_timeout*] +# (optional) Deprecated. Use database_idle_timeout instead +# Defaults to false +# +# [*database_connection*] +# (optional) Connection url to connect to nova database. +# Defaults to false +# +# [*slave_connection*] +# (optional) Connection url to connect to nova slave database (read-only). +# Defaults to false +# +# [*database_idle_timeout*] +# (optional) Timeout before idle db connections are reaped. +# Defaults to 3600 +# +# [*rpc_backend*] +# (optional) The rpc backend implementation to use, can be: +# rabbit (for rabbitmq) +# qpid (for qpid) +# zmq (for zeromq) +# Defaults to 'rabbit' +# +# [*image_service*] +# (optional) Service used to search for and retrieve images. +# Defaults to 'nova.image.local.LocalImageService' +# +# [*glance_api_servers*] +# (optional) List of addresses for api servers. +# Defaults to 'localhost:9292' +# +# [*memcached_servers*] +# (optional) Use memcached instead of in-process cache. Supply a list of memcached server IP's:Memcached Port. +# Defaults to false +# +# [*rabbit_host*] +# (optional) Location of rabbitmq installation. +# Defaults to 'localhost' +# +# [*rabbit_hosts*] +# (optional) List of clustered rabbit servers. +# Defaults to false +# +# [*rabbit_port*] +# (optional) Port for rabbitmq instance. +# Defaults to '5672' +# +# [*rabbit_password*] +# (optional) Password used to connect to rabbitmq. +# Defaults to 'guest' +# +# [*rabbit_userid*] +# (optional) User used to connect to rabbitmq. +# Defaults to 'guest' +# +# [*rabbit_virtual_host*] +# (optional) The RabbitMQ virtual host. +# Defaults to '/' +# +# [*rabbit_use_ssl*] +# (optional) Connect over SSL for RabbitMQ +# Defaults to false +# +# [*kombu_ssl_ca_certs*] +# (optional) SSL certification authority file (valid only if SSL enabled). +# Defaults to undef +# +# [*kombu_ssl_certfile*] +# (optional) SSL cert file (valid only if SSL enabled). +# Defaults to undef +# +# [*kombu_ssl_keyfile*] +# (optional) SSL key file (valid only if SSL enabled). +# Defaults to undef +# +# [*kombu_ssl_version*] +# (optional) SSL version to use (valid only if SSL enabled). +# Valid values are TLSv1, SSLv23 and SSLv3. SSLv2 may be +# available on some distributions. +# Defaults to 'TLSv1' +# +# [*amqp_durable_queues*] +# (optional) Define queues as "durable" to rabbitmq. +# Defaults to false +# +# [*qpid_hostname*] +# (optional) Location of qpid server +# Defaults to 'localhost' +# +# [*qpid_port*] +# (optional) Port for qpid server +# Defaults to '5672' +# +# [*qpid_username*] +# (optional) Username to use when connecting to qpid +# Defaults to 'guest' +# +# [*qpid_password*] +# (optional) Password to use when connecting to qpid +# Defaults to 'guest' +# +# [*qpid_heartbeat*] +# (optional) Seconds between connection keepalive heartbeats +# Defaults to 60 +# +# [*qpid_protocol*] +# (optional) Transport to use, either 'tcp' or 'ssl'' +# Defaults to 'tcp' +# +# [*qpid_sasl_mechanisms*] +# (optional) Enable one or more SASL mechanisms +# Defaults to false +# +# [*qpid_tcp_nodelay*] +# (optional) Disable Nagle algorithm +# Defaults to true +# +# [*service_down_time*] +# (optional) Maximum time since last check-in for up service. +# Defaults to 60 +# +# [*logdir*] +# (optional) Deprecated. Use log_dir instead. +# Defaults to false +# +# [*log_dir*] +# (optional) Directory where logs should be stored. +# If set to boolean false, it will not log to any directory. +# Defaults to '/var/log/nova' +# +# [*state_path*] +# (optional) Directory for storing state. +# Defaults to '/var/lib/nova' +# +# [*lock_path*] +# (optional) Directory for lock files. +# On RHEL will be '/var/lib/nova/tmp' and on Debian '/var/lock/nova' +# Defaults to $::nova::params::lock_path +# +# [*verbose*] +# (optional) Set log output to verbose output. +# Defaults to false +# +# [*periodic_interval*] +# (optional) Seconds between running periodic tasks. +# Defaults to '60' +# +# [*report_interval*] +# (optional) Interval at which nodes report to data store. +# Defaults to '10' +# +# [*monitoring_notifications*] +# (optional) Whether or not to send system usage data notifications out on the message queue. Only valid for stable/essex. +# Defaults to false +# +# [*use_syslog*] +# (optional) Use syslog for logging +# Defaults to false +# +# [*log_facility*] +# (optional) Syslog facility to receive log lines. +# Defaults to 'LOG_USER' +# +# [*use_ssl*] +# (optional) Enable SSL on the API server +# Defaults to false, not set +# +# [*enabled_ssl_apis*] +# (optional) List of APIs to SSL enable +# Defaults to [] +# Possible values : 'ec2', 'osapi_compute', 'metadata' +# +# [*cert_file*] +# (optinal) Certificate file to use when starting API server securely +# Defaults to false, not set +# +# [*key_file*] +# (optional) Private key file to use when starting API server securely +# Defaults to false, not set +# +# [*ca_file*] +# (optional) CA certificate file to use to verify connecting clients +# Defaults to false, not set_ +# +# [*nova_user_id*] +# (optional) Create the nova user with the specified gid. +# Changing to a new uid after specifying a different uid previously, +# or using this option after the nova account already exists will break +# the ownership of all files/dirs owned by nova. It is strongly encouraged +# not to use this option and instead create user before nova class or +# for network shares create netgroup into which you'll put nova on all the +# nodes. If undef no user will be created and user creation will standardly +# happen in nova-common package. +# Defaults to undef. +# +# [*nova_group_id*] +# (optional) Create the nova user with the specified gid. +# Changing to a new uid after specifying a different uid previously, +# or using this option after the nova account already exists will break +# the ownership of all files/dirs owned by nova. It is strongly encouraged +# not to use this option and instead create group before nova class or for +# network shares create netgroup into which you'll put nova on all the +# nodes. If undef no user or group will be created and creation will +# happen in nova-common package. +# Defaults to undef. +# +# [*nova_public_key*] +# (optional) Install public key in .ssh/authorized_keys for the 'nova' user. +# Expects a hash of the form { type => 'key-type', key => 'key-data' } where +# 'key-type' is one of (ssh-rsa, ssh-dsa, ssh-ecdsa) and 'key-data' is the +# actual key data (e.g, 'AAAA...'). +# +# [*nova_private_key*] +# (optional) Install private key into .ssh/id_rsa (or appropriate equivalent +# for key type). Expects a hash of the form { type => 'key-type', key => +# 'key-data' }, where 'key-type' is one of (ssh-rsa, ssh-dsa, ssh-ecdsa) and +# 'key-data' is the contents of the private key file. +# +# [*nova_shell*] +# (optional) Set shell for 'nova' user to the specified value. +# Defaults to '/bin/false'. +# +# [*mysql_module*] +# (optional) Deprecated. Does nothing. +# +# [*notification_driver*] +# (optional) Driver or drivers to handle sending notifications. +# Value can be a string or a list. +# Defaults to [] +# +# [*notification_topics*] +# (optional) AMQP topic used for OpenStack notifications +# Defaults to 'notifications' +# +# [*notify_api_faults*] +# (optional) If set, send api.fault notifications on caught +# exceptions in the API service +# Defaults to false +# +# [*notify_on_state_change*] +# (optional) If set, send compute.instance.update notifications +# on instance state changes. Valid values are None for no notifications, +# "vm_state" for notifications on VM state changes, or "vm_and_task_state" +# for notifications on VM and task state changes. +# Defaults to undef +# +# [*os_region_name*] +# (optional) Sets the os_region_name flag. For environments with +# more than one endpoint per service, this is required to make +# things such as cinder volume attach work. If you don't set this +# and you have multiple endpoints, you will get AmbiguousEndpoint +# exceptions in the nova API service. +# Defaults to undef +class nova( + $ensure_package = 'present', + $database_connection = false, + $slave_connection = false, + $database_idle_timeout = 3600, + $rpc_backend = 'rabbit', + $image_service = 'nova.image.glance.GlanceImageService', + # these glance params should be optional + # this should probably just be configured as a glance client + $glance_api_servers = 'localhost:9292', + $memcached_servers = false, + $rabbit_host = 'localhost', + $rabbit_hosts = false, + $rabbit_password = 'guest', + $rabbit_port = '5672', + $rabbit_userid = 'guest', + $rabbit_virtual_host = '/', + $rabbit_use_ssl = false, + $rabbit_ha_queues = undef, + $kombu_ssl_ca_certs = undef, + $kombu_ssl_certfile = undef, + $kombu_ssl_keyfile = undef, + $kombu_ssl_version = 'TLSv1', + $amqp_durable_queues = false, + $qpid_hostname = 'localhost', + $qpid_port = '5672', + $qpid_username = 'guest', + $qpid_password = 'guest', + $qpid_sasl_mechanisms = false, + $qpid_heartbeat = 60, + $qpid_protocol = 'tcp', + $qpid_tcp_nodelay = true, + $auth_strategy = 'keystone', + $service_down_time = 60, + $log_dir = '/var/log/nova', + $state_path = '/var/lib/nova', + $lock_path = $::nova::params::lock_path, + $verbose = false, + $debug = false, + $periodic_interval = '60', + $report_interval = '10', + $rootwrap_config = '/etc/nova/rootwrap.conf', + $use_ssl = false, + $enabled_ssl_apis = ['ec2', 'metadata', 'osapi_compute'], + $ca_file = false, + $cert_file = false, + $key_file = false, + $nova_user_id = undef, + $nova_group_id = undef, + $nova_public_key = undef, + $nova_private_key = undef, + $nova_shell = '/bin/false', + # deprecated in folsom + #$root_helper = $::nova::params::root_helper, + $monitoring_notifications = false, + $use_syslog = false, + $log_facility = 'LOG_USER', + $install_utilities = true, + $notification_driver = [], + $notification_topics = 'notifications', + $notify_api_faults = false, + $notify_on_state_change = undef, + # DEPRECATED PARAMETERS + $mysql_module = undef, + # this is how to query all resources from our clutser + $nova_cluster_id = undef, + $sql_connection = false, + $sql_idle_timeout = false, + $logdir = false, + $os_region_name = undef, +) inherits nova::params { + + # maintain backward compatibility + include nova::db + + if $mysql_module { + warning('The mysql_module parameter is deprecated. The latest 2.x mysql module will be used.') + } + + if $nova_cluster_id { + warning('The nova_cluster_id parameter is deprecated and has no effect.') + } + + validate_array($enabled_ssl_apis) + if empty($enabled_ssl_apis) and $use_ssl { + warning('enabled_ssl_apis is empty but use_ssl is set to true') + } + + if $use_ssl { + if !$cert_file { + fail('The cert_file parameter is required when use_ssl is set to true') + } + if !$key_file { + fail('The key_file parameter is required when use_ssl is set to true') + } + } + + if $kombu_ssl_ca_certs and !$rabbit_use_ssl { + fail('The kombu_ssl_ca_certs parameter requires rabbit_use_ssl to be set to true') + } + if $kombu_ssl_certfile and !$rabbit_use_ssl { + fail('The kombu_ssl_certfile parameter requires rabbit_use_ssl to be set to true') + } + if $kombu_ssl_keyfile and !$rabbit_use_ssl { + fail('The kombu_ssl_keyfile parameter requires rabbit_use_ssl to be set to true') + } + if ($kombu_ssl_certfile and !$kombu_ssl_keyfile) or ($kombu_ssl_keyfile and !$kombu_ssl_certfile) { + fail('The kombu_ssl_certfile and kombu_ssl_keyfile parameters must be used together') + } + + if $nova_group_id { + warning('The nova_group_id will be deprecated, please create group manually') + group { 'nova': + ensure => present, + system => true, + gid => $nova_group_id, + before => Package['nova-common'], + } + } + if $nova_user_id { + warning('The nova_user_id will be deprecated, please create user manually') + user { 'nova': + ensure => present, + system => true, + groups => 'nova', + home => '/var/lib/nova', + managehome => false, + shell => $nova_shell, + uid => $nova_user_id, + gid => $nova_group_id, + before => Package['nova-common'], + require => Group['nova'], + } + } + + if $nova_public_key or $nova_private_key { + file { '/var/lib/nova/.ssh': + ensure => directory, + mode => '0700', + owner => 'nova', + group => 'nova', + require => Package['nova-common'], + } + + if $nova_public_key { + if ! $nova_public_key[key] or ! $nova_public_key['type'] { + fail('You must provide both a key type and key data.') + } + + ssh_authorized_key { 'nova-migration-public-key': + ensure => present, + key => $nova_public_key[key], + type => $nova_public_key['type'], + user => 'nova', + require => File['/var/lib/nova/.ssh'], + } + } + + if $nova_private_key { + if ! $nova_private_key[key] or ! $nova_private_key['type'] { + fail('You must provide both a key type and key data.') + } + + $nova_private_key_file = $nova_private_key['type'] ? { + 'ssh-rsa' => '/var/lib/nova/.ssh/id_rsa', + 'ssh-dsa' => '/var/lib/nova/.ssh/id_dsa', + 'ssh-ecdsa' => '/var/lib/nova/.ssh/id_ecdsa', + default => undef + } + + if ! $nova_private_key_file { + fail("Unable to determine name of private key file. Type specified was '${nova_private_key['type']}' but should be one of: ssh-rsa, ssh-dsa, ssh-ecdsa.") + } + + file { $nova_private_key_file: + content => $nova_private_key[key], + mode => '0600', + owner => 'nova', + group => 'nova', + require => [ File['/var/lib/nova/.ssh'], Package['nova-common'] ], + } + } + } + + + # all nova_config resources should be applied + # after the nova common package + # before the file resource for nova.conf is managed + # and before the post config resource + Package['nova-common'] -> Nova_config<| |> -> File['/etc/nova/nova.conf'] + Nova_config<| |> ~> Exec['post-nova_config'] + + # TODO - see if these packages can be removed + # they should be handled as package deps by the OS + package { 'python': + ensure => present, + } + package { 'python-greenlet': + ensure => present, + require => Package['python'], + } + + if $install_utilities { + class { 'nova::utilities': } + } + + # this anchor is used to simplify the graph between nova components by + # allowing a resource to serve as a point where the configuration of nova begins + anchor { 'nova-start': } + + package { 'python-nova': + ensure => $ensure_package, + require => Package['python-greenlet'], + tag => ['openstack', 'nova'], + } + + package { 'nova-common': + ensure => $ensure_package, + name => $::nova::params::common_package_name, + require => [Package['python-nova'], Anchor['nova-start']], + tag => ['openstack', 'nova'], + } + + file { '/etc/nova/nova.conf': + mode => '0640', + owner => 'nova', + group => 'nova', + require => Package['nova-common'], + } + + # used by debian/ubuntu in nova::network_bridge to refresh + # interfaces based on /etc/network/interfaces + exec { 'networking-refresh': + command => '/sbin/ifdown -a ; /sbin/ifup -a', + refreshonly => true, + } + + nova_config { 'DEFAULT/image_service': value => $image_service } + + if $image_service == 'nova.image.glance.GlanceImageService' { + if $glance_api_servers { + nova_config { 'glance/api_servers': value => $glance_api_servers } + } + } + + nova_config { 'DEFAULT/auth_strategy': value => $auth_strategy } + + if $memcached_servers { + nova_config { 'DEFAULT/memcached_servers': value => join($memcached_servers, ',') } + } else { + nova_config { 'DEFAULT/memcached_servers': ensure => absent } + } + + # we keep "nova.openstack.common.rpc.impl_kombu" for backward compatibility + # but since Icehouse, "rabbit" is enough. + if $rpc_backend == 'nova.openstack.common.rpc.impl_kombu' or $rpc_backend == 'rabbit' { + # I may want to support exporting and collecting these + nova_config { + 'DEFAULT/rabbit_password': value => $rabbit_password, secret => true; + 'DEFAULT/rabbit_userid': value => $rabbit_userid; + 'DEFAULT/rabbit_virtual_host': value => $rabbit_virtual_host; + 'DEFAULT/rabbit_use_ssl': value => $rabbit_use_ssl; + 'DEFAULT/amqp_durable_queues': value => $amqp_durable_queues; + } + + if $rabbit_use_ssl { + + if $kombu_ssl_ca_certs { + nova_config { 'DEFAULT/kombu_ssl_ca_certs': value => $kombu_ssl_ca_certs; } + } else { + nova_config { 'DEFAULT/kombu_ssl_ca_certs': ensure => absent; } + } + + if $kombu_ssl_certfile or $kombu_ssl_keyfile { + nova_config { + 'DEFAULT/kombu_ssl_certfile': value => $kombu_ssl_certfile; + 'DEFAULT/kombu_ssl_keyfile': value => $kombu_ssl_keyfile; + } + } else { + nova_config { + 'DEFAULT/kombu_ssl_certfile': ensure => absent; + 'DEFAULT/kombu_ssl_keyfile': ensure => absent; + } + } + + if $kombu_ssl_version { + nova_config { 'DEFAULT/kombu_ssl_version': value => $kombu_ssl_version; } + } else { + nova_config { 'DEFAULT/kombu_ssl_version': ensure => absent; } + } + + } else { + nova_config { + 'DEFAULT/kombu_ssl_ca_certs': ensure => absent; + 'DEFAULT/kombu_ssl_certfile': ensure => absent; + 'DEFAULT/kombu_ssl_keyfile': ensure => absent; + 'DEFAULT/kombu_ssl_version': ensure => absent; + } + } + + if $rabbit_hosts { + nova_config { 'DEFAULT/rabbit_hosts': value => join($rabbit_hosts, ',') } + } else { + nova_config { 'DEFAULT/rabbit_host': value => $rabbit_host } + nova_config { 'DEFAULT/rabbit_port': value => $rabbit_port } + nova_config { 'DEFAULT/rabbit_hosts': value => "${rabbit_host}:${rabbit_port}" } + } + if $rabbit_ha_queues == undef { + if $rabbit_hosts { + nova_config { 'DEFAULT/rabbit_ha_queues': value => true } + } else { + nova_config { 'DEFAULT/rabbit_ha_queues': value => false } + } + } else { + nova_config { 'DEFAULT/rabbit_ha_queues': value => $rabbit_ha_queues } + } + } + + # we keep "nova.openstack.common.rpc.impl_qpid" for backward compatibility + # but since Icehouse, "qpid" is enough. + if $rpc_backend == 'nova.openstack.common.rpc.impl_qpid' or $rpc_backend == 'qpid' { + nova_config { + 'DEFAULT/qpid_hostname': value => $qpid_hostname; + 'DEFAULT/qpid_port': value => $qpid_port; + 'DEFAULT/qpid_username': value => $qpid_username; + 'DEFAULT/qpid_password': value => $qpid_password, secret => true; + 'DEFAULT/qpid_heartbeat': value => $qpid_heartbeat; + 'DEFAULT/qpid_protocol': value => $qpid_protocol; + 'DEFAULT/qpid_tcp_nodelay': value => $qpid_tcp_nodelay; + } + if is_array($qpid_sasl_mechanisms) { + nova_config { + 'DEFAULT/qpid_sasl_mechanisms': value => join($qpid_sasl_mechanisms, ' '); + } + } + elsif $qpid_sasl_mechanisms { + nova_config { + 'DEFAULT/qpid_sasl_mechanisms': value => $qpid_sasl_mechanisms; + } + } + else { + nova_config { + 'DEFAULT/qpid_sasl_mechanisms': ensure => absent; + } + } + } + + # SSL Options + if $use_ssl { + nova_config { + 'DEFAULT/enabled_ssl_apis' : value => join($enabled_ssl_apis, ','); + 'DEFAULT/ssl_cert_file' : value => $cert_file; + 'DEFAULT/ssl_key_file' : value => $key_file; + } + if $ca_file { + nova_config { 'DEFAULT/ssl_ca_file' : + value => $ca_file, + } + } else { + nova_config { 'DEFAULT/ssl_ca_file' : + ensure => absent, + } + } + } else { + nova_config { + 'DEFAULT/enabled_ssl_apis' : ensure => absent; + 'DEFAULT/ssl_cert_file' : ensure => absent; + 'DEFAULT/ssl_key_file' : ensure => absent; + 'DEFAULT/ssl_ca_file' : ensure => absent; + } + } + + if $logdir { + warning('The logdir parameter is deprecated, use log_dir instead.') + $log_dir_real = $logdir + } else { + $log_dir_real = $log_dir + } + + if $log_dir_real { + file { $log_dir_real: + ensure => directory, + mode => '0750', + owner => 'nova', + group => $::nova::params::nova_log_group, + require => Package['nova-common'], + } + nova_config { 'DEFAULT/log_dir': value => $log_dir_real;} + } else { + nova_config { 'DEFAULT/log_dir': ensure => absent;} + } + + if $monitoring_notifications { + warning('The monitoring_notifications parameter is deprecated, use notification_driver instead.') + $notification_driver_real = 'nova.openstack.common.notifier.rpc_notifier' + } else { + $notification_driver_real = is_string($notification_driver) ? { + true => $notification_driver, + default => join($notification_driver, ',') + } + } + + nova_config { + 'DEFAULT/verbose': value => $verbose; + 'DEFAULT/debug': value => $debug; + 'DEFAULT/rpc_backend': value => $rpc_backend; + 'DEFAULT/notification_driver': value => $notification_driver_real; + 'DEFAULT/notification_topics': value => $notification_topics; + 'DEFAULT/notify_api_faults': value => $notify_api_faults; + # Following may need to be broken out to different nova services + 'DEFAULT/state_path': value => $state_path; + 'DEFAULT/lock_path': value => $lock_path; + 'DEFAULT/service_down_time': value => $service_down_time; + 'DEFAULT/rootwrap_config': value => $rootwrap_config; + 'DEFAULT/report_interval': value => $report_interval; + } + + if $notify_on_state_change and $notify_on_state_change in ['vm_state', 'vm_and_task_state'] { + nova_config { + 'DEFAULT/notify_on_state_change': value => $notify_on_state_change; + } + } else { + nova_config { 'DEFAULT/notify_on_state_change': ensure => absent; } + } + + # Syslog configuration + if $use_syslog { + nova_config { + 'DEFAULT/use_syslog': value => true; + 'DEFAULT/syslog_log_facility': value => $log_facility; + } + } else { + nova_config { + 'DEFAULT/use_syslog': value => false; + } + } + + if $os_region_name { + nova_config { + 'DEFAULT/os_region_name': value => $os_region_name; + } + } + else { + nova_config { + 'DEFAULT/os_region_name': ensure => absent; + } + } + + exec { 'post-nova_config': + command => '/bin/echo "Nova config has changed"', + refreshonly => true, + } + +} diff --git a/3rdparty/modules/nova/manifests/keystone/auth.pp b/3rdparty/modules/nova/manifests/keystone/auth.pp new file mode 100644 index 000000000..4650c680a --- /dev/null +++ b/3rdparty/modules/nova/manifests/keystone/auth.pp @@ -0,0 +1,198 @@ +# == Class: nova::keystone::auth +# +# Creates nova endpoints and service account in keystone +# +# === Parameters: +# +# [*password*] +# Password to create for the service user +# +# [*auth_name*] +# (optional) The name of the nova service user +# Defaults to 'nova' +# +# [*auth_name_v3*] +# (optional) The name of the nova v3 service user +# Defaults to 'novav3' +# +# [*service_name*] +# (optional) Name of the service. +# Defaults to the value of auth_name. +# +# [*service_name_v3*] +# (optional) Name of the v3 service. +# Defaults to the value of auth_name_v3. +# +# [*public_address*] +# (optional) The public nova-api endpoint +# Defaults to '127.0.0.1' +# +# [*admin_address*] +# (optional) The admin nova-api endpoint +# Defaults to '127.0.0.1' +# +# [*internal_address*] +# (optional) The internal nova-api endpoint +# Defaults to '127.0.0.1' +# +# [*compute_port*] +# (optional) The port to use for the compute endpoint +# Defaults to '8774' +# +# [*ec2_port*] +# (optional) The port to use for the ec2 endpoint +# Defaults to '8773' +# +# [*compute_version*] +# (optional) The version of the compute api to put in the endpoint +# Defaults to 'v2' +# +# [*region*] +# (optional) The region in which to place the endpoints +# Defaults to 'RegionOne' +# +# [*tenant*] +# (optional) The tenant to use for the nova service user +# Defaults to 'services' +# +# [*email*] +# (optional) The email address for the nova service user +# Defaults to 'nova@localhost' +# +# [*configure_ec2_endpoint*] +# (optional) Whether to create an ec2 endpoint +# Defaults to true +# +# [*configure_endpoint*] +# (optional) Whether to create the endpoint. +# Defaults to true +# +# [*configure_endpoint_v3*] +# (optional) Whether to create the v3 endpoint. +# Defaults to true +# +# [*configure_user*] +# (optional) Whether to create the service user. +# Defaults to true +# +# [*configure_user_role*] +# (optional) Whether to configure the admin role for the service user. +# Defaults to true +# +# [*cinder*] +# (optional) Deprecated and has no effect +# Defaults to undef +# +# [*public_protocol*] +# (optional) Protocol to use for the public endpoint. Can be http or https. +# Defaults to 'http' +# +# [*admin_protocol*] +# Protocol for admin endpoints. Defaults to 'http'. +# +# [*internal_protocol*] +# Protocol for internal endpoints. Defaults to 'http'. +# +class nova::keystone::auth( + $password, + $auth_name = 'nova', + $auth_name_v3 = 'novav3', + $service_name = undef, + $service_name_v3 = undef, + $public_address = '127.0.0.1', + $admin_address = '127.0.0.1', + $internal_address = '127.0.0.1', + $compute_port = '8774', + $ec2_port = '8773', + $compute_version = 'v2', + $region = 'RegionOne', + $tenant = 'services', + $email = 'nova@localhost', + $configure_ec2_endpoint = true, + $cinder = undef, + $public_protocol = 'http', + $configure_endpoint = true, + $configure_endpoint_v3 = true, + $configure_user = true, + $configure_user_role = true, + $admin_protocol = 'http', + $internal_protocol = 'http' +) { + + if $cinder != undef { + warning('The cinder parameter is deprecated and has no effect.') + } + + if $service_name == undef { + $real_service_name = $auth_name + } else { + $real_service_name = $service_name + } + + if $service_name_v3 == undef { + $real_service_name_v3 = $auth_name_v3 + } else { + $real_service_name_v3 = $service_name_v3 + } + + Keystone_endpoint["${region}/${real_service_name}"] ~> Service <| name == 'nova-api' |> + + if $configure_user { + keystone_user { $auth_name: + ensure => present, + password => $password, + email => $email, + tenant => $tenant, + } + } + + if $configure_user_role { + keystone_user_role { "${auth_name}@${tenant}": + ensure => present, + roles => 'admin', + } + } + + keystone_service { $real_service_name: + ensure => present, + type => 'compute', + description => 'Openstack Compute Service', + } + + if $configure_endpoint { + keystone_endpoint { "${region}/${real_service_name}": + ensure => present, + public_url => "${public_protocol}://${public_address}:${compute_port}/${compute_version}/%(tenant_id)s", + admin_url => "${admin_protocol}://${admin_address}:${compute_port}/${compute_version}/%(tenant_id)s", + internal_url => "${internal_protocol}://${internal_address}:${compute_port}/${compute_version}/%(tenant_id)s", + } + } + + if $configure_endpoint_v3 { + keystone_service { $real_service_name_v3: + ensure => present, + type => 'computev3', + description => 'Openstack Compute Service v3', + } + keystone_endpoint { "${region}/${real_service_name_v3}": + ensure => present, + public_url => "${public_protocol}://${public_address}:${compute_port}/v3", + admin_url => "${admin_protocol}://${admin_address}:${compute_port}/v3", + internal_url => "${internal_protocol}://${internal_address}:${compute_port}/v3", + } + } + + if $configure_ec2_endpoint { + keystone_service { "${real_service_name}_ec2": + ensure => present, + type => 'ec2', + description => 'EC2 Service', + } + keystone_endpoint { "${region}/${real_service_name}_ec2": + ensure => present, + public_url => "${public_protocol}://${public_address}:${ec2_port}/services/Cloud", + admin_url => "${admin_protocol}://${admin_address}:${ec2_port}/services/Admin", + internal_url => "${internal_protocol}://${internal_address}:${ec2_port}/services/Cloud", + } + } +} diff --git a/3rdparty/modules/nova/manifests/logging.pp b/3rdparty/modules/nova/manifests/logging.pp new file mode 100644 index 000000000..ce4bd06c9 --- /dev/null +++ b/3rdparty/modules/nova/manifests/logging.pp @@ -0,0 +1,208 @@ +# Class nova::logging +# +# nova extended logging configuration +# +# == parameters +# +# [*logging_context_format_string*] +# (optional) Format string to use for log messages with context. +# Defaults to undef. +# Example: '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s\ +# [%(request_id)s %(user_identity)s] %(instance)s%(message)s' +# +# [*logging_default_format_string*] +# (optional) Format string to use for log messages without context. +# Defaults to undef. +# Example: '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s\ +# [-] %(instance)s%(message)s' +# +# [*logging_debug_format_suffix*] +# (optional) Formatted data to append to log format when level is DEBUG. +# Defaults to undef. +# Example: '%(funcName)s %(pathname)s:%(lineno)d' +# +# [*logging_exception_prefix*] +# (optional) Prefix each line of exception output with this format. +# Defaults to undef. +# Example: '%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s' +# +# [*log_config_append*] +# The name of an additional logging configuration file. +# Defaults to undef. +# See https://docs.python.org/2/howto/logging.html +# +# [*default_log_levels*] +# (optional) Hash of logger (keys) and level (values) pairs. +# Defaults to undef. +# Example: +# { 'amqp' => 'WARN', 'amqplib' => 'WARN', 'boto' => 'WARN', +# 'qpid' => 'WARN', 'sqlalchemy' => 'WARN', 'suds' => 'INFO', +# 'iso8601' => 'WARN', +# 'requests.packages.urllib3.connectionpool' => 'WARN' } +# +# [*publish_errors*] +# (optional) Publish error events (boolean value). +# Defaults to undef (false if unconfigured). +# +# [*fatal_deprecations*] +# (optional) Make deprecations fatal (boolean value) +# Defaults to undef (false if unconfigured). +# +# [*instance_format*] +# (optional) If an instance is passed with the log message, format it +# like this (string value). +# Defaults to undef. +# Example: '[instance: %(uuid)s] ' +# +# [*instance_uuid_format*] +# (optional) If an instance UUID is passed with the log message, format +# it like this (string value). +# Defaults to undef. +# Example: instance_uuid_format='[instance: %(uuid)s] ' + +# [*log_date_format*] +# (optional) Format string for %%(asctime)s in log records. +# Defaults to undef. +# Example: 'Y-%m-%d %H:%M:%S' + +class nova::logging( + $logging_context_format_string = undef, + $logging_default_format_string = undef, + $logging_debug_format_suffix = undef, + $logging_exception_prefix = undef, + $log_config_append = undef, + $default_log_levels = undef, + $publish_errors = undef, + $fatal_deprecations = undef, + $instance_format = undef, + $instance_uuid_format = undef, + $log_date_format = undef, +) { + + if $logging_context_format_string { + nova_config { + 'DEFAULT/logging_context_format_string' : + value => $logging_context_format_string; + } + } + else { + nova_config { + 'DEFAULT/logging_context_format_string' : ensure => absent; + } + } + + if $logging_default_format_string { + nova_config { + 'DEFAULT/logging_default_format_string' : + value => $logging_default_format_string; + } + } + else { + nova_config { + 'DEFAULT/logging_default_format_string' : ensure => absent; + } + } + + if $logging_debug_format_suffix { + nova_config { + 'DEFAULT/logging_debug_format_suffix' : + value => $logging_debug_format_suffix; + } + } + else { + nova_config { + 'DEFAULT/logging_debug_format_suffix' : ensure => absent; + } + } + + if $logging_exception_prefix { + nova_config { + 'DEFAULT/logging_exception_prefix' : value => $logging_exception_prefix; + } + } + else { + nova_config { + 'DEFAULT/logging_exception_prefix' : ensure => absent; + } + } + + if $log_config_append { + nova_config { + 'DEFAULT/log_config_append' : value => $log_config_append; + } + } + else { + nova_config { + 'DEFAULT/log_config_append' : ensure => absent; + } + } + + if $default_log_levels { + nova_config { + 'DEFAULT/default_log_levels' : + value => join(sort(join_keys_to_values($default_log_levels, '=')), ','); + } + } + else { + nova_config { + 'DEFAULT/default_log_levels' : ensure => absent; + } + } + + if $publish_errors { + nova_config { + 'DEFAULT/publish_errors' : value => $publish_errors; + } + } + else { + nova_config { + 'DEFAULT/publish_errors' : ensure => absent; + } + } + + if $fatal_deprecations { + nova_config { + 'DEFAULT/fatal_deprecations' : value => $fatal_deprecations; + } + } + else { + nova_config { + 'DEFAULT/fatal_deprecations' : ensure => absent; + } + } + + if $instance_format { + nova_config { + 'DEFAULT/instance_format' : value => $instance_format; + } + } + else { + nova_config { + 'DEFAULT/instance_format' : ensure => absent; + } + } + + if $instance_uuid_format { + nova_config { + 'DEFAULT/instance_uuid_format' : value => $instance_uuid_format; + } + } + else { + nova_config { + 'DEFAULT/instance_uuid_format' : ensure => absent; + } + } + + if $log_date_format { + nova_config { + 'DEFAULT/log_date_format' : value => $log_date_format; + } + } + else { + nova_config { + 'DEFAULT/log_date_format' : ensure => absent; + } + } + + +} diff --git a/3rdparty/modules/nova/manifests/manage/cells.pp b/3rdparty/modules/nova/manifests/manage/cells.pp new file mode 100644 index 000000000..059c7d545 --- /dev/null +++ b/3rdparty/modules/nova/manifests/manage/cells.pp @@ -0,0 +1,90 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# François Charlier +# +# 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. +# +# +# Configuring the database in each cell +# == Namevar +# The namevar will be the name of the cell +# +# == Parameters +# [*cell_type*] +# (optional) Whether the cell is a 'parent' or 'child' +# Defaults to 'parent' +# +# [*cell_parent_name*] +# (optional) If a child cell, this is the name of the 'parent' cell. +# If a parent cell, should be left to undef. +# Defaults to undef +# +# [*rabbit_username*] +# (optional) Username for the message broker in this cell +# Defaults to 'guest' +# +# [*rabbit_password*] +# (optional) Password for the message broker in this cell +# Defaults to 'guest' +# +# [*rabbit_hosts*] +# (optional) Address of the message broker in this cell +# Defaults to 'localhost' +# +# [*rabbit_port*] +# (optional) Port number of the message broker in this cell +# Defaults to '5672' +# +# [*rabbit_virtual_host*] +# (optional) The virtual host of the message broker in this cell +# Defaults to '/' +# +# [*weight_offset*] +# (optional) It might be used by some cell scheduling code in the future +# Defaults to '1.0' +# +# [*weight_scale*] +# (optional) It might be used by some cell scheduling code in the future +# Defaults to '1.0' +# +define nova::manage::cells ( + $cell_type = 'parent', + $cell_parent_name = undef, + $rabbit_username = 'guest', + $rabbit_password = 'guest', + $rabbit_hosts = 'localhost', + $rabbit_port = '5672', + $rabbit_virtual_host = '/', + $weight_offset = '1.0', + $weight_scale = '1.0' +) { + + File['/etc/nova/nova.conf'] -> Nova_cells[$name] + Exec<| title == 'nova-db-sync' |> -> Nova_cells[$name] + + nova_cells { $name: + ensure => present, + cell_type => $cell_type, + cell_parent_name => $cell_parent_name, + rabbit_username => $rabbit_username, + rabbit_password => $rabbit_password, + rabbit_hosts => $rabbit_hosts, + rabbit_port => $rabbit_port, + rabbit_virtual_host => $rabbit_virtual_host, + weight_offset => $weight_offset, + weight_scale => $weight_scale + } + +} diff --git a/3rdparty/modules/nova/manifests/manage/floating.pp b/3rdparty/modules/nova/manifests/manage/floating.pp new file mode 100644 index 000000000..6c6a14df4 --- /dev/null +++ b/3rdparty/modules/nova/manifests/manage/floating.pp @@ -0,0 +1,13 @@ +# Creates floating networks +define nova::manage::floating ( $network ) { + + File['/etc/nova/nova.conf'] -> Nova_floating[$name] + Exec<| title == 'nova-db-sync' |> -> Nova_floating[$name] + + nova_floating { $name: + ensure => present, + network => $network, + provider => 'nova_manage', + } + +} diff --git a/3rdparty/modules/nova/manifests/manage/network.pp b/3rdparty/modules/nova/manifests/manage/network.pp new file mode 100644 index 000000000..8a8312d32 --- /dev/null +++ b/3rdparty/modules/nova/manifests/manage/network.pp @@ -0,0 +1,44 @@ +# === Parameters: +# +# [*network*] +# (required) IPv4 CIDR of network to create. +# +# [*num_networks*] +# (optional) Number of networks to split $network into. +# Defaults to 1 +# +# [*network_size*] +# (optional) Size of the network to create +# Defaults to 255 +# +# [*vlan_start*] +# (optional) The vlan number to use if in vlan mode +# Defaults to undef +# +# [*project*] +# (optional) Project that network should be associated with +# Defaults to undef +# +define nova::manage::network ( + $network, + $label = 'novanetwork', + $num_networks = 1, + $network_size = 255, + $vlan_start = undef, + $project = undef +) { + + File['/etc/nova/nova.conf'] -> Nova_network[$name] + Exec<| title == 'nova-db-sync' |> -> Nova_network[$name] + + nova_network { $name: + ensure => present, + network => $network, + label => $label, + num_networks => $num_networks, + network_size => $network_size, + project => $project, + vlan_start => $vlan_start, + } + +} diff --git a/3rdparty/modules/nova/manifests/migration/libvirt.pp b/3rdparty/modules/nova/manifests/migration/libvirt.pp new file mode 100644 index 000000000..6ee441f42 --- /dev/null +++ b/3rdparty/modules/nova/manifests/migration/libvirt.pp @@ -0,0 +1,77 @@ +# == Class: nova::migration::libvirt +# +# Sets libvirt config that is required for migration +# +class nova::migration::libvirt { + + Package['libvirt'] -> File_line<| path == '/etc/libvirt/libvirtd.conf' |> + + case $::osfamily { + 'RedHat': { + file_line { '/etc/libvirt/libvirtd.conf listen_tls': + path => '/etc/libvirt/libvirtd.conf', + line => 'listen_tls = 0', + match => 'listen_tls =', + notify => Service['libvirt'], + } + + file_line { '/etc/libvirt/libvirtd.conf listen_tcp': + path => '/etc/libvirt/libvirtd.conf', + line => 'listen_tcp = 1', + match => 'listen_tcp =', + notify => Service['libvirt'], + } + + file_line { '/etc/libvirt/libvirtd.conf auth_tcp': + path => '/etc/libvirt/libvirtd.conf', + line => 'auth_tcp = "none"', + match => 'auth_tcp =', + notify => Service['libvirt'], + } + + file_line { '/etc/sysconfig/libvirtd libvirtd args': + path => '/etc/sysconfig/libvirtd', + line => 'LIBVIRTD_ARGS="--listen"', + match => 'LIBVIRTD_ARGS=', + notify => Service['libvirt'], + } + + Package['libvirt'] -> File_line<| path == '/etc/sysconfig/libvirtd' |> + } + + 'Debian': { + file_line { '/etc/libvirt/libvirtd.conf listen_tls': + path => '/etc/libvirt/libvirtd.conf', + line => 'listen_tls = 0', + match => 'listen_tls =', + notify => Service['libvirt'], + } + + file_line { '/etc/libvirt/libvirtd.conf listen_tcp': + path => '/etc/libvirt/libvirtd.conf', + line => 'listen_tcp = 1', + match => 'listen_tcp =', + notify => Service['libvirt'], + } + + file_line { '/etc/libvirt/libvirtd.conf auth_tcp': + path => '/etc/libvirt/libvirtd.conf', + line => 'auth_tcp = "none"', + match => 'auth_tcp =', + notify => Service['libvirt'], + } + file_line { "/etc/default/${::nova::compute::libvirt::libvirt_service_name} libvirtd opts": + path => "/etc/default/${::nova::compute::libvirt::libvirt_service_name}", + line => 'libvirtd_opts="-d -l"', + match => 'libvirtd_opts=', + notify => Service['libvirt'], + } + + Package['libvirt'] -> File_line<| path == "/etc/default/${::nova::compute::libvirt::libvirt_service_name}" |> + } + + default: { + warning("Unsupported osfamily: ${::osfamily}, make sure you are configuring this yourself") + } + } +} diff --git a/3rdparty/modules/nova/manifests/network.pp b/3rdparty/modules/nova/manifests/network.pp new file mode 100644 index 000000000..e928715eb --- /dev/null +++ b/3rdparty/modules/nova/manifests/network.pp @@ -0,0 +1,153 @@ +# == Class: nova::network +# +# Manages nova-network. +# +# An OpenStack deployment that includes compute and networking will use either +# nova-network or Neutron. Neutron is newer and nova-network is the legacy +# networking support built directly into Nova. However, nova-network is still +# fully supported, is not feature frozen, and is not yet officially deprecated. +# +# === Parameters: +# +# [*private_interface*] +# (optional) Interface used by private network. +# Defaults to undef +# +# [*fixed_range*] +# (optional) Fixed private network range. +# Defaults to '10.0.0.0/8' +# +# [*public_interface*] +# (optional) Interface used to connect vms to public network. +# Defaults to undef +# +# [*num_networks*] +# (optional) Number of networks that fixed range network should be +# split into. +# Defaults to 1 +# +# [*floating_range*] +# (optional) Range of floating ip addresses to create. +# Defaults to false +# +# [*enabled*] +# (optional) Whether the network service should be enabled. +# Defaults to false +# +# [*network_manager*] +# (optional) The type of network manager to use. +# Defaults to 'nova.network.manager.FlatDHCPManager' +# +# [*config_overrides*] +# (optional) Additional parameters to pass to the network manager class +# Defaults to {} +# +# [*create_networks*] +# (optional) Whether actual nova networks should be created using +# the fixed and floating ranges provided. +# Defaults to true +# +# [*ensure_package*] +# (optional) The state of the nova network package +# Defaults to 'present' +# +# [*install_service*] +# (optional) Whether to install and enable the service +# Defaults to true +# +class nova::network( + $private_interface = undef, + $fixed_range = '10.0.0.0/8', + $public_interface = undef, + $num_networks = 1, + $network_size = 255, + $floating_range = false, + $enabled = false, + $network_manager = 'nova.network.manager.FlatDHCPManager', + $config_overrides = {}, + $create_networks = true, + $ensure_package = 'present', + $install_service = true +) { + + include nova::params + + # forward all ipv4 traffic + # this is required for the vms to pass through the gateways + # public interface + Exec { + path => $::path + } + + ensure_resource('sysctl::value', 'net.ipv4.ip_forward', { value => '1' }) + + if $floating_range { + nova_config { 'DEFAULT/floating_range': value => $floating_range } + } + + if has_key($config_overrides, 'vlan_start') { + $vlan_start = $config_overrides['vlan_start'] + } else { + $vlan_start = undef + } + + if $install_service { + nova::generic_service { 'network': + enabled => $enabled, + package_name => $::nova::params::network_package_name, + service_name => $::nova::params::network_service_name, + ensure_package => $ensure_package, + before => Exec['networking-refresh'] + } + } + + if $create_networks { + nova::manage::network { 'nova-vm-net': + network => $fixed_range, + num_networks => $num_networks, + network_size => $network_size, + vlan_start => $vlan_start, + } + if $floating_range { + nova::manage::floating { 'nova-vm-floating': + network => $floating_range, + } + } + } + + case $network_manager { + + 'nova.network.manager.FlatDHCPManager': { + # I am not proud of this + $parameters = { fixed_range => $fixed_range, + public_interface => $public_interface, + flat_interface => $private_interface + } + $resource_parameters = merge($config_overrides, $parameters) + $flatdhcp_resource = {'nova::network::flatdhcp' => $resource_parameters } + create_resources('class', $flatdhcp_resource) + } + 'nova.network.manager.FlatManager': { + $parameters = { fixed_range => $fixed_range, + public_interface => $public_interface, + flat_interface => $private_interface + } + $resource_parameters = merge($config_overrides, $parameters) + $flat_resource = {'nova::network::flat' => $resource_parameters } + create_resources('class', $flat_resource) + } + 'nova.network.manager.VlanManager': { + $parameters = { fixed_range => $fixed_range, + public_interface => $public_interface, + vlan_interface => $private_interface + } + $resource_parameters = merge($config_overrides, $parameters) + $vlan_resource = { 'nova::network::vlan' => $resource_parameters } + create_resources('class', $vlan_resource) + } + default: { + fail("Unsupported network manager: ${nova::network_manager} The supported network managers are nova.network.manager.FlatManager, nova.network.FlatDHCPManager and nova.network.manager.VlanManager") + } + } + +} diff --git a/3rdparty/modules/nova/manifests/network/bridge.pp b/3rdparty/modules/nova/manifests/network/bridge.pp new file mode 100644 index 000000000..2286e0b41 --- /dev/null +++ b/3rdparty/modules/nova/manifests/network/bridge.pp @@ -0,0 +1,32 @@ +# bridge.pp +define nova::network::bridge ( + $ip, + $netmask = '255.255.255.0' +) { + + case $::osfamily { + + 'Debian': { + $context = '/files/etc/network/interfaces' + augeas { "bridge_${name}": + context => $context, + changes => [ + "set auto[child::1 = '${name}']/1 ${name}", + "set iface[. = '${name}'] ${name}", + "set iface[. = '${name}']/family inet", + "set iface[. = '${name}']/method static", + "set iface[. = '${name}']/address ${ip}", + "set iface[. = '${name}']/netmask ${netmask}", + "set iface[. = '${name}']/bridge_ports none", + ], + notify => Exec['networking-refresh'], + } + } + + 'RedHat' : { + } + + default: { fail('nova::network_bridge currently only supports osfamily Debian and RedHat') } + + } +} diff --git a/3rdparty/modules/nova/manifests/network/flat.pp b/3rdparty/modules/nova/manifests/network/flat.pp new file mode 100644 index 000000000..8c2d767d3 --- /dev/null +++ b/3rdparty/modules/nova/manifests/network/flat.pp @@ -0,0 +1,40 @@ +# == Class: nova::network::flat +# +# Configuration settings for nova flat network +# +# === Parameters: +# +# [*fixed_range*] +# (required) The IPv4 CIDR for the network +# +# [flat_interface] +# (optional) Interface that flat network will use for bridging +# Defaults to undef +# +# [*public_interface*] +# (optional) The interface to use for public traffic +# Defaults to undef +# +# [flat_network_bridge] +# (optional) The name of the bridge to use +# Defaults to 'br100' +# +class nova::network::flat ( + $fixed_range, + $flat_interface=undef, + $public_interface = undef, + $flat_network_bridge = 'br100' +) { + + if $public_interface { + nova_config { 'DEFAULT/public_interface': value => $public_interface } + } + + nova_config { + 'DEFAULT/network_manager': value => 'nova.network.manager.FlatManager'; + 'DEFAULT/fixed_range': value => $fixed_range; + 'DEFAULT/flat_interface': value => $flat_interface; + 'DEFAULT/flat_network_bridge': value => $flat_network_bridge; + } + +} diff --git a/3rdparty/modules/nova/manifests/network/flatdhcp.pp b/3rdparty/modules/nova/manifests/network/flatdhcp.pp new file mode 100644 index 000000000..76869007f --- /dev/null +++ b/3rdparty/modules/nova/manifests/network/flatdhcp.pp @@ -0,0 +1,74 @@ +# == Class: nova::network::flatdhcp +# +# Configures nova-network with flat dhcp option +# +# === Parameters: +# +# [*fixed_range*] +# (required) The IPv4 CIDR for the flat network +# +# [*flat_interface*] +# (optional) FlatDHCP will bridge into this interface +# Defaults to undef +# +# [*public_interface*] +# (optional) +# Defaults to undef +# +# [*flat_network_bridge*] +# (optional) Bridge for simple network instances ( +# Defaults to 'br100' +# +# [*force_dhcp_release*] +# (optional) Send a dhcp release on instance termination +# Defaults to true +# +# [*flat_injected*] +# (optional) Whether to attempt to inject network setup into guest +# Defaults to false +# +# [*dhcp_domain*] +# (optional) domain to use for building the hostnames +# Defaults to 'novalocal' +# +# [*dhcpbridge*] +# (optional) 'location of nova-dhcpbridge' +# Defaults to '/usr/bin/nova-dhcpbridge' +# +# [*dhcpbridge_flagfile*] +# (optional) location of flagfiles for dhcpbridge +# Defaults to '/etc/nova/nova.conf +# +class nova::network::flatdhcp ( + $fixed_range, + $flat_interface = undef, + $public_interface = undef, + $flat_network_bridge = 'br100', + $force_dhcp_release = true, + $flat_injected = false, + $dhcp_domain = 'novalocal', + $dhcpbridge = '/usr/bin/nova-dhcpbridge', + $dhcpbridge_flagfile = '/etc/nova/nova.conf' +) { + + if $::osfamily == 'RedHat' and $::operatingsystem != 'Fedora' { + package { 'dnsmasq-utils': ensure => present } + } + + if $public_interface { + nova_config { 'DEFAULT/public_interface': value => $public_interface } + } + + nova_config { + 'DEFAULT/network_manager': value => 'nova.network.manager.FlatDHCPManager'; + 'DEFAULT/fixed_range': value => $fixed_range; + 'DEFAULT/flat_interface': value => $flat_interface; + 'DEFAULT/flat_network_bridge': value => $flat_network_bridge; + 'DEFAULT/force_dhcp_release': value => $force_dhcp_release; + 'DEFAULT/flat_injected': value => $flat_injected; + 'DEFAULT/dhcp_domain': value => $dhcp_domain; + 'DEFAULT/dhcpbridge': value => $dhcpbridge; + 'DEFAULT/dhcpbridge_flagfile': value => $dhcpbridge_flagfile; + } + +} diff --git a/3rdparty/modules/nova/manifests/network/neutron.pp b/3rdparty/modules/nova/manifests/network/neutron.pp new file mode 100644 index 000000000..f9cc997ed --- /dev/null +++ b/3rdparty/modules/nova/manifests/network/neutron.pp @@ -0,0 +1,141 @@ +# == Class: nova::network::neutron +# +# Configures Nova network to use Neutron. +# +# === Parameters: +# +# [*neutron_admin_password*] +# (required) Password for connecting to Neutron network services in +# admin context through the OpenStack Identity service. +# +# [*neutron_auth_strategy*] +# (optional) Should be kept as default 'keystone' for all production deployments. +# Defaults to 'keystone' +# +# [*neutron_url*] +# (optional) URL for connecting to the Neutron networking service. +# Defaults to 'http://127.0.0.1:9696' +# +# [*neutron_url_timeout*] +# (optional) Timeout value for connecting to neutron in seconds. +# Defaults to '30' +# +# [*neutron_admin_tenant_name*] +# (optional) Tenant name for connecting to Neutron network services in +# admin context through the OpenStack Identity service. +# Defaults to 'services' +# +# [*neutron_default_tenant_id*] +# (optional) Default tenant id when creating neutron networks +# Defaults to 'default' +# +# [*neutron_region_name*] +# (optional) Region name for connecting to neutron in admin context +# through the OpenStack Identity service. +# Defaults to 'RegionOne' +# +# [*neutron_admin_username*] +# (optional) Username for connecting to Neutron network services in admin context +# through the OpenStack Identity service. +# Defaults to 'neutron' +# +# [*neutron_ovs_bridge*] +# (optional) Name of Integration Bridge used by Open vSwitch +# Defaults to 'br-int' +# +# [*neutron_extension_sync_interval*] +# (optional) Number of seconds before querying neutron for extensions +# Defaults to '600' +# +# [*neutron_ca_certificates_file*] +# (optional) Location of ca certicates file to use for neutronclient requests. +# Defaults to 'None' +# +# [*neutron_admin_auth_url*] +# (optional) Points to the OpenStack Identity server IP and port. +# This is the Identity (keystone) admin API server IP and port value, +# and not the Identity service API IP and port. +# Defaults to 'http://127.0.0.1:35357/v2.0' +# +# [*network_api_class*] +# (optional) The full class name of the network API class. +# The default configures Nova to use Neutron for the network API. +# Defaults to 'nova.network.neutronv2.api.API' +# +# [*security_group_api*] +# (optional) The full class name of the security API class. +# The default configures Nova to use Neutron for security groups. +# Set to 'nova' to use standard Nova security groups. +# Defaults to 'neutron' +# +# [*firewall_driver*] +# (optional) Firewall driver. +# This prevents nova from maintaining a firewall so it does not interfere +# with Neutron's. Set to 'nova.virt.firewall.IptablesFirewallDriver' +# to re-enable the Nova firewall. +# Defaults to 'nova.virt.firewall.NoopFirewallDriver' +# +# [*vif_plugging_is_fatal*] +# (optional) Fail to boot instance if vif plugging fails. +# This prevents nova from booting an instance if vif plugging notification +# is not received from neutron. +# Defaults to 'True' +# +# [*vif_plugging_timeout*] +# (optional) Number of seconds to wait for neutron vif plugging events. +# Set to '0' and vif_plugging_is_fatal to 'False' if vif plugging +# notification is not being used. +# Defaults to '300' +# +# [*dhcp_domain*] +# (optional) domain to use for building the hostnames +# Defaults to 'novalocal' +# +class nova::network::neutron ( + $neutron_admin_password, + $neutron_auth_strategy = 'keystone', + $neutron_url = 'http://127.0.0.1:9696', + $neutron_url_timeout = '30', + $neutron_admin_tenant_name = 'services', + $neutron_default_tenant_id = 'default', + $neutron_region_name = 'RegionOne', + $neutron_admin_username = 'neutron', + $neutron_admin_auth_url = 'http://127.0.0.1:35357/v2.0', + $neutron_ovs_bridge = 'br-int', + $neutron_extension_sync_interval = '600', + $neutron_ca_certificates_file = undef, + $network_api_class = 'nova.network.neutronv2.api.API', + $security_group_api = 'neutron', + $firewall_driver = 'nova.virt.firewall.NoopFirewallDriver', + $vif_plugging_is_fatal = true, + $vif_plugging_timeout = '300', + $dhcp_domain = 'novalocal', +) { + + nova_config { + 'DEFAULT/dhcp_domain': value => $dhcp_domain; + 'DEFAULT/firewall_driver': value => $firewall_driver; + 'DEFAULT/network_api_class': value => $network_api_class; + 'DEFAULT/security_group_api': value => $security_group_api; + 'DEFAULT/vif_plugging_is_fatal': value => $vif_plugging_is_fatal; + 'DEFAULT/vif_plugging_timeout': value => $vif_plugging_timeout; + 'neutron/auth_strategy': value => $neutron_auth_strategy; + 'neutron/url': value => $neutron_url; + 'neutron/url_timeout': value => $neutron_url_timeout; + 'neutron/admin_tenant_name': value => $neutron_admin_tenant_name; + 'neutron/default_tenant_id': value => $neutron_default_tenant_id; + 'neutron/region_name': value => $neutron_region_name; + 'neutron/admin_username': value => $neutron_admin_username; + 'neutron/admin_password': value => $neutron_admin_password, secret => true; + 'neutron/admin_auth_url': value => $neutron_admin_auth_url; + 'neutron/ovs_bridge': value => $neutron_ovs_bridge; + 'neutron/extension_sync_interval': value => $neutron_extension_sync_interval; + } + + if ! $neutron_ca_certificates_file { + nova_config { 'neutron/ca_certificates_file': ensure => absent } + } else { + nova_config { 'neutron/ca_certificates_file': value => $neutron_ca_certificates_file } + } + +} diff --git a/3rdparty/modules/nova/manifests/network/vlan.pp b/3rdparty/modules/nova/manifests/network/vlan.pp new file mode 100644 index 000000000..2328488a4 --- /dev/null +++ b/3rdparty/modules/nova/manifests/network/vlan.pp @@ -0,0 +1,67 @@ +# == Class: nova::network::vlan +# +# Configures nova network to use vlans +# +# === Parameters: +# +# [*fixed_range*] +# (required) IPv4 CIDR of the network +# +# [*vlan_interface*] +# (required) Physical ethernet adapter name for vlan networking +# +# [*public_interface*] +# (optional) Interface for public traffic +# Defaults to undef +# +# [*vlan_start*] +# (optional) First vlan to use +# Defaults to '300' +# +# [*force_dhcp_release*] +# (optional) Whether to send a dhcp release on instance termination +# Defaults to true +# +# [*dhcp_domain*] +# (optional) Domain to use for building the hostnames +# Defaults to 'novalocal' +# +# [*dhcpbridge*] +# (optional) location of nova-dhcpbridge +# Defaults to '/usr/bin/nova-dhcpbridge' +# +# [*dhcpbridge_flagfile*] +# (optional) location of flagfiles for dhcpbridge +# Defaults to '/etc/nova/nova.conf' +# +class nova::network::vlan ( + $fixed_range, + $vlan_interface, + $public_interface = undef, + $vlan_start = '300', + $force_dhcp_release = true, + $dhcp_domain = 'novalocal', + $dhcpbridge = '/usr/bin/nova-dhcpbridge', + $dhcpbridge_flagfile = '/etc/nova/nova.conf' +) { + + if $::osfamily == 'RedHat' and $::operatingsystem != 'Fedora' { + package { 'dnsmasq-utils': ensure => present } + } + + if $public_interface { + nova_config { 'DEFAULT/public_interface': value => $public_interface } + } + + nova_config { + 'DEFAULT/network_manager': value => 'nova.network.manager.VlanManager'; + 'DEFAULT/fixed_range': value => $fixed_range; + 'DEFAULT/vlan_interface': value => $vlan_interface; + 'DEFAULT/vlan_start': value => $vlan_start; + 'DEFAULT/force_dhcp_release': value => $force_dhcp_release; + 'DEFAULT/dhcp_domain': value => $dhcp_domain; + 'DEFAULT/dhcpbridge': value => $dhcpbridge; + 'DEFAULT/dhcpbridge_flagfile': value => $dhcpbridge_flagfile; + } + +} diff --git a/3rdparty/modules/nova/manifests/objectstore.pp b/3rdparty/modules/nova/manifests/objectstore.pp new file mode 100644 index 000000000..466be81db --- /dev/null +++ b/3rdparty/modules/nova/manifests/objectstore.pp @@ -0,0 +1,44 @@ +# == Class: nova::objectstore +# +# Manages the nova-objectstore service +# +# === Parameters: +# +# [*enabled*] +# (optional) Whether to enable the service +# Defaults to false +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*ensure_package*] +# (optional) The package state to set +# Defaults to 'present' +# +# [*bind_address*] +# (optional) The address to bind to +# Defaults to '0.0.0.0' +# +class nova::objectstore( + $enabled = false, + $manage_service = true, + $ensure_package = 'present', + $bind_address = '0.0.0.0' +) { + + include nova::params + + nova::generic_service { 'objectstore': + enabled => $enabled, + manage_service => $manage_service, + package_name => $::nova::params::objectstore_package_name, + service_name => $::nova::params::objectstore_service_name, + ensure_package => $ensure_package, + require => Package['nova-common'], + } + + nova_config { + 'DEFAULT/s3_listen': value => $bind_address; + } +} diff --git a/3rdparty/modules/nova/manifests/params.pp b/3rdparty/modules/nova/manifests/params.pp new file mode 100644 index 000000000..647a2d9ab --- /dev/null +++ b/3rdparty/modules/nova/manifests/params.pp @@ -0,0 +1,120 @@ +# == Class: nova::params +# +# These parameters need to be accessed from several locations and +# should be considered to be constant +class nova::params { + + case $::osfamily { + 'RedHat': { + # package names + $api_package_name = 'openstack-nova-api' + $cells_package_name = 'openstack-nova-cells' + $cert_package_name = 'openstack-nova-cert' + $common_package_name = 'openstack-nova-common' + $compute_package_name = 'openstack-nova-compute' + $conductor_package_name = 'openstack-nova-conductor' + $consoleauth_package_name = 'openstack-nova-console' + $doc_package_name = 'openstack-nova-doc' + $libvirt_package_name = 'libvirt' + $network_package_name = 'openstack-nova-network' + $numpy_package_name = 'numpy' + $objectstore_package_name = 'openstack-nova-objectstore' + $scheduler_package_name = 'openstack-nova-scheduler' + $tgt_package_name = 'scsi-target-utils' + $vncproxy_package_name = 'openstack-nova-novncproxy' + $serialproxy_package_name = 'openstack-nova-serialproxy' + $spicehtml5proxy_package_name = 'openstack-nova-console' + # service names + $api_service_name = 'openstack-nova-api' + $cells_service_name = 'openstack-nova-cells' + $cert_service_name = 'openstack-nova-cert' + $compute_service_name = 'openstack-nova-compute' + $conductor_service_name = 'openstack-nova-conductor' + $consoleauth_service_name = 'openstack-nova-consoleauth' + $libvirt_service_name = 'libvirtd' + $network_service_name = 'openstack-nova-network' + $objectstore_service_name = 'openstack-nova-objectstore' + $scheduler_service_name = 'openstack-nova-scheduler' + $tgt_service_name = 'tgtd' + $vncproxy_service_name = 'openstack-nova-novncproxy' + $serialproxy_service_name = 'openstack-nova-serialproxy' + $spicehtml5proxy_service_name = 'openstack-nova-spicehtml5proxy' + # redhat specific config defaults + $root_helper = 'sudo nova-rootwrap' + $lock_path = '/var/lib/nova/tmp' + $nova_log_group = 'nova' + case $::operatingsystem { + 'Fedora': { + $special_service_provider = undef + } + 'RedHat', 'CentOS', 'Scientific': { + if ($::operatingsystemmajrelease < 7) { + $special_service_provider = 'init' + } else { + $special_service_provider = undef + } + } + default: { + $special_service_provider = 'init' + } + } + } + 'Debian': { + # package names + $api_package_name = 'nova-api' + $cells_package_name = 'nova-cells' + $cert_package_name = 'nova-cert' + $common_package_name = 'nova-common' + $compute_package_name = 'nova-compute' + $conductor_package_name = 'nova-conductor' + $consoleauth_package_name = 'nova-consoleauth' + $doc_package_name = 'nova-doc' + $libvirt_package_name = 'libvirt-bin' + $network_package_name = 'nova-network' + $numpy_package_name = 'python-numpy' + $objectstore_package_name = 'nova-objectstore' + $scheduler_package_name = 'nova-scheduler' + $tgt_package_name = 'tgt' + $serialproxy_package_name = 'nova-serialproxy' + # service names + $api_service_name = 'nova-api' + $cells_service_name = 'nova-cells' + $cert_service_name = 'nova-cert' + $compute_service_name = 'nova-compute' + $conductor_service_name = 'nova-conductor' + $consoleauth_service_name = 'nova-consoleauth' + $libvirt_service_name = 'libvirt-bin' + $network_service_name = 'nova-network' + $objectstore_service_name = 'nova-objectstore' + $scheduler_service_name = 'nova-scheduler' + $vncproxy_service_name = 'nova-novncproxy' + $serialproxy_service_name = 'nova-serialproxy' + $tgt_service_name = 'tgt' + # debian specific nova config + $root_helper = 'sudo nova-rootwrap' + $lock_path = '/var/lock/nova' + case $::operatingsystem { + 'Debian': { + $spicehtml5proxy_package_name = 'nova-consoleproxy' + $spicehtml5proxy_service_name = 'nova-spicehtml5proxy' + $vncproxy_package_name = 'nova-consoleproxy' + # Use default provider on Debian + $special_service_provider = undef + $nova_log_group = 'nova' + } + default: { + $spicehtml5proxy_package_name = 'nova-spiceproxy' + $spicehtml5proxy_service_name = 'nova-spiceproxy' + $vncproxy_package_name = 'nova-novncproxy' + # some of the services need to be started form the special upstart provider + $special_service_provider = 'upstart' + $nova_log_group = 'adm' + } + } + } + default: { + fail("Unsupported osfamily: ${::osfamily} operatingsystem: ${::operatingsystem}, module ${module_name} only support osfamily RedHat and Debian") + } + } + +} diff --git a/3rdparty/modules/nova/manifests/policy.pp b/3rdparty/modules/nova/manifests/policy.pp new file mode 100644 index 000000000..48709da7d --- /dev/null +++ b/3rdparty/modules/nova/manifests/policy.pp @@ -0,0 +1,39 @@ +# == Class: nova::policy +# +# Configure the nova policies +# +# === Parameters +# +# [*policies*] +# (optional) Set of policies to configure for nova +# Example : +# { +# 'nova-context_is_admin' => { +# 'key' => 'context_is_admin', +# 'value' => 'true' +# }, +# 'nova-default' => { +# 'key' => 'default', +# 'value' => 'rule:admin_or_owner' +# } +# } +# Defaults to empty hash. +# +# [*policy_path*] +# (optional) Path to the nova policy.json file +# Defaults to /etc/nova/policy.json +# +class nova::policy ( + $policies = {}, + $policy_path = '/etc/nova/policy.json', +) { + + validate_hash($policies) + + Openstacklib::Policy::Base { + file_path => $policy_path, + } + + create_resources('openstacklib::policy::base', $policies) + +} diff --git a/3rdparty/modules/nova/manifests/qpid.pp b/3rdparty/modules/nova/manifests/qpid.pp new file mode 100644 index 000000000..8d83f78da --- /dev/null +++ b/3rdparty/modules/nova/manifests/qpid.pp @@ -0,0 +1,57 @@ +# == Class: nova::qpid +# +# Class for installing qpid server for nova +# +# === Parameters: +# +# [*enabled*] +# (optional) Whether to enable the service +# Defaults to true +# +# [*user*] +# (optional) The user to create in qpid +# Defaults to 'guest' +# +# [*password*] +# (optional) The password to create for the user +# Defaults to 'guest' +# +# [*file*] +# (optional) Sasl file for the user +# Defaults to '/var/lib/qpidd/qpidd.sasldb' +# +# [*realm*] +# (optional) Realm for the user +# Defaults to 'OPENSTACK' +# +class nova::qpid( + $enabled = true, + $user = 'guest', + $password = 'guest', + $file = '/var/lib/qpidd/qpidd.sasldb', + $realm = 'OPENSTACK' +) { + + # only configure nova after the queue is up + Class['qpid::server'] -> Package<| title == 'nova-common' |> + + if ($enabled) { + $service_ensure = 'running' + + qpid_user { $user: + password => $password, + file => $file, + realm => $realm, + provider => 'saslpasswd2', + require => Class['qpid::server'], + } + + } else { + $service_ensure = 'stopped' + } + + class { 'qpid::server': + service_ensure => $service_ensure + } + +} diff --git a/3rdparty/modules/nova/manifests/quota.pp b/3rdparty/modules/nova/manifests/quota.pp new file mode 100644 index 000000000..a9f7fa4d9 --- /dev/null +++ b/3rdparty/modules/nova/manifests/quota.pp @@ -0,0 +1,173 @@ +# == Class: nova::quota +# +# Class for overriding the default quota settings. +# +# === Parameters: +# +# [*quota_instances*] +# (optional) Number of instances +# Defaults to 10 +# +# [*quota_cores*] +# (optional) Number of cores +# Defaults to 20 +# +# [*quota_ram*] +# (optional) Ram in MB +# Defaults to 51200 +# +# [*quota_volumes*] +# (optional) Deprecated. This parameter does nothing and will be removed. +# Defaults to undef +# +# [*quota_gigabytes*] +# (optional) Deprecated. This parameter does nothing and will be removed. +# Defaults to undef +# +# [*quota_floating_ips*] +# (optional) Number of floating IPs +# Defaults to 10 +# +# [*quota_fixed_ips*] +# (optional) Number of fixed IPs (this should be at least the number of instances allowed) +# Defaults to -1 +# +# [*quota_metadata_items*] +# (optional) Number of metadata items per instance +# Defaults to 128 +# +# [*quota_max_injected_files*] +# (optional) Deprecated. Use quota_injected_files instead +# Defaults to undef +# +# [*quota_max_injected_file_content_bytes*] +# (optional) Deprecated. Use quota_injected_file_content_bytes instead +# Defaults to undef +# +# [*quota_max_injected_file_path_bytes*] +# (optional) Deprecated. Use quota_injected_file_path_bytes instead +# Defaults to undef +# +# [*quota_injected_files*] +# (optional) Number of files that can be injected per instance +# Defaults to 5 +# +# [*quota_injected_file_content_bytes*] +# (optional) Maximum size in bytes of injected files +# Defaults to 10240 +# +# [*quota_injected_file_path_bytes*] +# (optional) Deprecated. Use quota_injected_file_path_length instead +# Defaults to undef +# +# [*quota_injected_file_path_length*] +# (optional) Maximum size in bytes of injected file path +# Defaults to 255 +# +# [*quota_security_groups*] +# (optional) Number of security groups +# Defaults to 10 +# +# [*quota_security_group_rules*] +# (optional) Number of security group rules +# Defaults to 20 +# +# [*quota_key_pairs*] +# (optional) Number of key pairs +# Defaults to 100 +# +# [*reservation_expire*] +# (optional) Time until reservations expire in seconds +# Defaults to 86400 +# +# [*until_refresh*] +# (optional) Count of reservations until usage is refreshed +# Defaults to 0 +# +# [*max_age*] +# (optional) Number of seconds between subsequent usage refreshes +# Defaults to 0 +# +# [*quota_driver*] +# (optional) Driver to use for quota checks +# Defaults to 'nova.quota.DbQuotaDriver' +# +class nova::quota( + $quota_instances = 10, + $quota_cores = 20, + $quota_ram = 51200, + $quota_floating_ips = 10, + $quota_fixed_ips = -1, + $quota_metadata_items = 128, + $quota_injected_files = 5, + $quota_injected_file_content_bytes = 10240, + $quota_injected_file_path_length = 255, + $quota_security_groups = 10, + $quota_security_group_rules = 20, + $quota_key_pairs = 100, + $reservation_expire = 86400, + $until_refresh = 0, + $max_age = 0, + $quota_driver = 'nova.quota.DbQuotaDriver', + # DEPRECATED PARAMETERS + $quota_volumes = undef, + $quota_gigabytes = undef, + $quota_max_injected_files = undef, + $quota_injected_file_path_bytes = undef, + $quota_max_injected_file_content_bytes = undef, + $quota_max_injected_file_path_bytes = undef +) { + + if $quota_volumes { + warning('The quota_volumes parameter is deprecated and has no effect.') + } + + if $quota_gigabytes { + warning('The quota_gigabytes parameter is deprecated and has no effect.') + } + + if $quota_max_injected_files { + warning('The quota_max_injected_files parameter is deprecated, use quota_injected_files instead.') + $quota_injected_files_real = $quota_max_injected_files + } else { + $quota_injected_files_real = $quota_injected_files + } + + if $quota_max_injected_file_content_bytes { + warning('The quota_max_injected_file_content_bytes is deprecated, use quota_injected_file_content_bytes instead.') + $quota_injected_file_content_bytes_real = $quota_max_injected_file_content_bytes + } else { + $quota_injected_file_content_bytes_real = $quota_injected_file_content_bytes + } + + if $quota_max_injected_file_path_bytes { + fail('The quota_max_injected_file_path_bytes parameter is deprecated, use quota_injected_file_path_length instead.') + } + + if $quota_injected_file_path_bytes { + warning('The quota_injected_file_path_bytes parameter is deprecated, use quota_injected_file_path_length instead.') + $quota_injected_file_path_length_real = $quota_injected_file_path_bytes + } else { + $quota_injected_file_path_length_real = $quota_injected_file_path_length + } + + nova_config { + 'DEFAULT/quota_instances': value => $quota_instances; + 'DEFAULT/quota_cores': value => $quota_cores; + 'DEFAULT/quota_ram': value => $quota_ram; + 'DEFAULT/quota_floating_ips': value => $quota_floating_ips; + 'DEFAULT/quota_fixed_ips': value => $quota_fixed_ips; + 'DEFAULT/quota_metadata_items': value => $quota_metadata_items; + 'DEFAULT/quota_injected_files': value => $quota_injected_files_real; + 'DEFAULT/quota_injected_file_content_bytes': value => $quota_injected_file_content_bytes_real; + 'DEFAULT/quota_injected_file_path_length': value => $quota_injected_file_path_length_real; + 'DEFAULT/quota_security_groups': value => $quota_security_groups; + 'DEFAULT/quota_security_group_rules': value => $quota_security_group_rules; + 'DEFAULT/quota_key_pairs': value => $quota_key_pairs; + 'DEFAULT/reservation_expire': value => $reservation_expire; + 'DEFAULT/until_refresh': value => $until_refresh; + 'DEFAULT/max_age': value => $max_age; + 'DEFAULT/quota_driver': value => $quota_driver + } + +} diff --git a/3rdparty/modules/nova/manifests/rabbitmq.pp b/3rdparty/modules/nova/manifests/rabbitmq.pp new file mode 100644 index 000000000..45f7b40a7 --- /dev/null +++ b/3rdparty/modules/nova/manifests/rabbitmq.pp @@ -0,0 +1,98 @@ +# == Class: nova::rabbitmq +# +# Installs and manages rabbitmq server for nova +# +# == 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' +# +# [*port*] +# (optional) The port to use when connecting to Rabbit +# Defaults to '5672' +# +# [*virtual_host*] +# (optional) The virtual host to use when connecting to Rabbit +# Defaults to '/' +# +# [*cluster_disk_nodes*] +# (optional) Enables/disables RabbitMQ clustering. Specify an array of Rabbit Broker +# IP addresses to configure clustering. +# Defaults to false +# +# [*enabled*] +# (optional) Whether to enable the Rabbit service +# Defaults to false +# +# [*rabbitmq_class*] +# (optional) The rabbitmq puppet class to depend on, +# which is dependent on the puppet-rabbitmq version. +# Use the default for 1.x, use 'rabbitmq' for 3.x +# Defaults to 'rabbitmq::server' +# +class nova::rabbitmq( + $userid ='guest', + $password ='guest', + $port ='5672', + $virtual_host ='/', + $cluster_disk_nodes = false, + $enabled = true, + $rabbitmq_class = 'rabbitmq::server' +) { + + # only configure nova after the queue is up + Class[$rabbitmq_class] -> Anchor<| title == 'nova-start' |> + + if ($enabled) { + if $userid == 'guest' { + $delete_guest_user = false + } else { + $delete_guest_user = true + rabbitmq_user { $userid: + admin => true, + password => $password, + provider => 'rabbitmqctl', + require => Class[$rabbitmq_class], + } + # I need to figure out the appropriate permissions + rabbitmq_user_permissions { "${userid}@${virtual_host}": + configure_permission => '.*', + write_permission => '.*', + read_permission => '.*', + provider => 'rabbitmqctl', + }->Anchor<| title == 'nova-start' |> + } + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + + if $cluster_disk_nodes { + class { $rabbitmq_class: + service_ensure => $service_ensure, + port => $port, + delete_guest_user => $delete_guest_user, + config_cluster => true, + cluster_disk_nodes => $cluster_disk_nodes, + wipe_db_on_cookie_change => true, + } + } else { + class { $rabbitmq_class: + service_ensure => $service_ensure, + port => $port, + delete_guest_user => $delete_guest_user, + } + } + + if ($enabled) { + rabbitmq_vhost { $virtual_host: + provider => 'rabbitmqctl', + require => Class[$rabbitmq_class], + } + } +} diff --git a/3rdparty/modules/nova/manifests/scheduler.pp b/3rdparty/modules/nova/manifests/scheduler.pp new file mode 100644 index 000000000..e568debe2 --- /dev/null +++ b/3rdparty/modules/nova/manifests/scheduler.pp @@ -0,0 +1,36 @@ +# == Class: nova::schedule +# +# Install and manage nova scheduler +# +# === Parameters: +# +# [*enabled*] +# (optional) Whether to run the scheduler service +# Defaults to false +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*ensure_package*] +# (optional) The state of the scheduler package +# Defaults to 'present' +# +class nova::scheduler( + $enabled = false, + $manage_service = true, + $ensure_package = 'present' +) { + + include nova::db + include nova::params + + nova::generic_service { 'scheduler': + enabled => $enabled, + manage_service => $manage_service, + package_name => $::nova::params::scheduler_package_name, + service_name => $::nova::params::scheduler_service_name, + ensure_package => $ensure_package, + } + +} diff --git a/3rdparty/modules/nova/manifests/scheduler/filter.pp b/3rdparty/modules/nova/manifests/scheduler/filter.pp new file mode 100644 index 000000000..c4323951b --- /dev/null +++ b/3rdparty/modules/nova/manifests/scheduler/filter.pp @@ -0,0 +1,112 @@ +# == Class: nova:scheduler::filter +# +# This class is aim to configure nova.scheduler filter +# +# === Parameters: +# +# [*scheduler_host_manager*] +# (optional) The scheduler host manager class to use +# Defaults to 'nova.scheduler.host_manager.HostManager' +# +# [*scheduler_max_attempts*] +# (optional) Maximum number of attempts to schedule an instance +# Defaults to '3' +# +# [*scheduler_host_subset_size*] +# (optional) defines the subset size that a host is chosen from +# Defaults to '1' +# +# [*cpu_allocation_ratio*] +# (optional) Virtual CPU to Physical CPU allocation ratio +# Defaults to '16.0' +# +# [*disk_allocation_ratio*] +# (optional) Virtual disk to physical disk allocation ratio +# Defaults to '1.0' +# +# [*max_io_ops_per_host*] +# (optional) Ignore hosts that have too many builds/resizes/snaps/migrations +# Defaults to '8' +# +# [*isolated_images*] +# (optional) Images to run on isolated host +# Defaults to false +# +# [*isolated_hosts*] +# (optional) Host reserved for specific images +# Defaults to false +# +# [*max_instances_per_host*] +# (optional) Ignore hosts that have too many instances +# Defaults to '50' +# +# [*ram_allocation_ratio:*] +# (optional) Virtual ram to physical ram allocation ratio +# Defaults to '1.5' +# +# [*scheduler_available_filters*] +# (optional) Filter classes available to the scheduler +# Defaults to 'nova.scheduler.filters.all_filters' +# +# [*scheduler_default_filters*] +# (optional) An array of filters to be used by default +# Defaults to false +# +# [*scheduler_weight_classes*] +# (optional) Which weight class names to use for weighing hosts +# Defaults to 'nova.scheduler.weights.all_weighers' +# +class nova::scheduler::filter ( + $scheduler_host_manager = 'nova.scheduler.host_manager.HostManager', + $scheduler_max_attempts = '3', + $scheduler_host_subset_size = '1', + $cpu_allocation_ratio = '16.0', + $disk_allocation_ratio = '1.0', + $max_io_ops_per_host = '8', + $max_instances_per_host = '50', + $ram_allocation_ratio = '1.5', + $isolated_images = false, + $isolated_hosts = false, + $scheduler_available_filters = 'nova.scheduler.filters.all_filters', + $scheduler_default_filters = false, + $scheduler_weight_classes = 'nova.scheduler.weights.all_weighers', +) { + + nova_config { + 'DEFAULT/scheduler_host_manager': value => $scheduler_host_manager; + 'DEFAULT/scheduler_max_attempts': value => $scheduler_max_attempts; + 'DEFAULT/scheduler_host_subset_size': value => $scheduler_host_subset_size; + 'DEFAULT/cpu_allocation_ratio': value => $cpu_allocation_ratio; + 'DEFAULT/disk_allocation_ratio': value => $disk_allocation_ratio; + 'DEFAULT/max_io_ops_per_host': value => $max_io_ops_per_host; + 'DEFAULT/max_instances_per_host': value => $max_instances_per_host; + 'DEFAULT/ram_allocation_ratio': value => $ram_allocation_ratio; + 'DEFAULT/scheduler_available_filters': value => $scheduler_available_filters; + 'DEFAULT/scheduler_weight_classes': value => $scheduler_weight_classes + } + if ($scheduler_default_filters) { + nova_config { 'DEFAULT/scheduler_default_filters': value => join($scheduler_default_filters,',') + } + } else { + nova_config { 'DEFAULT/scheduler_default_filters': ensure => absent + } + } + if ($isolated_images) { + nova_config { + 'DEFAULT/isolated_images': value => join($isolated_images,',') + } + } else { + nova_config { + 'DEFAULT/isolated_images': ensure => absent + } + } + if ($isolated_hosts) { + nova_config { + 'DEFAULT/isolated_hosts': value => join($isolated_hosts,',') + } + } else { + nova_config { + 'DEFAULT/isolated_hosts': ensure => absent + } + } +} diff --git a/3rdparty/modules/nova/manifests/serialproxy.pp b/3rdparty/modules/nova/manifests/serialproxy.pp new file mode 100644 index 000000000..018d4cc96 --- /dev/null +++ b/3rdparty/modules/nova/manifests/serialproxy.pp @@ -0,0 +1,50 @@ +# == Class: nova:serialproxy +# +# Configures nova serialproxy +# +# === Parameters: +# +# [*enabled*] +# (optional) Whether to run the serialproxy service +# Defaults to false +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*serialproxy_host*] +# (optional) Host on which to listen for incoming requests +# Defaults to '0.0.0.0' +# +# [*serialproxy_port*] +# (optional) Port on which to listen for incoming requests +# Defaults to '6083' +# +# [*ensure_package*] +# (optional) The state of the nova-serialproxy package +# Defaults to 'present' +# +class nova::serialproxy( + $enabled = true, + $manage_service = true, + $serialproxy_host = '0.0.0.0', + $serialproxy_port = '6083', + $ensure_package = 'present' +) { + + include nova::params + + nova_config { + 'serial_console/serialproxy_port': value => $serialproxy_port; + 'serial_console/serialproxy_host': value => $serialproxy_host; + } + + nova::generic_service { 'serialproxy': + enabled => $enabled, + manage_service => $manage_service, + package_name => $::nova::params::serialproxy_package_name, + service_name => $::nova::params::serialproxy_service_name, + ensure_package => $ensure_package + } + +} diff --git a/3rdparty/modules/nova/manifests/spicehtml5proxy.pp b/3rdparty/modules/nova/manifests/spicehtml5proxy.pp new file mode 100644 index 000000000..b06c016ff --- /dev/null +++ b/3rdparty/modules/nova/manifests/spicehtml5proxy.pp @@ -0,0 +1,54 @@ +# == Class: nova::spice +# +# Configure spicehtml5 proxy +# +# SPICE is a new protocol which aims to address all the limitations in VNC, +# to provide good remote desktop support. This class aim to configure the nova +# services in charge of proxing websocket spicehtml5 request to kvm spice +# +# === Parameters: +# +# [*enabled*] +# (optional) enable spicehtml5proxy service +# true/false +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*host*] +# (optional) Listen address for the html5 console proxy +# Defaults to 0.0.0.0 +# +# [*port*] +# (optional) Listen port for the html5 console proxy +# Defaults to 6082 +# +# [*ensure_package*] +# (optional) Ensure package state +# Defaults to 'present' +# +class nova::spicehtml5proxy( + $enabled = false, + $manage_service = true, + $host = '0.0.0.0', + $port = '6082', + $ensure_package = 'present' +) { + + include nova::params + + nova_config { + 'DEFAULT/spicehtml5proxy_host': value => $host; + 'DEFAULT/spicehtml5proxy_port': value => $port; + } + + nova::generic_service { 'spicehtml5proxy': + enabled => $enabled, + manage_service => $manage_service, + package_name => $::nova::params::spicehtml5proxy_package_name, + service_name => $::nova::params::spicehtml5proxy_service_name, + ensure_package => $ensure_package, + } +} + diff --git a/3rdparty/modules/nova/manifests/utilities.pp b/3rdparty/modules/nova/manifests/utilities.pp new file mode 100644 index 000000000..04e817362 --- /dev/null +++ b/3rdparty/modules/nova/manifests/utilities.pp @@ -0,0 +1,21 @@ +# == Class nova::utilities +# +# Extra packages used by nova tools +# unzip swig screen parted curl euca2ools libguestfs-tools - extra packages +class nova::utilities { + if $::osfamily == 'Debian' { + ensure_packages(['unzip', 'screen', 'parted', 'curl', 'euca2ools']) + + package {'libguestfs-tools': + ensure => present, + responsefile => '/var/run/guestfs.seed', + require => File['guestfs.seed'] + } + + file {'guestfs.seed': + ensure => present, + path => '/var/run/guestfs.seed', + content => 'libguestfs0 libguestfs/update-appliance boolean true' + } + } +} diff --git a/3rdparty/modules/nova/manifests/vncproxy.pp b/3rdparty/modules/nova/manifests/vncproxy.pp new file mode 100644 index 000000000..f2ae993d7 --- /dev/null +++ b/3rdparty/modules/nova/manifests/vncproxy.pp @@ -0,0 +1,72 @@ +# == Class: nova:vncproxy +# +# Configures nova vnc proxy +# +# === Parameters: +# +# [*enabled*] +# (optional) Whether to run the vncproxy service +# Defaults to false +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*host*] +# (optional) Host on which to listen for incoming requests +# Defaults to '0.0.0.0' +# +# [*port*] +# (optional) Port on which to listen for incoming requests +# Defaults to '6080' +# +# [*ensure_package*] +# (optional) The state of the nova-novncproxy package +# Defaults to 'present' +# +# [*vncproxy_protocol*] +# (optional) The protocol to communicate with the VNC proxy server +# Defaults to 'http' +# +# [*vncproxy_path*] +# (optional) The path at the end of the uri for communication with the VNC +# proxy server +# Defaults to '/vnc_auto.html' +# +class nova::vncproxy( + $enabled = false, + $manage_service = true, + $vncproxy_protocol = 'http', + $host = '0.0.0.0', + $port = '6080', + $vncproxy_path = '/vnc_auto.html', + $ensure_package = 'present' +) { + + include nova::params + + # See http://nova.openstack.org/runnova/vncconsole.html for more details. + + nova_config { + 'DEFAULT/novncproxy_host': value => $host; + 'DEFAULT/novncproxy_port': value => $port; + } + + include ::nova::vncproxy::common + + if ! defined(Package['python-numpy']) { + package { 'python-numpy': + ensure => present, + name => $::nova::params::numpy_package_name, + } + } + nova::generic_service { 'vncproxy': + enabled => $enabled, + manage_service => $manage_service, + package_name => $::nova::params::vncproxy_package_name, + service_name => $::nova::params::vncproxy_service_name, + ensure_package => $ensure_package, + require => Package['python-numpy'] + } + +} diff --git a/3rdparty/modules/nova/manifests/vncproxy/common.pp b/3rdparty/modules/nova/manifests/vncproxy/common.pp new file mode 100644 index 000000000..15b46330d --- /dev/null +++ b/3rdparty/modules/nova/manifests/vncproxy/common.pp @@ -0,0 +1,54 @@ +# == Class: nova::vncproxy::common +# +# [*vncproxy_host*] +# (optional) The host of the VNC proxy server +# Defaults to false +# +# [*vncproxy_protocol*] +# (optional) The protocol to communicate with the VNC proxy server +# Defaults to 'http' +# +# [*vncproxy_port*] +# (optional) The port to communicate with the VNC proxy server +# Defaults to '6080' +# +# [*vncproxy_path*] +# (optional) The path at the end of the uri for communication with the VNC proxy server +# Defaults to '/vnc_auto.html' +# +class nova::vncproxy::common ( + $vncproxy_host = undef, + $vncproxy_protocol = undef, + $vncproxy_port = undef, + $vncproxy_path = undef, +) { + + $vncproxy_host_real = pick( + $vncproxy_host, + $::nova::compute::vncproxy_host, + $::nova::vncproxy::host, + false) + $vncproxy_protocol_real = pick( + $vncproxy_protocol, + $::nova::compute::vncproxy_protocol, + $::nova::vncproxy::vncproxy_protocol, + 'http') + $vncproxy_port_real = pick( + $vncproxy_port, + $::nova::compute::vncproxy_port, + $::nova::vncproxy::port, + 6080) + $vncproxy_path_real = pick( + $vncproxy_path, + $::nova::compute::vncproxy_path, + $::nova::vncproxy::vncproxy_path, + '/vnc_auto.html') + + if ($vncproxy_host_real) { + $vncproxy_base_url = "${vncproxy_protocol_real}://${vncproxy_host_real}:${vncproxy_port_real}${vncproxy_path_real}" + # config for vnc proxy + nova_config { + 'DEFAULT/novncproxy_base_url': value => $vncproxy_base_url; + } + } +} diff --git a/3rdparty/modules/nova/metadata.json b/3rdparty/modules/nova/metadata.json new file mode 100644 index 000000000..0d7f44ba0 --- /dev/null +++ b/3rdparty/modules/nova/metadata.json @@ -0,0 +1,60 @@ +{ + "name": "stackforge-nova", + "version": "5.1.0", + "author": "Puppet Labs and OpenStack Contributors", + "summary": "Puppet module for OpenStack Nova", + "license": "Apache-2.0", + "source": "git://github.com/openstack/puppet-nova.git", + "project_page": "https://launchpad.net/puppet-nova", + "issues_url": "https://bugs.launchpad.net/puppet-nova", + "dependencies": [ + {"name":"dprince/qpid","version_requirement":">=1.0.0 <2.0.0"}, + {"name":"duritong/sysctl","version_requirement":">=0.0.1 <1.0.0"}, + {"name":"stackforge/cinder","version_requirement":">=5.0.0 <6.0.0"}, + {"name":"stackforge/glance","version_requirement":">=5.0.0 <6.0.0"}, + {"name":"puppetlabs/inifile","version_requirement":">=1.0.0 <2.0.0"}, + {"name":"stackforge/keystone","version_requirement":">=5.0.0 <6.0.0"}, + {"name":"puppetlabs/rabbitmq","version_requirement":">=2.0.2 <4.0.0"}, + {"name":"puppetlabs/stdlib","version_requirement":">=4.0.0 <5.0.0"}, + {"name":"stackforge/openstacklib","version_requirement":">=5.0.0 <6.0.0"} + ], + "requirements": [ + { + "name": "pe", + "version_requirement": "3.x" + }, + { + "name": "puppet", + "version_requirement": "3.x" + } + ], + "operatingsystem_support": [ + { + "operatingsystem": "Debian", + "operatingsystemrelease": [ + "7" + ] + }, + { + "operatingsystem": "Fedora", + "operatingsystemrelease": [ + "20" + ] + }, + { + "operatingsystem": "RedHat", + "operatingsystemrelease": [ + "6.5", + "7" + ] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": [ + "12.04", + "14.04" + ] + } + ], + "description": "Installs and configures OpenStack Nova (Compute)." +} diff --git a/3rdparty/modules/nova/spec/classes/nova_api_spec.rb b/3rdparty/modules/nova/spec/classes/nova_api_spec.rb new file mode 100644 index 000000000..30fdca700 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_api_spec.rb @@ -0,0 +1,298 @@ +require 'spec_helper' + +describe 'nova::api' do + + let :pre_condition do + 'include nova' + end + + let :params do + { :admin_password => 'passw0rd' } + end + + let :facts do + { :processorcount => 5 } + end + + shared_examples 'nova-api' do + + context 'with default parameters' do + + it 'installs nova-api package and service' do + should contain_service('nova-api').with( + :name => platform_params[:nova_api_service], + :ensure => 'stopped', + :hasstatus => true, + :enable => false + ) + should contain_package('nova-api').with( + :name => platform_params[:nova_api_package], + :ensure => 'present', + :notify => 'Service[nova-api]', + :tag => ['openstack', 'nova'] + ) + should_not contain_exec('validate_nova_api') + end + + it 'configures keystone_authtoken middleware' do + should contain_nova_config( + 'keystone_authtoken/auth_host').with_value('127.0.0.1') + should contain_nova_config( + 'keystone_authtoken/auth_port').with_value('35357') + should contain_nova_config( + 'keystone_authtoken/auth_protocol').with_value('http') + should contain_nova_config( + 'keystone_authtoken/auth_uri').with_value('http://127.0.0.1:5000/') + should contain_nova_config( + 'keystone_authtoken/auth_admin_prefix').with_ensure('absent') + should contain_nova_config( + 'keystone_authtoken/auth_version').with_ensure('absent') + should contain_nova_config( + 'keystone_authtoken/admin_tenant_name').with_value('services') + should contain_nova_config( + 'keystone_authtoken/admin_user').with_value('nova') + should contain_nova_config( + 'keystone_authtoken/admin_password').with_value('passw0rd').with_secret(true) + end + + it 'configures various stuff' do + should contain_nova_config('DEFAULT/ec2_listen').with('value' => '0.0.0.0') + should contain_nova_config('DEFAULT/osapi_compute_listen').with('value' => '0.0.0.0') + should contain_nova_config('DEFAULT/metadata_listen').with('value' => '0.0.0.0') + should contain_nova_config('DEFAULT/osapi_volume_listen').with('value' => '0.0.0.0') + should contain_nova_config('DEFAULT/osapi_compute_workers').with('value' => '5') + should contain_nova_config('DEFAULT/ec2_workers').with('value' => '5') + should contain_nova_config('DEFAULT/metadata_workers').with('value' => '5') + end + + it 'do not configure v3 api' do + should contain_nova_config('osapi_v3/enabled').with('value' => false) + end + + it 'unconfigures neutron_metadata proxy' do + should contain_nova_config('neutron/service_metadata_proxy').with(:value => false) + should contain_nova_config('neutron/metadata_proxy_shared_secret').with(:ensure => 'absent') + end + end + + context 'with deprecated parameters' do + before do + params.merge!({ + :workers => 1, + }) + end + it 'configures various stuff' do + should contain_nova_config('DEFAULT/osapi_compute_workers').with('value' => '1') + end + end + + context 'with overridden parameters' do + before do + params.merge!({ + :enabled => true, + :ensure_package => '2012.1-2', + :auth_host => '10.0.0.1', + :auth_port => 1234, + :auth_protocol => 'https', + :auth_admin_prefix => '/keystone/admin', + :auth_uri => 'https://10.0.0.1:9999/', + :auth_version => 'v3.0', + :admin_tenant_name => 'service2', + :admin_user => 'nova2', + :admin_password => 'passw0rd2', + :api_bind_address => '192.168.56.210', + :metadata_listen => '127.0.0.1', + :volume_api_class => 'nova.volume.cinder.API', + :use_forwarded_for => false, + :ratelimits => '(GET, "*", .*, 100, MINUTE);(POST, "*", .*, 200, MINUTE)', + :neutron_metadata_proxy_shared_secret => 'secrete', + :osapi_compute_workers => 1, + :metadata_workers => 2, + :osapi_v3 => true, + :keystone_ec2_url => 'https://example.com:5000/v2.0/ec2tokens', + :pci_alias => "[{\"vendor_id\":\"8086\",\"product_id\":\"0126\",\"name\":\"graphic_card\"},{\"vendor_id\":\"9096\",\"product_id\":\"1520\",\"name\":\"network_card\"}]" + }) + end + + it 'installs nova-api package and service' do + should contain_package('nova-api').with( + :name => platform_params[:nova_api_package], + :ensure => '2012.1-2', + :tag => ['openstack', 'nova'] + ) + should contain_service('nova-api').with( + :name => platform_params[:nova_api_service], + :ensure => 'running', + :hasstatus => true, + :enable => true + ) + end + + it 'configures keystone_authtoken middleware' do + should contain_nova_config( + 'keystone_authtoken/auth_host').with_value('10.0.0.1') + should contain_nova_config( + 'keystone_authtoken/auth_port').with_value('1234') + should contain_nova_config( + 'keystone_authtoken/auth_protocol').with_value('https') + should contain_nova_config( + 'keystone_authtoken/auth_admin_prefix').with_value('/keystone/admin') + should contain_nova_config( + 'keystone_authtoken/auth_uri').with_value('https://10.0.0.1:9999/') + should contain_nova_config( + 'keystone_authtoken/auth_version').with_value('v3.0') + should contain_nova_config( + 'keystone_authtoken/admin_tenant_name').with_value('service2') + should contain_nova_config( + 'keystone_authtoken/admin_user').with_value('nova2') + should contain_nova_config( + 'keystone_authtoken/admin_password').with_value('passw0rd2').with_secret(true) + should contain_nova_paste_api_ini( + 'filter:ratelimit/limits').with_value('(GET, "*", .*, 100, MINUTE);(POST, "*", .*, 200, MINUTE)') + end + + it 'configures various stuff' do + should contain_nova_config('DEFAULT/ec2_listen').with('value' => '192.168.56.210') + should contain_nova_config('DEFAULT/osapi_compute_listen').with('value' => '192.168.56.210') + should contain_nova_config('DEFAULT/metadata_listen').with('value' => '127.0.0.1') + should contain_nova_config('DEFAULT/osapi_volume_listen').with('value' => '192.168.56.210') + should contain_nova_config('DEFAULT/use_forwarded_for').with('value' => false) + should contain_nova_config('DEFAULT/osapi_compute_workers').with('value' => '1') + should contain_nova_config('DEFAULT/metadata_workers').with('value' => '2') + should contain_nova_config('neutron/service_metadata_proxy').with('value' => true) + should contain_nova_config('neutron/metadata_proxy_shared_secret').with('value' => 'secrete') + should contain_nova_config('DEFAULT/keystone_ec2_url').with('value' => 'https://example.com:5000/v2.0/ec2tokens') + end + + it 'configure nova api v3' do + should contain_nova_config('osapi_v3/enabled').with('value' => true) + end + + it 'configures nova pci_alias entries' do + should contain_nova_config('DEFAULT/pci_alias').with( + 'value' => "[{\"vendor_id\":\"8086\",\"product_id\":\"0126\",\"name\":\"graphic_card\"},{\"vendor_id\":\"9096\",\"product_id\":\"1520\",\"name\":\"network_card\"}]" + ) + end + end + + [ + '/keystone/', + 'keystone/', + 'keystone', + '/keystone/admin/', + 'keystone/admin/', + 'keystone/admin' + ].each do |auth_admin_prefix| + context "with auth_admin_prefix_containing incorrect value #{auth_admin_prefix}" do + before do + params.merge!({ :auth_admin_prefix => auth_admin_prefix }) + end + it { expect { should contain_nova_config('keystone_authtoken/auth_admin_prefix') }.to \ + raise_error(Puppet::Error, /validate_re\(\): "#{auth_admin_prefix}" does not match/) } + end + end + + context 'while validating the service with default command' do + before do + params.merge!({ + :validate => true, + }) + end + it { should contain_exec('execute nova-api validation').with( + :path => '/usr/bin:/bin:/usr/sbin:/sbin', + :provider => 'shell', + :tries => '10', + :try_sleep => '2', + :command => 'nova --os-auth-url http://127.0.0.1:5000/ --os-tenant-name services --os-username nova --os-password passw0rd flavor-list', + )} + + it { should contain_anchor('create nova-api anchor').with( + :require => 'Exec[execute nova-api validation]', + )} + end + + context 'while validating the service with custom command' do + before do + params.merge!({ + :validate => true, + :validation_options => { 'nova-api' => { 'command' => 'my-script' } } + }) + end + it { should contain_exec('execute nova-api validation').with( + :path => '/usr/bin:/bin:/usr/sbin:/sbin', + :provider => 'shell', + :tries => '10', + :try_sleep => '2', + :command => 'my-script', + )} + + it { should contain_anchor('create nova-api anchor').with( + :require => 'Exec[execute nova-api validation]', + )} + end + + context 'while not managing service state' do + before do + params.merge!({ + :enabled => false, + :manage_service => false, + }) + end + + it { should contain_service('nova-api').without_ensure } + end + + context 'with default database parameters' do + let :pre_condition do + "include nova" + end + + it { should_not contain_nova_config('database/connection') } + it { should_not contain_nova_config('database/slave_connection') } + it { should_not contain_nova_config('database/idle_timeout').with_value('3600') } + end + + context 'with overridden database parameters' do + let :pre_condition do + "class { 'nova': + database_connection => 'mysql://user:pass@db/db', + slave_connection => 'mysql://user:pass@slave/db', + database_idle_timeout => '30', + } + " + end + + it { should contain_nova_config('database/connection').with_value('mysql://user:pass@db/db').with_secret(true) } + it { should contain_nova_config('database/slave_connection').with_value('mysql://user:pass@slave/db').with_secret(true) } + it { should contain_nova_config('database/idle_timeout').with_value('30') } + end + + end + + context 'on Debian platforms' do + before do + facts.merge!( :osfamily => 'Debian' ) + end + + let :platform_params do + { :nova_api_package => 'nova-api', + :nova_api_service => 'nova-api' } + end + + it_behaves_like 'nova-api' + end + + context 'on RedHat platforms' do + before do + facts.merge!( :osfamily => 'RedHat' ) + end + + let :platform_params do + { :nova_api_package => 'openstack-nova-api', + :nova_api_service => 'openstack-nova-api' } + end + + it_behaves_like 'nova-api' + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_cells_spec.rb b/3rdparty/modules/nova/spec/classes/nova_cells_spec.rb new file mode 100644 index 000000000..f6e1a67ba --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_cells_spec.rb @@ -0,0 +1,176 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# François Charlier +# +# 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 nova::cells class +# + +require 'spec_helper' + +describe 'nova::cells' do + + let :pre_condition do + "include nova" + end + + let :default_params do + {:enabled => true, + :bandwidth_update_interval => '600', + :call_timeout => '60', + :capabilities => ['hypervisor=xenserver;kvm','os=linux;windows'], + :db_check_interval => '60', + :driver => 'nova.cells.rpc_driver.CellsRPCDriver', + :instance_updated_at_threshold => '3600', + :instance_update_num_instances => '1', + :manager => 'nova.cells.manager.CellsManager', + :max_hop_count => '10', + :mute_child_interval => '300', + :mute_weight_multiplier => '-10.0', + :mute_weight_value => '1000.0', + :ram_weight_multiplier => '10.0', + :reserve_percent => '10.0', + :rpc_driver_queue_base => 'cells.intercell', + :scheduler_filter_classes => 'nova.cells.filters.all_filters', + :scheduler => 'nova.cells.scheduler.CellsScheduler', + :scheduler_retries => '10', + :scheduler_retry_delay => '2', + :scheduler_weight_classes => 'nova.cells.weights.all_weighers', + :weight_offset => '1.0', + :weight_scale => '1.0'} + end + + shared_examples_for 'nova-cells' do + + it { should contain_class('nova::params') } + + it 'installs nova-cells package' do + should contain_package('nova-cells').with( + :ensure => 'present', + :name => platform_params[:cells_package_name], + :tag => ['openstack', 'nova'] + ) + end + + it 'configures nova-cells service' do + should contain_service('nova-cells').with( + :ensure => 'running', + :name => platform_params[:cells_service_name] + ) + end + + it 'configures cell' do + should contain_nova_config('cells/bandwidth_update_interval').with(:value => '600') + should contain_nova_config('cells/call_timeout').with(:value => '60') + should contain_nova_config('cells/capabilities').with(:value => 'hypervisor=xenserver;kvm,os=linux;windows') + should contain_nova_config('cells/db_check_interval').with(:value => '60') + should contain_nova_config('cells/driver').with(:value => 'nova.cells.rpc_driver.CellsRPCDriver') + should contain_nova_config('cells/instance_updated_at_threshold').with(:value => '3600') + should contain_nova_config('cells/instance_update_num_instances').with(:value => '1') + should contain_nova_config('cells/manager').with(:value => 'nova.cells.manager.CellsManager') + should contain_nova_config('cells/max_hop_count').with(:value => '10') + should contain_nova_config('cells/mute_child_interval').with(:value => '300') + should contain_nova_config('cells/mute_weight_multiplier').with(:value => '-10.0') + should contain_nova_config('cells/mute_weight_value').with(:value => '1000.0') + should contain_nova_config('cells/ram_weight_multiplier').with(:value => '10.0') + should contain_nova_config('cells/reserve_percent').with(:value => '10.0') + should contain_nova_config('cells/rpc_driver_queue_base').with(:value => 'cells.intercell') + should contain_nova_config('cells/scheduler_filter_classes').with(:value => 'nova.cells.filters.all_filters') + should contain_nova_config('cells/scheduler_retries').with(:value => '10') + should contain_nova_config('cells/scheduler_retry_delay').with(:value => '2') + should contain_nova_config('cells/scheduler_weight_classes').with(:value => 'nova.cells.weights.all_weighers') + should contain_nova_config('cells/scheduler').with(:value => 'nova.cells.scheduler.CellsScheduler') + end + end + + shared_examples_for 'a parent cell' do + let :params do + { :enabled => true, + :cell_type => 'parent', + :cell_name => 'mommy' } + end + let :expected_params do + default_params.merge(params) + end + it { should contain_nova_config('cells/name').with_value(expected_params[:cell_name]) } + it { should contain_nova_config('DEFAULT/compute_api_class').with_value('nova.compute.cells_api.ComputeCellsAPI')} + it { should contain_nova_config('cells/cell_type').with_value('api')} + it_configures 'nova-cells' + end + + shared_examples_for 'a parent cell with manage_service as false' do + let :params do + { :enabled => true, + :manage_service => false, + :cell_type => 'parent', + :cell_name => 'mommy' } + end + let :expected_params do + default_params.merge(params) + end + it { should contain_service(platform_params[:cells_service_name]).without_ensure } + end + + shared_examples_for 'a child cell' do + let :params do + { :enabled => true, + :cell_type => 'child', + :cell_name => 'henry' } + end + let :expected_params do + default_params.merge(params) + end + it { should contain_nova_config('cells/name').with_value(expected_params[:cell_name]) } + it { should contain_nova_config('DEFAULT/quota_driver').with_value('nova.quota.NoopQuotaDriver')} + it { should contain_nova_config('cells/cell_type').with_value('compute')} + it_configures 'nova-cells' + end + + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { + :cells_package_name => 'nova-cells', + :cells_service_name => 'nova-cells' + } + end + + it_configures 'a parent cell' + it_configures 'a parent cell with manage_service as false' + it_configures 'a child cell' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { + :cells_package_name => 'openstack-nova-cells', + :cells_service_name => 'openstack-nova-cells' + } + end + + it_configures 'a parent cell' + it_configures 'a child cell' + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_cert_spec.rb b/3rdparty/modules/nova/spec/classes/nova_cert_spec.rb new file mode 100644 index 000000000..58998ee2a --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_cert_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' + +describe 'nova::cert' do + + let :pre_condition do + 'include nova' + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_behaves_like 'generic nova service', { + :name => 'nova-cert', + :package_name => 'nova-cert', + :service_name => 'nova-cert' } + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_behaves_like 'generic nova service', { + :name => 'nova-cert', + :package_name => 'openstack-nova-cert', + :service_name => 'openstack-nova-cert' } + end +end diff --git a/3rdparty/modules/nova/spec/classes/nova_client_spec.rb b/3rdparty/modules/nova/spec/classes/nova_client_spec.rb new file mode 100644 index 000000000..4caae33aa --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_client_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' + +describe 'nova::client' do + + context 'with default parameters' do + it { + should contain_package('python-novaclient').with( + :ensure => 'present', + :tag => ['openstack', 'nova'] + ) + } + end + + context 'with ensure parameter provided' do + let :params do + { :ensure => '2012.1-2' } + end + it { should contain_package('python-novaclient').with_ensure('2012.1-2') } + end +end diff --git a/3rdparty/modules/nova/spec/classes/nova_compute_ironic_spec.rb b/3rdparty/modules/nova/spec/classes/nova_compute_ironic_spec.rb new file mode 100644 index 000000000..87e239a78 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_compute_ironic_spec.rb @@ -0,0 +1,13 @@ +require 'spec_helper' +describe 'nova::compute::ironic' do + + it 'configures ironic in nova.conf' do + should contain_nova_config('ironic/admin_username').with_value('admin') + should contain_nova_config('ironic/admin_password').with_value('ironic') + should contain_nova_config('ironic/admin_url').with_value('http://127.0.0.1:35357/v2.0') + should contain_nova_config('ironic/admin_tenant_name').with_value('services') + should contain_nova_config('ironic/api_endpoint').with_value('http://127.0.0.1:6385/v1') + should contain_nova_config('DEFAULT/compute_driver').with_value('nova.virt.ironic.IronicDriver') + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_compute_libvirt_spec.rb b/3rdparty/modules/nova/spec/classes/nova_compute_libvirt_spec.rb new file mode 100644 index 000000000..4080d102c --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_compute_libvirt_spec.rb @@ -0,0 +1,272 @@ +require 'spec_helper' +describe 'nova::compute::libvirt' do + + let :pre_condition do + "include nova\ninclude nova::compute" + end + + describe 'on debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + describe 'with default parameters' do + + it { should contain_class('nova::params')} + + it { should contain_package('nova-compute-kvm').with( + :ensure => 'present', + :before => 'Package[nova-compute]', + :tag => ['openstack', 'nova'] + ) } + + it { should contain_package('libvirt').with( + :name => 'libvirt-bin', + :ensure => 'present' + ) } + + it { should contain_service('libvirt').with( + :name => 'libvirt-bin', + :enable => true, + :ensure => 'running', + :provider => 'upstart', + :require => 'Package[libvirt]', + :before => 'Service[nova-compute]' + )} + + it { should contain_nova_config('DEFAULT/compute_driver').with_value('libvirt.LibvirtDriver')} + it { should contain_nova_config('libvirt/virt_type').with_value('kvm')} + it { should contain_nova_config('libvirt/cpu_mode').with_value('host-model')} + it { should contain_nova_config('libvirt/disk_cachemodes').with_ensure('absent')} + it { should contain_nova_config('libvirt/inject_password').with_value(false)} + it { should contain_nova_config('libvirt/inject_key').with_value(false)} + it { should contain_nova_config('libvirt/inject_partition').with_value(-2)} + it { should contain_nova_config('DEFAULT/vncserver_listen').with_value('127.0.0.1')} + it { should contain_nova_config('DEFAULT/remove_unused_base_images').with_ensure('absent')} + it { should contain_nova_config('DEFAULT/remove_unused_original_minimum_age_seconds').with_ensure('absent')} + it { should contain_nova_config('libvirt/remove_unused_kernels').with_ensure('absent')} + it { should contain_nova_config('libvirt/remove_unused_resized_minimum_age_seconds').with_ensure('absent')} + end + + describe 'with params' do + let :params do + { :libvirt_virt_type => 'qemu', + :vncserver_listen => '0.0.0.0', + :libvirt_cpu_mode => 'host-passthrough', + :libvirt_disk_cachemodes => ['file=directsync','block=none'], + :remove_unused_base_images => true, + :remove_unused_kernels => true, + :remove_unused_resized_minimum_age_seconds => 3600, + :remove_unused_original_minimum_age_seconds => 3600, + :libvirt_service_name => 'custom_service' + } + end + + it { should contain_nova_config('libvirt/virt_type').with_value('qemu')} + it { should contain_nova_config('libvirt/cpu_mode').with_value('host-passthrough')} + it { should contain_nova_config('libvirt/disk_cachemodes').with_value('file=directsync,block=none')} + it { should contain_nova_config('DEFAULT/vncserver_listen').with_value('0.0.0.0')} + it { should contain_nova_config('DEFAULT/remove_unused_base_images').with_value(true)} + it { should contain_nova_config('DEFAULT/remove_unused_original_minimum_age_seconds').with_value(3600)} + it { should contain_nova_config('libvirt/remove_unused_kernels').with_value(true)} + it { should contain_nova_config('libvirt/remove_unused_resized_minimum_age_seconds').with_value(3600)} + it { should contain_service('libvirt').with( + :name => 'custom_service', + :enable => true, + :ensure => 'running', + :require => 'Package[libvirt]', + :before => 'Service[nova-compute]' + )} + end + + describe 'with deprecated params' do + let :params do + { :libvirt_type => 'qemu' + } + end + + it { should contain_nova_config('libvirt/virt_type').with_value('qemu')} + end + + describe 'with migration_support enabled' do + + context 'with vncserver_listen set to 0.0.0.0' do + let :params do + { :vncserver_listen => '0.0.0.0', + :migration_support => true } + end + + it { should contain_class('nova::migration::libvirt')} + it { should contain_nova_config('DEFAULT/vncserver_listen').with_value('0.0.0.0')} + it { should contain_file_line('/etc/default/libvirt-bin libvirtd opts').with(:line => 'libvirtd_opts="-d -l"') } + end + + context 'with vncserver_listen set to ::0' do + let :params do + { :vncserver_listen => '::0', + :migration_support => true } + end + + it { should contain_class('nova::migration::libvirt')} + it { should contain_nova_config('DEFAULT/vncserver_listen').with_value('::0')} + it { should contain_file_line('/etc/default/libvirt-bin libvirtd opts').with(:line => 'libvirtd_opts="-d -l"') } + end + + context 'with vncserver_listen not set to 0.0.0.0' do + let :params do + { :vncserver_listen => '127.0.0.1', + :migration_support => true } + end + + it { expect { should contain_class('nova::compute::libvirt') }.to \ + raise_error(Puppet::Error, /For migration support to work, you MUST set vncserver_listen to '0.0.0.0' or '::0'/) } + end + + context 'with custom libvirt service name on Debian plateforms' do + let :params do + { :libvirt_service_name => 'libvirtd', + :vncserver_listen => '0.0.0.0', + :migration_support => true } + end + it { should contain_file_line('/etc/default/libvirtd libvirtd opts').with(:line => 'libvirtd_opts="-d -l"') } + + end + end + end + + + describe 'on rhel platforms' do + let :facts do + { :operatingsystem => 'RedHat', :osfamily => 'RedHat', + :operatingsystemrelease => 6.5 } + end + + describe 'with default parameters' do + + it { should contain_class('nova::params')} + + it { should contain_package('libvirt').with( + :name => 'libvirt', + :ensure => 'present' + ) } + + it { should contain_service('libvirt').with( + :name => 'libvirtd', + :enable => true, + :ensure => 'running', + :provider => nil, + :require => 'Package[libvirt]', + :before => 'Service[nova-compute]' + )} + it { should contain_service('messagebus').with( + :ensure => 'running', + :enable => true, + :before => 'Service[libvirt]', + :provider => nil + ) } + + describe 'on rhel 7' do + let :facts do + super().merge(:operatingsystemrelease => 7.0) + end + + it { should contain_service('libvirt').with( + :provider => nil + )} + + it { should contain_service('messagebus').with( + :provider => nil + )} + end + + it { should contain_nova_config('DEFAULT/compute_driver').with_value('libvirt.LibvirtDriver')} + it { should contain_nova_config('libvirt/virt_type').with_value('kvm')} + it { should contain_nova_config('libvirt/inject_password').with_value(false)} + it { should contain_nova_config('libvirt/inject_key').with_value(false)} + it { should contain_nova_config('libvirt/inject_partition').with_value(-2)} + it { should contain_nova_config('DEFAULT/vncserver_listen').with_value('127.0.0.1')} + it { should contain_nova_config('DEFAULT/remove_unused_base_images').with_ensure('absent')} + it { should contain_nova_config('DEFAULT/remove_unused_original_minimum_age_seconds').with_ensure('absent')} + it { should contain_nova_config('libvirt/remove_unused_kernels').with_ensure('absent')} + it { should contain_nova_config('libvirt/remove_unused_resized_minimum_age_seconds').with_ensure('absent')} + end + + describe 'with params' do + let :params do + { :libvirt_virt_type => 'qemu', + :vncserver_listen => '0.0.0.0', + :remove_unused_base_images => true, + :remove_unused_kernels => true, + :remove_unused_resized_minimum_age_seconds => 3600, + :remove_unused_original_minimum_age_seconds => 3600 + } + end + + it { should contain_nova_config('libvirt/virt_type').with_value('qemu')} + it { should contain_nova_config('DEFAULT/vncserver_listen').with_value('0.0.0.0')} + it { should contain_nova_config('DEFAULT/remove_unused_base_images').with_value(true)} + it { should contain_nova_config('DEFAULT/remove_unused_original_minimum_age_seconds').with_value(3600)} + it { should contain_nova_config('libvirt/remove_unused_kernels').with_value(true)} + it { should contain_nova_config('libvirt/remove_unused_resized_minimum_age_seconds').with_value(3600)} + end + + describe 'with deprecated params' do + let :params do + { :libvirt_type => 'qemu' + } + end + + it { should contain_nova_config('libvirt/virt_type').with_value('qemu')} + end + + describe 'with migration_support enabled' do + + context 'with vncserver_listen set to 0.0.0.0' do + let :params do + { :vncserver_listen => '0.0.0.0', + :migration_support => true } + end + + it { should contain_class('nova::migration::libvirt')} + it { should contain_nova_config('DEFAULT/vncserver_listen').with_value('0.0.0.0')} + end + + context 'with vncserver_listen not set to 0.0.0.0' do + let :params do + { :vncserver_listen => '127.0.0.1', + :migration_support => true } + end + + it { expect { should contain_class('nova::compute::libvirt') }.to \ + raise_error(Puppet::Error, /For migration support to work, you MUST set vncserver_listen to '0.0.0.0'/) } + end + end + + describe 'with default parameters on Fedora' do + let :facts do + { :operatingsystem => 'Fedora', :osfamily => 'RedHat' } + end + + it { should contain_class('nova::params')} + + it { should contain_package('libvirt').with( + :name => 'libvirt', + :ensure => 'present' + ) } + + it { should contain_service('libvirt').with( + :name => 'libvirtd', + :enable => true, + :ensure => 'running', + :provider => nil, + :require => 'Package[libvirt]', + :before => 'Service[nova-compute]' + )} + + it { should contain_nova_config('DEFAULT/compute_driver').with_value('libvirt.LibvirtDriver')} + it { should contain_nova_config('libvirt/virt_type').with_value('kvm')} + it { should contain_nova_config('DEFAULT/vncserver_listen').with_value('127.0.0.1')} + end + + end +end diff --git a/3rdparty/modules/nova/spec/classes/nova_compute_neutron_spec.rb b/3rdparty/modules/nova/spec/classes/nova_compute_neutron_spec.rb new file mode 100644 index 000000000..030968fa8 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_compute_neutron_spec.rb @@ -0,0 +1,58 @@ +require 'spec_helper' +describe 'nova::compute::neutron' do + + context 'with default parameters' do + it { should contain_nova_config('libvirt/vif_driver').with_value('nova.virt.libvirt.vif.LibvirtGenericVIFDriver')} + it { should contain_nova_config('DEFAULT/force_snat_range').with(:value => '0.0.0.0/0') } + end + + context 'when overriding params' do + let :params do + {:libvirt_vif_driver => 'foo' } + end + it { should contain_nova_config('libvirt/vif_driver').with_value('foo')} + it { should contain_nova_config('DEFAULT/force_snat_range').with_ensure(:absent) } + end + + context 'when overriding with a removed libvirt_vif_driver param' do + let :params do + {:libvirt_vif_driver => 'nova.virt.libvirt.vif.LibvirtOpenVswitchDriver' } + end + it 'should fails to configure libvirt_vif_driver with old OVS driver' do + expect { subject }.to raise_error(Puppet::Error, /nova.virt.libvirt.vif.LibvirtOpenVswitchDriver as vif_driver is removed from Icehouse/) + end + end + + context 'with force_snat_range parameter set to false' do + let :params do + { :force_snat_range => false, } + end + it { should contain_nova_config('DEFAULT/force_snat_range').with_ensure('absent') } + end + + context 'with force_snat_range parameter set to 10.0.0.0/24' do + let :params do + { :force_snat_range => '10.0.0.0/24', } + end + + it { should contain_nova_config('DEFAULT/force_snat_range').with_value('10.0.0.0/24') } + end + + context 'with force_snat_range parameter set to fe80::/64' do + let :params do + { :force_snat_range => 'fe80::/64', } + end + + it { should contain_nova_config('DEFAULT/force_snat_range').with_value('fe80::/64') } + end + + context 'with force_snat_range parameter set ip without mask' do + let :params do + { :force_snat_range => '10.0.0.0', } + end + + it { expect { should contain_nova_config('DEFAULT/force_snat_range') }.to \ + raise_error(Puppet::Error, /force_snat_range should be IPv4 or IPv6/) } + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_compute_rbd_spec.rb b/3rdparty/modules/nova/spec/classes/nova_compute_rbd_spec.rb new file mode 100644 index 000000000..60eea2f17 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_compute_rbd_spec.rb @@ -0,0 +1,127 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Unit tests for nova::compute::rbd class +# + +require 'spec_helper' + +describe 'nova::compute::rbd' do + + let :params do + { :libvirt_rbd_user => 'nova', + :libvirt_rbd_secret_uuid => false, + :libvirt_images_rbd_pool => 'rbd', + :libvirt_images_rbd_ceph_conf => '/etc/ceph/ceph.conf' } + end + + shared_examples_for 'nova compute rbd' do + + it { should contain_class('nova::params') } + + it 'configure nova.conf with default parameters' do + should contain_nova_config('libvirt/images_type').with_value('rbd') + should contain_nova_config('libvirt/images_rbd_pool').with_value('rbd') + should contain_nova_config('libvirt/images_rbd_ceph_conf').with_value('/etc/ceph/ceph.conf') + should contain_nova_config('libvirt/rbd_user').with_value('nova') + end + + context 'when overriding default parameters' do + before :each do + params.merge!( + :libvirt_rbd_user => 'joe', + :libvirt_rbd_secret_uuid => false, + :libvirt_images_rbd_pool => 'AnotherPool', + :libvirt_images_rbd_ceph_conf => '/tmp/ceph.conf' + ) + end + + it 'configure nova.conf with overridden parameters' do + should contain_nova_config('libvirt/images_type').with_value('rbd') + should contain_nova_config('libvirt/images_rbd_pool').with_value('AnotherPool') + should contain_nova_config('libvirt/images_rbd_ceph_conf').with_value('/tmp/ceph.conf') + should contain_nova_config('libvirt/rbd_user').with_value('joe') + end + end + + context 'when using cephx' do + before :each do + params.merge!( + :libvirt_rbd_secret_uuid => 'UUID', + :rbd_keyring => 'client.rbd_test' + ) + end + + it 'configure nova.conf with RBD secret UUID' do + should contain_nova_config('libvirt/rbd_secret_uuid').with_value('UUID') + end + + it 'configure ceph on compute nodes' do + verify_contents(subject, '/etc/nova/secret.xml', [ + "", + " ", + " client.rbd_test secret", + " ", + " UUID", + "" + ]) + should contain_exec('get-or-set virsh secret').with( + :command => '/usr/bin/virsh secret-define --file /etc/nova/secret.xml | /usr/bin/awk \'{print $2}\' | sed \'/^$/d\' > /etc/nova/virsh.secret', + :creates => '/etc/nova/virsh.secret', + :require => 'File[/etc/nova/secret.xml]' + ) + + should contain_exec('set-secret-value virsh').with( + :command => "/usr/bin/virsh secret-set-value --secret UUID --base64 $(ceph auth get-key client.rbd_test)" + ) + end + end + + context 'when using cephx and passing libvirt_rbd_secret_key' do + before :each do + params.merge!( + :libvirt_rbd_secret_uuid => 'UUID', + :libvirt_rbd_secret_key => 'LIBVIRT/SECRET/KEY', + ) + end + + it 'set libvirt secret key from passed key' do + should contain_exec('set-secret-value virsh').with( + :command => "/usr/bin/virsh secret-set-value --secret #{params[:libvirt_rbd_secret_uuid]} --base64 #{params[:libvirt_rbd_secret_key]}" + ) + end + end + + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'nova compute rbd' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'nova compute rbd' + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_compute_serial_spec.rb b/3rdparty/modules/nova/spec/classes/nova_compute_serial_spec.rb new file mode 100644 index 000000000..ba835842e --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_compute_serial_spec.rb @@ -0,0 +1,21 @@ +require 'spec_helper' +describe 'nova::compute::serial' do + + it { should contain_nova_config('serial_console/enabled').with_value('true') } + it { should contain_nova_config('serial_console/port_range').with_value('10000:20000')} + it { should contain_nova_config('serial_console/base_url').with_value('ws://127.0.0.1:6083/')} + it { should contain_nova_config('serial_console/listen').with_value('127.0.0.1')} + it { should contain_nova_config('serial_console/proxyclient_address').with_value('127.0.0.1')} + + context 'when overriding params' do + let :params do + { + :proxyclient_address => '10.10.10.10', + :listen => '10.10.11.11', + } + end + it { should contain_nova_config('serial_console/proxyclient_address').with_value('10.10.10.10')} + it { should contain_nova_config('serial_console/listen').with_value('10.10.11.11')} + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_compute_spec.rb b/3rdparty/modules/nova/spec/classes/nova_compute_spec.rb new file mode 100644 index 000000000..e1ecd08be --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_compute_spec.rb @@ -0,0 +1,215 @@ +require 'spec_helper' + +describe 'nova::compute' do + + let :pre_condition do + 'include nova' + end + + shared_examples 'nova-compute' do + + context 'with default parameters' do + + it 'installs nova-compute package and service' do + should contain_service('nova-compute').with({ + :name => platform_params[:nova_compute_service], + :ensure => 'stopped', + :hasstatus => true, + :enable => false + }) + should contain_package('nova-compute').with({ + :name => platform_params[:nova_compute_package], + :tag => ['openstack', 'nova'] + }) + end + + it { should contain_nova_config('DEFAULT/network_device_mtu').with(:ensure => 'absent') } + it { should_not contain_nova_config('DEFAULT/novncproxy_base_url') } + + it { should_not contain_package('bridge-utils').with( + :ensure => 'present', + :before => 'Nova::Generic_service[compute]' + ) } + + it { should contain_package('pm-utils').with( + :ensure => 'present' + ) } + + it { should contain_nova_config('DEFAULT/force_raw_images').with(:value => true) } + + it 'configures availability zones' do + should contain_nova_config('DEFAULT/default_availability_zone').with_value('nova') + should contain_nova_config('DEFAULT/internal_service_availability_zone').with_value('internal') + end + + end + + context 'with overridden parameters' do + let :params do + { :enabled => true, + :ensure_package => '2012.1-2', + :vncproxy_host => '127.0.0.1', + :network_device_mtu => 9999, + :force_raw_images => false, + :reserved_host_memory => '0', + :compute_manager => 'ironic.nova.compute.manager.ClusteredComputeManager', + :pci_passthrough => "[{\"vendor_id\":\"8086\",\"product_id\":\"0126\"},{\"vendor_id\":\"9096\",\"product_id\":\"1520\",\"physical_network\":\"physnet1\"}]", + :default_availability_zone => 'az1', + :default_schedule_zone => 'az2', + :internal_service_availability_zone => 'az_int1', + } + end + + it 'installs nova-compute package and service' do + should contain_service('nova-compute').with({ + :name => platform_params[:nova_compute_service], + :ensure => 'running', + :hasstatus => true, + :enable => true + }) + should contain_package('nova-compute').with({ + :name => platform_params[:nova_compute_package], + :ensure => '2012.1-2', + :tag => ['openstack', 'nova'] + }) + end + + it 'configures ironic in nova.conf' do + should contain_nova_config('DEFAULT/reserved_host_memory_mb').with_value('0') + should contain_nova_config('DEFAULT/compute_manager').with_value('ironic.nova.compute.manager.ClusteredComputeManager') + end + + it 'configures network_device_mtu' do + should contain_nova_config('DEFAULT/network_device_mtu').with_value('9999') + end + + it 'configures vnc in nova.conf' do + should contain_nova_config('DEFAULT/vnc_enabled').with_value(true) + should contain_nova_config('DEFAULT/vncserver_proxyclient_address').with_value('127.0.0.1') + should contain_nova_config('DEFAULT/novncproxy_base_url').with_value( + 'http://127.0.0.1:6080/vnc_auto.html' + ) + end + + it 'configures availability zones' do + should contain_nova_config('DEFAULT/default_availability_zone').with_value('az1') + should contain_nova_config('DEFAULT/default_schedule_zone').with_value('az2') + should contain_nova_config('DEFAULT/internal_service_availability_zone').with_value('az_int1') + end + + it { should contain_nova_config('DEFAULT/force_raw_images').with(:value => false) } + + it 'configures nova pci_passthrough_whitelist entries' do + should contain_nova_config('DEFAULT/pci_passthrough_whitelist').with( + 'value' => "[{\"vendor_id\":\"8086\",\"product_id\":\"0126\"},{\"vendor_id\":\"9096\",\"product_id\":\"1520\",\"physical_network\":\"physnet1\"}]" + ) + end + end + + context 'with neutron_enabled set to false' do + let :params do + { :neutron_enabled => false } + end + + it 'installs bridge-utils package for nova-network' do + should contain_package('bridge-utils').with( + :ensure => 'present', + :before => 'Nova::Generic_service[compute]' + ) + end + end + + context 'with vnc_enabled set to false' do + let :params do + { :vnc_enabled => false } + end + + it 'disables vnc in nova.conf' do + should contain_nova_config('DEFAULT/vnc_enabled').with_value(false) + should contain_nova_config('DEFAULT/vncserver_proxyclient_address').with_value('127.0.0.1') + should_not contain_nova_config('DEFAULT/novncproxy_base_url') + end + end + + context 'with force_config_drive parameter set to true' do + let :params do + { :force_config_drive => true } + end + + it { should contain_nova_config('DEFAULT/force_config_drive').with_value(true) } + end + + context 'while not managing service state' do + let :params do + { :enabled => false, + :manage_service => false, + } + end + + it { should contain_service('nova-compute').without_ensure } + end + + context 'with instance_usage_audit parameter set to false' do + let :params do + { :instance_usage_audit => false, } + end + + it { should contain_nova_config('DEFAULT/instance_usage_audit').with_ensure('absent') } + it { should contain_nova_config('DEFAULT/instance_usage_audit_period').with_ensure('absent') } + end + + context 'with instance_usage_audit parameter and wrong period' do + let :params do + { :instance_usage_audit => true, + :instance_usage_audit_period => 'fake', } + end + + it { should contain_nova_config('DEFAULT/instance_usage_audit').with_ensure('absent') } + it { should contain_nova_config('DEFAULT/instance_usage_audit_period').with_ensure('absent') } + end + + context 'with instance_usage_audit parameter and period' do + let :params do + { :instance_usage_audit => true, + :instance_usage_audit_period => 'year', } + end + + it { should contain_nova_config('DEFAULT/instance_usage_audit').with_value(true) } + it { should contain_nova_config('DEFAULT/instance_usage_audit_period').with_value('year') } + end + context 'with vnc_keymap set to fr' do + let :params do + { :vnc_keymap => 'fr', } + end + + it { should contain_nova_config('DEFAULT/vnc_keymap').with_value('fr') } + end + end + + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { :nova_compute_package => 'nova-compute', + :nova_compute_service => 'nova-compute' } + end + + it_behaves_like 'nova-compute' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :nova_compute_package => 'openstack-nova-compute', + :nova_compute_service => 'openstack-nova-compute' } + end + + it_behaves_like 'nova-compute' + end +end diff --git a/3rdparty/modules/nova/spec/classes/nova_compute_spice_spec.rb b/3rdparty/modules/nova/spec/classes/nova_compute_spice_spec.rb new file mode 100644 index 000000000..56ed62171 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_compute_spice_spec.rb @@ -0,0 +1,23 @@ +require 'spec_helper' +describe 'nova::compute::spice' do + + it { should contain_nova_config('spice/enabled').with_value('true')} + it { should contain_nova_config('spice/agent_enabled').with_value('true')} + it { should contain_nova_config('spice/server_proxyclient_address').with_value('127.0.0.1')} + it { should_not contain_nova_config('spice/html5proxy_base_url')} + it { should contain_nova_config('spice/server_listen').with_value(nil)} + + context 'when overriding params' do + let :params do + { + :proxy_host => '10.10.10.10', + :server_listen => '10.10.11.11', + :agent_enabled => false + } + end + it { should contain_nova_config('spice/html5proxy_base_url').with_value('http://10.10.10.10:6082/spice_auto.html')} + it { should contain_nova_config('spice/server_listen').with_value('10.10.11.11')} + it { should contain_nova_config('spice/agent_enabled').with_value('false')} + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_compute_vmware_spec.rb b/3rdparty/modules/nova/spec/classes/nova_compute_vmware_spec.rb new file mode 100644 index 000000000..8242bdf93 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_compute_vmware_spec.rb @@ -0,0 +1,52 @@ +require 'spec_helper' + +describe 'nova::compute::vmware' do + + let :params do + {:host_ip => '127.0.0.1', + :host_username => 'root', + :host_password => 'passw0rd', + :cluster_name => 'cluster1'} + end + + let :optional_params do + {:api_retry_count => 10, + :maximum_objects => 100, + :task_poll_interval => 10.5, + :use_linked_clone => false, + :wsdl_location => 'http://127.0.0.1:8080/vmware/SDK/wsdl/vim25/vimService.wsdl'} + end + + it 'configures vmwareapi in nova.conf' do + should contain_nova_config('DEFAULT/compute_driver').with_value('vmwareapi.VMwareVCDriver') + should contain_nova_config('VMWARE/host_ip').with_value(params[:host_ip]) + should contain_nova_config('VMWARE/host_username').with_value(params[:host_username]) + should contain_nova_config('VMWARE/host_password').with_value(params[:host_password]) + should contain_nova_config('VMWARE/cluster_name').with_value(params[:cluster_name]) + should contain_nova_config('VMWARE/api_retry_count').with_value(5) + should contain_nova_config('VMWARE/maximum_objects').with_value(100) + should contain_nova_config('VMWARE/task_poll_interval').with_value(5.0) + should contain_nova_config('VMWARE/use_linked_clone').with_value(true) + should_not contain_nova_config('VMWARE/wsdl_location') + end + + it 'installs suds python package' do + should contain_package('python-suds').with( + :ensure => 'present' + ) + end + + context 'with optional parameters' do + before :each do + params.merge!(optional_params) + end + + it 'configures vmwareapi in nova.conf' do + should contain_nova_config('VMWARE/api_retry_count').with_value(params[:api_retry_count]) + should contain_nova_config('VMWARE/maximum_objects').with_value(params[:maximum_objects]) + should contain_nova_config('VMWARE/task_poll_interval').with_value(params[:task_poll_interval]) + should contain_nova_config('VMWARE/use_linked_clone').with_value(false) + should contain_nova_config('VMWARE/wsdl_location').with_value(params[:wsdl_location]) + end + end +end diff --git a/3rdparty/modules/nova/spec/classes/nova_compute_xenserver_spec.rb b/3rdparty/modules/nova/spec/classes/nova_compute_xenserver_spec.rb new file mode 100644 index 000000000..620bf4892 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_compute_xenserver_spec.rb @@ -0,0 +1,29 @@ +require 'spec_helper' + +describe 'nova::compute::xenserver' do + + let :params do + { :xenapi_connection_url => 'https://127.0.0.1', + :xenapi_connection_username => 'root', + :xenapi_connection_password => 'passw0rd' } + end + + context 'with required parameters' do + + it 'configures xenapi in nova.conf' do + should contain_nova_config('DEFAULT/compute_driver').with_value('xenapi.XenAPIDriver') + should contain_nova_config('DEFAULT/connection_type').with_value('xenapi') + should contain_nova_config('DEFAULT/xenapi_connection_url').with_value(params[:xenapi_connection_url]) + should contain_nova_config('DEFAULT/xenapi_connection_username').with_value(params[:xenapi_connection_username]) + should contain_nova_config('DEFAULT/xenapi_connection_password').with_value(params[:xenapi_connection_password]) + should contain_nova_config('DEFAULT/xenapi_inject_image').with_value(false) + end + + it 'installs xenapi with pip' do + should contain_package('xenapi').with( + :ensure => 'present', + :provider => 'pip' + ) + end + end +end diff --git a/3rdparty/modules/nova/spec/classes/nova_conductor_spec.rb b/3rdparty/modules/nova/spec/classes/nova_conductor_spec.rb new file mode 100644 index 000000000..1df7aad70 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_conductor_spec.rb @@ -0,0 +1,106 @@ +require 'spec_helper' + +describe 'nova::conductor' do + + let :pre_condition do + 'include nova' + end + + let :params do + { :enabled => true } + end + + shared_examples 'nova-conductor' do + + + it { should contain_package('nova-conductor').with( + :name => platform_params[:conductor_package_name], + :ensure => 'present' + ) } + + it { should contain_service('nova-conductor').with( + :name => platform_params[:conductor_service_name], + :hasstatus => 'true', + :ensure => 'running' + )} + + context 'with manage_service as false' do + let :params do + { :enabled => true, + :manage_service => false + } + end + it { should contain_service('nova-conductor').without_ensure } + end + + context 'with package version' do + let :params do + { :ensure_package => '2012.1-2' } + end + + it { should contain_package('nova-conductor').with( + :ensure => params[:ensure_package] + )} + end + + context 'with overriden workers parameter' do + before do + params.merge!({:workers => '5' }) + end + it { should contain_nova_config('conductor/workers').with_value('5') } + end + + context 'with default database parameters' do + let :pre_condition do + "include nova" + end + + it { should_not contain_nova_config('database/connection') } + it { should_not contain_nova_config('database/slave_connection') } + it { should_not contain_nova_config('database/idle_timeout').with_value('3600') } + end + + context 'with overridden database parameters' do + let :pre_condition do + "class { 'nova': + database_connection => 'mysql://user:pass@db/db', + slave_connection => 'mysql://user:pass@slave/db', + database_idle_timeout => '30', + } + " + end + + it { should contain_nova_config('database/connection').with_value('mysql://user:pass@db/db').with_secret(true) } + it { should contain_nova_config('database/slave_connection').with_value('mysql://user:pass@slave/db').with_secret(true) } + it { should contain_nova_config('database/idle_timeout').with_value('30') } + end + + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { :conductor_package_name => 'nova-conductor', + :conductor_service_name => 'nova-conductor' } + end + + it_configures 'nova-conductor' + end + + context 'on Redhat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :conductor_package_name => 'openstack-nova-conductor', + :conductor_service_name => 'openstack-nova-conductor' } + end + + it_configures 'nova-conductor' + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_config_spec.rb b/3rdparty/modules/nova/spec/classes/nova_config_spec.rb new file mode 100644 index 000000000..9bfe92a39 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_config_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' + +describe 'nova::config' do + + let :params do + { :nova_config => { + 'DEFAULT/foo' => { 'value' => 'fooValue' }, + 'DEFAULT/bar' => { 'value' => 'barValue' }, + 'DEFAULT/baz' => { 'ensure' => 'absent' } + }, + :nova_paste_api_ini => { + 'DEFAULT/foo2' => { 'value' => 'fooValue' }, + 'DEFAULT/bar2' => { 'value' => 'barValue' }, + 'DEFAULT/baz2' => { 'ensure' => 'absent' } + } + } + end + + it 'configures arbitrary nova configurations' do + should contain_nova_config('DEFAULT/foo').with_value('fooValue') + should contain_nova_config('DEFAULT/bar').with_value('barValue') + should contain_nova_config('DEFAULT/baz').with_ensure('absent') + end + + it 'configures arbitrary nova api-paste configurations' do + should contain_nova_paste_api_ini('DEFAULT/foo2').with_value('fooValue') + should contain_nova_paste_api_ini('DEFAULT/bar2').with_value('barValue') + should contain_nova_paste_api_ini('DEFAULT/baz2').with_ensure('absent') + end +end diff --git a/3rdparty/modules/nova/spec/classes/nova_consoleauth_spec.rb b/3rdparty/modules/nova/spec/classes/nova_consoleauth_spec.rb new file mode 100644 index 000000000..ef739bcef --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_consoleauth_spec.rb @@ -0,0 +1,30 @@ +require 'spec_helper' + +describe 'nova::consoleauth' do + + let :pre_condition do + 'include nova' + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_behaves_like 'generic nova service', { + :name => 'nova-consoleauth', + :package_name => 'nova-consoleauth', + :service_name => 'nova-consoleauth' } + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_behaves_like 'generic nova service', { + :name => 'nova-consoleauth', + :package_name => 'openstack-nova-console', + :service_name => 'openstack-nova-consoleauth' } + end +end diff --git a/3rdparty/modules/nova/spec/classes/nova_cron_archive_deleted_rows_spec.rb b/3rdparty/modules/nova/spec/classes/nova_cron_archive_deleted_rows_spec.rb new file mode 100644 index 000000000..c74ef691b --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_cron_archive_deleted_rows_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe 'nova::cron::archive_deleted_rows' do + + let :facts do + { :osfamily => 'Debian' } + end + + it 'configures a cron' do + should contain_cron('nova-manage db archive_deleted_rows').with( + :command => 'nova-manage db archive_deleted_rows --max_rows 100 >>/var/log/nova/nova-rowsflush.log 2>&1', + :environment => 'PATH=/bin:/usr/bin:/usr/sbin SHELL=/bin/sh', + :user => 'nova', + :minute => 1, + :hour => 0, + :monthday => '*', + :month => '*', + :weekday => '*', + :require => 'Package[nova-common]', + ) + end +end diff --git a/3rdparty/modules/nova/spec/classes/nova_db_mysql_spec.rb b/3rdparty/modules/nova/spec/classes/nova_db_mysql_spec.rb new file mode 100644 index 000000000..4ea871988 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_db_mysql_spec.rb @@ -0,0 +1,105 @@ +require 'spec_helper' + +describe 'nova::db::mysql' do + + let :pre_condition do + 'include mysql::server' + end + + let :required_params do + { :password => "qwerty" } + end + + context 'on a Debian osfamily' do + let :facts do + { :osfamily => "Debian" } + end + + context 'with only required parameters' do + let :params do + required_params + end + + it { should contain_openstacklib__db__mysql('nova').with( + :user => 'nova', + :password_hash => '*AA1420F182E88B9E5F874F6FBE7459291E8F4601', + :charset => 'utf8', + :collate => 'utf8_general_ci', + )} + end + + context 'when overriding charset' do + let :params do + { :charset => 'latin1' }.merge(required_params) + end + + it { should contain_openstacklib__db__mysql('nova').with_charset(params[:charset]) } + end + end + + context 'on a RedHat osfamily' do + let :facts do + { :osfamily => 'RedHat' } + end + + context 'with only required parameters' do + let :params do + required_params + end + + it { should contain_openstacklib__db__mysql('nova').with( + :user => 'nova', + :password_hash => '*AA1420F182E88B9E5F874F6FBE7459291E8F4601', + :charset => 'utf8', + :collate => 'utf8_general_ci', + )} + end + + context 'when overriding charset' do + let :params do + { :charset => 'latin1' }.merge(required_params) + end + + it { should contain_openstacklib__db__mysql('nova').with_charset(params[:charset]) } + end + end + + describe "overriding allowed_hosts param to array" do + let :facts do + { :osfamily => "Debian" } + end + let :params do + { + :password => 'novapass', + :allowed_hosts => ['127.0.0.1','%'] + } + end + + end + + describe "overriding allowed_hosts param to string" do + let :facts do + { :osfamily => 'RedHat' } + end + let :params do + { + :password => 'novapass2', + :allowed_hosts => '192.168.1.1' + } + end + + end + + describe "overriding allowed_hosts param equals to host param " do + let :facts do + { :osfamily => 'RedHat' } + end + let :params do + { + :password => 'novapass2', + :allowed_hosts => '127.0.0.1' + } + end + + end +end diff --git a/3rdparty/modules/nova/spec/classes/nova_db_postgresql_spec.rb b/3rdparty/modules/nova/spec/classes/nova_db_postgresql_spec.rb new file mode 100644 index 000000000..714e9425f --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_db_postgresql_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper' + +describe 'nova::db::postgresql' do + let :required_params do + { :password => "qwerty" } + end + + context 'on a RedHat osfamily' do + let :facts do + { + :postgres_default_version => '8.4', + :osfamily => 'RedHat' + } + end + + context 'with only required parameters' do + let :params do + required_params + end + + it { should contain_postgresql__db('nova').with( + :user => 'nova', + :password => 'qwerty' + )} + end + + end + + context 'on a Debian osfamily' do + let :facts do + { + :postgres_default_version => '8.4', + :osfamily => 'Debian' + } + end + + context 'with only required parameters' do + let :params do + required_params + end + + it { should contain_postgresql__db('nova').with( + :user => 'nova', + :password => 'qwerty' + )} + end + + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_db_spec.rb b/3rdparty/modules/nova/spec/classes/nova_db_spec.rb new file mode 100644 index 000000000..ec458b212 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_db_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +describe 'nova::db' do + + let :params do + {} + end + + shared_examples 'nova-db' do + + context 'with default parameters' do + it { should_not contain_nova_config('database/connection') } + it { should_not contain_nova_config('database/slave_connection') } + it { should_not contain_nova_config('database/idle_timeout') } + end + + context 'with overriden parameters' do + before :each do + params.merge!( + :database_connection => 'mysql://user:pass@db/db', + :slave_connection => 'mysql://user:pass@slave/db', + :database_idle_timeout => '30', + ) + end + + it { should contain_nova_config('database/connection').with_value('mysql://user:pass@db/db').with_secret(true) } + it { should contain_nova_config('database/slave_connection').with_value('mysql://user:pass@slave/db').with_secret(true) } + it { should contain_nova_config('database/idle_timeout').with_value('30') } + end + + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'nova-db' + end + + context 'on Redhat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'nova-db' + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_init_spec.rb b/3rdparty/modules/nova/spec/classes/nova_init_spec.rb new file mode 100644 index 000000000..f40dc565a --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_init_spec.rb @@ -0,0 +1,657 @@ +require 'spec_helper' + +describe 'nova' do + + shared_examples 'nova' do + + context 'with default parameters' do + + it 'installs packages' do + should contain_package('python').with_ensure('present') + should contain_package('python-greenlet').with( + :ensure => 'present', + :require => 'Package[python]' + ) + should contain_package('python-nova').with( + :ensure => 'present', + :require => 'Package[python-greenlet]' + ) + should contain_package('nova-common').with( + :name => platform_params[:nova_common_package], + :ensure => 'present', + :tag => ['openstack', 'nova'] + ) + end + + it 'does not create user and group' do + should_not contain_group('nova').with( + :ensure => 'present', + :system => true, + :before => 'User[nova]' + ) + should_not contain_user('nova').with( + :ensure => 'present', + :system => true, + :groups => 'nova', + :home => '/var/lib/nova', + :managehome => false, + :shell => '/bin/false' + ) + end + + it 'creates various files and folders' do + should contain_file('/var/log/nova').with( + :ensure => 'directory', + :mode => '0750', + :owner => 'nova', + :require => 'Package[nova-common]' + ) + should contain_file('/etc/nova/nova.conf').with( + :mode => '0640', + :owner => 'nova', + :group => 'nova', + :require => 'Package[nova-common]' + ) + end + + it 'configures rootwrap' do + should contain_nova_config('DEFAULT/rootwrap_config').with_value('/etc/nova/rootwrap.conf') + end + + it { should contain_exec('networking-refresh').with( + :command => '/sbin/ifdown -a ; /sbin/ifup -a', + :refreshonly => true + )} + + it 'configures image service' do + should contain_nova_config('DEFAULT/image_service').with_value('nova.image.glance.GlanceImageService') + should contain_nova_config('glance/api_servers').with_value('localhost:9292') + end + + it 'configures auth_strategy' do + should contain_nova_config('DEFAULT/auth_strategy').with_value('keystone') + should_not contain_nova_config('DEFAULT/use_deprecated_auth').with_value(false) + end + + it 'configures rabbit' do + should contain_nova_config('DEFAULT/rpc_backend').with_value('rabbit') + should contain_nova_config('DEFAULT/rabbit_host').with_value('localhost') + should contain_nova_config('DEFAULT/rabbit_password').with_value('guest').with_secret(true) + should contain_nova_config('DEFAULT/rabbit_port').with_value('5672') + should contain_nova_config('DEFAULT/rabbit_userid').with_value('guest') + should contain_nova_config('DEFAULT/rabbit_virtual_host').with_value('/') + end + + it 'configures various things' do + should contain_nova_config('DEFAULT/verbose').with_value(false) + should contain_nova_config('DEFAULT/debug').with_value(false) + should contain_nova_config('DEFAULT/log_dir').with_value('/var/log/nova') + should contain_nova_config('DEFAULT/state_path').with_value('/var/lib/nova') + should contain_nova_config('DEFAULT/lock_path').with_value(platform_params[:lock_path]) + should contain_nova_config('DEFAULT/service_down_time').with_value('60') + should contain_nova_config('DEFAULT/rootwrap_config').with_value('/etc/nova/rootwrap.conf') + should contain_nova_config('DEFAULT/report_interval').with_value('10') + should contain_nova_config('DEFAULT/os_region_name').with_ensure('absent') + end + + it 'installs utilities' do + should contain_class('nova::utilities') + end + + it 'disables syslog' do + should contain_nova_config('DEFAULT/use_syslog').with_value(false) + end + end + + context 'with overridden parameters' do + + let :params do + { :verbose => true, + :debug => true, + :log_dir => '/var/log/nova2', + :image_service => 'nova.image.local.LocalImageService', + :rabbit_host => 'rabbit', + :rabbit_userid => 'rabbit_user', + :rabbit_port => '5673', + :rabbit_password => 'password', + :rabbit_ha_queues => 'undef', + :lock_path => '/var/locky/path', + :state_path => '/var/lib/nova2', + :service_down_time => '120', + :auth_strategy => 'foo', + :ensure_package => '2012.1.1-15.el6', + :memcached_servers => ['memcached01:11211', 'memcached02:11211'], + :install_utilities => false, + :notification_driver => 'ceilometer.compute.nova_notifier', + :notification_topics => 'openstack', + :notify_api_faults => true, + :nova_user_id => '499', + :nova_group_id => '499', + :report_interval => '60', + :nova_shell => '/bin/bash', + :os_region_name => 'MyRegion' } + end + + it 'creates user and group' do + should contain_group('nova').with( + :ensure => 'present', + :system => true, + :gid => '499', + :before => 'Package[nova-common]' + ) + should contain_user('nova').with( + :ensure => 'present', + :system => true, + :groups => 'nova', + :home => '/var/lib/nova', + :managehome => false, + :shell => '/bin/bash', + :uid => '499', + :gid => '499', + :require => 'Group[nova]' + ) + end + + it 'installs packages' do + should contain_package('nova-common').with('ensure' => '2012.1.1-15.el6') + should contain_package('python-nova').with('ensure' => '2012.1.1-15.el6') + end + + it 'configures image service' do + should contain_nova_config('DEFAULT/image_service').with_value('nova.image.local.LocalImageService') + should_not contain_nova_config('glance/api_servers') + end + + it 'configures auth_strategy' do + should contain_nova_config('DEFAULT/auth_strategy').with_value('foo') + should_not contain_nova_config('DEFAULT/use_deprecated_auth').with_value(true) + end + + it 'configures rabbit' do + should contain_nova_config('DEFAULT/rpc_backend').with_value('rabbit') + should contain_nova_config('DEFAULT/rabbit_host').with_value('rabbit') + should contain_nova_config('DEFAULT/rabbit_password').with_value('password').with_secret(true) + should contain_nova_config('DEFAULT/rabbit_port').with_value('5673') + should contain_nova_config('DEFAULT/rabbit_userid').with_value('rabbit_user') + should contain_nova_config('DEFAULT/rabbit_virtual_host').with_value('/') + end + + it 'configures memcached_servers' do + should contain_nova_config('DEFAULT/memcached_servers').with_value('memcached01:11211,memcached02:11211') + end + + it 'configures various things' do + should contain_nova_config('DEFAULT/verbose').with_value(true) + should contain_nova_config('DEFAULT/debug').with_value(true) + should contain_nova_config('DEFAULT/log_dir').with_value('/var/log/nova2') + should contain_nova_config('DEFAULT/state_path').with_value('/var/lib/nova2') + should contain_nova_config('DEFAULT/lock_path').with_value('/var/locky/path') + should contain_nova_config('DEFAULT/service_down_time').with_value('120') + should contain_nova_config('DEFAULT/notification_driver').with_value('ceilometer.compute.nova_notifier') + should contain_nova_config('DEFAULT/notification_topics').with_value('openstack') + should contain_nova_config('DEFAULT/notify_api_faults').with_value(true) + should contain_nova_config('DEFAULT/report_interval').with_value('60') + should contain_nova_config('DEFAULT/os_region_name').with_value('MyRegion') + end + + context 'with multiple notification_driver' do + before { params.merge!( :notification_driver => ['ceilometer.compute.nova_notifier', 'nova.openstack.common.notifier.rpc_notifier']) } + + it { should contain_nova_config('DEFAULT/notification_driver').with_value( + 'ceilometer.compute.nova_notifier,nova.openstack.common.notifier.rpc_notifier' + ) } + end + + it 'does not install utilities' do + should_not contain_class('nova::utilities') + end + + context 'with logging directory disabled' do + before { params.merge!( :log_dir => false) } + + it { should contain_nova_config('DEFAULT/log_dir').with_ensure('absent') } + end + end + + context 'with wrong notify_on_state_change parameter' do + let :params do + { :notify_on_state_change => 'vm_status' } + end + + it 'configures database' do + should contain_nova_config('DEFAULT/notify_on_state_change').with_ensure('absent') + end + end + + context 'with notify_on_state_change parameter' do + let :params do + { :notify_on_state_change => 'vm_state' } + end + + it 'configures database' do + should contain_nova_config('DEFAULT/notify_on_state_change').with_value('vm_state') + end + end + + context 'with syslog enabled' do + let :params do + { :use_syslog => 'true' } + end + + it 'configures syslog' do + should contain_nova_config('DEFAULT/use_syslog').with_value(true) + should contain_nova_config('DEFAULT/syslog_log_facility').with_value('LOG_USER') + end + end + + context 'with syslog enabled and log_facility parameter' do + let :params do + { :use_syslog => 'true', + :log_facility => 'LOG_LOCAL0' } + end + + it 'configures syslog' do + should contain_nova_config('DEFAULT/use_syslog').with_value(true) + should contain_nova_config('DEFAULT/syslog_log_facility').with_value('LOG_LOCAL0') + end + end + + context 'with rabbit_hosts parameter' do + let :params do + { :rabbit_hosts => ['rabbit:5673', 'rabbit2:5674'] } + end + + it 'configures rabbit' do + should_not contain_nova_config('DEFAULT/rabbit_host') + should_not contain_nova_config('DEFAULT/rabbit_port') + should contain_nova_config('DEFAULT/rabbit_hosts').with_value('rabbit:5673,rabbit2:5674') + should contain_nova_config('DEFAULT/rabbit_ha_queues').with_value(true) + should contain_nova_config('DEFAULT/rabbit_use_ssl').with_value(false) + should contain_nova_config('DEFAULT/amqp_durable_queues').with_value(false) + should contain_nova_config('DEFAULT/kombu_ssl_ca_certs').with_ensure('absent') + should contain_nova_config('DEFAULT/kombu_ssl_certfile').with_ensure('absent') + should contain_nova_config('DEFAULT/kombu_ssl_keyfile').with_ensure('absent') + should contain_nova_config('DEFAULT/kombu_ssl_version').with_ensure('absent') + end + end + + context 'with rabbit_hosts parameter (one server)' do + let :params do + { :rabbit_hosts => ['rabbit:5673'] } + end + + it 'configures rabbit' do + should_not contain_nova_config('DEFAULT/rabbit_host') + should_not contain_nova_config('DEFAULT/rabbit_port') + should contain_nova_config('DEFAULT/rabbit_hosts').with_value('rabbit:5673') + should contain_nova_config('DEFAULT/rabbit_ha_queues').with_value(true) + should contain_nova_config('DEFAULT/rabbit_use_ssl').with_value(false) + should contain_nova_config('DEFAULT/amqp_durable_queues').with_value(false) + end + end + + context 'with rabbit_ha_queues set to true' do + let :params do + { :rabbit_ha_queues => 'true' } + end + + it 'configures rabbit' do + should contain_nova_config('DEFAULT/rabbit_ha_queues').with_value(true) + end + end + + context 'with amqp_durable_queues parameter' do + let :params do + { :rabbit_hosts => ['rabbit:5673'], + :amqp_durable_queues => 'true' } + end + + it 'configures rabbit' do + should_not contain_nova_config('DEFAULT/rabbit_host') + should_not contain_nova_config('DEFAULT/rabbit_port') + should contain_nova_config('DEFAULT/rabbit_hosts').with_value('rabbit:5673') + should contain_nova_config('DEFAULT/rabbit_ha_queues').with_value(true) + should contain_nova_config('DEFAULT/rabbit_use_ssl').with_value(false) + should contain_nova_config('DEFAULT/amqp_durable_queues').with_value(true) + should contain_nova_config('DEFAULT/kombu_ssl_ca_certs').with_ensure('absent') + should contain_nova_config('DEFAULT/kombu_ssl_certfile').with_ensure('absent') + should contain_nova_config('DEFAULT/kombu_ssl_keyfile').with_ensure('absent') + should contain_nova_config('DEFAULT/kombu_ssl_version').with_ensure('absent') + end + end + + context 'with rabbit ssl enabled with kombu' do + let :params do + { :rabbit_hosts => ['rabbit:5673'], + :rabbit_use_ssl => 'true', + :kombu_ssl_ca_certs => '/etc/ca.cert', + :kombu_ssl_certfile => '/etc/certfile', + :kombu_ssl_keyfile => '/etc/key', + :kombu_ssl_version => 'TLSv1', } + end + + it 'configures rabbit' do + should contain_nova_config('DEFAULT/rabbit_use_ssl').with_value(true) + should contain_nova_config('DEFAULT/kombu_ssl_ca_certs').with_value('/etc/ca.cert') + should contain_nova_config('DEFAULT/kombu_ssl_certfile').with_value('/etc/certfile') + should contain_nova_config('DEFAULT/kombu_ssl_keyfile').with_value('/etc/key') + should contain_nova_config('DEFAULT/kombu_ssl_version').with_value('TLSv1') + end + end + + context 'with rabbit ssl enabled without kombu' do + let :params do + { :rabbit_hosts => ['rabbit:5673'], + :rabbit_use_ssl => 'true', } + end + + it 'configures rabbit' do + should contain_nova_config('DEFAULT/rabbit_use_ssl').with_value(true) + should contain_nova_config('DEFAULT/kombu_ssl_ca_certs').with_ensure('absent') + should contain_nova_config('DEFAULT/kombu_ssl_certfile').with_ensure('absent') + should contain_nova_config('DEFAULT/kombu_ssl_keyfile').with_ensure('absent') + should contain_nova_config('DEFAULT/kombu_ssl_version').with_value('TLSv1') + end + end + + context 'with rabbit ssl disabled' do + let :params do + { + :rabbit_password => 'pass', + :rabbit_use_ssl => false, + :kombu_ssl_version => 'TLSv1', + } + end + + it 'configures rabbit' do + should contain_nova_config('DEFAULT/rabbit_use_ssl').with_value('false') + should contain_nova_config('DEFAULT/kombu_ssl_ca_certs').with_ensure('absent') + should contain_nova_config('DEFAULT/kombu_ssl_certfile').with_ensure('absent') + should contain_nova_config('DEFAULT/kombu_ssl_keyfile').with_ensure('absent') + should contain_nova_config('DEFAULT/kombu_ssl_version').with_ensure('absent') + end + end + + context 'with qpid rpc_backend' do + let :params do + { :rpc_backend => 'qpid' } + end + + context 'with default parameters' do + it 'configures qpid' do + should contain_nova_config('DEFAULT/rpc_backend').with_value('qpid') + should contain_nova_config('DEFAULT/qpid_hostname').with_value('localhost') + should contain_nova_config('DEFAULT/qpid_port').with_value('5672') + should contain_nova_config('DEFAULT/qpid_username').with_value('guest') + should contain_nova_config('DEFAULT/qpid_password').with_value('guest').with_secret(true) + should contain_nova_config('DEFAULT/qpid_heartbeat').with_value('60') + should contain_nova_config('DEFAULT/qpid_protocol').with_value('tcp') + should contain_nova_config('DEFAULT/qpid_tcp_nodelay').with_value(true) + end + end + + context 'with qpid_password parameter (without qpid_sasl_mechanisms)' do + before do + params.merge!({ :qpid_password => 'guest' }) + end + it { should contain_nova_config('DEFAULT/qpid_sasl_mechanisms').with_ensure('absent') } + end + + context 'with qpid_password parameter (with qpid_sasl_mechanisms)' do + before do + params.merge!({ + :qpid_password => 'guest', + :qpid_sasl_mechanisms => 'A' + }) + end + it { should contain_nova_config('DEFAULT/qpid_sasl_mechanisms').with_value('A') } + end + + context 'with qpid_password parameter (with array of qpid_sasl_mechanisms)' do + before do + params.merge!({ + :qpid_password => 'guest', + :qpid_sasl_mechanisms => [ 'DIGEST-MD5', 'GSSAPI', 'PLAIN' ] + }) + end + it { should contain_nova_config('DEFAULT/qpid_sasl_mechanisms').with_value('DIGEST-MD5 GSSAPI PLAIN') } + end + end + + context 'with qpid rpc_backend with old parameter' do + let :params do + { :rpc_backend => 'nova.openstack.common.rpc.impl_qpid' } + end + + it { should contain_nova_config('DEFAULT/rpc_backend').with_value('nova.openstack.common.rpc.impl_qpid') } + end + + context 'with rabbitmq rpc_backend with old parameter' do + let :params do + { :rpc_backend => 'nova.openstack.common.rpc.impl_kombu' } + end + + it { should contain_nova_config('DEFAULT/rpc_backend').with_value('nova.openstack.common.rpc.impl_kombu') } + end + + context 'with ssh public key' do + let :params do + { + :nova_public_key => {'type' => 'ssh-rsa', + 'key' => 'keydata'} + } + end + + it 'should install ssh public key' do + should contain_ssh_authorized_key('nova-migration-public-key').with( + :ensure => 'present', + :key => 'keydata', + :type => 'ssh-rsa' + ) + end + end + + context 'with ssh public key missing key type' do + let :params do + { + :nova_public_key => {'type' => '', + 'key' => 'keydata'} + } + end + + it 'should raise an error' do + expect { + should contain_ssh_authorized_key('nova-migration-public-key').with( + :ensure => 'present', + :key => 'keydata', + :type => '' + ) + }.to raise_error Puppet::Error, /You must provide both a key type and key data./ + end + end + + context 'with ssh public key missing key data' do + let :params do + { + :nova_public_key => {'type' => 'ssh-rsa', + 'key' => ''} + } + end + + it 'should raise an error' do + expect { + should contain_ssh_authorized_key('nova-migration-public-key').with( + :ensure => 'present', + :key => 'keydata', + :type => '' + ) + }.to raise_error Puppet::Error, /You must provide both a key type and key data./ + end + end + + context 'with ssh private key' do + let :params do + { + :nova_private_key => {'type' => 'ssh-rsa', + 'key' => 'keydata'} + } + end + + it 'should install ssh private key' do + should contain_file('/var/lib/nova/.ssh/id_rsa').with( + :content => 'keydata' + ) + end + end + + context 'with ssh private key missing key type' do + let :params do + { + :nova_private_key => {'type' => '', + 'key' => 'keydata'} + } + end + + it 'should raise an error' do + expect { + should contain_file('/var/lib/nova/.ssh/id_rsa').with( + :content => 'keydata' + ) + }.to raise_error Puppet::Error, /You must provide both a key type and key data./ + end + end + + context 'with ssh private key having incorrect key type' do + let :params do + { + :nova_private_key => {'type' => 'invalid', + 'key' => 'keydata'} + } + end + + it 'should raise an error' do + expect { + should contain_file('/var/lib/nova/.ssh/id_rsa').with( + :content => 'keydata' + ) + }.to raise_error Puppet::Error, /Unable to determine name of private key file./ + end + end + + context 'with ssh private key missing key data' do + let :params do + { + :nova_private_key => {'type' => 'ssh-rsa', + 'key' => ''} + } + end + + it 'should raise an error' do + expect { + should contain_file('/var/lib/nova/.ssh/id_rsa').with( + :content => 'keydata' + ) + }.to raise_error Puppet::Error, /You must provide both a key type and key data./ + end + end + + context 'with SSL socket options set' do + let :params do + { + :use_ssl => true, + :enabled_ssl_apis => ['ec2', 'osapi_compute'], + :cert_file => '/path/to/cert', + :ca_file => '/path/to/ca', + :key_file => '/path/to/key', + } + end + + it { should contain_nova_config('DEFAULT/enabled_ssl_apis').with_value('ec2,osapi_compute') } + it { should contain_nova_config('DEFAULT/ssl_ca_file').with_value('/path/to/ca') } + it { should contain_nova_config('DEFAULT/ssl_cert_file').with_value('/path/to/cert') } + it { should contain_nova_config('DEFAULT/ssl_key_file').with_value('/path/to/key') } + end + + context 'with SSL socket options set with wrong parameters' do + let :params do + { + :use_ssl => true, + :enabled_ssl_apis => ['ec2'], + :ca_file => '/path/to/ca', + :key_file => '/path/to/key', + } + end + + it_raises 'a Puppet::Error', /The cert_file parameter is required when use_ssl is set to true/ + end + + context 'with SSL socket options set to false' do + let :params do + { + :use_ssl => false, + :enabled_ssl_apis => [], + :cert_file => false, + :ca_file => false, + :key_file => false, + } + end + + it { should contain_nova_config('DEFAULT/enabled_ssl_apis').with_ensure('absent') } + it { should contain_nova_config('DEFAULT/ssl_ca_file').with_ensure('absent') } + it { should contain_nova_config('DEFAULT/ssl_cert_file').with_ensure('absent') } + it { should contain_nova_config('DEFAULT/ssl_key_file').with_ensure('absent') } + end + + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian', + :operatingsystem => 'Debian' } + end + + let :platform_params do + { :nova_common_package => 'nova-common', + :lock_path => '/var/lock/nova' } + end + + it_behaves_like 'nova' + it 'creates the log folder with the right group for Debian' do + should contain_file('/var/log/nova').with(:group => 'nova') + end + end + + context 'on Ubuntu platforms' do + let :facts do + { :osfamily => 'Debian', + :operatingsystem => 'Ubuntu' } + end + + let :platform_params do + { :nova_common_package => 'nova-common', + :lock_path => '/var/lock/nova' } + end + + it_behaves_like 'nova' + it 'creates the log folder with the right group for Ubuntu' do + should contain_file('/var/log/nova').with(:group => 'adm') + end + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :nova_common_package => 'openstack-nova-common', + :lock_path => '/var/lib/nova/tmp' } + end + + it_behaves_like 'nova' + + it 'creates the log folder with the right group for RedHat' do + should contain_file('/var/log/nova').with(:group => 'nova') + end + end +end diff --git a/3rdparty/modules/nova/spec/classes/nova_keystone_endpoint_spec.rb b/3rdparty/modules/nova/spec/classes/nova_keystone_endpoint_spec.rb new file mode 100644 index 000000000..7b515e4f0 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_keystone_endpoint_spec.rb @@ -0,0 +1,216 @@ +require 'spec_helper' + +describe 'nova::keystone::auth' do + + let :params do + {:password => 'nova_password'} + end + + context 'with default parameters' do + + it { should contain_keystone_user('nova').with( + :ensure => 'present', + :password => 'nova_password' + ) } + + it { should contain_keystone_user_role('nova@services').with( + :ensure => 'present', + :roles => 'admin' + )} + + it { should contain_keystone_service('nova').with( + :ensure => 'present', + :type => 'compute', + :description => 'Openstack Compute Service' + )} + + it { should contain_keystone_service('novav3').with( + :ensure => 'present', + :type => 'computev3', + :description => 'Openstack Compute Service v3' + )} + + it { should contain_keystone_service('nova_ec2').with( + :ensure => 'present', + :type => 'ec2', + :description => 'EC2 Service' + )} + + it { should contain_keystone_endpoint('RegionOne/nova').with( + :ensure => 'present', + :public_url => 'http://127.0.0.1:8774/v2/%(tenant_id)s', + :admin_url => 'http://127.0.0.1:8774/v2/%(tenant_id)s', + :internal_url => 'http://127.0.0.1:8774/v2/%(tenant_id)s' + )} + + it { should contain_keystone_endpoint('RegionOne/novav3').with( + :ensure => 'present', + :public_url => 'http://127.0.0.1:8774/v3', + :admin_url => 'http://127.0.0.1:8774/v3', + :internal_url => 'http://127.0.0.1:8774/v3' + )} + + it { should contain_keystone_endpoint('RegionOne/nova_ec2').with( + :ensure => 'present', + :public_url => 'http://127.0.0.1:8773/services/Cloud', + :admin_url => 'http://127.0.0.1:8773/services/Admin', + :internal_url => 'http://127.0.0.1:8773/services/Cloud' + )} + + end + + context 'when setting auth name' do + before do + params.merge!( :auth_name => 'foo' ) + end + + it { should contain_keystone_user('foo').with( + :ensure => 'present', + :password => 'nova_password' + ) } + + it { should contain_keystone_user_role('foo@services').with( + :ensure => 'present', + :roles => 'admin' + )} + + it { should contain_keystone_service('foo').with( + :ensure => 'present', + :type => 'compute', + :description => 'Openstack Compute Service' + )} + + it { should contain_keystone_service('foo_ec2').with( + :ensure => 'present', + :type => 'ec2', + :description => 'EC2 Service' + )} + + end + + context 'when overriding endpoint params' do + before do + params.merge!( + :public_address => '10.0.0.1', + :admin_address => '10.0.0.2', + :internal_address => '10.0.0.3', + :compute_port => '9774', + :ec2_port => '9773', + :compute_version => 'v2.2', + :region => 'RegionTwo', + :admin_protocol => 'https', + :internal_protocol => 'https', + :public_protocol => 'https' + ) + end + + it { should contain_keystone_endpoint('RegionTwo/nova').with( + :ensure => 'present', + :public_url => 'https://10.0.0.1:9774/v2.2/%(tenant_id)s', + :admin_url => 'https://10.0.0.2:9774/v2.2/%(tenant_id)s', + :internal_url => 'https://10.0.0.3:9774/v2.2/%(tenant_id)s' + )} + + it { should contain_keystone_endpoint('RegionTwo/nova_ec2').with( + :ensure => 'present', + :public_url => 'https://10.0.0.1:9773/services/Cloud', + :admin_url => 'https://10.0.0.2:9773/services/Admin', + :internal_url => 'https://10.0.0.3:9773/services/Cloud' + )} + + end + + describe 'when disabling endpoint configuration' do + before do + params.merge!( :configure_endpoint => false ) + end + + it { should_not contain_keystone_endpoint('RegionOne/nova') } + end + + describe 'when disabling EC2 endpoint' do + before do + params.merge!( :configure_ec2_endpoint => false ) + end + + it { should_not contain_keystone_service('nova_ec2') } + it { should_not contain_keystone_endpoint('RegionOne/nova_ec2') } + end + + describe 'when disabling user configuration' do + before do + params.merge!( :configure_user => false ) + end + + it { should_not contain_keystone_user('nova') } + + it { should contain_keystone_user_role('nova@services') } + + it { should contain_keystone_service('nova').with( + :ensure => 'present', + :type => 'compute', + :description => 'Openstack Compute Service' + )} + end + + describe 'when disabling user and user role configuration' do + let :params do + { + :configure_user => false, + :configure_user_role => false, + :password => 'nova_password' + } + end + + it { should_not contain_keystone_user('nova') } + + it { should_not contain_keystone_user_role('nova@services') } + + it { should contain_keystone_service('nova').with( + :ensure => 'present', + :type => 'compute', + :description => 'Openstack Compute Service' + )} + end + + describe 'when configuring nova-api and the keystone endpoint' do + let :pre_condition do + "class { 'nova::api': admin_password => 'test' } + include nova" + end + + let :facts do + { :osfamily => "Debian"} + end + + let :params do + { + :password => 'test' + } + end + + it { should contain_keystone_endpoint('RegionOne/nova').with_notify('Service[nova-api]') } + end + + describe 'when overriding service names' do + + let :params do + { + :service_name => 'nova_service', + :service_name_v3 => 'nova_service_v3', + :password => 'nova_password' + } + end + + it { should contain_keystone_user('nova') } + it { should contain_keystone_user_role('nova@services') } + it { should contain_keystone_service('nova_service') } + it { should contain_keystone_service('nova_service_v3') } + it { should contain_keystone_service('nova_service_ec2') } + it { should contain_keystone_endpoint('RegionOne/nova_service') } + it { should contain_keystone_endpoint('RegionOne/nova_service_v3') } + it { should contain_keystone_endpoint('RegionOne/nova_service_ec2') } + + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_logging_spec.rb b/3rdparty/modules/nova/spec/classes/nova_logging_spec.rb new file mode 100644 index 000000000..5b1bcc666 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_logging_spec.rb @@ -0,0 +1,107 @@ +require 'spec_helper' + +describe 'nova::logging' do + + let :params do + { + } + end + + let :log_params do + { + :logging_context_format_string => '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s', + :logging_default_format_string => '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s', + :logging_debug_format_suffix => '%(funcName)s %(pathname)s:%(lineno)d', + :logging_exception_prefix => '%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s', + :log_config_append => '/etc/nova/logging.conf', + :publish_errors => true, + :default_log_levels => { + 'amqp' => 'WARN', 'amqplib' => 'WARN', 'boto' => 'WARN', + 'qpid' => 'WARN', 'sqlalchemy' => 'WARN', 'suds' => 'INFO', + 'iso8601' => 'WARN', + 'requests.packages.urllib3.connectionpool' => 'WARN' }, + :fatal_deprecations => true, + :instance_format => '[instance: %(uuid)s] ', + :instance_uuid_format => '[instance: %(uuid)s] ', + :log_date_format => '%Y-%m-%d %H:%M:%S', + } + end + + shared_examples_for 'nova-logging' do + + context 'with extended logging options' do + before { params.merge!( log_params ) } + it_configures 'logging params set' + end + + context 'without extended logging options' do + it_configures 'logging params unset' + end + + end + + shared_examples_for 'logging params set' do + it 'enables logging params' do + should contain_nova_config('DEFAULT/logging_context_format_string').with_value( + '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s') + + should contain_nova_config('DEFAULT/logging_default_format_string').with_value( + '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s') + + should contain_nova_config('DEFAULT/logging_debug_format_suffix').with_value( + '%(funcName)s %(pathname)s:%(lineno)d') + + should contain_nova_config('DEFAULT/logging_exception_prefix').with_value( + '%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s') + + should contain_nova_config('DEFAULT/log_config_append').with_value( + '/etc/nova/logging.conf') + should contain_nova_config('DEFAULT/publish_errors').with_value( + true) + + should contain_nova_config('DEFAULT/default_log_levels').with_value( + 'amqp=WARN,amqplib=WARN,boto=WARN,iso8601=WARN,qpid=WARN,requests.packages.urllib3.connectionpool=WARN,sqlalchemy=WARN,suds=INFO') + + should contain_nova_config('DEFAULT/fatal_deprecations').with_value( + true) + + should contain_nova_config('DEFAULT/instance_format').with_value( + '[instance: %(uuid)s] ') + + should contain_nova_config('DEFAULT/instance_uuid_format').with_value( + '[instance: %(uuid)s] ') + + should contain_nova_config('DEFAULT/log_date_format').with_value( + '%Y-%m-%d %H:%M:%S') + end + end + + + shared_examples_for 'logging params unset' do + [ :logging_context_format_string, :logging_default_format_string, + :logging_debug_format_suffix, :logging_exception_prefix, + :log_config_append, :publish_errors, + :default_log_levels, :fatal_deprecations, + :instance_format, :instance_uuid_format, + :log_date_format, ].each { |param| + it { should contain_nova_config("DEFAULT/#{param}").with_ensure('absent') } + } + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'nova-logging' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'nova-logging' + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_migration_libvirt_spec.rb b/3rdparty/modules/nova/spec/classes/nova_migration_libvirt_spec.rb new file mode 100644 index 000000000..9cedb5c01 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_migration_libvirt_spec.rb @@ -0,0 +1,60 @@ +# +# Copyright (C) 2013 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Unit tests for nova::migration::libvirt class +# + +require 'spec_helper' + +describe 'nova::migration::libvirt' do + + + let :pre_condition do + 'include nova + include nova::compute + include nova::compute::libvirt' + end + + shared_examples_for 'nova migration with libvirt' do + + it 'configure libvirtd.conf' do + should contain_file_line('/etc/libvirt/libvirtd.conf listen_tls').with(:line => 'listen_tls = 0') + should contain_file_line('/etc/libvirt/libvirtd.conf listen_tcp').with(:line => 'listen_tcp = 1') + should contain_file_line('/etc/libvirt/libvirtd.conf auth_tcp').with(:line => 'auth_tcp = "none"') + end + + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'nova migration with libvirt' + it { should contain_file_line('/etc/default/libvirt-bin libvirtd opts').with(:line => 'libvirtd_opts="-d -l"') } + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'nova migration with libvirt' + it { should contain_file_line('/etc/sysconfig/libvirtd libvirtd args').with(:line => 'LIBVIRTD_ARGS="--listen"') } + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_network_flat_spec.rb b/3rdparty/modules/nova/spec/classes/nova_network_flat_spec.rb new file mode 100644 index 000000000..d0c21d3de --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_network_flat_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe 'nova::network::flat' do + + describe 'with only required parameters' do + let :params do + { + :fixed_range => '10.0.0.0/32' + } + end + + it { should contain_nova_config('DEFAULT/network_manager').with_value('nova.network.manager.FlatManager') } + it { should_not contain_nova_config('DEFAULT/public_interface') } + it { should contain_nova_config('DEFAULT/fixed_range').with_value('10.0.0.0/32') } + it { should contain_nova_config('DEFAULT/flat_network_bridge').with_value('br100') } + it { should contain_nova_config('DEFAULT/flat_interface').with_value(nil) } + end + + describe 'when overriding class parameters' do + + let :params do + { + :flat_interface => 'eth1', + :fixed_range => '10.0.0.0/32', + :public_interface => 'eth0', + :flat_network_bridge => 'br1001', + } + end + + it { should contain_nova_config('DEFAULT/public_interface').with_value('eth0') } + it { should contain_nova_config('DEFAULT/flat_network_bridge').with_value('br1001') } + it { should contain_nova_config('DEFAULT/fixed_range').with_value('10.0.0.0/32') } + it { should contain_nova_config('DEFAULT/flat_interface').with_value('eth1') } + + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_network_flatdhcp_spec.rb b/3rdparty/modules/nova/spec/classes/nova_network_flatdhcp_spec.rb new file mode 100644 index 000000000..9b146ea4d --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_network_flatdhcp_spec.rb @@ -0,0 +1,49 @@ +require 'spec_helper' + +describe 'nova::network::flatdhcp' do + + describe 'with only required parameters' do + let :params do + { + :flat_interface => 'eth1', + :fixed_range => '10.0.0.0/32' + } + end + + it { should contain_nova_config('DEFAULT/network_manager').with_value('nova.network.manager.FlatDHCPManager') } + it { should_not contain_nova_config('DEFAULT/public_interface') } + it { should contain_nova_config('DEFAULT/fixed_range').with_value('10.0.0.0/32') } + it { should contain_nova_config('DEFAULT/flat_interface').with_value('eth1') } + it { should contain_nova_config('DEFAULT/flat_interface').with_value('eth1') } + it { should contain_nova_config('DEFAULT/flat_network_bridge').with_value('br100') } + it { should contain_nova_config('DEFAULT/force_dhcp_release').with_value(true) } + it { should contain_nova_config('DEFAULT/flat_injected').with_value(false) } + it { should contain_nova_config('DEFAULT/dhcpbridge').with_value('/usr/bin/nova-dhcpbridge') } + it { should contain_nova_config('DEFAULT/dhcpbridge_flagfile').with_value('/etc/nova/nova.conf') } + end + + describe 'when overriding class parameters' do + + let :params do + { + :flat_interface => 'eth1', + :fixed_range => '10.0.0.0/32', + :public_interface => 'eth0', + :flat_network_bridge => 'br1001', + :force_dhcp_release => false, + :flat_injected => true, + :dhcpbridge => '/usr/bin/dhcpbridge', + :dhcpbridge_flagfile => '/etc/nova/nova-dhcp.conf' + } + end + + it { should contain_nova_config('DEFAULT/public_interface').with_value('eth0') } + it { should contain_nova_config('DEFAULT/flat_network_bridge').with_value('br1001') } + it { should contain_nova_config('DEFAULT/force_dhcp_release').with_value(false) } + it { should contain_nova_config('DEFAULT/flat_injected').with_value(true) } + it { should contain_nova_config('DEFAULT/dhcpbridge').with_value('/usr/bin/dhcpbridge') } + it { should contain_nova_config('DEFAULT/dhcpbridge_flagfile').with_value('/etc/nova/nova-dhcp.conf') } + + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_network_neutron_spec.rb b/3rdparty/modules/nova/spec/classes/nova_network_neutron_spec.rb new file mode 100644 index 000000000..20eaafc83 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_network_neutron_spec.rb @@ -0,0 +1,100 @@ +require 'spec_helper' + +describe 'nova::network::neutron' do + + let :default_params do + { :neutron_auth_strategy => 'keystone', + :neutron_url => 'http://127.0.0.1:9696', + :neutron_url_timeout => '30', + :neutron_admin_tenant_name => 'services', + :neutron_default_tenant_id => 'default', + :neutron_region_name => 'RegionOne', + :neutron_admin_username => 'neutron', + :neutron_admin_auth_url => 'http://127.0.0.1:35357/v2.0', + :neutron_ovs_bridge => 'br-int', + :neutron_extension_sync_interval => '600', + :security_group_api => 'neutron', + :firewall_driver => 'nova.virt.firewall.NoopFirewallDriver', + :vif_plugging_is_fatal => true, + :vif_plugging_timeout => '300', + :dhcp_domain => 'novalocal' + } + end + + let :params do + { :neutron_admin_password => 's3cr3t' } + end + + + context 'with required parameters' do + it 'configures neutron endpoint in nova.conf' do + should contain_nova_config('neutron/admin_password').with_value(params[:neutron_admin_password]).with_secret(true) + should contain_nova_config('DEFAULT/network_api_class').with_value('nova.network.neutronv2.api.API') + should contain_nova_config('DEFAULT/dhcp_domain').with_value(default_params[:dhcp_domain]) + should contain_nova_config('neutron/auth_strategy').with_value(default_params[:neutron_auth_strategy]) + should contain_nova_config('neutron/url').with_value(default_params[:neutron_url]) + should contain_nova_config('neutron/url_timeout').with_value(default_params[:neutron_url_timeout]) + should contain_nova_config('neutron/admin_tenant_name').with_value(default_params[:neutron_admin_tenant_name]) + should contain_nova_config('neutron/default_tenant_id').with_value(default_params[:neutron_default_tenant_id]) + should contain_nova_config('neutron/region_name').with_value(default_params[:neutron_region_name]) + should contain_nova_config('neutron/admin_username').with_value(default_params[:neutron_admin_username]) + should contain_nova_config('neutron/admin_auth_url').with_value(default_params[:neutron_admin_auth_url]) + should contain_nova_config('neutron/extension_sync_interval').with_value(default_params[:neutron_extension_sync_interval]) + end + it 'configures Nova to use Neutron Bridge Security Groups and Firewall' do + should contain_nova_config('DEFAULT/firewall_driver').with_value(default_params[:firewall_driver]) + should contain_nova_config('DEFAULT/security_group_api').with_value(default_params[:security_group_api]) + should contain_nova_config('neutron/ovs_bridge').with_value(default_params[:neutron_ovs_bridge]) + end + it 'configures neutron vif plugging events in nova.conf' do + should contain_nova_config('DEFAULT/vif_plugging_is_fatal').with_value(default_params[:vif_plugging_is_fatal]) + should contain_nova_config('DEFAULT/vif_plugging_timeout').with_value(default_params[:vif_plugging_timeout]) + end + end + + context 'when overriding class parameters' do + before do + params.merge!( + :neutron_url => 'http://10.0.0.1:9696', + :neutron_url_timeout => '30', + :neutron_admin_tenant_name => 'openstack', + :neutron_default_tenant_id => 'default', + :neutron_region_name => 'RegionTwo', + :neutron_admin_username => 'neutron2', + :neutron_admin_auth_url => 'http://10.0.0.1:35357/v2.0', + :network_api_class => 'network.api.class', + :security_group_api => 'nova', + :firewall_driver => 'nova.virt.firewall.IptablesFirewallDriver', + :neutron_ovs_bridge => 'br-int', + :neutron_extension_sync_interval => '600', + :vif_plugging_is_fatal => false, + :vif_plugging_timeout => '0', + :dhcp_domain => 'foo' + ) + end + + it 'configures neutron endpoint in nova.conf' do + should contain_nova_config('neutron/auth_strategy').with_value(default_params[:neutron_auth_strategy]) + should contain_nova_config('neutron/admin_password').with_value(params[:neutron_admin_password]).with_secret(true) + should contain_nova_config('DEFAULT/network_api_class').with_value('network.api.class') + should contain_nova_config('DEFAULT/dhcp_domain').with_value(params[:dhcp_domain]) + should contain_nova_config('neutron/url').with_value(params[:neutron_url]) + should contain_nova_config('neutron/url_timeout').with_value(params[:neutron_url_timeout]) + should contain_nova_config('neutron/admin_tenant_name').with_value(params[:neutron_admin_tenant_name]) + should contain_nova_config('neutron/default_tenant_id').with_value(params[:neutron_default_tenant_id]) + should contain_nova_config('neutron/region_name').with_value(params[:neutron_region_name]) + should contain_nova_config('neutron/admin_username').with_value(params[:neutron_admin_username]) + should contain_nova_config('neutron/admin_auth_url').with_value(params[:neutron_admin_auth_url]) + should contain_nova_config('neutron/extension_sync_interval').with_value(params[:neutron_extension_sync_interval]) + end + it 'configures Nova to use Neutron Security Groups and Firewall' do + should contain_nova_config('DEFAULT/firewall_driver').with_value(params[:firewall_driver]) + should contain_nova_config('DEFAULT/security_group_api').with_value(params[:security_group_api]) + should contain_nova_config('neutron/ovs_bridge').with_value(params[:neutron_ovs_bridge]) + end + it 'configures neutron vif plugging events in nova.conf' do + should contain_nova_config('DEFAULT/vif_plugging_is_fatal').with_value(params[:vif_plugging_is_fatal]) + should contain_nova_config('DEFAULT/vif_plugging_timeout').with_value(params[:vif_plugging_timeout]) + end + end +end diff --git a/3rdparty/modules/nova/spec/classes/nova_network_spec.rb b/3rdparty/modules/nova/spec/classes/nova_network_spec.rb new file mode 100644 index 000000000..811ba9c71 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_network_spec.rb @@ -0,0 +1,215 @@ +require 'spec_helper' + +describe 'nova::network' do + + let :pre_condition do + 'include nova' + end + + let :default_params do + { + :private_interface => 'eth1', + :fixed_range => '10.0.0.0/32', + } + end + + let :params do + default_params + end + + describe 'on debian platforms' do + + let :facts do + { :osfamily => 'Debian' } + end + + it { should contain_sysctl__value('net.ipv4.ip_forward').with_value('1') } + + describe 'when installing service' do + + it { should contain_package('nova-network').with( + 'name' => 'nova-network', + 'ensure' => 'present', + 'notify' => 'Service[nova-network]' + ) } + + describe 'with enabled as true' do + let :params do + default_params.merge(:enabled => true) + end + it { should contain_service('nova-network').with( + 'name' => 'nova-network', + 'ensure' => 'running', + 'hasstatus' => true, + 'enable' => true + )} + end + describe 'when enabled is set to false' do + it { should contain_service('nova-network').with( + 'name' => 'nova-network', + 'ensure' => 'stopped', + 'hasstatus' => true, + 'enable' => false + )} + end + end + describe 'when not installing service' do + + let :params do + default_params.merge(:install_service => false) + end + + it { should_not contain_package('nova-network') } + it { should_not contain_service('nova-network') } + + end + + describe 'when not creating networks' do + let :params do + default_params.merge(:create_networks => false) + end + it { should_not contain_nova__manage__network('nova-vm-net') } + it { should_not contain_nova__manage__floating('nova-vm-floating') } + end + + describe 'when creating networks' do + it { should contain_nova__manage__network('nova-vm-net').with( + :network => '10.0.0.0/32', + :num_networks => '1' + ) } + it { should_not contain__nova__manage__floating('nova-vm-floating') } + describe 'when number of networks is set' do + let :params do + default_params.merge(:num_networks => '2') + end + it { should contain_nova__manage__network('nova-vm-net').with( + :num_networks => '2' + ) } + end + describe 'when floating range is set' do + let :params do + default_params.merge(:floating_range => '10.0.0.0/30') + end + it { should contain_nova_config('DEFAULT/floating_range').with_value('10.0.0.0/30') } + it { should contain_nova__manage__floating('nova-vm-floating').with_network('10.0.0.0/30') } + end + end + describe 'when configuring networks' do + describe 'when configuring flatdhcpmanager' do + let :params do + default_params.merge(:network_manager => 'nova.network.manager.FlatDHCPManager') + end + it { should contain_class('nova::network::flatdhcp').with( + :fixed_range => '10.0.0.0/32', + :public_interface => nil, + :flat_interface => 'eth1', + :flat_network_bridge => 'br100', + :force_dhcp_release => true, + :flat_injected => false, + :dhcp_domain => 'novalocal', + :dhcpbridge => '/usr/bin/nova-dhcpbridge', + :dhcpbridge_flagfile => '/etc/nova/nova.conf' + ) } + describe 'when overriding parameters' do + let :params do + default_params.merge( + { + :network_manager => 'nova.network.manager.FlatDHCPManager', + :public_interface => 'eth0', + :config_overrides => + { + 'flat_network_bridge' => 'br400', + 'force_dhcp_release' => false, + 'flat_injected' => true, + 'dhcp_domain' => 'not-novalocal', + 'dhcpbridge' => '/tmp/bridge', + 'dhcpbridge_flagfile' => '/tmp/file', + } + } + ) + end + it { should contain_class('nova::network::flatdhcp').with( + :fixed_range => '10.0.0.0/32', + :public_interface => 'eth0', + :flat_interface => 'eth1', + :flat_network_bridge => 'br400', + #:force_dhcp_release => false, + :flat_injected => true, + :dhcp_domain => 'not-novalocal', + :dhcpbridge => '/tmp/bridge', + :dhcpbridge_flagfile => '/tmp/file' + ) } + + end + end + describe 'when configuring flatmanager' do + let :params do + default_params.merge(:network_manager => 'nova.network.manager.FlatManager') + end + it { should contain_class('nova::network::flat').with( + :fixed_range => '10.0.0.0/32', + :public_interface => nil, + :flat_interface => 'eth1', + :flat_network_bridge => 'br100' + ) } + describe 'when overriding flat network params' do + let :params do + default_params.merge( + { + :network_manager => 'nova.network.manager.FlatManager', + :public_interface => 'eth0', + :config_overrides => {'flat_network_bridge' => 'br400' } + } + ) + end + it { should contain_class('nova::network::flat').with( + :public_interface => 'eth0', + :flat_network_bridge => 'br400' + ) } + end + end + describe 'when configuring vlan' do + let :params do + default_params.merge(:network_manager => 'nova.network.manager.VlanManager') + end + it { should contain_class('nova::network::vlan').with( + :fixed_range => '10.0.0.0/32', + :public_interface => nil, + :vlan_interface => 'eth1', + :force_dhcp_release => true, + :dhcp_domain => 'novalocal', + :dhcpbridge => '/usr/bin/nova-dhcpbridge', + :dhcpbridge_flagfile => '/etc/nova/nova.conf' + ) } + describe 'when overriding parameters' do + let :params do + default_params.merge( + { + } + ) + end + end + end + end + describe 'with package version' do + let :params do + default_params.merge(:ensure_package => '2012.1-2') + end + it { should contain_package('nova-network').with( + 'ensure' => '2012.1-2' + )} + end + end + describe 'on rhel' do + let :facts do + { :osfamily => 'RedHat' } + end + it { should contain_service('nova-network').with( + 'name' => 'openstack-nova-network', + 'ensure' => 'stopped', + 'hasstatus' => true, + 'enable' => false + )} + it { should contain_package('nova-network').with_name('openstack-nova-network') } + end +end diff --git a/3rdparty/modules/nova/spec/classes/nova_network_vlan_spec.rb b/3rdparty/modules/nova/spec/classes/nova_network_vlan_spec.rb new file mode 100644 index 000000000..ddfaaba1e --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_network_vlan_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' + +describe 'nova::network::vlan' do + + describe 'with only required parameters' do + let :params do + { + :vlan_interface => 'eth1', + :fixed_range => '10.0.0.0/32' + } + end + + it { should contain_nova_config('DEFAULT/network_manager').with_value('nova.network.manager.VlanManager') } + it { should_not contain_nova_config('DEFAULT/public_interface') } + it { should contain_nova_config('DEFAULT/fixed_range').with_value('10.0.0.0/32') } + it { should contain_nova_config('DEFAULT/vlan_start').with_value('300') } + it { should contain_nova_config('DEFAULT/vlan_interface').with_value('eth1') } + it { should contain_nova_config('DEFAULT/force_dhcp_release').with_value(true) } + it { should contain_nova_config('DEFAULT/dhcpbridge').with_value('/usr/bin/nova-dhcpbridge') } + it { should contain_nova_config('DEFAULT/dhcpbridge_flagfile').with_value('/etc/nova/nova.conf') } + + end + + describe 'with parameters overridden' do + + let :params do + { + :vlan_interface => 'eth1', + :fixed_range => '10.0.0.0/32', + :public_interface => 'eth0', + :vlan_start => '100', + :force_dhcp_release => false, + :dhcpbridge => '/usr/bin/dhcpbridge', + :dhcpbridge_flagfile => '/etc/nova/nova-dhcp.conf' + } + end + + it { should contain_nova_config('DEFAULT/network_manager').with_value('nova.network.manager.VlanManager') } + it { should contain_nova_config('DEFAULT/public_interface').with_value('eth0') } + it { should contain_nova_config('DEFAULT/fixed_range').with_value('10.0.0.0/32') } + it { should contain_nova_config('DEFAULT/vlan_start').with_value('100') } + it { should contain_nova_config('DEFAULT/vlan_interface').with_value('eth1') } + it { should contain_nova_config('DEFAULT/force_dhcp_release').with_value(false) } + it { should contain_nova_config('DEFAULT/dhcpbridge').with_value('/usr/bin/dhcpbridge') } + it { should contain_nova_config('DEFAULT/dhcpbridge_flagfile').with_value('/etc/nova/nova-dhcp.conf') } + end +end diff --git a/3rdparty/modules/nova/spec/classes/nova_objectstore_spec.rb b/3rdparty/modules/nova/spec/classes/nova_objectstore_spec.rb new file mode 100644 index 000000000..7d0477d24 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_objectstore_spec.rb @@ -0,0 +1,48 @@ +require 'spec_helper' + +describe 'nova::objectstore' do + + let :pre_condition do + 'include nova' + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_behaves_like 'generic nova service', { + :name => 'nova-objectstore', + :package_name => 'nova-objectstore', + :service_name => 'nova-objectstore' } + it { should contain_nova_config('DEFAULT/s3_listen').with_value('0.0.0.0') } + + context 'with custom bind parameter' do + let :params do + { :bind_address => '192.168.0.1'} + end + it { should contain_nova_config('DEFAULT/s3_listen').with_value('192.168.0.1') } + end + + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_behaves_like 'generic nova service', { + :name => 'nova-objectstore', + :package_name => 'openstack-nova-objectstore', + :service_name => 'openstack-nova-objectstore' } + it { should contain_nova_config('DEFAULT/s3_listen').with_value('0.0.0.0')} + + context 'with custom bind parameter' do + let :params do + { :bind_address => '192.168.0.1'} + end + it { should contain_nova_config('DEFAULT/s3_listen').with_value('192.168.0.1') } + end + + end +end diff --git a/3rdparty/modules/nova/spec/classes/nova_policy_spec.rb b/3rdparty/modules/nova/spec/classes/nova_policy_spec.rb new file mode 100644 index 000000000..2d6992e9e --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_policy_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +describe 'nova::policy' do + + shared_examples_for 'nova policies' do + let :params do + { + :policy_path => '/etc/nova/policy.json', + :policies => { + 'context_is_admin' => { + 'key' => 'context_is_admin', + 'value' => 'foo:bar' + } + } + } + end + + it 'set up the policies' do + should contain_openstacklib__policy__base('context_is_admin').with({ + :key => 'context_is_admin', + :value => 'foo:bar' + }) + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'nova policies' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'nova policies' + end +end diff --git a/3rdparty/modules/nova/spec/classes/nova_qpid_spec.rb b/3rdparty/modules/nova/spec/classes/nova_qpid_spec.rb new file mode 100644 index 000000000..6a2e4b204 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_qpid_spec.rb @@ -0,0 +1,50 @@ +require 'spec_helper' + +describe 'nova::qpid' do + + let :facts do + {:puppetversion => '2.7'} + end + + describe 'with defaults' do + + it 'should contain all of the default resources' do + + should contain_class('qpid::server').with( + :service_ensure => 'running', + :port => '5672' + ) + + end + + it 'should contain user' do + + should contain_qpid_user('guest').with( + :password => 'guest', + :file => '/var/lib/qpidd/qpidd.sasldb', + :realm => 'OPENSTACK', + :provider => 'saslpasswd2' + ) + + end + + end + + describe 'when disabled' do + let :params do + { + :enabled => false + } + end + + it 'should be disabled' do + + should_not contain_qpid_user('guest') + should contain_class('qpid::server').with( + :service_ensure => 'stopped' + ) + + end + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_quota_spec.rb b/3rdparty/modules/nova/spec/classes/nova_quota_spec.rb new file mode 100644 index 000000000..8d6eeb530 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_quota_spec.rb @@ -0,0 +1,95 @@ +require 'spec_helper' + +describe 'nova::quota' do + + let :params do + {} + end + + let :default_params do + { :quota_instances => 10, + :quota_cores => 20, + :quota_ram => 51200, + :quota_floating_ips => 10, + :quota_fixed_ips => -1, + :quota_metadata_items => 128, + :quota_injected_files => 5, + :quota_injected_file_content_bytes => 10240, + :quota_injected_file_path_length => 255, + :quota_security_groups => 10, + :quota_security_group_rules => 20, + :quota_key_pairs => 100, + :reservation_expire => 86400, + :until_refresh => 0, + :max_age => 0, + :quota_driver => 'nova.quota.DbQuotaDriver' } + end + + shared_examples_for 'nova quota' do + let :params_hash do + default_params.merge(params) + end + + it 'configures quota in nova.conf' do + params_hash.each_pair do |config,value| + should contain_nova_config("DEFAULT/#{config}").with_value( value ) + end + end + end + + context 'with default parameters' do + it_configures 'nova quota' + end + + context 'with provided parameters' do + before do + params.merge!({ + :quota_instances => 20, + :quota_cores => 40, + :quota_ram => 102400, + :quota_floating_ips => 20, + :quota_fixed_ips => 512, + :quota_metadata_items => 256, + :quota_injected_files => 10, + :quota_injected_file_content_bytes => 20480, + :quota_injected_file_path_length => 254, + :quota_security_groups => 20, + :quota_security_group_rules => 40, + :quota_key_pairs => 200, + :reservation_expire => 6400, + :until_refresh => 30, + :max_age => 60 + }) + end + + it_configures 'nova quota' + end + + context 'with deprecated parameters' do + let :params do { + :quota_max_injected_files => 10, + :quota_max_injected_file_content_bytes => 20480, + :quota_injected_file_path_bytes => 254 + } + end + + it { + should contain_nova_config('DEFAULT/quota_injected_files').with_value('10') + should contain_nova_config('DEFAULT/quota_injected_file_content_bytes').with_value('20480') + should contain_nova_config('DEFAULT/quota_injected_file_path_length').with_value('254') + } + end + + it { should contain_nova_config('DEFAULT/quota_ram').with_value('51200') } + + describe 'when overriding params' do + + let :params do + {:quota_ram => '1'} + end + + it { should contain_nova_config('DEFAULT/quota_ram').with_value('1') } + + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_rabbitmq_spec.rb b/3rdparty/modules/nova/spec/classes/nova_rabbitmq_spec.rb new file mode 100644 index 000000000..a5c7537e7 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_rabbitmq_spec.rb @@ -0,0 +1,105 @@ +require 'spec_helper' + +describe 'nova::rabbitmq' do + + let :facts do + { + :puppetversion => '2.7', + :osfamily => 'Debian' + } + end + + describe 'with defaults' do + + it 'should contain all of the default resources' do + + should contain_class('rabbitmq::server').with( + :service_ensure => 'running', + :port => '5672', + :delete_guest_user => false + ) + + should contain_rabbitmq_vhost('/').with( + :provider => 'rabbitmqctl' + ) + end + + end + + describe 'when a rabbitmq user is specified' do + + let :params do + { + :userid => 'dan', + :password => 'pass' + } + end + + it 'should contain user and permissions' do + + should contain_rabbitmq_user('dan').with( + :admin => true, + :password => 'pass', + :provider => 'rabbitmqctl' + ) + + should contain_rabbitmq_user_permissions('dan@/').with( + :configure_permission => '.*', + :write_permission => '.*', + :read_permission => '.*', + :provider => 'rabbitmqctl' + ) + + end + + end + + describe 'when disabled' do + let :params do + { + :userid => 'dan', + :password => 'pass', + :enabled => false + } + end + + it 'should be disabled' do + + should_not contain_rabbitmq_user('dan') + should_not contain_rabbitmq_user_permissions('dan@/') + should contain_class('rabbitmq::server').with( + :service_ensure => 'stopped', + :port => '5672', + :delete_guest_user => false + ) + + should_not contain_rabbitmq_vhost('/') + + end + end + + describe 'with clustering' do + + let :params do + { + :cluster_disk_nodes => ['rabbit01', 'rabbit02', 'rabbit03'] + } + end + + it 'should contain all the clustering resources' do + + should contain_class('rabbitmq::server').with( + :service_ensure => 'running', + :port => '5672', + :delete_guest_user => false, + :config_cluster => true, + :cluster_disk_nodes => ['rabbit01', 'rabbit02', 'rabbit03'], + :wipe_db_on_cookie_change => true + ) + + end + + end + + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_scheduler_filter_spec.rb b/3rdparty/modules/nova/spec/classes/nova_scheduler_filter_spec.rb new file mode 100644 index 000000000..a39726f36 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_scheduler_filter_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' + +describe 'nova::scheduler::filter' do + + it { should contain_nova_config('DEFAULT/scheduler_host_manager').with_value('nova.scheduler.host_manager.HostManager') } + it { should contain_nova_config('DEFAULT/scheduler_max_attempts').with_value('3') } + it { should contain_nova_config('DEFAULT/scheduler_host_subset_size').with_value('1') } + it { should contain_nova_config('DEFAULT/cpu_allocation_ratio').with_value('16.0') } + it { should contain_nova_config('DEFAULT/disk_allocation_ratio').with_value('1.0') } + it { should contain_nova_config('DEFAULT/max_io_ops_per_host').with_value('8') } + it { should contain_nova_config('DEFAULT/max_instances_per_host').with_value('50') } + it { should contain_nova_config('DEFAULT/ram_allocation_ratio').with_value('1.5') } + it { should contain_nova_config('DEFAULT/scheduler_available_filters').with_value('nova.scheduler.filters.all_filters') } + it { should contain_nova_config('DEFAULT/scheduler_weight_classes').with_value('nova.scheduler.weights.all_weighers') } + + describe 'when overriding params' do + + let :params do + {:scheduler_max_attempts => '4', + :isolated_images => ['ubuntu1','centos2'], + :isolated_hosts => ['192.168.1.2','192.168.1.3'], + :scheduler_default_filters => ['RetryFilter','AvailabilityZoneFilter','RamFilter'] + } + end + + it { should contain_nova_config('DEFAULT/scheduler_max_attempts').with_value('4') } + it { should contain_nova_config('DEFAULT/isolated_images').with_value('ubuntu1,centos2') } + it { should contain_nova_config('DEFAULT/isolated_hosts').with_value('192.168.1.2,192.168.1.3') } + it { should contain_nova_config('DEFAULT/scheduler_default_filters').with_value('RetryFilter,AvailabilityZoneFilter,RamFilter') } + + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_scheduler_spec.rb b/3rdparty/modules/nova/spec/classes/nova_scheduler_spec.rb new file mode 100644 index 000000000..46836974d --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_scheduler_spec.rb @@ -0,0 +1,99 @@ +require 'spec_helper' + +describe 'nova::scheduler' do + + let :pre_condition do + 'include nova' + end + + let :params do + { :enabled => true } + end + + shared_examples 'nova-scheduler' do + + + it { should contain_package('nova-scheduler').with( + :name => platform_params[:scheduler_package_name], + :ensure => 'present' + ) } + + it { should contain_service('nova-scheduler').with( + :name => platform_params[:scheduler_service_name], + :hasstatus => 'true', + :ensure => 'running' + )} + + context 'with manage_service as false' do + let :params do + { :enabled => true, + :manage_service => false + } + end + it { should contain_service('nova-scheduler').without_ensure } + end + + context 'with package version' do + let :params do + { :ensure_package => '2012.1-2' } + end + + it { should contain_package('nova-scheduler').with( + :ensure => params[:ensure_package] + )} + end + + context 'with default database parameters' do + let :pre_condition do + "include nova" + end + + it { should_not contain_nova_config('database/connection') } + it { should_not contain_nova_config('database/slave_connection') } + it { should_not contain_nova_config('database/idle_timeout').with_value('3600') } + end + + context 'with overridden database parameters' do + let :pre_condition do + "class { 'nova': + database_connection => 'mysql://user:pass@db/db', + slave_connection => 'mysql://user:pass@slave/db', + database_idle_timeout => '30', + } + " + end + + it { should contain_nova_config('database/connection').with_value('mysql://user:pass@db/db').with_secret(true) } + it { should contain_nova_config('database/slave_connection').with_value('mysql://user:pass@slave/db').with_secret(true) } + it { should contain_nova_config('database/idle_timeout').with_value('30') } + end + + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + let :platform_params do + { :scheduler_package_name => 'nova-scheduler', + :scheduler_service_name => 'nova-scheduler' } + end + + it_configures 'nova-scheduler' + end + + context 'on Redhat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :scheduler_package_name => 'openstack-nova-scheduler', + :scheduler_service_name => 'openstack-nova-scheduler' } + end + + it_configures 'nova-scheduler' + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_serial_proxy_spec.rb b/3rdparty/modules/nova/spec/classes/nova_serial_proxy_spec.rb new file mode 100644 index 000000000..1dcaca165 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_serial_proxy_spec.rb @@ -0,0 +1,92 @@ +require 'spec_helper' + +describe 'nova::serialproxy' do + + let :pre_condition do + 'include nova' + end + + let :params do + { :enabled => true } + end + + shared_examples 'nova-serialproxy' do + + it 'configures nova.conf' do + should contain_nova_config('serial_console/serialproxy_host').with(:value => '0.0.0.0') + should contain_nova_config('serial_console/serialproxy_port').with(:value => '6083') + end + + it { should contain_package('nova-serialproxy').with( + :name => platform_params[:serialproxy_package_name], + :ensure => 'present' + ) } + + it { should contain_service('nova-serialproxy').with( + :name => platform_params[:serialproxy_service_name], + :hasstatus => 'true', + :ensure => 'running' + )} + + context 'with manage_service as false' do + let :params do + { :enabled => true, + :manage_service => false + } + end + it { should contain_service('nova-serialproxy').without_ensure } + end + + context 'with package version' do + let :params do + { :ensure_package => '2012.2' } + end + + it { should contain_package('nova-serialproxy').with( + :ensure => params[:ensure_package] + )} + end + end + + context 'on Ubuntu system' do + let :facts do + { :osfamily => 'Debian', + :operatingsystem => 'Ubuntu' } + end + + let :platform_params do + { :serialproxy_package_name => 'nova-serialproxy', + :serialproxy_service_name => 'nova-serialproxy' } + end + + it_configures 'nova-serialproxy' + end + + context 'on Debian system' do + let :facts do + { :osfamily => 'Debian', + :operatingsystem => 'Debian' } + end + + let :platform_params do + { :serialproxy_package_name => 'nova-serialproxy', + :serialproxy_service_name => 'nova-serialproxy' } + end + + it_configures 'nova-serialproxy' + end + + context 'on Redhat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :serialproxy_package_name => 'openstack-nova-serialproxy', + :serialproxy_service_name => 'openstack-nova-serialproxy' } + end + + it_configures 'nova-serialproxy' + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_spicehtml5_proxy_spec.rb b/3rdparty/modules/nova/spec/classes/nova_spicehtml5_proxy_spec.rb new file mode 100644 index 000000000..529ee0ebd --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_spicehtml5_proxy_spec.rb @@ -0,0 +1,92 @@ +require 'spec_helper' + +describe 'nova::spicehtml5proxy' do + + let :pre_condition do + 'include nova' + end + + let :params do + { :enabled => true } + end + + shared_examples 'nova-spicehtml5proxy' do + + it 'configures nova.conf' do + should contain_nova_config('DEFAULT/spicehtml5proxy_host').with(:value => '0.0.0.0') + should contain_nova_config('DEFAULT/spicehtml5proxy_port').with(:value => '6082') + end + + it { should contain_package('nova-spicehtml5proxy').with( + :name => platform_params[:spicehtml5proxy_package_name], + :ensure => 'present' + ) } + + it { should contain_service('nova-spicehtml5proxy').with( + :name => platform_params[:spicehtml5proxy_service_name], + :hasstatus => 'true', + :ensure => 'running' + )} + + context 'with manage_service as false' do + let :params do + { :enabled => true, + :manage_service => false + } + end + it { should contain_service('nova-spicehtml5proxy').without_ensure } + end + + context 'with package version' do + let :params do + { :ensure_package => '2012.1-2' } + end + + it { should contain_package('nova-spicehtml5proxy').with( + :ensure => params[:ensure_package] + )} + end + end + + context 'on Ubuntu system' do + let :facts do + { :osfamily => 'Debian', + :operatingsystem => 'Ubuntu' } + end + + let :platform_params do + { :spicehtml5proxy_package_name => 'nova-spiceproxy', + :spicehtml5proxy_service_name => 'nova-spiceproxy' } + end + + it_configures 'nova-spicehtml5proxy' + end + + context 'on Debian system' do + let :facts do + { :osfamily => 'Debian', + :operatingsystem => 'Debian' } + end + + let :platform_params do + { :spicehtml5proxy_package_name => 'nova-consoleproxy', + :spicehtml5proxy_service_name => 'nova-spicehtml5proxy' } + end + + it_configures 'nova-spicehtml5proxy' + end + + context 'on Redhat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + let :platform_params do + { :spicehtml5proxy_package_name => 'openstack-nova-console', + :spicehtml5proxy_service_name => 'openstack-nova-spicehtml5proxy' } + end + + it_configures 'nova-spicehtml5proxy' + end + +end diff --git a/3rdparty/modules/nova/spec/classes/nova_utilities_spec.rb b/3rdparty/modules/nova/spec/classes/nova_utilities_spec.rb new file mode 100644 index 000000000..52d722d6a --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_utilities_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe 'nova::utilities' do + + describe 'on debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it 'installes utilities' do + should contain_package('unzip').with_ensure('present') + should contain_package('screen').with_ensure('present') + should contain_package('parted').with_ensure('present') + should contain_package('curl').with_ensure('present') + should contain_package('euca2ools').with_ensure('present') + should contain_package('libguestfs-tools').with_ensure('present') + end + end +end diff --git a/3rdparty/modules/nova/spec/classes/nova_vnc_proxy_spec.rb b/3rdparty/modules/nova/spec/classes/nova_vnc_proxy_spec.rb new file mode 100644 index 000000000..0b1268651 --- /dev/null +++ b/3rdparty/modules/nova/spec/classes/nova_vnc_proxy_spec.rb @@ -0,0 +1,86 @@ +require 'spec_helper' + +describe 'nova::vncproxy' do + + let :pre_condition do + 'include nova' + end + + let :params do + {:enabled => true} + end + + describe 'on debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it { should contain_package('python-numpy').with( + :ensure => 'present', + :name => 'python-numpy' + )} + + it { should contain_nova_config('DEFAULT/novncproxy_host').with(:value => '0.0.0.0') } + it { should contain_nova_config('DEFAULT/novncproxy_port').with(:value => '6080') } + it { should contain_nova_config('DEFAULT/novncproxy_base_url').with(:value => 'http://0.0.0.0:6080/vnc_auto.html') } + + it { should contain_package('nova-vncproxy').with( + :name => 'nova-novncproxy', + :ensure => 'present' + ) } + it { should contain_service('nova-vncproxy').with( + :name => 'nova-novncproxy', + :hasstatus => true, + :ensure => 'running' + )} + + describe 'with manage_service as false' do + let :params do + { :enabled => true, + :manage_service => false + } + end + it { should contain_service('nova-vncproxy').without_ensure } + end + + describe 'with package version' do + let :params do + {:ensure_package => '2012.1-2'} + end + it { should contain_package('nova-vncproxy').with( + 'ensure' => '2012.1-2' + )} + end + + end + + describe 'on debian OS' do + let :facts do + { :osfamily => 'Debian', :operatingsystem => 'Debian' } + end + it { should contain_package('nova-vncproxy').with( + :name => "nova-consoleproxy", + :ensure => 'present' + )} + it { should contain_service('nova-vncproxy').with( + :name => 'nova-novncproxy', + :hasstatus => true, + :ensure => 'running' + )} + end + + + describe 'on Redhatish platforms' do + + let :facts do + { :osfamily => 'Redhat' } + end + + it { should contain_package('python-numpy').with( + :name => 'numpy', + :ensure => 'present' + )} + + end + +end diff --git a/3rdparty/modules/nova/spec/defines/nova_generic_service_spec.rb b/3rdparty/modules/nova/spec/defines/nova_generic_service_spec.rb new file mode 100644 index 000000000..1cad4f7a5 --- /dev/null +++ b/3rdparty/modules/nova/spec/defines/nova_generic_service_spec.rb @@ -0,0 +1,32 @@ +require 'spec_helper' + +describe 'nova::generic_service' do + describe 'package should come before service' do + let :pre_condition do + 'include nova' + end + + let :params do + { + :package_name => 'foo', + :service_name => 'food', + :enabled => true + } + end + + let :facts do + { :osfamily => 'Debian' } + end + + let :title do + 'foo' + end + + it { should contain_service('nova-foo').with( + 'name' => 'food', + 'ensure' => 'running', + 'enable' => true, + 'require' => ['Package[nova-common]', 'Package[foo]'] + )} + end +end diff --git a/3rdparty/modules/nova/spec/defines/nova_manage_networks_spec.rb b/3rdparty/modules/nova/spec/defines/nova_manage_networks_spec.rb new file mode 100644 index 000000000..2444a2a32 --- /dev/null +++ b/3rdparty/modules/nova/spec/defines/nova_manage_networks_spec.rb @@ -0,0 +1,56 @@ +require 'spec_helper' + +describe 'nova::manage::network' do + + let :facts do + {:osfamily => 'RedHat'} + end + + let :pre_condition do + 'include nova' + end + + let :title do + 'foo' + end + + describe 'with only required parameters' do + let :params do + { + :network => '10.0.0.0/24' + } + end + it { should contain_nova_network('foo').with( + :ensure => 'present', + :network => '10.0.0.0/24', + :label => 'novanetwork', + :num_networks => 1, + :project => nil + ) } + end + describe 'when overriding num networks' do + let :params do + { + :network => '10.0.0.0/20', + :num_networks => 2 + } + end + it { should contain_nova_network('foo').with( + :network => '10.0.0.0/20', + :num_networks => 2 + ) } + end + + describe 'when overriding projects' do + let :params do + { + :network => '10.0.0.0/20', + :project => 'foo' + } + end + it { should contain_nova_network('foo').with( + :network => '10.0.0.0/20', + :project => 'foo' + ) } + end +end diff --git a/3rdparty/modules/nova/spec/fixtures/manifests/site.pp b/3rdparty/modules/nova/spec/fixtures/manifests/site.pp new file mode 100644 index 000000000..bae85c0cb --- /dev/null +++ b/3rdparty/modules/nova/spec/fixtures/manifests/site.pp @@ -0,0 +1,7 @@ +node default {} + +node 'test-001.example.org' { + include ::nova + include ::nova::consoleauth + include ::nova::spicehtml5proxy +} diff --git a/3rdparty/modules/nova/spec/hosts/test-001_spec.rb b/3rdparty/modules/nova/spec/hosts/test-001_spec.rb new file mode 100644 index 000000000..08c823f8f --- /dev/null +++ b/3rdparty/modules/nova/spec/hosts/test-001_spec.rb @@ -0,0 +1,19 @@ +require 'spec_helper' + +describe 'test-001.example.org' do + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + # Bug #1278452 + it 'nova::consoleauth and nova::spicehtml5proxy do not conflict' do + should contain_class('nova::consoleauth') + should contain_class('nova::spicehtml5proxy') + + should contain_nova__generic_service('consoleauth') + should contain_nova__generic_service('spicehtml5proxy') + end + end +end diff --git a/3rdparty/modules/nova/spec/shared_examples.rb b/3rdparty/modules/nova/spec/shared_examples.rb new file mode 100644 index 000000000..b7b16517e --- /dev/null +++ b/3rdparty/modules/nova/spec/shared_examples.rb @@ -0,0 +1,57 @@ +shared_examples_for "a Puppet::Error" do |description| + it "with message matching #{description.inspect}" do + expect { should have_class_count(1) }.to raise_error(Puppet::Error, description) + end +end + +shared_examples 'generic nova service' do |service| + + context 'with default parameters' do + it 'installs package and service' do + should contain_package(service[:name]).with({ + :name => service[:package_name], + :ensure => 'present', + :notify => "Service[#{service[:name]}]", + :tag => ['openstack', 'nova'] + }) + should contain_service(service[:name]).with({ + :name => service[:service_name], + :ensure => 'stopped', + :hasstatus => true, + :enable => false + }) + end + end + + context 'with overridden parameters' do + let :params do + { :enabled => true, + :ensure_package => '2012.1-2' } + end + + it 'installs package and service' do + should contain_package(service[:name]).with({ + :name => service[:package_name], + :ensure => '2012.1-2', + :notify => "Service[#{service[:name]}]" + }) + should contain_service(service[:name]).with({ + :name => service[:service_name], + :ensure => 'running', + :hasstatus => true, + :enable => true + }) + end + end + + context 'while not managing service state' do + let :params do + { :enabled => false, + :manage_service => false } + end + + it 'does not control service state' do + should contain_service(service[:name]).without_ensure + end + end +end diff --git a/3rdparty/modules/nova/spec/spec_helper.rb b/3rdparty/modules/nova/spec/spec_helper.rb new file mode 100644 index 000000000..53d4dd02d --- /dev/null +++ b/3rdparty/modules/nova/spec/spec_helper.rb @@ -0,0 +1,7 @@ +require 'puppetlabs_spec_helper/module_spec_helper' +require 'shared_examples' + +RSpec.configure do |c| + c.alias_it_should_behave_like_to :it_configures, 'configures' + c.alias_it_should_behave_like_to :it_raises, 'raises' +end diff --git a/3rdparty/modules/nova/spec/type/nova_aggregate_spec.rb b/3rdparty/modules/nova/spec/type/nova_aggregate_spec.rb new file mode 100644 index 000000000..dc5db974a --- /dev/null +++ b/3rdparty/modules/nova/spec/type/nova_aggregate_spec.rb @@ -0,0 +1,66 @@ +# run with: rspec spec/type/nova_aggregate_spec.rb + +require 'spec_helper' + + +describe Puppet::Type.type(:nova_aggregate) do + before :each do + @provider_class = described_class.provide(:simple) do + mk_resource_methods + def create; end + def delete; end + def exists?; get(:ensure) != :absent; end + def flush; end + def self.instances; []; end + end + end + + it "should be able to create an instance" do + described_class.new(:name => 'agg0').should_not be_nil + end + + it "should be able to create an more complex instance" do + described_class.new(:name => 'agg0', + :availability_zone => 'myzone', + :metadata => "a=b, c=d", + :hosts => "host1").should_not be_nil + end + + it "should be able to create an more complex instance with multiple hosts" do + described_class.new(:name => 'agg0', + :availability_zone => 'myzone', + :metadata => "a=b, c=d", + :hosts => "host1, host2").should_not be_nil + end + + it "should be able to create a instance and have the default values" do + c = described_class.new(:name => 'agg0') + c[:name].should == "agg0" + c[:availability_zone].should == nil + c[:metadata].should == nil + c[:hosts].should == nil + end + + it "should return the given values" do + c = described_class.new(:name => 'agg0', + :availability_zone => 'myzone', + :metadata => " a = b , c= d ", + :hosts => " host1, host2 ") + c[:name].should == "agg0" + c[:availability_zone].should == "myzone" + c[:metadata].should == {"a" => "b", "c" => "d"} + c[:hosts].should == ["host1" , "host2"] + end + + it "should return the given values" do + c = described_class.new(:name => 'agg0', + :availability_zone => "", + :metadata => "", + :hosts => "") + c[:name].should == "agg0" + c[:availability_zone].should == "" + c[:metadata].should == {} + c[:hosts].should == [] + end + +end diff --git a/3rdparty/modules/nova/spec/unit/provider/nova_config/ini_setting_spec.rb b/3rdparty/modules/nova/spec/unit/provider/nova_config/ini_setting_spec.rb new file mode 100644 index 000000000..0f58316d3 --- /dev/null +++ b/3rdparty/modules/nova/spec/unit/provider/nova_config/ini_setting_spec.rb @@ -0,0 +1,38 @@ +# +# these tests are a little concerning b/c they are hacking around the +# modulepath, so these tests will not catch issues that may eventually arise +# related to loading these plugins. +# I could not, for the life of me, figure out how to programatcally set the modulepath +$LOAD_PATH.push( + File.join( + File.dirname(__FILE__), + '..', + '..', + '..', + 'fixtures', + 'modules', + 'inifile', + 'lib') +) +require 'spec_helper' +provider_class = Puppet::Type.type(:nova_config).provider(:ini_setting) +describe provider_class do + + it 'should default to the default setting when no other one is specified' do + resource = Puppet::Type::Nova_config.new( + {:name => 'DEFAULT/foo', :value => 'bar'} + ) + provider = provider_class.new(resource) + provider.section.should == 'DEFAULT' + provider.setting.should == 'foo' + end + + it 'should allow setting to be set explicitly' do + resource = Puppet::Type::Nova_config.new( + {:name => 'dude/foo', :value => 'bar'} + ) + provider = provider_class.new(resource) + provider.section.should == 'dude' + provider.setting.should == 'foo' + end +end diff --git a/3rdparty/modules/nova/spec/unit/provider/nova_spec.rb b/3rdparty/modules/nova/spec/unit/provider/nova_spec.rb new file mode 100644 index 000000000..6f757e746 --- /dev/null +++ b/3rdparty/modules/nova/spec/unit/provider/nova_spec.rb @@ -0,0 +1,274 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/nova' +require 'rspec/mocks' + +describe Puppet::Provider::Nova do + + def klass + described_class + end + + let :credential_hash do + { + 'auth_host' => '192.168.56.210', + 'auth_port' => '35357', + 'auth_protocol' => 'https', + 'admin_tenant_name' => 'admin_tenant', + 'admin_user' => 'admin', + 'admin_password' => 'password', + } + end + + let :auth_endpoint do + 'https://192.168.56.210:35357/v2.0/' + end + + let :credential_error do + /Nova types will not work/ + end + + after :each do + klass.reset + end + + describe 'when determining credentials' do + + it 'should fail if config is empty' do + conf = {} + klass.expects(:nova_conf).returns(conf) + expect do + klass.nova_credentials + end.to raise_error(Puppet::Error, credential_error) + end + + it 'should fail if config does not have keystone_authtoken section.' do + conf = {'foo' => 'bar'} + klass.expects(:nova_conf).returns(conf) + expect do + klass.nova_credentials + end.to raise_error(Puppet::Error, credential_error) + end + + it 'should fail if config does not contain all auth params' do + conf = {'keystone_authtoken' => {'invalid_value' => 'foo'}} + klass.expects(:nova_conf).returns(conf) + expect do + klass.nova_credentials + end.to raise_error(Puppet::Error, credential_error) + end + + it 'should use specified host/port/protocol in the auth endpoint' do + conf = {'keystone_authtoken' => credential_hash} + klass.expects(:nova_conf).returns(conf) + klass.get_auth_endpoint.should == auth_endpoint + end + + end + + describe 'when invoking the nova cli' do + + it 'should set auth credentials in the environment' do + authenv = { + :OS_AUTH_URL => auth_endpoint, + :OS_USERNAME => credential_hash['admin_user'], + :OS_TENANT_NAME => credential_hash['admin_tenant_name'], + :OS_PASSWORD => credential_hash['admin_password'], + } + klass.expects(:get_nova_credentials).with().returns(credential_hash) + klass.expects(:withenv).with(authenv) + klass.auth_nova('test_retries') + end + + ['[Errno 111] Connection refused', + '(HTTP 400)'].reverse.each do |valid_message| + it "should retry when nova cli returns with error #{valid_message}" do + klass.expects(:get_nova_credentials).with().returns({}) + klass.expects(:sleep).with(10).returns(nil) + klass.expects(:nova).twice.with(['test_retries']).raises( + Exception, valid_message).then.returns('') + klass.auth_nova('test_retries') + end + end + + end + + describe 'when parse a string line' do + it 'should return the same string' do + res = klass.str2hash("zone1") + res.should == "zone1" + end + + it 'should return the string without quotes' do + res = klass.str2hash("'zone1'") + res.should == "zone1" + end + + it 'should return the same string' do + res = klass.str2hash("z o n e1") + res.should == "z o n e1" + end + + it 'should return a hash' do + res = klass.str2hash("a=b") + res.should == {"a"=>"b"} + end + + it 'should return a hash with containing spaces' do + res = klass.str2hash("a b = c d") + res.should == {"a b "=>" c d"} + end + + it 'should return the same string' do + res = klass.str2list("zone1") + res.should == "zone1" + end + + it 'should return a list of strings' do + res = klass.str2list("zone1, zone2") + res.should == ["zone1", "zone2"] + end + + + it 'should return a list of strings' do + res = klass.str2list("zo n e1, zone2 ") + res.should == ["zo n e1", "zone2"] + end + + it 'should return a hash with multiple keys' do + res = klass.str2list("a=b, c=d") + res.should == {"a"=>"b", "c"=>"d"} + end + + it 'should return a single hash' do + res = klass.str2list("a=b") + res.should == {"a"=>"b"} + end + end + + describe 'when parsing cli output' do + + it 'should return a list with hashes' do + output = <<-EOT ++----+-------+-------------------+ +| Id | Name | Availability Zone | ++----+-------+-------------------+ +| 1 | haha | haha2 | +| 2 | haha2 | - | ++----+-------+-------------------+ + EOT + res = klass.cliout2list(output) + res.should == [{"Id"=>"1", "Name"=>"haha", "Availability Zone"=>"haha2"}, + {"Id"=>"2", "Name"=>"haha2", "Availability Zone"=>""}] + end + + it 'should return a list with hashes' do + output = <<-EOT ++----+-------+-------------------+-------+--------------------------------------------------+ +| Id | Name | Availability Zone | Hosts | Metadata | ++----+-------+-------------------+-------+--------------------------------------------------+ +| 16 | agg94 | my_-zone1 | | 'a=b', 'availability_zone= my_-zone1', 'x_q-r=y' | ++----+-------+-------------------+-------+--------------------------------------------------+ +EOT + res = klass.cliout2list(output) + res.should == [{"Id"=>"16", + "Name"=>"agg94", + "Availability Zone"=>"my_-zone1", + "Hosts"=>"", + "Metadata"=> { + "a"=>"b", + "availability_zone"=>" my_-zone1", + "x_q-r"=>"y" + } + }] + end + + it 'should return a empty list' do + output = <<-EOT ++----+------+-------------------+ +| Id | Name | Availability Zone | ++----+------+-------------------+ ++----+------+-------------------+ + EOT + res = klass.cliout2list(output) + res.should == [] + end + + it 'should return a empty list because no input available' do + output = <<-EOT + EOT + res = klass.cliout2list(output) + res.should == [] + end + + it 'should return a list with hashes' do + output = <<-EOT ++----+----------------+-------------------+ +| Id | Name | Availability Zone | ++----+----------------+-------------------+ +| 6 | my | zone1 | +| 8 | my2 | - | ++----+----------------+-------------------+ + EOT + res = klass.cliout2list(output) + res.should == [{"Id"=>"6", "Name"=>"my", "Availability Zone"=>"zone1"}, + {"Id"=>"8", "Name"=>"my2", "Availability Zone"=>""}] + end + end + + describe 'when handling cli output' do + it 'should return the availble Id' do + output = <<-EOT ++----+-------+-------------------+ +| Id | Name | Availability Zone | ++----+-------+-------------------+ +| 1 | haha | haha2 | +| 2 | haha2 | - | ++----+-------+-------------------+ + EOT + klass.expects(:auth_nova).returns(output) + res = klass.nova_aggregate_resources_get_name_by_id("haha2") + res.should eql(2) + end + + it 'should return nil because given name is not available' do + output = <<-EOT ++----+-------+-------------------+ +| Id | Name | Availability Zone | ++----+-------+-------------------+ +| 1 | haha | haha2 | +| 2 | haha2 | - | ++----+-------+-------------------+ + EOT + klass.expects(:auth_nova).returns(output) + res = klass.nova_aggregate_resources_get_name_by_id("notavailable") + res.should eql(nil) + end + end + + describe 'when getting details for given Id' do + it 'should return a Hash with the details' do + output = <<-EOT ++----+-------+-------------------+-------+--------------------------------------------------+ +| Id | Name | Availability Zone | Hosts | Metadata | ++----+-------+-------------------+-------+--------------------------------------------------+ +| 16 | agg94 | my_-zone1 | | 'a=b', 'availability_zone= my_-zone1', 'x_q-r=y' | ++----+-------+-------------------+-------+--------------------------------------------------+ + EOT + klass.expects(:auth_nova).returns(output) + res = klass.nova_aggregate_resources_attr(16) + res.should == { + "Id"=>"16", + "Name"=>"agg94", + "Availability Zone"=>"my_-zone1", + "Hosts"=>[], + "Metadata"=>{ + "a"=>"b", + "availability_zone"=>" my_-zone1", + "x_q-r"=>"y" + } + } + end + + end +end diff --git a/3rdparty/modules/nova/spec/unit/type/nova_config_spec.rb b/3rdparty/modules/nova/spec/unit/type/nova_config_spec.rb new file mode 100644 index 000000000..353fff087 --- /dev/null +++ b/3rdparty/modules/nova/spec/unit/type/nova_config_spec.rb @@ -0,0 +1,52 @@ +require 'puppet' +require 'puppet/type/nova_config' +describe 'Puppet::Type.type(:nova_config)' do + before :each do + @nova_config = Puppet::Type.type(:nova_config).new(:name => 'DEFAULT/foo', :value => 'bar') + end + + it 'should require a name' do + expect { + Puppet::Type.type(:nova_config).new({}) + }.to raise_error(Puppet::Error, 'Title or name must be provided') + end + + it 'should not expect a name with whitespace' do + expect { + Puppet::Type.type(:nova_config).new(:name => 'f oo') + }.to raise_error(Puppet::Error, /Parameter name failed/) + end + + it 'should fail when there is no section' do + expect { + Puppet::Type.type(:nova_config).new(:name => 'foo') + }.to raise_error(Puppet::Error, /Parameter name failed/) + end + + it 'should not require a value when ensure is absent' do + Puppet::Type.type(:nova_config).new(:name => 'DEFAULT/foo', :ensure => :absent) + end + + it 'should accept a valid value' do + @nova_config[:value] = 'bar' + @nova_config[:value].should == 'bar' + end + + it 'should not accept a value with whitespace' do + @nova_config[:value] = 'b ar' + @nova_config[:value].should == 'b ar' + end + + it 'should accept valid ensure values' do + @nova_config[:ensure] = :present + @nova_config[:ensure].should == :present + @nova_config[:ensure] = :absent + @nova_config[:ensure].should == :absent + end + + it 'should not accept invalid ensure values' do + expect { + @nova_config[:ensure] = :latest + }.to raise_error(Puppet::Error, /Invalid value/) + end +end diff --git a/3rdparty/modules/nova/spec/unit/type/nova_network_spec.rb b/3rdparty/modules/nova/spec/unit/type/nova_network_spec.rb new file mode 100644 index 000000000..943716d0d --- /dev/null +++ b/3rdparty/modules/nova/spec/unit/type/nova_network_spec.rb @@ -0,0 +1,11 @@ +require 'puppet' +require 'puppet/type/nova_network' +describe 'Puppet::Type.type(:nova_network)' do + it 'should reject an invalid ipv4 CIDR value' do + expect { Puppet::Type.type(:nova_network).new(:network => '192.168.1.0') }.to raise_error(Puppet::Error, /Invalid value/) + expect { Puppet::Type.type(:nova_network).new(:network => '::1/24') }.to raise_error(Puppet::Error, /Invalid value/) + end + it 'should accept a valid ipv4 CIDR value' do + Puppet::Type.type(:nova_network).new(:network => '192.168.1.0/24') + end +end diff --git a/3rdparty/modules/nova/templates/secret.xml-compute.erb b/3rdparty/modules/nova/templates/secret.xml-compute.erb new file mode 100644 index 000000000..a17d70e05 --- /dev/null +++ b/3rdparty/modules/nova/templates/secret.xml-compute.erb @@ -0,0 +1,6 @@ + + + <%= rbd_keyring %> secret + + <%= @libvirt_rbd_secret_uuid %> + diff --git a/3rdparty/modules/openstacklib/Gemfile b/3rdparty/modules/openstacklib/Gemfile new file mode 100644 index 000000000..fedea5277 --- /dev/null +++ b/3rdparty/modules/openstacklib/Gemfile @@ -0,0 +1,22 @@ +source 'https://rubygems.org' + +group :development, :test do + gem 'puppetlabs_spec_helper', :require => false + gem 'metadata-json-lint' + gem 'puppet-lint', '~> 0.3.2' + gem 'rspec-puppet', '~> 1.0.1' + gem 'rake', '10.1.1' + gem 'rspec' + gem 'mocha' + gem 'json' + gem 'faraday', '0.8.8', :require => false + gem 'vcr', :require => false +end + +if puppetversion = ENV['PUPPET_GEM_VERSION'] + gem 'puppet', puppetversion, :require => false +else + gem 'puppet', :require => false +end + +# vim:ft=ruby diff --git a/3rdparty/modules/openstacklib/LICENSE b/3rdparty/modules/openstacklib/LICENSE new file mode 100644 index 000000000..7aaad113c --- /dev/null +++ b/3rdparty/modules/openstacklib/LICENSE @@ -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 2014 Puppet Labs Inc + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/3rdparty/modules/openstacklib/README.md b/3rdparty/modules/openstacklib/README.md new file mode 100644 index 000000000..4e9b7aeab --- /dev/null +++ b/3rdparty/modules/openstacklib/README.md @@ -0,0 +1,271 @@ +openstacklib +============ + +5.1.0 - 2014.2 - Juno +#### 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) +8. [Release Notes - Notes on the most recent updates to the module](#release-notes) + +Overview +-------- + +The openstacklib module is a part of [Stackforge](https://github.com/stackforge), +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. These modules can be found, all +pulled together in the [openstack module](https://github.com/stackforge/puppet-openstack). + +Setup +----- + +### Installing openstacklib + + example% puppet module install puppetlabs/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::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' + +### Types and Providers + +#### Aviator + +#####`Puppet::add_aviator_params` + +The aviator type is not a real type, but it serves to simulate a mixin model, +whereby other types can call out to the Puppet::add\_aviator\_params method in +order to add aviator-specific parameters to themselves. Currently this adds the +auth parameter to the given type. The method must be called after the type is +declared, e.g.: + +```puppet +require 'puppet/type/aviator' +Puppet::Type.newtype(:my_type) do +# ... +end +Puppet::add_aviator_params(:my_type) +``` + +#####`Puppet::Provider::Aviator` + +The aviator provider is a parent provider intended to serve as a base for other +providers that need to authenticate against keystone in order to accomplish a +task. + +**`Puppet::Provider::Aviator#authenticate`** + +Either creates an authenticated session or sets up an unauthenticated session +with instance variables initialized with a token to inject into the next request. +It takes as arguments a set of authentication parameters as a hash and a path +to a log file. Puppet::Provider::Aviator#authencate looks for five different +possible methods of authenticating, in the following order: + +1) Username and password credentials in the auth parameters +2) The path to an openrc file containing credentials to read in the auth + parameters +3) A service token in the auth parameters +4) Environment variables set for the environment in which Puppet is running +5) A service token in /etc/keystone/keystone.conf. This option provides + backwards compatibility with earlier keystone providers. + +If the provider has password credentials, it can create an authenticated +session. If it only has a service token, it initializes an unauthenciated +session and a hash of session data that can be injected into a future request. + +**`Puppet::Provider::Aviator#make_request`** + +After creating a session, the make\_request method provides an interface that +providers can use to make requests without worrying about whether they have an +authenticated or unauthenticated session. It takes as arguments the +Aviator::Service it is making a request at (for example, keystone), a symbol for +the request (for example, :list\_tenants), and optionally a block to execute +that will set parameters for an update request. + +Implementation +-------------- + +### openstacklib + +openstacklib is a combination of Puppet manifest and ruby code to delivery +configuration and extra functionality through types and providers. + +Limitations +----------- + +* Limitations will be added as they are discovered. + +Development +----------- + +Developer documentation for the entire puppet-openstack project. + +* https://wiki.openstack.org/wiki/Puppet-openstack#Developer_documentation + +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 +``` + +Release Notes +------------- + +**5.1.0** + +* Update .gitreview file for project rename +* Adding augeas insertion check +* MySQL: change default MySQL collate to utf8_general_ci +* spec: pin rspec-puppet to 1.0.1 + +**5.0.0** + +* This is the initial release of this module. diff --git a/3rdparty/modules/openstacklib/Rakefile b/3rdparty/modules/openstacklib/Rakefile new file mode 100644 index 000000000..67e846c11 --- /dev/null +++ b/3rdparty/modules/openstacklib/Rakefile @@ -0,0 +1,7 @@ +require 'rubygems' +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' + +PuppetLint.configuration.fail_on_warnings = true +PuppetLint.configuration.send('disable_80chars') +PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"] diff --git a/3rdparty/modules/openstacklib/checksums.json b/3rdparty/modules/openstacklib/checksums.json new file mode 100644 index 000000000..c808945bc --- /dev/null +++ b/3rdparty/modules/openstacklib/checksums.json @@ -0,0 +1,30 @@ +{ + "Gemfile": "2c4e4ae399db74816aafb47dbc3951a5", + "LICENSE": "53173ea25085d832ebb1e9d131dc645d", + "README.md": "023e14103588e6eb16aee599338f0798", + "Rakefile": "a61c67fc9275174b6d502c7a97d58fba", + "lib/puppet/parser/functions/os_database_connection.rb": "f50c5c418a4745f67b863351aa421371", + "lib/puppet/provider/aviator.rb": "dfec34e1929a1bb260d26b5382d596a2", + "lib/puppet/util/aviator.rb": "6a2f5145b59f2011f04b9598db4d66d6", + "manifests/db/mysql/host_access.pp": "0d4b41a44213cd2cae0febe63032b74e", + "manifests/db/mysql.pp": "4b2ac1ae2ef9c32c2bdcf5330faa2c85", + "manifests/messaging/rabbitmq.pp": "4f2a699c774c57aa645ef7300c87eb9c", + "manifests/policy/base.pp": "9fcbf53d8442a2e258cbe1260ac6dc6b", + "manifests/policy.pp": "843e98d897e3df8d8d70f8017f7b6e6e", + "manifests/service_validation.pp": "7b0ed110553298231d947a131e2570f5", + "metadata.json": "a1e6434b728214cb8a0f235468260e86", + "spec/classes/init_spec.rb": "62493b66358f3c7acf24b0cfe8a98391", + "spec/classes/openstacklib_policy_spec.rb": "806f398cc4a8a9cf11c005608879374c", + "spec/defines/openstacklib_db_mysql_host_access_spec.rb": "4e498ba905f57bebc98480207f73e253", + "spec/defines/openstacklib_db_mysql_spec.rb": "edac2c0018bb0baaf4b55920b39564e6", + "spec/defines/openstacklib_messaging_rabbitmq_spec.rb": "7551d7034f07951fff7cd28ca05adf42", + "spec/defines/openstacklib_policy_spec.rb": "6fc8d604b44f2c559bcd2222210031b3", + "spec/defines/openstacklib_service_validation_spec.rb": "cbb6e09a2c2bca9b04d699e3509b4827", + "spec/fixtures/vcr/aviator/request/with_session.yml": "36b855c8d25e2652a711b4d76ab16b20", + "spec/fixtures/vcr/aviator/request/without_session.yml": "ab811807ab346574e7cab61bf111be20", + "spec/fixtures/vcr/aviator/session/with_password.yml": "4ceea78a734539233b9de4fe60cb856c", + "spec/fixtures/vcr/aviator/session/with_token.yml": "ab811807ab346574e7cab61bf111be20", + "spec/functions/os_database_connection_spec.rb": "0cfa88f055785516f56672b1f773a461", + "spec/spec_helper.rb": "93f9c20dc020eba3bc244c347b8e5d34", + "spec/unit/provider/aviator_spec.rb": "2d736d88dbcd3bb2b4960067df71d51f" +} \ No newline at end of file diff --git a/3rdparty/modules/openstacklib/lib/puppet/parser/functions/os_database_connection.rb b/3rdparty/modules/openstacklib/lib/puppet/parser/functions/os_database_connection.rb new file mode 100644 index 000000000..8764f1b8f --- /dev/null +++ b/3rdparty/modules/openstacklib/lib/puppet/parser/functions/os_database_connection.rb @@ -0,0 +1,72 @@ +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| + unless (v[key].class == String) or (v[key] == :undef) + raise(Puppet::ParseError, "os_database_connection(): #{key} should be a String") + 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 + + if v.include?('charset') + parts[:query] = "charset=#{v['charset']}" + end + + 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 diff --git a/3rdparty/modules/openstacklib/lib/puppet/provider/aviator.rb b/3rdparty/modules/openstacklib/lib/puppet/provider/aviator.rb new file mode 100644 index 000000000..8de1bf201 --- /dev/null +++ b/3rdparty/modules/openstacklib/lib/puppet/provider/aviator.rb @@ -0,0 +1,297 @@ +require 'puppet' +require 'puppet/feature/aviator' +require 'puppet/util/inifile' + +class Puppet::Provider::Aviator < Puppet::Provider + + def session + @session ||= authenticate(resource[:auth], resource[:log_file]) + end + + def self.session + @session ||= authenticate(nil, nil) + end + + def request(service, request, &block) + self.class.make_request(service, request, session_data, &block) + end + + def self.request(service, request, &block) + self.make_request(service, request, session_data, &block) + end + + # needed for tests + def session_data + @session_data + end + + def self.session_data + @session_data + end + + def session_data=(data) + @session_data=data + end + + def self.session_data=(data) + @session_data=data + end + + private + + # Attempt to find credentials in this order: + # 1. username,password,tenant,host set in type parameters + # 2. openrc file path set in type parameters + # 3. service token and host set in type parameters + # 4. username,password,tenant,host set in environment variables + # 5. service token and host set in keystone.conf (backwards compatible version) + def authenticate(auth_params, log_file) + auth_params ||= {} + if password_credentials_set?(auth_params) + @session = get_authenticated_session(auth_params, log_file) + + elsif openrc_set?(auth_params) + credentials = get_credentials_from_openrc(auth_params['openrc']) + @session = get_authenticated_session(credentials, log_file) + + elsif service_credentials_set?(auth_params) + session_hash = get_unauthenticated_session(auth_params, log_file) + @session_data = session_hash[:data] + @session = session_hash[:session] + + elsif env_vars_set? + credentials = get_credentials_from_env + @session = get_authenticated_session(credentials, log_file) + + else # Last effort: try to get the token from keystone.conf + session_hash = self.class.try_auth_with_token(keystone_file, log_file) + @session_data = session_hash[:data] + @session = session_hash[:session] + end + end + + def self.authenticate(auth_params, log_file) + auth_params = {} unless auth_params + if env_vars_set? + credentials = get_credentials_from_env + @session = get_authenticated_session(credentials, log_file) + + else # Last effort: try to get the token from keystone.conf + session_hash = try_auth_with_token(keystone_file, log_file) + @session_data = session_hash[:data] + @session = session_hash[:session] + end + end + + + def self.try_auth_with_token(conf_file, log_file) + service_token = get_admin_token_from_keystone_file(conf_file) + auth_url = get_auth_url_from_keystone_file(conf_file) + session_hash = {} + if service_token + credentials = { + 'service_token' => service_token, + 'host_uri' => auth_url, + } + session_hash = get_unauthenticated_session(credentials, log_file) + else # All authentication efforts failed + raise(Puppet::Error, 'No credentials provided.') + end + end + + + def self.make_request(service, request, session_data, &block) + response = nil + if service && service.default_session_data + response = service.request(request, :endpoint_type => 'admin') do |params| + yield(params) if block + end + elsif session_data + response = service.request(request, :endpoint_type => 'admin', + :session_data => session_data) do |params| + yield(params) if block + end + else + raise(Puppet::Error, 'Cannot make a request with no session data.') + end + if response.body.hash['error'] + raise(Puppet::Error, "Error making request: #{response.body.hash['error']['code']} #{response.body.hash['error']['title']}") + end + response + end + + + def password_credentials_set?(auth_params) + auth_params['username'] && auth_params['password'] && auth_params['tenant_name'] && auth_params['host_uri'] + end + + + def openrc_set?(auth_params) + auth_params['openrc'] + end + + + def service_credentials_set?(auth_params) + auth_params['service_token'] && auth_params['host_uri'] + end + + + def self.env_vars_set? + ENV['OS_USERNAME'] && ENV['OS_PASSWORD'] && ENV['OS_TENANT_NAME'] && ENV['OS_AUTH_URL'] + end + + + def env_vars_set? + self.class.env_vars_set? + end + + + def get_credentials_from_openrc(file) + creds = {} + begin + File.open(file).readlines.delete_if{|l| l=~ /^#/}.each do |line| + key, value = line.split('=') + key = key.split(' ').last + value = value.chomp.gsub(/'/, '') + creds[key] = value + end + return creds + rescue Exception => error + return {} + end + end + + + def self.get_credentials_from_env + ENV.to_hash.dup.delete_if { |key, _| ! (key =~ /^OS/) } # Ruby 1.8.7 + end + + def get_credentials_from_env + self.class.get_credentials_from_env + end + + + def self.keystone_file + keystone_file = Puppet::Util::IniConfig::File.new + keystone_file.read('/etc/keystone/keystone.conf') + keystone_file + end + + def keystone_file + return @keystone_file if @keystone_file + @keystone_file = Puppet::Util::IniConfig::File.new + @keystone_file.read('/etc/keystone/keystone.conf') + @keystone_file + end + + + def self.get_admin_token_from_keystone_file(conf_file) + if conf_file and conf_file['DEFAULT'] and conf_file['DEFAULT']['admin_token'] + return "#{conf_file['DEFAULT']['admin_token'].strip}" + else + return nil + end + end + + def get_admin_token_from_keystone_file + conf_file = keystone_file + self.class.get_admin_token_from_keystone_file(conf_file) + end + + + def self.get_auth_url_from_keystone_file(conf_file) + if conf_file + if conf_file['DEFAULT'] + if conf_file['DEFAULT']['admin_endpoint'] + auth_url = conf_file['DEFAULT']['admin_endpoint'].strip + return versioned_endpoint(auth_url) + end + + if conf_file['DEFAULT']['admin_port'] + admin_port = conf_file['DEFAULT']['admin_port'].strip + else + admin_port = '35357' + end + + if conf_file['DEFAULT']['admin_bind_host'] + host = conf_file['DEFAULT']['admin_bind_host'].strip + if host == "0.0.0.0" + host = "127.0.0.1" + end + else + host = "127.0.0.1" + end + end + + if conf_file['ssl'] && conf_file['ssl']['enable'] && conf_file['ssl']['enable'].strip.downcase == 'true' + protocol = 'https' + else + protocol = 'http' + end + end + + "#{protocol}://#{host}:#{admin_port}/v2.0/" + end + + def get_auth_url_from_keystone_file + self.class.get_auth_url_from_keystone_file(keystone_file) + end + + + def self.make_configuration(credentials) + host_uri = versioned_endpoint(credentials['host_uri'] || credentials['OS_AUTH_URL'], credentials['api_version']) + { + :provider => 'openstack', + :auth_service => { + :name => 'identity', + :host_uri => host_uri, + :request => 'create_token', + :validator => 'list_tenants', + }, + :auth_credentials => { + :username => credentials['username'] || credentials['OS_USERNAME'], + :password => credentials['password'] || credentials['OS_PASSWORD'], + :tenant_name => credentials['tenant_name'] || credentials['OS_TENANT_NAME'] + } + } + end + + + def self.get_authenticated_session(credentials, log_file) + configuration = make_configuration(credentials) + session = ::Aviator::Session.new(:config => configuration, :log_file => log_file) + session.authenticate + session + end + + def get_authenticated_session(credentials, log_file) + self.class.get_authenticated_session(credentials, log_file) + end + + + def self.get_unauthenticated_session(credentials, log_file) + configuration = { + :provider => 'openstack', + } + session_data = { + :base_url => credentials['host_uri'], + :service_token => credentials['service_token'] + } + session = ::Aviator::Session.new(:config => configuration, :log_file => log_file) + { :session => session, :data => session_data } + end + + def get_unauthenticated_session(credentials, log_file) + self.class.get_unauthenticated_session(credentials, log_file) + end + + + def self.versioned_endpoint(endpoint, version = 'v2.0') + version = 'v2.0' if version.nil? + if endpoint =~ /\/#{version}\/?$/ || endpoint =~ /\/v2.0\/?$/ || endpoint =~ /\/v3\/?$/ + endpoint + else + "#{endpoint.chomp('/')}/#{version}" + end + end +end diff --git a/3rdparty/modules/openstacklib/lib/puppet/util/aviator.rb b/3rdparty/modules/openstacklib/lib/puppet/util/aviator.rb new file mode 100644 index 000000000..bc24b025d --- /dev/null +++ b/3rdparty/modules/openstacklib/lib/puppet/util/aviator.rb @@ -0,0 +1,46 @@ +# Add the auth parameter to whatever type is given +module Puppet::Util::Aviator + def self.add_aviator_params(type) + + type.newparam(:auth) do + + desc < { + 'username' => 'test', + 'password' => 'passw0rd', + 'tenant_name' => 'test', + 'host_uri' => 'http://localhost:35357/v2.0', +} + +or a path to an openrc file containing these credentials, e.g.: + +auth => { + 'openrc' => '/root/openrc', +} + +or a service token and host, e.g.: + +auth => { + 'service_token' => 'ADMIN', + 'host_uri' => 'http://localhost:35357/v2.0', +} + +If not present, the provider will first look for environment variables +for password credentials and then to /etc/keystone/keystone.conf for a +service token. +EOT + + validate do |value| + raise(Puppet::Error, 'This property must be a hash') unless value.is_a?(Hash) + end + end + + type.newparam(:log_file) do + desc 'Log file. Defaults to no logging.' + defaultto('/dev/null') + end + end +end diff --git a/3rdparty/modules/openstacklib/manifests/db/mysql.pp b/3rdparty/modules/openstacklib/manifests/db/mysql.pp new file mode 100644 index 000000000..7cf101029 --- /dev/null +++ b/3rdparty/modules/openstacklib/manifests/db/mysql.pp @@ -0,0 +1,68 @@ +# == 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' + +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', +) { + + include ::mysql::client + + mysql_database { $dbname: + ensure => present, + charset => $charset, + collate => $collate, + require => [ Class['mysql::server'], Class['mysql::client'] ], + } + + $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, + } +} diff --git a/3rdparty/modules/openstacklib/manifests/db/mysql/host_access.pp b/3rdparty/modules/openstacklib/manifests/db/mysql/host_access.pp new file mode 100644 index 000000000..4909f631a --- /dev/null +++ b/3rdparty/modules/openstacklib/manifests/db/mysql/host_access.pp @@ -0,0 +1,41 @@ +# 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 +# +define openstacklib::db::mysql::host_access ( + $user, + $password_hash, + $database, + $privileges, +) { + validate_re($title, '_', 'Title must be $dbname_$host') + + $host = inline_template('<%= @title.split("_").last %>') + + mysql_user { "${user}@${host}": + password_hash => $password_hash, + require => Mysql_database[$database], + } + + mysql_grant { "${user}@${host}/${database}.*": + privileges => $privileges, + table => "${database}.*", + require => Mysql_user["${user}@${host}"], + user => "${user}@${host}", + } +} diff --git a/3rdparty/modules/openstacklib/manifests/messaging/rabbitmq.pp b/3rdparty/modules/openstacklib/manifests/messaging/rabbitmq.pp new file mode 100644 index 000000000..16f6c62a7 --- /dev/null +++ b/3rdparty/modules/openstacklib/manifests/messaging/rabbitmq.pp @@ -0,0 +1,105 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Definition: 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', + }) + } + +} diff --git a/3rdparty/modules/openstacklib/manifests/policy.pp b/3rdparty/modules/openstacklib/manifests/policy.pp new file mode 100644 index 000000000..b11142757 --- /dev/null +++ b/3rdparty/modules/openstacklib/manifests/policy.pp @@ -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) + +} diff --git a/3rdparty/modules/openstacklib/manifests/policy/base.pp b/3rdparty/modules/openstacklib/manifests/policy/base.pp new file mode 100644 index 000000000..01919fe65 --- /dev/null +++ b/3rdparty/modules/openstacklib/manifests/policy/base.pp @@ -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"] + } + +} + diff --git a/3rdparty/modules/openstacklib/manifests/service_validation.pp b/3rdparty/modules/openstacklib/manifests/service_validation.pp new file mode 100644 index 000000000..8a9ccd051 --- /dev/null +++ b/3rdparty/modules/openstacklib/manifests/service_validation.pp @@ -0,0 +1,69 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Definition: 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' +# +# [*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' +# +define openstacklib::service_validation( + $command, + $service_name = $name, + $path = '/usr/bin:/bin:/usr/sbin:/sbin', + $provider = shell, + $tries = '10', + $try_sleep = '2', +) { + + exec { "execute ${service_name} validation": + path => $path, + provider => $provider, + command => $command, + tries => $tries, + try_sleep => $try_sleep, + } + + anchor { "create ${service_name} anchor": + require => Exec["execute ${service_name} validation"], + } + +} diff --git a/3rdparty/modules/openstacklib/metadata.json b/3rdparty/modules/openstacklib/metadata.json new file mode 100644 index 000000000..e941bfdf1 --- /dev/null +++ b/3rdparty/modules/openstacklib/metadata.json @@ -0,0 +1,55 @@ +{ + "name": "stackforge-openstacklib", + "version": "5.1.0", + "author": "Puppet Labs and OpenStack Contributors", + "summary": "Puppet OpenStack Libraries", + "license": "Apache-2.0", + "source": "git://github.com/openstack/puppet-openstacklib.git", + "project_page": "https://launchpad.net/puppet-openstacklib", + "issues_url": "https://bugs.launchpad.net/puppet-openstacklib", + "dependencies": [ + {"name":"aimonb/aviator","version_requirement":">=0.4.2 <1.0.0"}, + {"name":"puppetlabs/mysql","version_requirement":">=2.2.0 <3.0.0"}, + {"name":"puppetlabs/stdlib","version_requirement":">=4.0.0 <5.0.0"}, + {"name":"puppetlabs/rabbitmq","version_requirement":">=2.0.2 <4.0.0"} + ], + "requirements": [ + { + "name": "pe", + "version_requirement": "3.x" + }, + { + "name": "puppet", + "version_requirement": "3.x" + } + ], + "operatingsystem_support": [ + { + "operatingsystem": "Debian", + "operatingsystemrelease": [ + "7" + ] + }, + { + "operatingsystem": "Fedora", + "operatingsystemrelease": [ + "20" + ] + }, + { + "operatingsystem": "RedHat", + "operatingsystemrelease": [ + "6.5", + "7" + ] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": [ + "12.04", + "14.04" + ] + } + ], + "description": "Puppet module library to expose common functionality between OpenStack modules." +} diff --git a/3rdparty/modules/openstacklib/spec/classes/init_spec.rb b/3rdparty/modules/openstacklib/spec/classes/init_spec.rb new file mode 100644 index 000000000..f8ec36959 --- /dev/null +++ b/3rdparty/modules/openstacklib/spec/classes/init_spec.rb @@ -0,0 +1 @@ +require 'spec_helper' diff --git a/3rdparty/modules/openstacklib/spec/classes/openstacklib_policy_spec.rb b/3rdparty/modules/openstacklib/spec/classes/openstacklib_policy_spec.rb new file mode 100644 index 000000000..9d6927c52 --- /dev/null +++ b/3rdparty/modules/openstacklib/spec/classes/openstacklib_policy_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' + +describe 'openstacklib::policy' 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 + should contain_openstacklib__policy__base('foo').with( + :file_path => '/etc/nova/policy.json', + :key => 'context_is_admin', + :value => 'foo:bar' + ) + end + +end diff --git a/3rdparty/modules/openstacklib/spec/defines/openstacklib_db_mysql_host_access_spec.rb b/3rdparty/modules/openstacklib/spec/defines/openstacklib_db_mysql_host_access_spec.rb new file mode 100644 index 000000000..8f47bfa13 --- /dev/null +++ b/3rdparty/modules/openstacklib/spec/defines/openstacklib_db_mysql_host_access_spec.rb @@ -0,0 +1,50 @@ +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 { should contain_mysql_user("#{params[:user]}@10.0.0.1").with( + :password_hash => params[:password_hash] + )} + + it { should contain_mysql_grant("#{params[:user]}@10.0.0.1/#{params[:database]}.*").with( + :user => "#{params[:user]}@10.0.0.1", + :privileges => 'ALL', + :table => "#{params[:database]}.*" + )} + end + + end + + context 'on a Debian osfamily' do + let :facts do + { :osfamily => "Debian" } + end + + include_examples 'openstacklib::db::mysql::host_access examples' + end + + context 'on a RedHat osfamily' do + let :facts do + { :osfamily => 'RedHat' } + end + + include_examples 'openstacklib::db::mysql::host_access examples' + end +end diff --git a/3rdparty/modules/openstacklib/spec/defines/openstacklib_db_mysql_spec.rb b/3rdparty/modules/openstacklib/spec/defines/openstacklib_db_mysql_spec.rb new file mode 100644 index 000000000..fc9b54ec3 --- /dev/null +++ b/3rdparty/modules/openstacklib/spec/defines/openstacklib_db_mysql_spec.rb @@ -0,0 +1,163 @@ +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 { should contain_mysql_database(title).with( + :charset => 'utf8', + :collate => 'utf8_general_ci' + )} + it { should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with( + :user => title, + :database => title, + :privileges => 'ALL' + )} + end + + context 'with overriding dbname parameter' do + let :params do + { :dbname => 'foobar' }.merge(required_params) + end + + it { should contain_mysql_database(params[:dbname]).with( + :charset => 'utf8', + :collate => 'utf8_general_ci' + )} + it { should contain_openstacklib__db__mysql__host_access("#{params[:dbname]}_127.0.0.1").with( + :user => title, + :database => params[:dbname], + :privileges => 'ALL' + )} + end + + context 'with overriding user parameter' do + let :params do + { :user => 'foobar' }.merge(required_params) + end + + it { should contain_mysql_database(title).with( + :charset => 'utf8', + :collate => 'utf8_general_ci' + )} + it { should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with( + :user => params[:user], + :database => title, + :privileges => 'ALL', + )} + end + + context 'when overriding charset parameter' do + let :params do + { :charset => 'latin1' }.merge(required_params) + end + + it { should contain_mysql_database(title).with_charset(params[:charset]) } + end + + context 'when omitting the required parameter password_hash' do + let :params do + required_params.delete(:password_hash) + end + it { expect { should raise_error(Puppet::Error) } } + 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 { should 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 { should 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 {should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with( + :user => title, + :password_hash => params[:password_hash], + :database => title + )} + it {should contain_openstacklib__db__mysql__host_access("#{title}_%").with( + :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 {should 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 {should contain_openstacklib__db__mysql__host_access("#{title}_127.0.0.1").with( + :user => title, + :password_hash => params[:password_hash], + :database => title + )} + end + + end + + context 'on a Debian osfamily' do + let :facts do + { :osfamily => "Debian" } + end + + include_examples 'openstacklib::db::mysql examples' + end + + context 'on a RedHat osfamily' do + let :facts do + { :osfamily => 'RedHat' } + end + + include_examples 'openstacklib::db::mysql examples' + end +end diff --git a/3rdparty/modules/openstacklib/spec/defines/openstacklib_messaging_rabbitmq_spec.rb b/3rdparty/modules/openstacklib/spec/defines/openstacklib_messaging_rabbitmq_spec.rb new file mode 100644 index 000000000..953c53be3 --- /dev/null +++ b/3rdparty/modules/openstacklib/spec/defines/openstacklib_messaging_rabbitmq_spec.rb @@ -0,0 +1,101 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +require 'spec_helper' + +describe 'openstacklib::messaging::rabbitmq' do + + let (:title) { 'nova' } + + shared_examples 'openstacklib::messaging::rabbitmq examples' do + + let :params do + {} + end + + context 'with default parameters' do + it { should contain_rabbitmq_user('guest').with( + :admin => false, + :password => 'guest', + :provider => 'rabbitmqctl', + )} + it { should contain_rabbitmq_user_permissions('guest@/').with( + :configure_permission => '.*', + :write_permission => '.*', + :read_permission => '.*', + :provider => 'rabbitmqctl', + )} + it { should 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 { should contain_rabbitmq_user('nova').with( + :admin => true, + :password => 'secrete', + :provider => 'rabbitmqctl', + )} + it { should contain_rabbitmq_user_permissions('nova@/nova').with( + :configure_permission => '.nova', + :write_permission => '.nova', + :read_permission => '.nova', + :provider => 'rabbitmqctl', + )} + it { should contain_rabbitmq_vhost('/nova').with( + :provider => 'rabbitmqctl', + )} + end + + context 'when disabling vhost management' do + before :each do + params.merge!( :manage_vhost => false ) + end + + it { should_not contain_rabbitmq_vhost } + end + + end + + context 'on a Debian osfamily' do + let :facts do + { :osfamily => "Debian" } + end + + include_examples 'openstacklib::messaging::rabbitmq examples' + end + + context 'on a RedHat osfamily' do + let :facts do + { :osfamily => 'RedHat' } + end + + include_examples 'openstacklib::messaging::rabbitmq examples' + end +end diff --git a/3rdparty/modules/openstacklib/spec/defines/openstacklib_policy_spec.rb b/3rdparty/modules/openstacklib/spec/defines/openstacklib_policy_spec.rb new file mode 100644 index 000000000..89be58c79 --- /dev/null +++ b/3rdparty/modules/openstacklib/spec/defines/openstacklib_policy_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' + +describe 'openstacklib::policy::base' do + + let :title do + 'nova-contest_is_admin' + end + + let :params do + {:file_path => '/etc/nova/policy.json', + :key => 'context_is_admin', + :value => 'foo:bar'} + end + + it 'configures the proper policy' do + should contain_augeas('/etc/nova/policy.json-context_is_admin-foo:bar').with( + 'lens' => 'Json.lns', + 'incl' => '/etc/nova/policy.json', + 'changes' => 'set dict/entry[*][.="context_is_admin"]/string foo:bar', + 'require' => 'Augeas[/etc/nova/policy.json-context_is_admin-foo:bar-add]' + ) + end + + it 'configures the proper policy' do + should contain_augeas('/etc/nova/policy.json-context_is_admin-foo:bar-add').with( + 'lens' => 'Json.lns', + 'incl' => '/etc/nova/policy.json', + 'changes' => [ + 'set dict/entry[last()+1] "context_is_admin"', + 'set dict/entry[last()]/string "foo:bar"' + ], + 'onlyif' => 'match dict/entry[*][.="context_is_admin"] size == 0' + ) + end + +end + diff --git a/3rdparty/modules/openstacklib/spec/defines/openstacklib_service_validation_spec.rb b/3rdparty/modules/openstacklib/spec/defines/openstacklib_service_validation_spec.rb new file mode 100644 index 000000000..17e4389a6 --- /dev/null +++ b/3rdparty/modules/openstacklib/spec/defines/openstacklib_service_validation_spec.rb @@ -0,0 +1,73 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +require 'spec_helper' + +describe '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 { should contain_exec("execute #{title} validation").with( + :path => '/usr/bin:/bin:/usr/sbin:/sbin', + :provider => 'shell', + :command => 'nova list', + :tries => '10', + :try_sleep => '2', + )} + + it { should 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 { should raise_error(Puppet::Error) } } + end + + end + + context 'on a Debian osfamily' do + let :facts do + { :osfamily => "Debian" } + end + + include_examples 'openstacklib::service_validation examples' + end + + context 'on a RedHat osfamily' do + let :facts do + { :osfamily => 'RedHat' } + end + + include_examples 'openstacklib::service_validation examples' + end +end diff --git a/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/request/with_session.yml b/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/request/with_session.yml new file mode 100644 index 000000000..2d052df25 --- /dev/null +++ b/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/request/with_session.yml @@ -0,0 +1,67 @@ +--- + http_interactions: + - request: + method: post + uri: "http://192.168.11.4:35357/v2.0/tokens" + body: + encoding: UTF-8 + string: "{\x22auth\x22:{\x22passwordCredentials\x22:{\x22username\x22:\x22admin\x22,\x22password\x22:\x22fyby-tet\x22},\x22tenantName\x22:\x22admin\x22}}" + headers: + Content-Type: + - application/json + User-Agent: + - "Faraday v0.8.8" + response: + status: + code: 200 + message: + headers: + vary: + - X-Auth-Token + content-type: + - application/json + content-length: + - "9780" + date: + - "Tue, 30 Sep 2014 06:59:48 GMT" + connection: + - close + body: + encoding: UTF-8 + string: "{\x22access\x22: {\x22token\x22: {\x22issued_at\x22: \x222014-09-30T06:59:48.338940\x22, \x22expires\x22: \x222014-09-30T07:59:48Z\x22, \x22id\x22: \x22MIIRIAYJKoZIhvcNAQcCoIIRETCCEQ0CAQExCTAHBgUrDgMCGjCCD3YGCSqGSIb3DQEHAaCCD2cEgg9jeyJhY2Nlc3MiOiB7InRva2VuIjogeyJpc3N1ZWRfYXQiOiAiMjAxNC0wOS0zMFQwNjo1OTo0OC4zMzg5NDAiLCAiZXhwaXJlcyI6ICIyMDE0LTA5LTMwVDA3OjU5OjQ4WiIsICJpZCI6ICJwbGFjZWhvbGRlciIsICJ0ZW5hbnQiOiB7ImRlc2NyaXB0aW9uIjogImFkbWluIHRlbmFudCIsICJlbmFibGVkIjogdHJ1ZSwgImlkIjogImM1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgIm5hbWUiOiAiYWRtaW4ifX0sICJzZXJ2aWNlQ2F0YWxvZyI6IFt7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc0L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMWJiNzU4NWIzMzgxNGI4Mjk4NzJlYjQ0MjAyMTg5OGEiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NC92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJjb21wdXRlIiwgIm5hbWUiOiAibm92YSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJpZCI6ICJhYTdkNDU2NTNhYjI0ZGY2YmE5ZDE4NGE1ZWRkNGYxMyIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo5Njk2LyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJuZXR3b3JrIiwgIm5hbWUiOiAibmV1dHJvbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMmJmNGQ5YzZiYTgwNDM1M2JjZGNlZGZjNTAxMDNiYjYiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWV2MiIsICJuYW1lIjogImNpbmRlcnYyIn0sIHsiZW5kcG9pbnRzIjogW3siYWRtaW5VUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjMiLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3NC92MyIsICJpZCI6ICIzZmQ4NDBjYmFkZDM0NmFiOTE2YjA2YWYxZjRlNWJmMCIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo4Nzc0L3YzIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImNvbXB1dGV2MyIsICJuYW1lIjogIm5vdmF2MyJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5MjkyIiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40OjkyOTIiLCAiaWQiOiAiMTJjOTM1NzkwYmM5NGE3ODljNzJmOWJiYjIxZjM5YmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6OTI5MiJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJpbWFnZSIsICJuYW1lIjogImdsYW5jZSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc3IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzciLCAiaWQiOiAiMWNlNDkwMWQ4OTE1NDIzZTk2ZGFiM2ZlMWZiMzY2M2MiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJtZXRlcmluZyIsICJuYW1lIjogImNlaWxvbWV0ZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAiaWQiOiAiNWU4ZjExYzk3ZTgwNDNiNWJkZTA1YmVhMmRlNDYxNmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODAwMC92MS8ifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiY2xvdWRmb3JtYXRpb24iLCAibmFtZSI6ICJoZWF0LWNmbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiNTRiOWVjMjhiYzYwNDI1MmIwMGNmZTZlMGU0NGFhOTQiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWUiLCAibmFtZSI6ICJjaW5kZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3My9zZXJ2aWNlcy9BZG1pbiIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4NzczL3NlcnZpY2VzL0Nsb3VkIiwgImlkIjogIjA3NWVjNzliMGJlMzQxYmFhYmUyZTliMTIwNTkxZjQ4IiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40Ojg3NzMvc2VydmljZXMvQ2xvdWQifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiZWMyIiwgIm5hbWUiOiAibm92YV9lYzIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwNC92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4MDA0L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgImlkIjogIjI2MmM0YjM3MzY3ODQ2OGE5ODU1YTNlYmM2MDE1OTYwIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40OjgwMDQvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAib3JjaGVzdHJhdGlvbiIsICJuYW1lIjogImhlYXQifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6MzUzNTcvdjIuMCIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo1MDAwL3YyLjAiLCAiaWQiOiAiMDg5ZmRiMjIyNDk1NDZiOTlhMWU1N2FlYzBiMWU3NmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6NTAwMC92Mi4wIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImlkZW50aXR5IiwgIm5hbWUiOiAia2V5c3RvbmUifV0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJhZG1pbiIsICJyb2xlc19saW5rcyI6IFtdLCAiaWQiOiAiM2Y3NmI5NDY2NzQzNGNmM2JkYzMyM2NmMDIxYzUwZjgiLCAicm9sZXMiOiBbeyJuYW1lIjogImFkbWluIn1dLCAibmFtZSI6ICJhZG1pbiJ9LCAibWV0YWRhdGEiOiB7ImlzX2FkbWluIjogMCwgInJvbGVzIjogWyIxZThiYzVkMWYzYTQ0OGU5YTJhMWNkYTU4ZDk3ZjkyYiJdfX19MYIBgTCCAX0CAQEwXDBXMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVW5zZXQxDjAMBgNVBAcMBVVuc2V0MQ4wDAYDVQQKDAVVbnNldDEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tAgEBMAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIIBAHGQ0NFb0OcE74KIU9DmmvgVyYCrNwwWrwG1CObr9111AHfEr+bn6YfX1ePRUhB2KpcuBPLeIfM-RlLHNwpLzYtvKIwdj0TxIecbF9PuTkWMEZ9Kxl+KE8F4dJOnv0XnAiWZ8QzrMZOo4d+owLJmNNLE1TKfGqv8ughdcrjHtUicHT2E0AOfO3ylEhJPsazUl8XIIWQ4sMWTrs0ROMiZnWPWbomYb49LIaREHD6nDfZX+EDZbHSfPVLTYVL-+qkiIH52-lXqz-OKPCn+Lt3RzXYDzapZd8cpzVgJpTuq2YKMZ+H06yvHFCTZNN49j6kZHz0Qkn2MjbwU8sH10wA7W6k=\x22, \x22tenant\x22: {\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}}, \x22serviceCatalog\x22: [{\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8774/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8774/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x221bb7585b33814b829872eb442021898a\x22, \x22publicURL\x22: \x22http://192.168.11.4:8774/v2/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22compute\x22, \x22name\x22: \x22nova\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:9696/\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:9696/\x22, \x22id\x22: \x22aa7d45653ab24df6ba9d184a5edd4f13\x22, \x22publicURL\x22: \x22http://192.168.11.4:9696/\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22network\x22, \x22name\x22: \x22neutron\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8776/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8776/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x222bf4d9c6ba804353bcdcedfc50103bb6\x22, \x22publicURL\x22: \x22http://192.168.11.4:8776/v2/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22volumev2\x22, \x22name\x22: \x22cinderv2\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8774/v3\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8774/v3\x22, \x22id\x22: \x223fd840cbadd346ab916b06af1f4e5bf0\x22, \x22publicURL\x22: \x22http://192.168.11.4:8774/v3\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22computev3\x22, \x22name\x22: \x22novav3\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:9292\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:9292\x22, \x22id\x22: \x2212c935790bc94a789c72f9bbb21f39bc\x22, \x22publicURL\x22: \x22http://192.168.11.4:9292\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22image\x22, \x22name\x22: \x22glance\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8777\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8777\x22, \x22id\x22: \x221ce4901d8915423e96dab3fe1fb3663c\x22, \x22publicURL\x22: \x22http://192.168.11.4:8777\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22metering\x22, \x22name\x22: \x22ceilometer\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8000/v1/\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8000/v1/\x22, \x22id\x22: \x225e8f11c97e8043b5bde05bea2de4616c\x22, \x22publicURL\x22: \x22http://192.168.11.4:8000/v1/\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22cloudformation\x22, \x22name\x22: \x22heat-cfn\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8776/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8776/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x2254b9ec28bc604252b00cfe6e0e44aa94\x22, \x22publicURL\x22: \x22http://192.168.11.4:8776/v1/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22volume\x22, \x22name\x22: \x22cinder\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8773/services/Admin\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8773/services/Cloud\x22, \x22id\x22: \x22075ec79b0be341baabe2e9b120591f48\x22, \x22publicURL\x22: \x22http://192.168.11.4:8773/services/Cloud\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22ec2\x22, \x22name\x22: \x22nova_ec2\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8004/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8004/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x22262c4b373678468a9855a3ebc6015960\x22, \x22publicURL\x22: \x22http://192.168.11.4:8004/v1/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22orchestration\x22, \x22name\x22: \x22heat\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:35357/v2.0\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:5000/v2.0\x22, \x22id\x22: \x22089fdb22249546b99a1e57aec0b1e76c\x22, \x22publicURL\x22: \x22http://192.168.11.4:5000/v2.0\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22identity\x22, \x22name\x22: \x22keystone\x22}], \x22user\x22: {\x22username\x22: \x22admin\x22, \x22roles_links\x22: [], \x22id\x22: \x223f76b94667434cf3bdc323cf021c50f8\x22, \x22roles\x22: [{\x22name\x22: \x22admin\x22}], \x22name\x22: \x22admin\x22}, \x22metadata\x22: {\x22is_admin\x22: 0, \x22roles\x22: [\x221e8bc5d1f3a448e9a2a1cda58d97f92b\x22]}}}" + http_version: + recorded_at: "Tue, 30 Sep 2014 06:59:48 GMT" + - request: + method: get + uri: "http://172.16.33.4:35357/v2.0/tenants" + body: + encoding: US-ASCII + string: "" + headers: + Content-Type: + - application/json + User-Agent: + - "Faraday v0.8.8" + X-Auth-Token: + - "MIIRIAYJKoZIhvcNAQcCoIIRETCCEQ0CAQExCTAHBgUrDgMCGjCCD3YGCSqGSIb3DQEHAaCCD2cEgg9jeyJhY2Nlc3MiOiB7InRva2VuIjogeyJpc3N1ZWRfYXQiOiAiMjAxNC0wOS0zMFQwNjo1OTo0OC4zMzg5NDAiLCAiZXhwaXJlcyI6ICIyMDE0LTA5LTMwVDA3OjU5OjQ4WiIsICJpZCI6ICJwbGFjZWhvbGRlciIsICJ0ZW5hbnQiOiB7ImRlc2NyaXB0aW9uIjogImFkbWluIHRlbmFudCIsICJlbmFibGVkIjogdHJ1ZSwgImlkIjogImM1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgIm5hbWUiOiAiYWRtaW4ifX0sICJzZXJ2aWNlQ2F0YWxvZyI6IFt7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc0L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMWJiNzU4NWIzMzgxNGI4Mjk4NzJlYjQ0MjAyMTg5OGEiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NC92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJjb21wdXRlIiwgIm5hbWUiOiAibm92YSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJpZCI6ICJhYTdkNDU2NTNhYjI0ZGY2YmE5ZDE4NGE1ZWRkNGYxMyIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo5Njk2LyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJuZXR3b3JrIiwgIm5hbWUiOiAibmV1dHJvbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMmJmNGQ5YzZiYTgwNDM1M2JjZGNlZGZjNTAxMDNiYjYiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWV2MiIsICJuYW1lIjogImNpbmRlcnYyIn0sIHsiZW5kcG9pbnRzIjogW3siYWRtaW5VUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjMiLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3NC92MyIsICJpZCI6ICIzZmQ4NDBjYmFkZDM0NmFiOTE2YjA2YWYxZjRlNWJmMCIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo4Nzc0L3YzIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImNvbXB1dGV2MyIsICJuYW1lIjogIm5vdmF2MyJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5MjkyIiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40OjkyOTIiLCAiaWQiOiAiMTJjOTM1NzkwYmM5NGE3ODljNzJmOWJiYjIxZjM5YmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6OTI5MiJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJpbWFnZSIsICJuYW1lIjogImdsYW5jZSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc3IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzciLCAiaWQiOiAiMWNlNDkwMWQ4OTE1NDIzZTk2ZGFiM2ZlMWZiMzY2M2MiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJtZXRlcmluZyIsICJuYW1lIjogImNlaWxvbWV0ZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAiaWQiOiAiNWU4ZjExYzk3ZTgwNDNiNWJkZTA1YmVhMmRlNDYxNmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODAwMC92MS8ifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiY2xvdWRmb3JtYXRpb24iLCAibmFtZSI6ICJoZWF0LWNmbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiNTRiOWVjMjhiYzYwNDI1MmIwMGNmZTZlMGU0NGFhOTQiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWUiLCAibmFtZSI6ICJjaW5kZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3My9zZXJ2aWNlcy9BZG1pbiIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4NzczL3NlcnZpY2VzL0Nsb3VkIiwgImlkIjogIjA3NWVjNzliMGJlMzQxYmFhYmUyZTliMTIwNTkxZjQ4IiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40Ojg3NzMvc2VydmljZXMvQ2xvdWQifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiZWMyIiwgIm5hbWUiOiAibm92YV9lYzIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwNC92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4MDA0L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgImlkIjogIjI2MmM0YjM3MzY3ODQ2OGE5ODU1YTNlYmM2MDE1OTYwIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40OjgwMDQvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAib3JjaGVzdHJhdGlvbiIsICJuYW1lIjogImhlYXQifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6MzUzNTcvdjIuMCIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo1MDAwL3YyLjAiLCAiaWQiOiAiMDg5ZmRiMjIyNDk1NDZiOTlhMWU1N2FlYzBiMWU3NmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6NTAwMC92Mi4wIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImlkZW50aXR5IiwgIm5hbWUiOiAia2V5c3RvbmUifV0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJhZG1pbiIsICJyb2xlc19saW5rcyI6IFtdLCAiaWQiOiAiM2Y3NmI5NDY2NzQzNGNmM2JkYzMyM2NmMDIxYzUwZjgiLCAicm9sZXMiOiBbeyJuYW1lIjogImFkbWluIn1dLCAibmFtZSI6ICJhZG1pbiJ9LCAibWV0YWRhdGEiOiB7ImlzX2FkbWluIjogMCwgInJvbGVzIjogWyIxZThiYzVkMWYzYTQ0OGU5YTJhMWNkYTU4ZDk3ZjkyYiJdfX19MYIBgTCCAX0CAQEwXDBXMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVW5zZXQxDjAMBgNVBAcMBVVuc2V0MQ4wDAYDVQQKDAVVbnNldDEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tAgEBMAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIIBAHGQ0NFb0OcE74KIU9DmmvgVyYCrNwwWrwG1CObr9111AHfEr+bn6YfX1ePRUhB2KpcuBPLeIfM-RlLHNwpLzYtvKIwdj0TxIecbF9PuTkWMEZ9Kxl+KE8F4dJOnv0XnAiWZ8QzrMZOo4d+owLJmNNLE1TKfGqv8ughdcrjHtUicHT2E0AOfO3ylEhJPsazUl8XIIWQ4sMWTrs0ROMiZnWPWbomYb49LIaREHD6nDfZX+EDZbHSfPVLTYVL-+qkiIH52-lXqz-OKPCn+Lt3RzXYDzapZd8cpzVgJpTuq2YKMZ+H06yvHFCTZNN49j6kZHz0Qkn2MjbwU8sH10wA7W6k=" + response: + status: + code: 200 + message: + headers: + vary: + - X-Auth-Token + content-type: + - application/json + content-length: + - "491" + date: + - "Tue, 30 Sep 2014 06:59:48 GMT" + connection: + - close + body: + encoding: UTF-8 + string: "{\x22tenants_links\x22: [], \x22tenants\x22: [{\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x2234e463e2bab24f78990ca864e4a28ba2\x22, \x22name\x22: \x22test2\x22}, {\x22description\x22: \x22Tenant for the openstack services\x22, \x22enabled\x22: true, \x22id\x22: \x2268c8fcf77aff4b409cc158c0f6cbff7b\x22, \x22name\x22: \x22services\x22}, {\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c330f1bc663648df9c1e7835a1e7a955\x22, \x22name\x22: \x22test\x22}, {\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}]}" + http_version: + recorded_at: "Tue, 30 Sep 2014 06:59:48 GMT" + recorded_with: "VCR 2.9.3" \ No newline at end of file diff --git a/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/request/without_session.yml b/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/request/without_session.yml new file mode 100644 index 000000000..784fb2fea --- /dev/null +++ b/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/request/without_session.yml @@ -0,0 +1,36 @@ +--- + http_interactions: + - request: + method: get + uri: "http://192.168.11.4:35357/v2.0/tenants" + body: + encoding: US-ASCII + string: "" + headers: + Content-Type: + - application/json + User-Agent: + - "Faraday v0.8.8" + X-Auth-Token: + - sosp-kyl + response: + status: + code: 200 + message: + headers: + vary: + - X-Auth-Token + content-type: + - application/json + content-length: + - "491" + date: + - "Tue, 30 Sep 2014 06:59:48 GMT" + connection: + - close + body: + encoding: UTF-8 + string: "{\x22tenants_links\x22: [], \x22tenants\x22: [{\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x2234e463e2bab24f78990ca864e4a28ba2\x22, \x22name\x22: \x22test2\x22}, {\x22description\x22: \x22Tenant for the openstack services\x22, \x22enabled\x22: true, \x22id\x22: \x2268c8fcf77aff4b409cc158c0f6cbff7b\x22, \x22name\x22: \x22services\x22}, {\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c330f1bc663648df9c1e7835a1e7a955\x22, \x22name\x22: \x22test\x22}, {\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}]}" + http_version: + recorded_at: "Tue, 30 Sep 2014 06:59:48 GMT" + recorded_with: "VCR 2.9.3" \ No newline at end of file diff --git a/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/session/with_password.yml b/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/session/with_password.yml new file mode 100644 index 000000000..3faa47433 --- /dev/null +++ b/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/session/with_password.yml @@ -0,0 +1,67 @@ +--- + http_interactions: + - request: + method: post + uri: "http://192.168.11.4:35357/v2.0/tokens" + body: + encoding: UTF-8 + string: "{\x22auth\x22:{\x22passwordCredentials\x22:{\x22username\x22:\x22admin\x22,\x22password\x22:\x22fyby-tet\x22},\x22tenantName\x22:\x22admin\x22}}" + headers: + Content-Type: + - application/json + User-Agent: + - "Faraday v0.8.8" + response: + status: + code: 200 + message: + headers: + vary: + - X-Auth-Token + content-type: + - application/json + content-length: + - "9780" + date: + - "Tue, 30 Sep 2014 07:16:15 GMT" + connection: + - close + body: + encoding: UTF-8 + string: "{\x22access\x22: {\x22token\x22: {\x22issued_at\x22: \x222014-09-30T07:16:15.042778\x22, \x22expires\x22: \x222014-09-30T08:16:15Z\x22, \x22id\x22: \x22MIIRIAYJKoZIhvcNAQcCoIIRETCCEQ0CAQExCTAHBgUrDgMCGjCCD3YGCSqGSIb3DQEHAaCCD2cEgg9jeyJhY2Nlc3MiOiB7InRva2VuIjogeyJpc3N1ZWRfYXQiOiAiMjAxNC0wOS0zMFQwNzoxNjoxNS4wNDI3NzgiLCAiZXhwaXJlcyI6ICIyMDE0LTA5LTMwVDA4OjE2OjE1WiIsICJpZCI6ICJwbGFjZWhvbGRlciIsICJ0ZW5hbnQiOiB7ImRlc2NyaXB0aW9uIjogImFkbWluIHRlbmFudCIsICJlbmFibGVkIjogdHJ1ZSwgImlkIjogImM1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgIm5hbWUiOiAiYWRtaW4ifX0sICJzZXJ2aWNlQ2F0YWxvZyI6IFt7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc0L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMWJiNzU4NWIzMzgxNGI4Mjk4NzJlYjQ0MjAyMTg5OGEiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NC92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJjb21wdXRlIiwgIm5hbWUiOiAibm92YSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJpZCI6ICJhYTdkNDU2NTNhYjI0ZGY2YmE5ZDE4NGE1ZWRkNGYxMyIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo5Njk2LyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJuZXR3b3JrIiwgIm5hbWUiOiAibmV1dHJvbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMmJmNGQ5YzZiYTgwNDM1M2JjZGNlZGZjNTAxMDNiYjYiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWV2MiIsICJuYW1lIjogImNpbmRlcnYyIn0sIHsiZW5kcG9pbnRzIjogW3siYWRtaW5VUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjMiLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3NC92MyIsICJpZCI6ICIzZmQ4NDBjYmFkZDM0NmFiOTE2YjA2YWYxZjRlNWJmMCIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo4Nzc0L3YzIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImNvbXB1dGV2MyIsICJuYW1lIjogIm5vdmF2MyJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5MjkyIiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40OjkyOTIiLCAiaWQiOiAiMTJjOTM1NzkwYmM5NGE3ODljNzJmOWJiYjIxZjM5YmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6OTI5MiJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJpbWFnZSIsICJuYW1lIjogImdsYW5jZSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc3IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzciLCAiaWQiOiAiMWNlNDkwMWQ4OTE1NDIzZTk2ZGFiM2ZlMWZiMzY2M2MiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJtZXRlcmluZyIsICJuYW1lIjogImNlaWxvbWV0ZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAiaWQiOiAiNWU4ZjExYzk3ZTgwNDNiNWJkZTA1YmVhMmRlNDYxNmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODAwMC92MS8ifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiY2xvdWRmb3JtYXRpb24iLCAibmFtZSI6ICJoZWF0LWNmbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiNTRiOWVjMjhiYzYwNDI1MmIwMGNmZTZlMGU0NGFhOTQiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWUiLCAibmFtZSI6ICJjaW5kZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3My9zZXJ2aWNlcy9BZG1pbiIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4NzczL3NlcnZpY2VzL0Nsb3VkIiwgImlkIjogIjA3NWVjNzliMGJlMzQxYmFhYmUyZTliMTIwNTkxZjQ4IiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40Ojg3NzMvc2VydmljZXMvQ2xvdWQifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiZWMyIiwgIm5hbWUiOiAibm92YV9lYzIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwNC92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4MDA0L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgImlkIjogIjI2MmM0YjM3MzY3ODQ2OGE5ODU1YTNlYmM2MDE1OTYwIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40OjgwMDQvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAib3JjaGVzdHJhdGlvbiIsICJuYW1lIjogImhlYXQifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6MzUzNTcvdjIuMCIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo1MDAwL3YyLjAiLCAiaWQiOiAiMDg5ZmRiMjIyNDk1NDZiOTlhMWU1N2FlYzBiMWU3NmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6NTAwMC92Mi4wIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImlkZW50aXR5IiwgIm5hbWUiOiAia2V5c3RvbmUifV0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJhZG1pbiIsICJyb2xlc19saW5rcyI6IFtdLCAiaWQiOiAiM2Y3NmI5NDY2NzQzNGNmM2JkYzMyM2NmMDIxYzUwZjgiLCAicm9sZXMiOiBbeyJuYW1lIjogImFkbWluIn1dLCAibmFtZSI6ICJhZG1pbiJ9LCAibWV0YWRhdGEiOiB7ImlzX2FkbWluIjogMCwgInJvbGVzIjogWyIxZThiYzVkMWYzYTQ0OGU5YTJhMWNkYTU4ZDk3ZjkyYiJdfX19MYIBgTCCAX0CAQEwXDBXMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVW5zZXQxDjAMBgNVBAcMBVVuc2V0MQ4wDAYDVQQKDAVVbnNldDEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tAgEBMAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIIBAEOAl3MRmSUB+J+kRi+qRhwOrNRmj-wDqT5nJTlbafOjofSXsHG683LaipA7oPoH-ARUPDxXIZfevRue7bQQB3I4cWIUSItIPyW4xDpF+iHy3QOm+I-3v3ctze2Z3Rp0TRaYFsItTZZETsSXI28yBt9+3Dsk3a7Vv10HAZetbV1i6qu6avLcJsmN-1J3KLwCDSEvpMgDAcpzAnhba1fi+X8GrCCTz4c1uIcPfsHxX4g8gNkB4-VT0lkRmfSxdrGeRz0uN12oDqgCL64IV1mJ6Bi9Unh15QFcLwU0F8ote+joG9G29fw3WDzneXHIeEIZSBXmOAX2kQBOnZa2sZg8gls=\x22, \x22tenant\x22: {\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}}, \x22serviceCatalog\x22: [{\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8774/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8774/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x221bb7585b33814b829872eb442021898a\x22, \x22publicURL\x22: \x22http://192.168.11.4:8774/v2/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22compute\x22, \x22name\x22: \x22nova\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:9696/\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:9696/\x22, \x22id\x22: \x22aa7d45653ab24df6ba9d184a5edd4f13\x22, \x22publicURL\x22: \x22http://192.168.11.4:9696/\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22network\x22, \x22name\x22: \x22neutron\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8776/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8776/v2/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x222bf4d9c6ba804353bcdcedfc50103bb6\x22, \x22publicURL\x22: \x22http://192.168.11.4:8776/v2/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22volumev2\x22, \x22name\x22: \x22cinderv2\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8774/v3\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8774/v3\x22, \x22id\x22: \x223fd840cbadd346ab916b06af1f4e5bf0\x22, \x22publicURL\x22: \x22http://192.168.11.4:8774/v3\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22computev3\x22, \x22name\x22: \x22novav3\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:9292\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:9292\x22, \x22id\x22: \x2212c935790bc94a789c72f9bbb21f39bc\x22, \x22publicURL\x22: \x22http://192.168.11.4:9292\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22image\x22, \x22name\x22: \x22glance\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8777\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8777\x22, \x22id\x22: \x221ce4901d8915423e96dab3fe1fb3663c\x22, \x22publicURL\x22: \x22http://192.168.11.4:8777\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22metering\x22, \x22name\x22: \x22ceilometer\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8000/v1/\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8000/v1/\x22, \x22id\x22: \x225e8f11c97e8043b5bde05bea2de4616c\x22, \x22publicURL\x22: \x22http://192.168.11.4:8000/v1/\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22cloudformation\x22, \x22name\x22: \x22heat-cfn\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8776/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8776/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x2254b9ec28bc604252b00cfe6e0e44aa94\x22, \x22publicURL\x22: \x22http://192.168.11.4:8776/v1/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22volume\x22, \x22name\x22: \x22cinder\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8773/services/Admin\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8773/services/Cloud\x22, \x22id\x22: \x22075ec79b0be341baabe2e9b120591f48\x22, \x22publicURL\x22: \x22http://192.168.11.4:8773/services/Cloud\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22ec2\x22, \x22name\x22: \x22nova_ec2\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:8004/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:8004/v1/c518b36fa220499b85ba9a71014ce2a5\x22, \x22id\x22: \x22262c4b373678468a9855a3ebc6015960\x22, \x22publicURL\x22: \x22http://192.168.11.4:8004/v1/c518b36fa220499b85ba9a71014ce2a5\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22orchestration\x22, \x22name\x22: \x22heat\x22}, {\x22endpoints\x22: [{\x22adminURL\x22: \x22http://172.16.33.4:35357/v2.0\x22, \x22region\x22: \x22openstack\x22, \x22internalURL\x22: \x22http://172.16.33.4:5000/v2.0\x22, \x22id\x22: \x22089fdb22249546b99a1e57aec0b1e76c\x22, \x22publicURL\x22: \x22http://192.168.11.4:5000/v2.0\x22}], \x22endpoints_links\x22: [], \x22type\x22: \x22identity\x22, \x22name\x22: \x22keystone\x22}], \x22user\x22: {\x22username\x22: \x22admin\x22, \x22roles_links\x22: [], \x22id\x22: \x223f76b94667434cf3bdc323cf021c50f8\x22, \x22roles\x22: [{\x22name\x22: \x22admin\x22}], \x22name\x22: \x22admin\x22}, \x22metadata\x22: {\x22is_admin\x22: 0, \x22roles\x22: [\x221e8bc5d1f3a448e9a2a1cda58d97f92b\x22]}}}" + http_version: + recorded_at: "Tue, 30 Sep 2014 07:16:15 GMT" + - request: + method: get + uri: "http://192.168.11.4:5000/v2.0/tenants" + body: + encoding: US-ASCII + string: "" + headers: + Content-Type: + - application/json + User-Agent: + - "Faraday v0.8.8" + X-Auth-Token: + - "MIIRIAYJKoZIhvcNAQcCoIIRETCCEQ0CAQExCTAHBgUrDgMCGjCCD3YGCSqGSIb3DQEHAaCCD2cEgg9jeyJhY2Nlc3MiOiB7InRva2VuIjogeyJpc3N1ZWRfYXQiOiAiMjAxNC0wOS0zMFQwNzoxNjoxNS4wNDI3NzgiLCAiZXhwaXJlcyI6ICIyMDE0LTA5LTMwVDA4OjE2OjE1WiIsICJpZCI6ICJwbGFjZWhvbGRlciIsICJ0ZW5hbnQiOiB7ImRlc2NyaXB0aW9uIjogImFkbWluIHRlbmFudCIsICJlbmFibGVkIjogdHJ1ZSwgImlkIjogImM1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgIm5hbWUiOiAiYWRtaW4ifX0sICJzZXJ2aWNlQ2F0YWxvZyI6IFt7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc0L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMWJiNzU4NWIzMzgxNGI4Mjk4NzJlYjQ0MjAyMTg5OGEiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NC92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJjb21wdXRlIiwgIm5hbWUiOiAibm92YSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5Njk2LyIsICJpZCI6ICJhYTdkNDU2NTNhYjI0ZGY2YmE5ZDE4NGE1ZWRkNGYxMyIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo5Njk2LyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJuZXR3b3JrIiwgIm5hbWUiOiAibmV1dHJvbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YyL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjIvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiMmJmNGQ5YzZiYTgwNDM1M2JjZGNlZGZjNTAxMDNiYjYiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92Mi9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWV2MiIsICJuYW1lIjogImNpbmRlcnYyIn0sIHsiZW5kcG9pbnRzIjogW3siYWRtaW5VUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzQvdjMiLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3NC92MyIsICJpZCI6ICIzZmQ4NDBjYmFkZDM0NmFiOTE2YjA2YWYxZjRlNWJmMCIsICJwdWJsaWNVUkwiOiAiaHR0cDovLzE5Mi4xNjguMTEuNDo4Nzc0L3YzIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImNvbXB1dGV2MyIsICJuYW1lIjogIm5vdmF2MyJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo5MjkyIiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40OjkyOTIiLCAiaWQiOiAiMTJjOTM1NzkwYmM5NGE3ODljNzJmOWJiYjIxZjM5YmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6OTI5MiJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJpbWFnZSIsICJuYW1lIjogImdsYW5jZSJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc3IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzciLCAiaWQiOiAiMWNlNDkwMWQ4OTE1NDIzZTk2ZGFiM2ZlMWZiMzY2M2MiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3NyJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJtZXRlcmluZyIsICJuYW1lIjogImNlaWxvbWV0ZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAicmVnaW9uIjogIm9wZW5zdGFjayIsICJpbnRlcm5hbFVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwMC92MS8iLCAiaWQiOiAiNWU4ZjExYzk3ZTgwNDNiNWJkZTA1YmVhMmRlNDYxNmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODAwMC92MS8ifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiY2xvdWRmb3JtYXRpb24iLCAibmFtZSI6ICJoZWF0LWNmbiJ9LCB7ImVuZHBvaW50cyI6IFt7ImFkbWluVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4Nzc2L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgInJlZ2lvbiI6ICJvcGVuc3RhY2siLCAiaW50ZXJuYWxVUkwiOiAiaHR0cDovLzE3Mi4xNi4zMy40Ojg3NzYvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUiLCAiaWQiOiAiNTRiOWVjMjhiYzYwNDI1MmIwMGNmZTZlMGU0NGFhOTQiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6ODc3Ni92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSJ9XSwgImVuZHBvaW50c19saW5rcyI6IFtdLCAidHlwZSI6ICJ2b2x1bWUiLCAibmFtZSI6ICJjaW5kZXIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODc3My9zZXJ2aWNlcy9BZG1pbiIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4NzczL3NlcnZpY2VzL0Nsb3VkIiwgImlkIjogIjA3NWVjNzliMGJlMzQxYmFhYmUyZTliMTIwNTkxZjQ4IiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40Ojg3NzMvc2VydmljZXMvQ2xvdWQifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAiZWMyIiwgIm5hbWUiOiAibm92YV9lYzIifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6ODAwNC92MS9jNTE4YjM2ZmEyMjA0OTliODViYTlhNzEwMTRjZTJhNSIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo4MDA0L3YxL2M1MThiMzZmYTIyMDQ5OWI4NWJhOWE3MTAxNGNlMmE1IiwgImlkIjogIjI2MmM0YjM3MzY3ODQ2OGE5ODU1YTNlYmM2MDE1OTYwIiwgInB1YmxpY1VSTCI6ICJodHRwOi8vMTkyLjE2OC4xMS40OjgwMDQvdjEvYzUxOGIzNmZhMjIwNDk5Yjg1YmE5YTcxMDE0Y2UyYTUifV0sICJlbmRwb2ludHNfbGlua3MiOiBbXSwgInR5cGUiOiAib3JjaGVzdHJhdGlvbiIsICJuYW1lIjogImhlYXQifSwgeyJlbmRwb2ludHMiOiBbeyJhZG1pblVSTCI6ICJodHRwOi8vMTcyLjE2LjMzLjQ6MzUzNTcvdjIuMCIsICJyZWdpb24iOiAib3BlbnN0YWNrIiwgImludGVybmFsVVJMIjogImh0dHA6Ly8xNzIuMTYuMzMuNDo1MDAwL3YyLjAiLCAiaWQiOiAiMDg5ZmRiMjIyNDk1NDZiOTlhMWU1N2FlYzBiMWU3NmMiLCAicHVibGljVVJMIjogImh0dHA6Ly8xOTIuMTY4LjExLjQ6NTAwMC92Mi4wIn1dLCAiZW5kcG9pbnRzX2xpbmtzIjogW10sICJ0eXBlIjogImlkZW50aXR5IiwgIm5hbWUiOiAia2V5c3RvbmUifV0sICJ1c2VyIjogeyJ1c2VybmFtZSI6ICJhZG1pbiIsICJyb2xlc19saW5rcyI6IFtdLCAiaWQiOiAiM2Y3NmI5NDY2NzQzNGNmM2JkYzMyM2NmMDIxYzUwZjgiLCAicm9sZXMiOiBbeyJuYW1lIjogImFkbWluIn1dLCAibmFtZSI6ICJhZG1pbiJ9LCAibWV0YWRhdGEiOiB7ImlzX2FkbWluIjogMCwgInJvbGVzIjogWyIxZThiYzVkMWYzYTQ0OGU5YTJhMWNkYTU4ZDk3ZjkyYiJdfX19MYIBgTCCAX0CAQEwXDBXMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFVW5zZXQxDjAMBgNVBAcMBVVuc2V0MQ4wDAYDVQQKDAVVbnNldDEYMBYGA1UEAwwPd3d3LmV4YW1wbGUuY29tAgEBMAcGBSsOAwIaMA0GCSqGSIb3DQEBAQUABIIBAEOAl3MRmSUB+J+kRi+qRhwOrNRmj-wDqT5nJTlbafOjofSXsHG683LaipA7oPoH-ARUPDxXIZfevRue7bQQB3I4cWIUSItIPyW4xDpF+iHy3QOm+I-3v3ctze2Z3Rp0TRaYFsItTZZETsSXI28yBt9+3Dsk3a7Vv10HAZetbV1i6qu6avLcJsmN-1J3KLwCDSEvpMgDAcpzAnhba1fi+X8GrCCTz4c1uIcPfsHxX4g8gNkB4-VT0lkRmfSxdrGeRz0uN12oDqgCL64IV1mJ6Bi9Unh15QFcLwU0F8ote+joG9G29fw3WDzneXHIeEIZSBXmOAX2kQBOnZa2sZg8gls=" + response: + status: + code: 200 + message: + headers: + vary: + - X-Auth-Token + content-type: + - application/json + content-length: + - "143" + date: + - "Tue, 30 Sep 2014 07:16:15 GMT" + connection: + - close + body: + encoding: UTF-8 + string: "{\x22tenants_links\x22: [], \x22tenants\x22: [{\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}]}" + http_version: + recorded_at: "Tue, 30 Sep 2014 07:16:15 GMT" + recorded_with: "VCR 2.9.3" \ No newline at end of file diff --git a/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/session/with_token.yml b/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/session/with_token.yml new file mode 100644 index 000000000..784fb2fea --- /dev/null +++ b/3rdparty/modules/openstacklib/spec/fixtures/vcr/aviator/session/with_token.yml @@ -0,0 +1,36 @@ +--- + http_interactions: + - request: + method: get + uri: "http://192.168.11.4:35357/v2.0/tenants" + body: + encoding: US-ASCII + string: "" + headers: + Content-Type: + - application/json + User-Agent: + - "Faraday v0.8.8" + X-Auth-Token: + - sosp-kyl + response: + status: + code: 200 + message: + headers: + vary: + - X-Auth-Token + content-type: + - application/json + content-length: + - "491" + date: + - "Tue, 30 Sep 2014 06:59:48 GMT" + connection: + - close + body: + encoding: UTF-8 + string: "{\x22tenants_links\x22: [], \x22tenants\x22: [{\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x2234e463e2bab24f78990ca864e4a28ba2\x22, \x22name\x22: \x22test2\x22}, {\x22description\x22: \x22Tenant for the openstack services\x22, \x22enabled\x22: true, \x22id\x22: \x2268c8fcf77aff4b409cc158c0f6cbff7b\x22, \x22name\x22: \x22services\x22}, {\x22description\x22: \x22Test tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c330f1bc663648df9c1e7835a1e7a955\x22, \x22name\x22: \x22test\x22}, {\x22description\x22: \x22admin tenant\x22, \x22enabled\x22: true, \x22id\x22: \x22c518b36fa220499b85ba9a71014ce2a5\x22, \x22name\x22: \x22admin\x22}]}" + http_version: + recorded_at: "Tue, 30 Sep 2014 06:59:48 GMT" + recorded_with: "VCR 2.9.3" \ No newline at end of file diff --git a/3rdparty/modules/openstacklib/spec/functions/os_database_connection_spec.rb b/3rdparty/modules/openstacklib/spec/functions/os_database_connection_spec.rb new file mode 100644 index 000000000..6819e7e8f --- /dev/null +++ b/3rdparty/modules/openstacklib/spec/functions/os_database_connection_spec.rb @@ -0,0 +1,134 @@ +require 'spec_helper' + +describe 'os_database_connection' do + + it 'refuses String' do + should run.with_params('foo').\ + and_raise_error(Puppet::ParseError, /Requires an hash/) + end + + it 'refuses Array' do + should run.with_params(['foo']).\ + and_raise_error(Puppet::ParseError, /Requires an hash/) + end + + it 'refuses without at least one argument' do + should run.with_params().\ + and_raise_error(Puppet::ParseError, /Wrong number of arguments/) + end + + it 'refuses too many arguments' do + should run.with_params('foo', 'bar').\ + and_raise_error(Puppet::ParseError, /Wrong number of arguments/) + end + + it 'fails if port is provided with missing host' do + should run.with_params({ + 'dialect' => 'sqlite', + 'database' => '/var/lib/keystone/keystone.db', + 'port' => '3306', + '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 + should run.with_params({ + 'dialect' => 'mysql', + 'host' => '127.0.0.1', + 'port' => '3306', + 'database' => 'test', + 'username' => 'guest', + 'password' => 's3cr3t', + 'charset' => 'utf-8' + }).and_return('mysql://guest:s3cr3t@127.0.0.1:3306/test?charset=utf-8') + end + + it 'without port' do + should run.with_params({ + 'dialect' => 'mysql', + 'host' => '127.0.0.1', + 'database' => 'test', + 'username' => 'guest', + 'password' => 's3cr3t', + 'charset' => 'utf-8' + }).and_return('mysql://guest:s3cr3t@127.0.0.1/test?charset=utf-8') + end + + it 'without host and port' do + should run.with_params({ + 'dialect' => 'sqlite', + 'database' => '/var/lib/keystone/keystone.db', + 'charset' => 'utf-8' + }).and_return('sqlite:////var/lib/keystone/keystone.db?charset=utf-8') + end + + it 'without username and password' do + should run.with_params({ + 'dialect' => 'mysql', + 'host' => '127.0.0.1', + 'port' => '3306', + 'database' => 'test', + 'charset' => 'utf-8' + }).and_return('mysql://127.0.0.1:3306/test?charset=utf-8') + end + + it 'with username set to undef' do + should run.with_params({ + 'dialect' => 'mysql', + 'host' => '127.0.0.1', + 'port' => '3306', + 'database' => 'test', + 'username' => :undef, + '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 + should run.with_params({ + 'dialect' => 'mysql', + 'host' => '127.0.0.1', + 'port' => '3306', + 'database' => 'test', + 'username' => '', + 'charset' => 'utf-8' + }).and_return('mysql://127.0.0.1:3306/test?charset=utf-8') + end + + it 'without password' do + should run.with_params({ + 'dialect' => 'mysql', + 'host' => '127.0.0.1', + 'port' => '3306', + 'database' => 'test', + 'username' => 'guest', + 'charset' => 'utf-8' + }).and_return('mysql://guest@127.0.0.1:3306/test?charset=utf-8') + end + + it 'with password set to undef' do + should run.with_params({ + 'dialect' => 'mysql', + 'host' => '127.0.0.1', + 'port' => '3306', + 'database' => 'test', + 'username' => 'guest', + 'password' => :undef, + '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 + should run.with_params({ + 'dialect' => 'mysql', + 'host' => '127.0.0.1', + 'port' => '3306', + 'database' => 'test', + 'username' => 'guest', + 'password' => '', + 'charset' => 'utf-8' + }).and_return('mysql://guest@127.0.0.1:3306/test?charset=utf-8') + end + end +end diff --git a/3rdparty/modules/openstacklib/spec/spec_helper.rb b/3rdparty/modules/openstacklib/spec/spec_helper.rb new file mode 100644 index 000000000..ecd609ae7 --- /dev/null +++ b/3rdparty/modules/openstacklib/spec/spec_helper.rb @@ -0,0 +1,7 @@ +require 'puppetlabs_spec_helper/module_spec_helper' +require 'vcr' + +VCR.configure do |c| + c.cassette_library_dir = 'spec/fixtures/vcr' + c.hook_into :faraday +end diff --git a/3rdparty/modules/openstacklib/spec/unit/provider/aviator_spec.rb b/3rdparty/modules/openstacklib/spec/unit/provider/aviator_spec.rb new file mode 100644 index 000000000..35564e64a --- /dev/null +++ b/3rdparty/modules/openstacklib/spec/unit/provider/aviator_spec.rb @@ -0,0 +1,320 @@ +# Load libraries from aviator here to simulate how they live together in a real puppet run +$LOAD_PATH.push(File.join(File.dirname(__FILE__), '..', '..', 'fixtures', 'modules', 'aviator', 'lib')) +require 'puppet' +require 'vcr' +require 'spec_helper' +require 'puppet/provider/aviator' + + +describe Puppet::Provider::Aviator do + + before(:each) do + ENV['OS_USERNAME'] = nil + ENV['OS_PASSWORD'] = nil + ENV['OS_TENANT_NAME'] = nil + ENV['OS_AUTH_URL'] = nil + end + + let(:log_file) { '/tmp/aviator_spec.log' } + + let(:type) do + Puppet::Type.newtype(:test_resource) do + newparam(:name, :namevar => true) + newparam(:auth) + newparam(:log_file) + end + end + + + shared_examples 'creating a session using environment variables' do + it 'creates an authenticated session' do + ENV['OS_USERNAME'] = 'admin' + ENV['OS_PASSWORD'] = 'fyby-tet' + ENV['OS_TENANT_NAME'] = 'admin' + ENV['OS_AUTH_URL'] = 'http://192.168.11.4:35357/v2.0' + response = nil + VCR.use_cassette('aviator/session/with_password') do + session = provider.session + response = session.identity_service.request(:list_tenants, :session_data => provider.session_data) + end + expect(response.status).to eq(200) + end + end + + shared_examples 'creating a session using a service token from keystone.conf' do + it 'creates an unauthenticated session' do + data = "[DEFAULT]\nadmin_token=sosp-kyl\nadmin_endpoint=http://192.168.11.4:35357/v2.0" + response = nil + VCR.use_cassette('aviator/session/with_token') do + # Stubbing File.read produces inconsistent results because of how IniConfig + # overrides the File class in some versions of Puppet. + # Stubbing FileType.filetype(:flat) simplifies working with IniConfig + Puppet::Util::FileType.filetype(:flat).any_instance.expects(:read).returns(StringIO.new(data).read) + session = provider.session + Puppet::Util::FileType.filetype(:flat).any_instance.unstub(:read) + response = session.identity_service.request(:list_tenants, :session_data => provider.session_data) + end + + expect(response.status).to eq(200) + end + end + + shared_examples 'it has no credentials' do + it 'fails to authenticate' do + expect{ provider.session }.to raise_error(Puppet::Error, /No credentials provided/) + end + end + + shared_examples 'making request with an existing session' do + it 'makes a successful request' do + VCR.use_cassette('aviator/request/with_session') do + session = provider.session + response = provider.request(session.identity_service, :list_tenants) + expect(response.status).to eq(200) + end + end + end + + shared_examples 'making request with injected session data' do + it 'makes a successful request' do + VCR.use_cassette('aviator/request/without_session') do + session = provider.session + response = provider.request(session.identity_service, :list_tenants) + expect(response.status).to eq(200) + end + end + end + + shared_examples 'making request with no session or session data' do + it 'fails to make a request' do + expect{ provider.request(nil, :list_tenants) }.to raise_error(Puppet::Error, /Cannot make a request/) + end + end + + describe '#session' do + + context 'with valid password credentials in parameters' do + let(:resource_attrs) do + { + :name => 'stubresource', + :auth => { + 'username' => 'admin', + 'password' => 'fyby-tet', + 'tenant_name' => 'admin', + 'host_uri' => 'http://192.168.11.4:35357/v2.0', + } + } + end + + it 'creates a session' do + provider = Puppet::Provider::Aviator.new(type.new(resource_attrs)) + response = nil + VCR.use_cassette('aviator/session/with_password') do + session = provider.session + response = session.identity_service.request(:list_tenants) + end + expect(response.status).to eq(200) + end + end + + context 'with valid openrc file in parameters' do + data = "export OS_USERNAME='admin'\nexport OS_PASSWORD='fyby-tet'\nexport OS_TENANT_NAME='admin'\nexport OS_AUTH_URL='http://192.168.11.4:35357/v2.0'" + let(:resource_attrs) do + { + :name => 'stubresource', + :auth => { + 'openrc' => '/root/openrc' + } + } + end + + it 'creates a session' do + provider = Puppet::Provider::Aviator.new(type.new(resource_attrs)) + response = nil + VCR.use_cassette('aviator/session/with_password') do + File.expects(:open).with('/root/openrc').returns(StringIO.new(data)) + session = provider.session + File.unstub(:open) # Ignore File.open calls to cassette file + response = session.identity_service.request(:list_tenants) + end + expect(response.status).to eq(200) + end + end + + context 'with valid service token in parameters' do + let(:resource_attrs) do + { + :name => 'stubresource', + :auth => { + 'service_token' => 'sosp-kyl', + 'host_uri' => 'http://192.168.11.4:35357/v2.0' + } + } + end + + subject(:session) do + provider = Puppet::Provider::Aviator.new(type.new(resource_attrs)) + VCR.use_cassette('aviator/session/with_token') do + session = provider.session + response = session.identity_service.request(:list_tenants, :session_data => provider.session_data) + end + end + + it 'creates a session' do + expect(session.status).to eq(200) + end + + end + + context 'with valid password credentials in environment variables' do + it_behaves_like 'creating a session using environment variables' do + let(:resource_attrs) do + { + :name => 'stubresource', + } + end + let(:provider) do + Puppet::Provider::Aviator.new(type.new(resource_attrs)) + end + end + end + + context 'with valid service token in keystone.conf' do + it_behaves_like 'creating a session using a service token from keystone.conf' do + let(:resource_attrs) do + { + :name => 'stubresource', + } + end + let(:provider) do + Puppet::Provider::Aviator.new(type.new(resource_attrs)) + end + end + + end + + context 'with no valid credentials' do + it_behaves_like 'it has no credentials' do + let(:resource_attrs) do + { + :name => 'stubresource', + } + end + let(:provider) { Puppet::Provider::Aviator.new(type.new(resource_attrs)) } + end + end + + end + + + describe '::session' do + + context 'with valid password credentials in environment variables' do + it_behaves_like 'creating a session using environment variables' do + let(:provider) { Puppet::Provider::Aviator.dup } + end + end + + context 'with valid service token in keystone.conf' do + it_behaves_like 'creating a session using a service token from keystone.conf' do + let(:provider) { Puppet::Provider::Aviator.dup } + end + end + + context 'with no valid credentials' do + it_behaves_like 'it has no credentials' do + let(:provider) { Puppet::Provider::Aviator.dup } + end + end + end + + describe '#request' do + context 'when a session exists' do + it_behaves_like 'making request with an existing session' do + let(:resource_attrs) do + { + :name => 'stubresource', + :auth => { + 'username' => 'admin', + 'password' => 'fyby-tet', + 'tenant_name' => 'admin', + 'host_uri' => 'http://192.168.11.4:35357/v2.0', + } + } + end + let (:provider) { Puppet::Provider::Aviator.new(type.new(resource_attrs)) } + end + end + + context 'when injecting session data' do + let(:resource_attrs) do + { + :name => 'stubresource', + :auth => { + 'service_token' => 'sosp-kyl', + 'host_uri' => 'http://192.168.11.4:35357/v2.0' + } + } + end + let(:provider) { Puppet::Provider::Aviator.new(type.new(resource_attrs)) } + it 'makes a successful request' do + provider = Puppet::Provider::Aviator.new(type.new(resource_attrs)) + VCR.use_cassette('aviator/request/without_session') do + session = provider.session + response = provider.request(session.identity_service, :list_tenants) + expect(response.status).to eq(200) + end + end + end + + context 'when there is no session or session data' do + it_behaves_like 'making request with no session or session data' do + let(:resource_attrs) do + { + :name => 'stubresource', + } + end + let(:provider) {Puppet::Provider::Aviator.new(type.new(resource_attrs)) } + end + end + end + + describe '::request' do + context 'when a session exists' do + + it_behaves_like 'making request with an existing session' do + let(:provider) { provider = Puppet::Provider::Aviator.dup } + before(:each) do + ENV['OS_USERNAME'] = 'admin' + ENV['OS_PASSWORD'] = 'fyby-tet' + ENV['OS_TENANT_NAME'] = 'admin' + ENV['OS_AUTH_URL'] = 'http://192.168.11.4:35357/v2.0' + end + end + end + + context 'when injecting session data' do + let(:session_data) do + { + :base_url => 'http://192.168.11.4:35357/v2.0', + :service_token => 'sosp-kyl' + } + end + it 'makes a successful request' do + provider = Puppet::Provider::Aviator.dup + VCR.use_cassette('aviator/request/without_session') do + session = ::Aviator::Session.new(:config => { :provider => 'openstack' }, :log_file => log_file) + provider.session_data = session_data + response = provider.request(session.identity_service, :list_tenants) + expect(response.status).to eq(200) + end + end + end + + context 'when there is no session or session data' do + it_behaves_like 'making request with no session or session data' do + let(:provider) { Puppet::Provider::Aviator.dup } + end + end + end +end diff --git a/3rdparty/modules/qpid/CHANGELOG b/3rdparty/modules/qpid/CHANGELOG new file mode 100644 index 000000000..40767513e --- /dev/null +++ b/3rdparty/modules/qpid/CHANGELOG @@ -0,0 +1,9 @@ +2013-7-23 1.0.2 +- Allow custer configuration to be optional (ggillies) + +2013-7-8 1.0.1 +- Use correct mechanism option (mmagr) +- Update saslpasswd2 exists? to handle errors. + +2012-4-08 1.0.0 +- Initial Release. Manage the package, file and service. diff --git a/3rdparty/modules/qpid/LICENSE b/3rdparty/modules/qpid/LICENSE new file mode 100644 index 000000000..8d968b6cb --- /dev/null +++ b/3rdparty/modules/qpid/LICENSE @@ -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. diff --git a/3rdparty/modules/qpid/Modulefile b/3rdparty/modules/qpid/Modulefile new file mode 100644 index 000000000..f5a7a8a9c --- /dev/null +++ b/3rdparty/modules/qpid/Modulefile @@ -0,0 +1,10 @@ +name 'dprince/qpid' +version '1.0.2' +source 'git://github.com/dprince/puppet-qpid.git' +author 'Dan Prince ' +license 'Apache' +summary 'Qpid Puppet Module' +description 'This module manages Qpid.' +project_page 'https://github.com/dprince/puppet-qpid' + +dependency 'puppetlabs/stdlib', '>= 0.0.1' diff --git a/3rdparty/modules/qpid/README b/3rdparty/modules/qpid/README new file mode 100644 index 000000000..ece93c842 --- /dev/null +++ b/3rdparty/modules/qpid/README @@ -0,0 +1,16 @@ +# Qpid Puppet Module +Dan Prince + +This module manages the Qpid. + +examples: + +class { 'qpid::server': } + +qpid_user { 'foo': + password => 'changeme', + file => '/var/lib/qpidd/qpidd.sasldb', + realm => 'TEST', + provider => 'saslpasswd2', + require => Class['qpid::server'], +} diff --git a/3rdparty/modules/qpid/lib/puppet/provider/qpid_user/default.rb b/3rdparty/modules/qpid/lib/puppet/provider/qpid_user/default.rb new file mode 100644 index 000000000..b3a3e1658 --- /dev/null +++ b/3rdparty/modules/qpid/lib/puppet/provider/qpid_user/default.rb @@ -0,0 +1,22 @@ +Puppet::Type.type(:qpid_user).provide(:default) do + + def self.instances + [] + end + + def create + default_fail + end + + def destroy + default_fail + end + + def exists? + default_fail + end + + def default_fail + fail('The default provider for qpid_user... all it does is fail.') + end +end diff --git a/3rdparty/modules/qpid/lib/puppet/provider/qpid_user/saslpasswd2.rb b/3rdparty/modules/qpid/lib/puppet/provider/qpid_user/saslpasswd2.rb new file mode 100644 index 000000000..9cd2dc5a2 --- /dev/null +++ b/3rdparty/modules/qpid/lib/puppet/provider/qpid_user/saslpasswd2.rb @@ -0,0 +1,38 @@ +Puppet::Type.type(:qpid_user).provide(:saslpasswd2) do + + commands :saslpasswd2 => 'saslpasswd2' + optional_commands :sasldblistusers2 => 'sasldblistusers2' + defaultfor :feature => :posix + + def self.instances + sasldblistusers2('-f', resource[:file]).split(/\n/)[1..-2].map do |line| + if line =~ /^(\S+)@(\S+):.*$/ + new(:name => $1, :realm => $2) + else + raise Puppet::Error, "Cannot parse invalid user line: #{line}" + end + end + end + + def create + if not system(%{echo "#{resource[:password]}" | saslpasswd2 -f #{resource[:file]} -u #{resource[:realm]} #{resource[:name]}}) + + raise Puppet::Error, "Failed to create user." + end + end + + def destroy + saslpasswd2('-f', resource[:file], '-u', resource[:realm], '-d', resource[:name]) + end + + def exists? + begin + out = sasldblistusers2('-f', resource[:file]).split(/\n/)[1..-2].detect do |line| + line.match(/^#{resource[:name]}@#{resource[:realm]}:.*$/) + end + rescue + return false + end + end + +end diff --git a/3rdparty/modules/qpid/lib/puppet/type/qpid_user.rb b/3rdparty/modules/qpid/lib/puppet/type/qpid_user.rb new file mode 100644 index 000000000..8b0751c64 --- /dev/null +++ b/3rdparty/modules/qpid/lib/puppet/type/qpid_user.rb @@ -0,0 +1,39 @@ +Puppet::Type.newtype(:qpid_user) do + desc 'Type for managing qpid users' + + ensurable do + defaultto(:present) + newvalue(:present) do + provider.create + end + newvalue(:absent) do + provider.destroy + end + end + + newparam(:name, :namevar => true) do + desc 'Name of user' + newvalues(/^\S+$/) + end + + newparam(:realm) do + desc 'Realm for this user' + newvalues(/^\S+$/) + end + + newparam(:file) do + desc 'Location of the sasl password file' + newvalues(/^\S+$/) + end + + newparam(:password) do + desc 'User password to be set *on creation*' + end + + validate do + if self[:ensure] == :present and ! self[:password] + raise ArgumentError, 'must set password when creating user' unless self[:password] + end + end + +end diff --git a/3rdparty/modules/qpid/manifests/server.pp b/3rdparty/modules/qpid/manifests/server.pp new file mode 100644 index 000000000..6328a1832 --- /dev/null +++ b/3rdparty/modules/qpid/manifests/server.pp @@ -0,0 +1,72 @@ +# Class: qpid::server +# +# This module manages the installation and config of the qpid server. +class qpid::server( + $config_file = '/etc/qpidd.conf', + $package_name = 'qpid-cpp-server', + $package_ensure = present, + $service_name = 'qpidd', + $service_ensure = running, + $port = '5672', + $max_connections = '500', + $worker_threads = '17', + $connection_backlog = '10', + $auth = 'no', + $realm = 'QPID', + $log_to_file = 'UNSET', + $clustered = false, + $cluster_mechanism = 'ANONYMOUS' +) { + + validate_re($port, '\d+') + validate_re($max_connections, '\d+') + validate_re($worker_threads, '\d+') + validate_re($connection_backlog, '\d+') + validate_re($auth, '^(yes$|no$)') + + package { $package_name: + ensure => $package_ensure + } + + if $clustered == true { + case $::operatingsystem { + fedora: { + $mechanism_option = 'ha-mechanism' + package {"qpid-cpp-server-ha": + ensure => installed, + } + } + default: { + $mechanism_option = 'cluster-mechanism' + package {"qpid-cpp-server-cluster": + ensure => installed, + } + } + } + } + + file { $config_file: + ensure => present, + owner => 'root', + group => 'root', + mode => 644, + content => template('qpid/qpidd.conf.erb'), + subscribe => Package[$package_name] + } + + if $log_to_file != 'UNSET' { + file { $log_to_file: + ensure => present, + owner => 'qpidd', + group => 'qpidd', + mode => 644, + notify => Service[$service_name] + } + } + + service { $service_name: + ensure => $service_ensure, + subscribe => [Package[$package_name], File[$config_file]] + } + +} diff --git a/3rdparty/modules/qpid/metadata.json b/3rdparty/modules/qpid/metadata.json new file mode 100644 index 000000000..9e642027e --- /dev/null +++ b/3rdparty/modules/qpid/metadata.json @@ -0,0 +1,67 @@ +{ + "name": "dprince/qpid", + "version": "1.0.2", + "source": "git://github.com/dprince/puppet-qpid.git", + "author": "Dan Prince ", + "license": "Apache", + "summary": "Qpid Puppet Module", + "description": "This module manages Qpid.", + "project_page": "https://github.com/dprince/puppet-qpid", + "dependencies": [ + { + "name": "puppetlabs/stdlib", + "version_requirement": ">= 0.0.1" + } + ], + "types": [ + { + "name": "qpid_user", + "doc": "Type for managing qpid users", + "properties": [ + { + "name": "ensure", + "doc": " Valid values are `present`, `absent`." + } + ], + "parameters": [ + { + "name": "name", + "doc": "Name of user Values can match `/^\\S+$/`." + }, + { + "name": "realm", + "doc": "Realm for this user Values can match `/^\\S+$/`." + }, + { + "name": "file", + "doc": "Location of the sasl password file Values can match `/^\\S+$/`." + }, + { + "name": "password", + "doc": "User password to be set *on creation*" + } + ], + "providers": [ + { + "name": "default", + "doc": "" + }, + { + "name": "saslpasswd2", + "doc": "Required binaries: `saslpasswd2`, `sasldblistusers2`. Default for `feature` == `posix`." + } + ] + } + ], + "checksums": { + "CHANGELOG": "886717e644c62a756df7b3b7ca457fd4", + "LICENSE": "0e5ccf641e613489e66aa98271dbe798", + "Modulefile": "8be4e13c5003b8108ff4dfcfb68b33b2", + "README": "0fc7835dc5f0d6ff16a5cb28154af353", + "lib/puppet/provider/qpid_user/default.rb": "0b0856ef1e1d92f1115a9d3dd833e475", + "lib/puppet/provider/qpid_user/saslpasswd2.rb": "28d770fd44b23aaf1bf48afce7222047", + "lib/puppet/type/qpid_user.rb": "f104d60fc6f5f3a9f9d3ac26f11e239b", + "manifests/server.pp": "e5cd7de5955263df8faca03642534fa8", + "templates/qpidd.conf.erb": "05ecde6fff47678eadc4608d646b51df" + } +} \ No newline at end of file diff --git a/3rdparty/modules/qpid/templates/qpidd.conf.erb b/3rdparty/modules/qpid/templates/qpidd.conf.erb new file mode 100644 index 000000000..c8f69d7c7 --- /dev/null +++ b/3rdparty/modules/qpid/templates/qpidd.conf.erb @@ -0,0 +1,19 @@ +# GENERATED BY PUPPET +# +# Configuration file for qpidd. Entries are of the form: +# name=value +# +# (Note: no spaces on either side of '='). Using default settings: +# "qpidd --help" or "man qpidd" for more details. +port=<%= port %> +max-connections=<%= max_connections %> +worker-threads=<%= worker_threads %> +connection-backlog=<%= connection_backlog %> +auth=<%= auth %> +realm=<%= realm %> +<% if clustered == true %> +<%= mechanism_option %>=<%= cluster_mechanism %> +<% end %> +<% if log_to_file != 'UNSET' %> +log-to-file=<%= log_to_file %> +<% end %> diff --git a/3rdparty/modules/sysctl/Gemfile b/3rdparty/modules/sysctl/Gemfile new file mode 100644 index 000000000..6efd0b00c --- /dev/null +++ b/3rdparty/modules/sysctl/Gemfile @@ -0,0 +1,17 @@ +source 'https://rubygems.org' + +if ENV.key?('PUPPET_VERSION') + puppetversion = "~> #{ENV['PUPPET_VERSION']}" +else + puppetversion = ['>= 3.7.4'] +end + +gem 'puppet', puppetversion +# Support ruby 1.8.7 +# https://github.com/rspec/rspec-core/issues/1864 +if RUBY_VERSION < "1.9" + gem 'rspec', '< 3.2.0' +end +gem 'puppet-lint' +gem 'puppetlabs_spec_helper' +gem 'rake' diff --git a/3rdparty/modules/sysctl/README.md b/3rdparty/modules/sysctl/README.md new file mode 100644 index 000000000..aeaedc706 --- /dev/null +++ b/3rdparty/modules/sysctl/README.md @@ -0,0 +1,58 @@ +Requirements +============ + +[![Build Status](https://travis-ci.org/duritong/puppet-sysctl.png?branch=master)](https://travis-ci.org/duritong/puppet-sysctl) + +Overview +-------- + +This modules allows to configure sysctl. + +Usage +----- + + node "mynode" inherits ... { + sysctl::value { "vm.nr_hugepages": value => "1583"} + } + +When setting a key that contains multiple values, use a tab to separate the +values: + + node "mynode" inherits ... { + sysctl::value { 'net.ipv4.tcp_rmem': + value => "4096\t131072\t131072", + } + } + +If another config file then /etc/sysctl.conf (default) is required, use target for this: + + node "mynode" inherits ... { + sysctl::value { 'net.ipv4.tcp_rmem': + value => "4096\t131072\t131072", + target => '/etc/sysctl.d/mysysctl.conf', + } + } + +To avoid duplication the sysctl::value calls multiple settings can be +managed like this: + + $my_sysctl_settings = { + "net.ipv4.ip_forward" => { value => 1 }, + "net.ipv6.conf.all.forwarding" => { value => 1 }, + } + + # Specify defaults for all the sysctl::value to be created ( + $my_sysctl_defaults = { + require => Package['aa'] + } + + create_resources(sysctl::value,$my_sysctl_settings,$my_sysctl_defaults) + +License +------- + +Copyright (C) 2011 Immerda Project Group + +Author mh , Modified by Nicolas Zin , Modified by Artem Sidorenko + +Licence: GPL v2 diff --git a/3rdparty/modules/sysctl/Rakefile b/3rdparty/modules/sysctl/Rakefile new file mode 100644 index 000000000..489e9e7b9 --- /dev/null +++ b/3rdparty/modules/sysctl/Rakefile @@ -0,0 +1,32 @@ +require 'bundler' +Bundler.require(:rake) + +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' + +Rake::Task[:lint].clear +PuppetLint::RakeTask.new :lint do |config| + config.ignore_paths = ["spec/**/*.pp", "vendor/**/*.pp", "pkg/**/*.pp"] + config.log_format = '%{path}:%{linenumber}:%{KIND}: %{message}' + # TODO: remove this check once the relative config + # is supported by puppet-lint release + config.disable_checks = [ 'autoloader_layout' ] +end + +# use librarian-puppet to manage fixtures instead of .fixtures.yml +# offers more possibilities like explicit version management, forge downloads,... +task :librarian_spec_prep do +# sh "librarian-puppet install --path=spec/fixtures/modules/" + pwd = `pwd`.strip + # because we don't have librarian-puppet + unless File.directory?("#{pwd}/spec/fixtures/modules") + sh "mkdir -p #{pwd}/spec/fixtures/modules" + end + unless File.directory?("#{pwd}/spec/fixtures/modules/sysctl") + sh "ln -s #{pwd} #{pwd}/spec/fixtures/modules/sysctl" + end +end +task :spec_prep => :librarian_spec_prep + + +task :default => [:spec, :lint] diff --git a/3rdparty/modules/sysctl/checksums.json b/3rdparty/modules/sysctl/checksums.json new file mode 100644 index 000000000..619132f78 --- /dev/null +++ b/3rdparty/modules/sysctl/checksums.json @@ -0,0 +1,16 @@ +{ + "Gemfile": "32463b87afeb13e4ee75b3d2b1f744ba", + "README.md": "b5335702ab6b120493cf88faaf9be346", + "Rakefile": "b995712132d301b58983732c96de889a", + "lib/puppet/provider/sysctl/parsed.rb": "f1ad6c1cd610b6fe33fcd245759c09d1", + "lib/puppet/provider/sysctl_runtime/sysctl_runtime.rb": "fd75e9c999cd6c34c7a04d8154bbc166", + "lib/puppet/type/sysctl.rb": "e922bf4d4526967e95f6cec7d55f643a", + "lib/puppet/type/sysctl_runtime.rb": "0b6f7cc9b83b2ce2fbac6b6c23b063d1", + "manifests/base.pp": "6ff4e93ca575e9a5a525b622f33f5ea3", + "manifests/value.pp": "4600b4ba68a47e62ad87b2d56dcbcd9e", + "manifests/values.pp": "90079d054e73c557c74036faaf52c9b7", + "metadata.json": "9abed1fc7e8fea7045e46abc4adfcd56", + "spec/classes/sysctl_values_spec.rb": "4f4d1f2d27e18e99ef13cb5cdd81b192", + "spec/defines/value_spec.rb": "3c3a09d3c5dbad5cf6f1741955c8b4f2", + "spec/spec_helper.rb": "86e4b77c1f52c96afeb2f312fe53d1d9" +} \ No newline at end of file diff --git a/3rdparty/modules/sysctl/lib/puppet/provider/sysctl/parsed.rb b/3rdparty/modules/sysctl/lib/puppet/provider/sysctl/parsed.rb new file mode 100644 index 000000000..56c1ae47a --- /dev/null +++ b/3rdparty/modules/sysctl/lib/puppet/provider/sysctl/parsed.rb @@ -0,0 +1,17 @@ +require 'puppet/provider/parsedfile' + +sysctlconf = "/etc/sysctl.conf" + +Puppet::Type.type(:sysctl).provide(:parsed, + :parent => Puppet::Provider::ParsedFile, + :default_target => sysctlconf, + :filetype => :flat + ) do + + confine :exists => sysctlconf + text_line :comment, :match => /^\s*#/; + text_line :blank, :match => /^\s*$/; + + record_line :parsed, :fields => %w{name val}, :joiner => '=', :separator => /\s*=\s*/ + +end diff --git a/3rdparty/modules/sysctl/lib/puppet/provider/sysctl_runtime/sysctl_runtime.rb b/3rdparty/modules/sysctl/lib/puppet/provider/sysctl_runtime/sysctl_runtime.rb new file mode 100644 index 000000000..b0f35aca4 --- /dev/null +++ b/3rdparty/modules/sysctl/lib/puppet/provider/sysctl_runtime/sysctl_runtime.rb @@ -0,0 +1,50 @@ +Puppet::Type.type(:sysctl_runtime).provide(:sysctl_runtime, + :parent => Puppet::Provider + ) do + desc "This provider changes the runtime values of kernel parameters" + + commands :sysctl => 'sysctl' + + mk_resource_methods + + def self.instances + #we don't use here the sysctl command to be able + #to disable combining of stderr/stdout output. + #Sysctl produces mixed output in case of error, + #and it can't be parsed. + #https://ask.puppetlabs.com/question/6299/combine-false-for-provider-commands/ + executor = (Facter.value(:puppetversion).to_i < 3) ? Puppet::Util : Puppet::Util::Execution + output = executor.execute("#{Puppet::Util.which('sysctl')} -a", { + :failonfail => true, + :combine => false, + :custom_environment => {} + }) + output.split("\n").collect do |line| + # lovely linux shows "fs.dir-notify-enable = 1" + # lovely openbsd shows "fs.dir-notify-enable=1" + name, val = line.split(/\s?[=:]\s?/,2) + if name && val # maybe the line didn't match key = val + new( + :name => name, + :val => val + ) + end + end.compact + end + + def self.prefetch(resources) + sysctl_flags = instances + resources.keys.each do |res| + if provider = sysctl_flags.find{ |sres| sres.name == res } + resources[res].provider = provider + else + raise(Puppet::ParseError, "sysctl parameter #{res} wasn't found on this system") + end + end + end + + def val=(value) + sysctl("#{resource[:name]}=#{value}") + end + +end diff --git a/3rdparty/modules/sysctl/lib/puppet/type/sysctl.rb b/3rdparty/modules/sysctl/lib/puppet/type/sysctl.rb new file mode 100644 index 000000000..722bef703 --- /dev/null +++ b/3rdparty/modules/sysctl/lib/puppet/type/sysctl.rb @@ -0,0 +1,41 @@ +Puppet::Type.newtype(:sysctl) do + + @doc = "Manages kernel parameters in /etc/sysctl.conf. By default this will + only edit the configuration file, and not change any of the runtime + values. If you wish changes to be activated right away, you can do + so with an exec like so: + + exec { load-sysctl: + command => \"/sbin/sysctl -p /etc/sysctl.conf\", + refreshonly => true + } + + Set any changes you want to happen right away to notify this command, + or you can set it as the default: + + Sysctl { + notify => Exec[load-sysctl] + }" + + ensurable + + newparam(:name, :namevar => true) do + desc "Name of the parameter" + isnamevar + end + + newproperty(:val) do + desc "Value the parameter should be set to" + end + + newproperty(:target) do + desc "Name of the file to store parameters in" + defaultto { if @resource.class.defaultprovider and + @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile) + @resource.class.defaultprovider.default_target + else + nil + end + } + end +end diff --git a/3rdparty/modules/sysctl/lib/puppet/type/sysctl_runtime.rb b/3rdparty/modules/sysctl/lib/puppet/type/sysctl_runtime.rb new file mode 100644 index 000000000..f8b0c643a --- /dev/null +++ b/3rdparty/modules/sysctl/lib/puppet/type/sysctl_runtime.rb @@ -0,0 +1,14 @@ +Puppet::Type.newtype(:sysctl_runtime) do + + @doc = "Manages kernel runtime parameters. This type doesn't change any configuration files." + + newparam(:name, :namevar => true) do + desc "Name of the parameter" + isnamevar + end + + newproperty(:val) do + desc "Value the parameter should be set to" + end + +end diff --git a/3rdparty/modules/sysctl/manifests/base.pp b/3rdparty/modules/sysctl/manifests/base.pp new file mode 100644 index 000000000..552acd2ab --- /dev/null +++ b/3rdparty/modules/sysctl/manifests/base.pp @@ -0,0 +1,9 @@ +# common things for sysctl +class sysctl::base { + file { '/etc/sysctl.conf': + ensure => 'present', + owner => 'root', + group => '0', + mode => '0644', + } +} diff --git a/3rdparty/modules/sysctl/manifests/value.pp b/3rdparty/modules/sysctl/manifests/value.pp new file mode 100644 index 000000000..cb57f14f3 --- /dev/null +++ b/3rdparty/modules/sysctl/manifests/value.pp @@ -0,0 +1,28 @@ +# Manage sysctl value +# +# It not only manages the entry within +# /etc/sysctl.conf, but also checks the +# current active version. +# +# Parameters +# +# * value: to set. +# * key Key to set, default: $name +# * target: an alternative target for your sysctl values. +define sysctl::value ( + $value, + $key = $name, + $target = undef, +) { + require sysctl::base + $val1 = inline_template("<%= String(@value).split(/[\s\t]/).reject(&:empty?).flatten.join(\"\t\") %>") + + sysctl { $key : + val => $val1, + target => $target, + before => Sysctl_runtime[$key], + } + sysctl_runtime { $key: + val => $val1, + } +} diff --git a/3rdparty/modules/sysctl/manifests/values.pp b/3rdparty/modules/sysctl/manifests/values.pp new file mode 100644 index 000000000..efc775604 --- /dev/null +++ b/3rdparty/modules/sysctl/manifests/values.pp @@ -0,0 +1,18 @@ +# +# Author: Emilien Macchi +# +# == Class: sysctl::values +# +# Class wrapper to create sysctl values with Hiera. +# +# === Parameters: +# +# [*args*] A sysctl config hash +# Required. +# +# [*defaults*] A config hash +# Optional. Defaults to a empty hash +# +class sysctl::values($args, $defaults = {}) { + create_resources(sysctl::value, $args, $defaults) +} diff --git a/3rdparty/modules/sysctl/metadata.json b/3rdparty/modules/sysctl/metadata.json new file mode 100644 index 000000000..cc482f172 --- /dev/null +++ b/3rdparty/modules/sysctl/metadata.json @@ -0,0 +1,100 @@ +{ + "name": "duritong-sysctl", + "version": "0.0.11", + "author": "duritong", + "summary": "This modules allows you to configure sysctl.", + "license": "GPL-2.0", + "source": "https://github.com/duritong/puppet-sysctl", + "project_page": "https://github.com/duritong/puppet-sysctl", + "issues_url": "https://github.com/duritong/puppet-sysctl/issues", + "dependencies": [ + + ], + "description": "This modules allows you to configure sysctl.", + "operatingsystem_support": [ + { + "operatingsystem": "RedHat", + "operatingsystemrelease": [ + "4", + "5", + "6", + "7" + ] + }, + { + "operatingsystem": "CentOS", + "operatingsystemrelease": [ + "4", + "5", + "6", + "7" + ] + }, + { + "operatingsystem": "OracleLinux", + "operatingsystemrelease": [ + "4", + "5", + "6", + "7" + ] + }, + { + "operatingsystem": "Scientific", + "operatingsystemrelease": [ + "4", + "5", + "6", + "7" + ] + }, + { + "operatingsystem": "SLES", + "operatingsystemrelease": [ + "10 SP4", + "11 SP1", + "12" + ] + }, + { + "operatingsystem": "Debian", + "operatingsystemrelease": [ + "6", + "7", + "8" + ] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": [ + "10.04", + "12.04", + "14.04" + ] + }, + { + "operatingsystem": "Solaris", + "operatingsystemrelease": [ + "10", + "11" + ] + }, + { + "operatingsystem": "FreeBSD", + "operatingsystemrelease": [ + "9", + "10" + ] + }, + { + "operatingsystem": "OpenBSD", + "operatingsystemrelease": [ + "5.3", + "5.4", + "5.5", + "5.6", + "5.7" + ] + } + ] +} diff --git a/3rdparty/modules/sysctl/spec/classes/sysctl_values_spec.rb b/3rdparty/modules/sysctl/spec/classes/sysctl_values_spec.rb new file mode 100644 index 000000000..150e2daa9 --- /dev/null +++ b/3rdparty/modules/sysctl/spec/classes/sysctl_values_spec.rb @@ -0,0 +1,49 @@ +# +# Author: Emilien Macchi +# +require 'spec_helper' + +describe 'sysctl::values' do + + shared_examples_for 'sysctl values' do + let :params do + { + :args => { + 'net.ipv4.ip_forward' => { + 'value' => '1', + }, + 'net.ipv6.conf.all.forwarding' => { + 'value' => '1', + }, + }, + } + end + + it { + is_expected.to contain_sysctl('net.ipv4.ip_forward').with('val' => "1") + is_expected.to contain_sysctl('net.ipv6.conf.all.forwarding').with('val' => "1") + } + end + + describe 'Debian' do + let :facts do + { + :osfamily => 'Debian', + } + end + + it_configures 'sysctl values' + end + + + describe 'RHEL' do + let :facts do + { + :osfamily => 'RedHat', + } + end + + it_configures 'sysctl values' + end + +end diff --git a/3rdparty/modules/sysctl/spec/defines/value_spec.rb b/3rdparty/modules/sysctl/spec/defines/value_spec.rb new file mode 100644 index 000000000..d8be5e277 --- /dev/null +++ b/3rdparty/modules/sysctl/spec/defines/value_spec.rb @@ -0,0 +1,28 @@ +require 'spec_helper' + +describe 'sysctl::value' do + let(:title) { 'rspec_test' } + context 'string value' do + let(:params){ { :value => 'foo bar baz' } } + + it do + should contain_sysctl('rspec_test').with( + :val => "foo\tbar\tbaz", + :before => 'Sysctl_runtime[rspec_test]' + ) + should contain_sysctl_runtime('rspec_test').with_val("foo\tbar\tbaz") + end + end + + context 'fixnum value' do + let(:params){ { :value => 1 } } + it do + should contain_sysctl('rspec_test').with( + :val => "1", + :before => 'Sysctl_runtime[rspec_test]' + ) + should contain_sysctl_runtime('rspec_test').with_val("1") + end + end + +end diff --git a/3rdparty/modules/sysctl/spec/spec_helper.rb b/3rdparty/modules/sysctl/spec/spec_helper.rb new file mode 100644 index 000000000..4267a3c81 --- /dev/null +++ b/3rdparty/modules/sysctl/spec/spec_helper.rb @@ -0,0 +1,10 @@ +require 'rspec-puppet' + +fixture_path = File.expand_path(File.join(__FILE__, '..', 'fixtures')) + +RSpec.configure do |c| + c.module_path = File.join(fixture_path, 'modules') + c.manifest_dir = File.join(fixture_path, 'manifests') + c.environmentpath = File.join(Dir.pwd, 'spec') + c.alias_it_should_behave_like_to(:it_configures, 'configures') +end diff --git a/3rdparty/modules/vswitch/Gemfile b/3rdparty/modules/vswitch/Gemfile new file mode 100644 index 000000000..ce3a2f593 --- /dev/null +++ b/3rdparty/modules/vswitch/Gemfile @@ -0,0 +1,20 @@ +source 'https://rubygems.org' + +group :development, :test do + gem 'puppetlabs_spec_helper', :require => false + gem 'metadata-json-lint' + gem 'puppet-lint', '~> 0.3.2' + gem 'rspec-puppet', '~> 1.0.1' + gem 'rake', '10.1.1' + gem 'rspec', '< 2.99' + gem 'json' + gem 'webmock' +end + +if puppetversion = ENV['PUPPET_GEM_VERSION'] + gem 'puppet', puppetversion, :require => false +else + gem 'puppet', :require => false +end + +# vim:ft=ruby diff --git a/3rdparty/modules/vswitch/LICENSE b/3rdparty/modules/vswitch/LICENSE new file mode 100644 index 000000000..68c771a09 --- /dev/null +++ b/3rdparty/modules/vswitch/LICENSE @@ -0,0 +1,176 @@ + + 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. + diff --git a/3rdparty/modules/vswitch/README.md b/3rdparty/modules/vswitch/README.md new file mode 100644 index 000000000..5bf824f32 --- /dev/null +++ b/3rdparty/modules/vswitch/README.md @@ -0,0 +1,38 @@ +VSwitch +======= + +1.1.0 - 2014.2 - Juno + +A Puppet module providing things for vSwitches. At the moment OVS is the only +one I've added but please feel free to contribute new providers through +Stackforge. It's based upon types and providers so we can support more then just +OVS or one vSwitch type. + +The current layout is: + +* bridges - A "Bridge" is basically the thing you plug ports / interfaces into. +* ports - A Port is a interface you plug into the bridge (switch). + +## USAGE: +To create a new bridge, use the `vs_bridge` type: + +``` +vs_bridge { 'br-ex': + ensure => present, +} +``` + +You can then attach a device to the bridge with a virtual port: +``` +vs_port { 'eth2': + ensure => present, + bridge => 'br-ex', +} +``` + +## TODO: +* OpenFlow controller settings +* OpenFlow Settings +* OpenFlow Tables +* More facts +* Others that are not named here diff --git a/3rdparty/modules/vswitch/Rakefile b/3rdparty/modules/vswitch/Rakefile new file mode 100644 index 000000000..56dc07de3 --- /dev/null +++ b/3rdparty/modules/vswitch/Rakefile @@ -0,0 +1,7 @@ +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' + +PuppetLint.configuration.fail_on_warnings = true +PuppetLint.configuration.send('disable_80chars') +PuppetLint.configuration.send('disable_class_parameter_defaults') +PuppetLint.configuration.send('disable_class_inherits_from_params_class') diff --git a/3rdparty/modules/vswitch/checksums.json b/3rdparty/modules/vswitch/checksums.json new file mode 100644 index 000000000..267db2adb --- /dev/null +++ b/3rdparty/modules/vswitch/checksums.json @@ -0,0 +1,20 @@ +{ + "Gemfile": "d4d7764cdbc3efe027de184f3f0dc215", + "LICENSE": "1dece7821bf3fd70fe1309eaa37d52a2", + "README.md": "23a2e5c93039cc0cc3853db4d5f32d42", + "Rakefile": "e64db1215b97906c4b9d4b4074a581e6", + "lib/puppet/provider/vs_bridge/ovs.rb": "763685a7c8b104d2c49c4383ff049e2d", + "lib/puppet/provider/vs_port/ovs.rb": "f5eee11043a88b97c11fa1494c358d85", + "lib/puppet/provider/vs_port/ovs_redhat.rb": "90daefd00383792a0803b238cd867cca", + "lib/puppet/provider/vs_port/ovs_redhat_el6.rb": "d2eb749b1b8999b15cb1a09f0196703c", + "lib/puppet/type/vs_bridge.rb": "20c831445148365dc964c26a1b6a7bba", + "lib/puppet/type/vs_port.rb": "16fe96502fe7aa6fbb61d54c210043ee", + "lib/puppetx/redhat/ifcfg.rb": "fee5e9c48f51e9a8331cd9f90ce7a3c4", + "manifests/init.pp": "91bb614ff5526fb0628ae2578f5413f1", + "manifests/ovs.pp": "49b76ee45bd50385371f36774ac69b69", + "manifests/params.pp": "db5d7504251b8196cada65ec1b633344", + "metadata.json": "61e5146f2473bdf16deab0977f0ffd76", + "spec/classes/vswitch_ovs_spec.rb": "49f8c0f41f35592c7e83cdb44fe5b4fa", + "spec/spec_helper.rb": "0db89c9a486df193c0e40095422e19dc", + "spec/unit/puppet/lib/type/vs_bridge_spec.rb": "14c0c2b44d97724753efcc32858942ce" +} \ No newline at end of file diff --git a/3rdparty/modules/vswitch/lib/puppet/provider/vs_bridge/ovs.rb b/3rdparty/modules/vswitch/lib/puppet/provider/vs_bridge/ovs.rb new file mode 100644 index 000000000..cd51ba33a --- /dev/null +++ b/3rdparty/modules/vswitch/lib/puppet/provider/vs_bridge/ovs.rb @@ -0,0 +1,43 @@ +require 'puppet' + +Puppet::Type.type(:vs_bridge).provide(:ovs) do + commands :vsctl => 'ovs-vsctl' + commands :ip => 'ip' + + def exists? + vsctl("br-exists", @resource[:name]) + rescue Puppet::ExecutionFailure + return false + end + + def create + vsctl('add-br', @resource[:name]) + ip('link', 'set', @resource[:name], 'up') + external_ids = @resource[:external_ids] if @resource[:external_ids] + end + + def destroy + ip('link', 'set', @resource[:name], 'down') + vsctl('del-br', @resource[:name]) + end + + def _split(string, splitter=',') + return Hash[string.split(splitter).map{|i| i.split('=')}] + end + + def external_ids + result = vsctl('br-get-external-id', @resource[:name]) + return result.split("\n").join(',') + end + + def external_ids=(value) + old_ids = _split(external_ids) + new_ids = _split(value) + + new_ids.each_pair do |k,v| + unless old_ids.has_key?(k) + vsctl('br-set-external-id', @resource[:name], k, v) + end + end + end +end diff --git a/3rdparty/modules/vswitch/lib/puppet/provider/vs_port/ovs.rb b/3rdparty/modules/vswitch/lib/puppet/provider/vs_port/ovs.rb new file mode 100644 index 000000000..483b13bc1 --- /dev/null +++ b/3rdparty/modules/vswitch/lib/puppet/provider/vs_port/ovs.rb @@ -0,0 +1,21 @@ +require 'puppet' + +Puppet::Type.type(:vs_port).provide(:ovs) do + desc 'Openvswitch port manipulation' + + commands :vsctl => 'ovs-vsctl' + + def exists? + vsctl('list-ports', @resource[:bridge]).include? @resource[:interface] + rescue Puppet::ExecutionFailure => e + return false + end + + def create + vsctl('add-port', @resource[:bridge], @resource[:interface]) + end + + def destroy + vsctl('del-port', @resource[:bridge], @resource[:interface]) + end +end diff --git a/3rdparty/modules/vswitch/lib/puppet/provider/vs_port/ovs_redhat.rb b/3rdparty/modules/vswitch/lib/puppet/provider/vs_port/ovs_redhat.rb new file mode 100644 index 000000000..41f644542 --- /dev/null +++ b/3rdparty/modules/vswitch/lib/puppet/provider/vs_port/ovs_redhat.rb @@ -0,0 +1,162 @@ +require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..', 'puppetx', 'redhat', 'ifcfg.rb')) + +BASE = '/etc/sysconfig/network-scripts/ifcfg-' + +# When not seedling from interface file +DEFAULT = { + 'ONBOOT' => 'yes', + 'BOOTPROTO' => 'dhcp', + 'PEERDNS' => 'no', + 'NM_CONTROLLED' => 'no', + 'NOZEROCONF' => 'yes' } + +Puppet::Type.type(:vs_port).provide(:ovs_redhat, :parent => :ovs) do + desc 'Openvswitch port manipulation for RedHat OSes family' + + confine :osfamily => :redhat + defaultfor :osfamily => :redhat + + commands :ip => 'ip' + commands :ifdown => 'ifdown' + commands :ifup => 'ifup' + commands :vsctl => 'ovs-vsctl' + + def create + unless vsctl('list-ports', + @resource[:bridge]).include? @resource[:interface] + super + end + + if interface_physical? + template = DEFAULT + extras = nil + + if link? + extras = dynamic_default if dynamic? + if File.exist?(BASE + @resource[:interface]) + template = cleared(from_str(File.read(BASE + @resource[:interface]))) + end + end + + port = IFCFG::Port.new(@resource[:interface], @resource[:bridge]) + if vlan? + port.set('VLAN' => 'yes') + end + + if bonding? + port.set('BONDING_MASTER' => 'yes') + config = from_str(File.read(BASE + @resource[:interface])) + port.set('BONDING_OPTS' => config['BONDING_OPTS']) if config.has_key?('BONDING_OPTS') + end + + port.save(BASE + @resource[:interface]) + + bridge = IFCFG::Bridge.new(@resource[:bridge], template) + bridge.set(extras) if extras + bridge.save(BASE + @resource[:bridge]) + + ifdown(@resource[:bridge]) + ifdown(@resource[:interface]) + ifup(@resource[:interface]) + ifup(@resource[:bridge]) + end + end + + def exists? + if interface_physical? + super && + IFCFG::OVS.exists?(@resource[:interface]) && + IFCFG::OVS.exists?(@resource[:bridge]) + else + super + end + end + + def destroy + if interface_physical? + ifdown(@resource[:bridge]) + ifdown(@resource[:interface]) + IFCFG::OVS.remove(@resource[:interface]) + IFCFG::OVS.remove(@resource[:bridge]) + end + super + end + + private + + def bonding? + # To do: replace with iproute2 commands + if File.exists?("/proc/net/bonding/#{@resource[:interface]}") + return true + else + return false + end + rescue Errno::ENOENT + return false + end + + def dynamic? + device = '' + device = ip('addr', 'show', @resource[:interface]) + return device =~ /dynamic/ ? true : false + end + + def link? + if File.read("/sys/class/net/#{@resource[:interface]}/operstate") =~ /up/ + return true + else + return false + end + rescue Errno::ENOENT + return false + end + + def dynamic_default + list = { 'OVSDHCPINTERFACES' => @resource[:interface] } + # Persistent MAC address taken from interface + bridge_mac_address = File.read("/sys/class/net/#{@resource[:interface]}/address").chomp + if bridge_mac_address != '' + list.merge!({ 'OVS_EXTRA' => + "\"set bridge #{@resource[:bridge]} other-config:hwaddr=#{bridge_mac_address}\"" }) + end + list + end + + def interface_physical? + # OVS ports don't have entries in /sys/class/net + # Alias interfaces (ethX:Y) must use ethX entries + interface = @resource[:interface].sub(/:\d/, '') + ! Dir["/sys/class/net/#{interface}"].empty? + end + + def from_str(data) + items = {} + data.each_line do |line| + if m = line.match(/^([A-Za-z_]*)=(.*)$/) + items.merge!(m[1] => m[2]) + end + end + items + end + + def cleared(data) + data.each do |key, value| + case key + when /vlan/i + data.delete(key) + when /bonding/i + data.delete(key) + end + end + end + + def vlan? + if File.read('/proc/net/vlan/config') =~ /#{@resource[:interface]}/ + return true + else + return false + end + rescue Errno::ENOENT + return false + end +end diff --git a/3rdparty/modules/vswitch/lib/puppet/provider/vs_port/ovs_redhat_el6.rb b/3rdparty/modules/vswitch/lib/puppet/provider/vs_port/ovs_redhat_el6.rb new file mode 100644 index 000000000..c50a9b9f9 --- /dev/null +++ b/3rdparty/modules/vswitch/lib/puppet/provider/vs_port/ovs_redhat_el6.rb @@ -0,0 +1,17 @@ +Puppet::Type.type(:vs_port).provide(:ovs_redhat_el6, :parent => :ovs_redhat) do + desc 'Openvswitch port manipulation for RedHat OSes family' + + confine :osfamily => :redhat, :operatingsystemmajrelease => 6 + defaultfor :osfamily => :redhat, :operatingsystemmajrelease => 6 + + private + + def dynamic? + # iproute doesn't behave as expected on rhel6 for dynamic interfaces + if File.read(BASE + @resource[:interface]) =~ /^BOOTPROTO=['"]?dhcp['"]?$/ + return true + else + return false + end + end +end diff --git a/3rdparty/modules/vswitch/lib/puppet/type/vs_bridge.rb b/3rdparty/modules/vswitch/lib/puppet/type/vs_bridge.rb new file mode 100644 index 000000000..cbcce902a --- /dev/null +++ b/3rdparty/modules/vswitch/lib/puppet/type/vs_bridge.rb @@ -0,0 +1,30 @@ +require 'puppet' + +Puppet::Type.newtype(:vs_bridge) do + desc 'A Switch - For example "br-int" in OpenStack' + + ensurable + + newparam(:name, :namevar => true) do + desc 'The bridge to configure' + + validate do |value| + if !value.is_a?(String) + raise ArgumentError, "Invalid name #{value}. Requires a String, not a #{value.class}" + end + end + end + + newproperty(:external_ids) do + desc 'External IDs for the bridge: "key1=value2,key2=value2"' + + validate do |value| + if !value.is_a?(String) + raise ArgumentError, "Invalid external_ids #{value}. Requires a String, not a #{value.class}" + end + if value !~ /^(?>[a-zA-Z]\S*=\S*){1}(?>[,][a-zA-Z]\S*=\S*)*$/ + raise ArgumentError, "Invalid external_ids #{value}. Must a list of key1=value2,key2=value2" + end + end + end +end diff --git a/3rdparty/modules/vswitch/lib/puppet/type/vs_port.rb b/3rdparty/modules/vswitch/lib/puppet/type/vs_port.rb new file mode 100644 index 000000000..4527bd994 --- /dev/null +++ b/3rdparty/modules/vswitch/lib/puppet/type/vs_port.rb @@ -0,0 +1,31 @@ +require 'puppet' + +Puppet::Type.newtype(:vs_port) do + desc 'A Virtual Switch Port' + + ensurable + + newparam(:interface, :namevar => true) do + desc 'The interface to attach to the bridge' + + validate do |value| + if !value.is_a?(String) + raise ArgumentError, "Invalid interface #{value}. Requires a String, not a #{value.class}" + end + end + end + + newparam(:bridge) do + desc 'The bridge to attach to' + + validate do |value| + if !value.is_a?(String) + raise ArgumentError, "Invalid bridge #{value}. Requires a String, not a #{value.class}'" + end + end + end + + autorequire(:vs_bridge) do + self[:bridge] if self[:bridge] + end +end diff --git a/3rdparty/modules/vswitch/lib/puppetx/redhat/ifcfg.rb b/3rdparty/modules/vswitch/lib/puppetx/redhat/ifcfg.rb new file mode 100644 index 000000000..262e6e1ea --- /dev/null +++ b/3rdparty/modules/vswitch/lib/puppetx/redhat/ifcfg.rb @@ -0,0 +1,82 @@ +module IFCFG + class OVS + attr_reader :ifcfg + + def self.exists?(name) + File.exist?(BASE + name) + end + + def self.remove(name) + File.delete(BASE + name) + rescue Errno::ENOENT + end + + def initialize(name, seed=nil) + @name = name + @ifcfg = {} + set(seed) + set_key('DEVICE', @name) + set_key('DEVICETYPE', 'ovs') + replace_key('BOOTPROTO', 'OVSBOOTPROTO') if self.class == IFCFG::Bridge + end + + def del_key(key) + @ifcfg.delete(key) + end + + def key?(key) + @ifcfg.has_key?(key) + end + + def key(key) + @ifcfg.has_key?(key) + end + + def replace_key(key, new_key) + value = @ifcfg[key] + @ifcfg.delete(key) + set_key(new_key, value) + end + + def set(list) + if list != nil && list.class == Hash + list.each { |key, value| set_key(key, value) } + end + end + + def set_key(key, value) + @ifcfg.delete_if { |k, v| k == key } if self.key?(key) + @ifcfg.merge!({key => value }) + end + + def to_s + str = '' + @ifcfg.each { |x, y| + str << "#{x}=#{y}\n" + } + str + end + + def save(filename) + File.open(filename, 'w') { |file| file << self.to_s } + end + end + + class Bridge < OVS + def initialize(name, template=nil) + super(name, template) + set_key('TYPE', 'OVSBridge') + del_key('HWADDR') + end + end + + class Port < OVS + def initialize(name, bridge) + super(name) + set_key('TYPE', 'OVSPort') + set_key('OVS_BRIDGE', bridge) + set_key('ONBOOT', 'yes') + set_key('BOOTPROTO', 'none') + end + end +end diff --git a/3rdparty/modules/vswitch/manifests/init.pp b/3rdparty/modules/vswitch/manifests/init.pp new file mode 100644 index 000000000..196e655b8 --- /dev/null +++ b/3rdparty/modules/vswitch/manifests/init.pp @@ -0,0 +1,32 @@ +# == Class: vswitch +# +# Install and configure vswitch (ovs and others) using puppet. +# +# === Parameters +# +# [*provider*] +# Select vswitch to install +# +# === Examples +# +# class { 'vswitch': +# provider => 'ovs', +# } +# +# === Authors +# +# - Endre Karlson +# - Dan Bode +# - Ian Wells +# - Gilles Dubreuil +# +# === Copyright +# +# Apache License 2.0 (see LICENSE file) +# +class vswitch ( + $provider = $vswitch::params::provider +) { + $cls = "vswitch::${provider}" + include $cls +} diff --git a/3rdparty/modules/vswitch/manifests/ovs.pp b/3rdparty/modules/vswitch/manifests/ovs.pp new file mode 100644 index 000000000..9ce892ccf --- /dev/null +++ b/3rdparty/modules/vswitch/manifests/ovs.pp @@ -0,0 +1,59 @@ +# vswitch: open-vswitch +# +class vswitch::ovs( + $package_ensure = 'present' +) { + + include 'vswitch::params' + + case $::osfamily { + 'Debian': { + # OVS doesn't build unless the kernel headers are present. + $kernelheaders_pkg = "linux-headers-${::kernelrelease}" + if ! defined(Package[$kernelheaders_pkg]) { + package { $kernelheaders_pkg: ensure => $package_ensure } + } + case $::operatingsystem { + 'ubuntu': { + $ovs_status = '/sbin/status openvswitch-switch | fgrep "start/running"' + } + default: { + $ovs_status = '/etc/init.d/openvswitch-switch status | fgrep "is running"' + } + } + service {'openvswitch': + ensure => true, + enable => true, + name => $::vswitch::params::ovs_service_name, + hasstatus => false, # the supplied command returns true even if it's not running + # Not perfect - should spot if either service is not running - but it'll do + status => $ovs_status + } + exec { 'rebuild-ovsmod': + command => '/usr/sbin/dpkg-reconfigure openvswitch-datapath-dkms > /tmp/reconf-log', + creates => "/lib/modules/${::kernelrelease}/updates/dkms/openvswitch_mod.ko", + require => [Package['openvswitch-datapath-dkms', $kernelheaders_pkg]], + before => Package['openvswitch-switch'], + refreshonly => true + } + } + 'Redhat': { + service {'openvswitch': + ensure => true, + enable => true, + name => $::vswitch::params::ovs_service_name, + } + } + default: { + fail( "${::osfamily} not yet supported by puppet-vswitch") + } + } + + package { $::vswitch::params::ovs_package_name: + ensure => $package_ensure, + before => Service['openvswitch'], + } + + Service['openvswitch'] -> Vs_port<||> + Service['openvswitch'] -> Vs_bridge<||> +} diff --git a/3rdparty/modules/vswitch/manifests/params.pp b/3rdparty/modules/vswitch/manifests/params.pp new file mode 100644 index 000000000..71f116978 --- /dev/null +++ b/3rdparty/modules/vswitch/manifests/params.pp @@ -0,0 +1,19 @@ +# vswitch params +# +class vswitch::params { + case $::osfamily { + 'Redhat': { + $ovs_package_name = 'openvswitch' + $ovs_service_name = 'openvswitch' + $provider = 'ovs_redhat' + } + 'Debian': { + $ovs_package_name = ['openvswitch-switch', 'openvswitch-datapath-dkms'] + $ovs_service_name = 'openvswitch-switch' + $provider = 'ovs' + } + default: { + fail " Osfamily ${::osfamily} not supported yet" + } + } # Case $::osfamily +} diff --git a/3rdparty/modules/vswitch/metadata.json b/3rdparty/modules/vswitch/metadata.json new file mode 100644 index 000000000..ef6999181 --- /dev/null +++ b/3rdparty/modules/vswitch/metadata.json @@ -0,0 +1,59 @@ +{ + "name": "stackforge-vswitch", + "version": "1.1.0", + "author": "Endre Karlson, Dan Bode and StackForge Contributors", + "summary": "A module for providing things (ports, bridges) to vSwitches (OVS)", + "license": "Apache-2.0", + "source": "git://github.com/openstack/puppet-vswitch.git", + "project_page": "https://launchpad.net/puppet-vswitch", + "issues_url": "https://bugs.launchpad.net/puppet-vswitch", + "dependencies": [ + + ], + "operatingsystem_support": [ + { + "operatingsystem": "Fedora", + "operatingsystemrelease": [ + "20" + ] + }, + { + "operatingsystem": "RedHat", + "operatingsystemrelease": [ + "6", + "7" + ] + }, + { + "operatingsystem": "CentOS", + "operatingsystemrelease": [ + "6", + "7" + ] + }, + { + "operatingsystem": "Debian", + "operatingsystemrelease": [ + "6", + "7" + ] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": [ + "12.04", + "14.04" + ] + } + ], + "requirements": [ + { + "name": "pe", + "version_requirement": "3.x" + }, + { + "name": "puppet", + "version_requirement": "3.x" + } + ] +} diff --git a/3rdparty/modules/vswitch/spec/classes/vswitch_ovs_spec.rb b/3rdparty/modules/vswitch/spec/classes/vswitch_ovs_spec.rb new file mode 100644 index 000000000..de7e14651 --- /dev/null +++ b/3rdparty/modules/vswitch/spec/classes/vswitch_ovs_spec.rb @@ -0,0 +1,27 @@ +require 'spec_helper' + +describe 'vswitch::ovs' do + + context 'on redhat with default parameters' do + + let :facts do + {:osfamily => 'Redhat'} + end + + it 'should contain the correct package and service' do + + should contain_service('openvswitch').with( + :ensure => true, + :enable => true, + :name => 'openvswitch' + ) + + should contain_package('openvswitch').with( + :name => 'openvswitch', + :ensure => 'present', + :before => 'Service[openvswitch]' + ) + + end + end +end diff --git a/3rdparty/modules/vswitch/spec/spec_helper.rb b/3rdparty/modules/vswitch/spec/spec_helper.rb new file mode 100644 index 000000000..2c6f56649 --- /dev/null +++ b/3rdparty/modules/vswitch/spec/spec_helper.rb @@ -0,0 +1 @@ +require 'puppetlabs_spec_helper/module_spec_helper' diff --git a/3rdparty/modules/vswitch/spec/unit/puppet/lib/type/vs_bridge_spec.rb b/3rdparty/modules/vswitch/spec/unit/puppet/lib/type/vs_bridge_spec.rb new file mode 100644 index 000000000..4b88b317f --- /dev/null +++ b/3rdparty/modules/vswitch/spec/unit/puppet/lib/type/vs_bridge_spec.rb @@ -0,0 +1,11 @@ +require 'spec_helper' + +describe Puppet::Type.type(:vs_bridge) do + + it "should support present as a value for ensure" do + expect do + described_class.new(:name => 'foo', :ensure => :present, :external_ids => 'foo=br-ex,blah-id=bar)') + end.to_not raise_error + end + +end