From 24ed319d05e6d33a29a761f626a833222700f60d Mon Sep 17 00:00:00 2001 From: mgrosz Date: Wed, 9 Dec 2015 19:39:41 +0200 Subject: [PATCH] puppet-vitrage: Initial commit This is the initial commit for puppet-vitrage. It has been automatically generated using cookiecutter[1] and msync[2] [1] https://github.com/openstack/puppet-openstack-cookiecutter [2] https://github.com/openstack/puppet-modulesync-configs Change-Id: Ieb46f034ed35fb5e3c187f78f730139b469d9cf4 --- .gitignore | 11 ++ Gemfile | 37 +++++ LICENSE | 13 ++ README.md | 81 ++++++++++ Rakefile | 85 +++++++++++ .../provider/vitrage_config/ini_setting.rb | 10 ++ lib/puppet/type/vitrage_config.rb | 53 +++++++ manifests/config.pp | 30 ++++ manifests/db.pp | 93 +++++++++++ manifests/db/mysql.pp | 69 +++++++++ manifests/db/postgresql.pp | 47 ++++++ manifests/db/sync.pp | 23 +++ manifests/init.pp | 11 ++ manifests/keystone/auth.pp | 91 +++++++++++ manifests/logging.pp | 140 +++++++++++++++++ manifests/params.pp | 17 +++ manifests/policy.pp | 39 +++++ metadata.json | 34 +++++ spec/acceptance/nodesets/centos-70-x64.yml | 11 ++ spec/acceptance/nodesets/default.yml | 10 ++ spec/acceptance/nodesets/nodepool-centos7.yml | 10 ++ spec/acceptance/nodesets/nodepool-trusty.yml | 10 ++ .../nodesets/ubuntu-server-1404-x64.yml | 11 ++ spec/classes/vitrage_db_mysql_spec.rb | 93 +++++++++++ spec/classes/vitrage_db_postgresql_spec.rb | 58 +++++++ spec/classes/vitrage_db_spec.rb | 82 ++++++++++ spec/classes/vitrage_keystone_auth_spec.rb | 123 +++++++++++++++ spec/classes/vitrage_logging_spec.rb | 144 ++++++++++++++++++ spec/classes/vitrage_policy_spec.rb | 41 +++++ spec/shared_examples.rb | 5 + spec/spec_helper.rb | 13 ++ spec/spec_helper_acceptance.rb | 56 +++++++ .../vitrage_config/ini_setting_spec.rb | 68 +++++++++ spec/unit/type/vitrage_config_spec.rb | 64 ++++++++ tests/init.pp | 12 ++ 35 files changed, 1695 insertions(+) create mode 100644 .gitignore create mode 100644 Gemfile create mode 100644 LICENSE create mode 100644 README.md create mode 100644 Rakefile create mode 100644 lib/puppet/provider/vitrage_config/ini_setting.rb create mode 100644 lib/puppet/type/vitrage_config.rb create mode 100644 manifests/config.pp create mode 100644 manifests/db.pp create mode 100644 manifests/db/mysql.pp create mode 100644 manifests/db/postgresql.pp create mode 100644 manifests/db/sync.pp create mode 100644 manifests/init.pp create mode 100644 manifests/keystone/auth.pp create mode 100644 manifests/logging.pp create mode 100644 manifests/params.pp create mode 100644 manifests/policy.pp create mode 100644 metadata.json create mode 100644 spec/acceptance/nodesets/centos-70-x64.yml create mode 100644 spec/acceptance/nodesets/default.yml create mode 100644 spec/acceptance/nodesets/nodepool-centos7.yml create mode 100644 spec/acceptance/nodesets/nodepool-trusty.yml create mode 100644 spec/acceptance/nodesets/ubuntu-server-1404-x64.yml create mode 100644 spec/classes/vitrage_db_mysql_spec.rb create mode 100644 spec/classes/vitrage_db_postgresql_spec.rb create mode 100644 spec/classes/vitrage_db_spec.rb create mode 100644 spec/classes/vitrage_keystone_auth_spec.rb create mode 100644 spec/classes/vitrage_logging_spec.rb create mode 100644 spec/classes/vitrage_policy_spec.rb create mode 100644 spec/shared_examples.rb create mode 100644 spec/spec_helper.rb create mode 100644 spec/spec_helper_acceptance.rb create mode 100644 spec/unit/provider/vitrage_config/ini_setting_spec.rb create mode 100644 spec/unit/type/vitrage_config_spec.rb create mode 100644 tests/init.pp diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..15c55ef --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +pkg/ +Gemfile.lock +vendor/ +spec/fixtures/ +.vagrant/ +.bundle/ +coverage/ +.idea/ +*.swp +*.iml +openstack/ diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..fc22143 --- /dev/null +++ b/Gemfile @@ -0,0 +1,37 @@ +source ENV['GEM_SOURCE'] || "https://rubygems.org" + +group :development, :test do + gem 'puppetlabs_spec_helper', :require => 'false' + gem 'rspec-puppet', '~> 2.2.0', :require => 'false' + gem 'metadata-json-lint', :require => 'false' + gem 'puppet-lint-param-docs', :require => 'false' + gem 'puppet-lint-absolute_classname-check', :require => 'false' + gem 'puppet-lint-absolute_template_path', :require => 'false' + gem 'puppet-lint-trailing_newline-check', :require => 'false' + gem 'puppet-lint-unquoted_string-check', :require => 'false' + gem 'puppet-lint-leading_zero-check', :require => 'false' + gem 'puppet-lint-variable_contains_upcase', :require => 'false' + gem 'puppet-lint-numericvariable', :require => 'false' + gem 'json', :require => 'false' + gem 'webmock', :require => 'false' +end + +group :system_tests do + gem 'beaker-rspec', :require => 'false' + gem 'beaker-puppet_install_helper', :require => 'false' + gem 'r10k', :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/LICENSE b/LICENSE new file mode 100644 index 0000000..8c06f5e --- /dev/null +++ b/LICENSE @@ -0,0 +1,13 @@ +Copyright 2015 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. diff --git a/README.md b/README.md new file mode 100644 index 0000000..1578dce --- /dev/null +++ b/README.md @@ -0,0 +1,81 @@ +vitrage +======= + +#### Table of Contents + +1. [Overview - What is the vitrage module?](#overview) +2. [Module Description - What does the module do?](#module-description) +3. [Setup - The basics of getting started with vitrage](#setup) +4. [Implementation - An under-the-hood peek at what the module is doing](#implementation) +5. [Limitations - OS compatibility, etc.](#limitations) +6. [Development - Guide for contributing to the module](#development) +7. [Contributors - Those with commits](#contributors) + +Overview +-------- + +Vitrage module is an engine for organizing, analyzing and expanding OpenStack alarms & events, yielding insights regarding the Root Cause of problems and deducing the existence of problems before they are directly detected. + +Module Description +------------------ + +The vitrage puppet module is a thorough attempt to make Puppet capable of managing the entirety of vitrage. + +Setup +----- + +**What the vitrage module affects** + +* [Vitrage](https://wiki.openstack.org/wiki/Vitrage), the Root Cause Analysis engine for organizing, analyzing and expanding OpenStack alarms & events for Openstack. + +### Installing vitrage + + vitrage is not currently in Puppet Forge, but is anticipated to be added soon. Once that happens, you'll be able to install vitrage with: + puppet module install openstack/vitrage + +### Beginning with vitrage + +To utilize the vitrage 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. + +Implementation +-------------- + +### vitrage + +vitrage is a combination of Puppet manifest and ruby code to delivery configuration and extra functionality through types and providers. + +Limitations +------------ + +* None. + +Beaker-Rspec +------------ + +This module has beaker-rspec tests + +To run the tests on the default vagrant node: + +```shell +bundle install +bundle exec rake acceptance +``` + +Development +----------- + +Developer documentation for the entire puppet-openstack project. + +* https://wiki.openstack.org/wiki/Puppet-openstack#Developer_documentation + +Contributors +------------ + +* The github [contributor graph] (https://github.com/openstack/puppet-vitrage/graphs/contributors) + +Release Notes +------------- + +**0.0.1** + +* Initial \ No newline at end of file diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..ed79bea --- /dev/null +++ b/Rakefile @@ -0,0 +1,85 @@ +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' +require 'puppet-syntax/tasks/puppet-syntax' +require 'json' + +modname = JSON.parse(open('metadata.json').read)['name'].split('-')[1] + +PuppetSyntax.exclude_paths ||= [] +PuppetSyntax.exclude_paths << "spec/fixtures/**/*" +PuppetSyntax.exclude_paths << "pkg/**/*" +PuppetSyntax.exclude_paths << "vendor/**/*" + +Rake::Task[:lint].clear +PuppetLint::RakeTask.new :lint do |config| + config.ignore_paths = ["spec/**/*.pp", "vendor/**/*.pp"] + config.fail_on_warnings = true + config.log_format = '%{path}:%{linenumber}:%{KIND}: %{message}' + config.disable_checks = ["80chars", "class_inherits_from_params_class", "only_variable_string"] +end + +desc "Run acceptance tests" +RSpec::Core::RakeTask.new(:acceptance) do |t| + t.pattern = 'spec/acceptance' +end + +Rake::Task[:spec_prep].clear +desc 'Create the fixtures directory' +task :spec_prep do + # Allow to test the module with custom dependencies + # like you could do with .fixtures file + if ENV['PUPPETFILE'] + puppetfile = ENV['PUPPETFILE'] + if ENV['GEM_HOME'] + gem_home = ENV['GEM_HOME'] + gem_bin_dir = "#{gem_home}" + '/bin/' + else + gem_bin_dir = '' + end + r10k = ['env'] + r10k += ["PUPPETFILE=#{puppetfile}"] + r10k += ["PUPPETFILE_DIR=#{Dir.pwd}/spec/fixtures/modules"] + r10k += ["#{gem_bin_dir}r10k"] + r10k += ['puppetfile', 'install', '-v'] + sh(*r10k) + else + # otherwise, use official OpenStack Puppetfile + zuul_ref = ENV['ZUUL_REF'] + zuul_branch = ENV['ZUUL_BRANCH'] + zuul_url = ENV['ZUUL_URL'] + repo = 'openstack/puppet-openstack-integration' + rm_rf(repo) + if File.exists?('/usr/zuul-env/bin/zuul-cloner') + zuul_clone_cmd = ['/usr/zuul-env/bin/zuul-cloner'] + zuul_clone_cmd += ['--cache-dir', '/opt/git'] + zuul_clone_cmd += ['--zuul-ref', "#{zuul_ref}"] + zuul_clone_cmd += ['--zuul-branch', "#{zuul_branch}"] + zuul_clone_cmd += ['--zuul-url', "#{zuul_url}"] + zuul_clone_cmd += ['git://git.openstack.org', "#{repo}"] + sh(*zuul_clone_cmd) + else + sh("git clone https://git.openstack.org/#{repo} #{repo}") + end + script = ['env'] + script += ["PUPPETFILE_DIR=#{Dir.pwd}/spec/fixtures/modules"] + script += ["ZUUL_REF=#{zuul_ref}"] + script += ["ZUUL_BRANCH=#{zuul_branch}"] + script += ["ZUUL_URL=#{zuul_url}"] + script += ['bash', "#{repo}/install_modules_unit.sh"] + sh(*script) + end + rm_rf("spec/fixtures/modules/#{modname}") + ln_s(Dir.pwd, "spec/fixtures/modules/#{modname}") + mkdir_p('spec/fixtures/manifests') + touch('spec/fixtures/manifests/site.pp') +end + +Rake::Task[:spec_clean].clear +desc 'Clean up the fixtures directory' +task :spec_clean do + rm_rf('spec/fixtures/modules') + rm_rf('openstack') + if File.zero?('spec/fixtures/manifests/site.pp') + rm_f('spec/fixtures/manifests/site.pp') + end +end diff --git a/lib/puppet/provider/vitrage_config/ini_setting.rb b/lib/puppet/provider/vitrage_config/ini_setting.rb new file mode 100644 index 0000000..3c4b00c --- /dev/null +++ b/lib/puppet/provider/vitrage_config/ini_setting.rb @@ -0,0 +1,10 @@ +Puppet::Type.type(:vitrage_config).provide( + :ini_setting, + :parent => Puppet::Type.type(:openstack_config).provider(:ini_setting) +) do + + def self.file_path + '/etc/vitrage/vitrage.conf' + end + +end diff --git a/lib/puppet/type/vitrage_config.rb b/lib/puppet/type/vitrage_config.rb new file mode 100644 index 0000000..dec3c05 --- /dev/null +++ b/lib/puppet/type/vitrage_config.rb @@ -0,0 +1,53 @@ +Puppet::Type.newtype(:vitrage_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from vitrage.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 + + newparam(:ensure_absent_val) do + desc 'A value that is specified as the value property will behave as if ensure => absent was specified' + defaultto('') + end + + autorequire(:package) do + 'vitrage' + end + +end diff --git a/manifests/config.pp b/manifests/config.pp new file mode 100644 index 0000000..69f864b --- /dev/null +++ b/manifests/config.pp @@ -0,0 +1,30 @@ +# == Class: vitrage::config +# +# This class is used to manage arbitrary vitrage configurations. +# +# === Parameters +# +# [*vitrage_config*] +# (optional) Allow configuration of arbitrary vitrage configurations. +# The value is an hash of vitrage_config resources. Example: +# { 'DEFAULT/foo' => { value => 'fooValue'}, +# 'DEFAULT/bar' => { value => 'barValue'} +# } +# In yaml format, Example: +# vitrage_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 vitrage::config ( + $vitrage_config = {}, +) { + + validate_hash($vitrage_config) + + create_resources('vitrage_config', $vitrage_config) +} diff --git a/manifests/db.pp b/manifests/db.pp new file mode 100644 index 0000000..328a668 --- /dev/null +++ b/manifests/db.pp @@ -0,0 +1,93 @@ +# == Class: vitrage::db +# +# Configure the vitrage database +# +# === Parameters +# +# [*database_connection*] +# Url used to connect to database. +# (Optional) Defaults to "mysql://vitrage:secrete@localhost:3306/vitrage". +# +# [*database_max_retries*] +# (Optional) Maximum number of database connection retries during startup. +# Set to -1 to specify an infinite retry count. +# Defaults to $::os_service_default. +# +# [*database_idle_timeout*] +# (Optional) Timeout before idle SQL connections are reaped. +# Defaults to $::os_service_default. +# +# [*database_retry_interval*] +# (optional) Interval between retries of opening a database connection. +# Defaults to $::os_service_default. +# +# [*database_min_pool_size*] +# (optional) Minimum number of SQL connections to keep open in a pool. +# Defaults to $::os_service_default. +# +# [*database_max_pool_size*] +# (optional) Maximum number of SQL connections to keep open in a pool. +# Defaults to $::os_service_default. +# +# [*database_max_overflow*] +# (optional) If set, use this value for max_overflow with sqlalchemy. +# Defaults to $::os_service_default. +# +class vitrage::db ( + $database_connection = 'mysql://vitrage:secrete@localhost:3306/vitrage', + $database_idle_timeout = $::os_service_default, + $database_min_pool_size = $::os_service_default, + $database_max_pool_size = $::os_service_default, + $database_max_retries = $::os_service_default, + $database_retry_interval = $::os_service_default, + $database_max_overflow = $::os_service_default, +) { + + $database_connection_real = pick($::vitrage::database_connection, $database_connection) + $database_idle_timeout_real = pick($::vitrage::database_idle_timeout, $database_idle_timeout) + $database_min_pool_size_real = pick($::vitrage::database_min_pool_size, $database_min_pool_size) + $database_max_pool_size_real = pick($::vitrage::database_max_pool_size, $database_max_pool_size) + $database_max_retries_real = pick($::vitrage::database_max_retries, $database_max_retries) + $database_retry_interval_real = pick($::vitrage::database_retry_interval, $database_retry_interval) + $database_max_overflow_real = pick($::vitrage::database_max_overflow, $database_max_overflow) + + validate_re($database_connection_real, + '(sqlite|mysql|postgresql):\/\/(\S+:\S+@\S+\/\S+)?') + + case $database_connection_real { + /^mysql:\/\//: { + $backend_package = false + require 'mysql::bindings' + require 'mysql::bindings::python' + } + /^postgresql:\/\//: { + $backend_package = false + require 'postgresql::lib::python' + } + /^sqlite:\/\//: { + $backend_package = $::vitrage::params::sqlite_package_name + } + default: { + fail('Unsupported backend configured') + } + } + + if $backend_package and !defined(Package[$backend_package]) { + package {'vitrage-backend-package': + ensure => present, + name => $backend_package, + tag => 'openstack', + } + } + + vitrage_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_real; + 'database/max_retries': value => $database_max_retries_real; + 'database/retry_interval': value => $database_retry_interval_real; + 'database/max_pool_size': value => $database_max_pool_size_real; + 'database/max_overflow': value => $database_max_overflow_real; + } + +} diff --git a/manifests/db/mysql.pp b/manifests/db/mysql.pp new file mode 100644 index 0000000..caf5d52 --- /dev/null +++ b/manifests/db/mysql.pp @@ -0,0 +1,69 @@ +# The vitrage::db::mysql class implements mysql backend for vitrage +# +# This class can be used to create tables, users and grant +# privelege for a mysql vitrage database. +# +# == parameters +# +# [*password*] +# (Mandatory) Password to connect to the database. +# Defaults to 'false'. +# +# [*dbname*] +# (Optional) Name of the database. +# Defaults to 'vitrage'. +# +# [*user*] +# (Optional) User to connect to the database. +# Defaults to 'vitrage'. +# +# [*host*] +# (Optional) The default source host user is allowed to connect from. +# Defaults to '127.0.0.1' +# +# [*allowed_hosts*] +# (Optional) Other hosts the user is allowed to connect from. +# Defaults to 'undef'. +# +# [*charset*] +# (Optional) The database charset. +# Defaults to 'utf8' +# +# [*collate*] +# (Optional) The database collate. +# Only used with mysql modules >= 2.2. +# Defaults to 'utf8_general_ci' +# +# == Dependencies +# Class['mysql::server'] +# +# == Examples +# +# == Authors +# +# == Copyright +# +class vitrage::db::mysql( + $password, + $dbname = 'vitrage', + $user = 'vitrage', + $host = '127.0.0.1', + $charset = 'utf8', + $collate = 'utf8_general_ci', + $allowed_hosts = undef +) { + + validate_string($password) + + ::openstacklib::db::mysql { 'vitrage': + user => $user, + password_hash => mysql_password($password), + dbname => $dbname, + host => $host, + charset => $charset, + collate => $collate, + allowed_hosts => $allowed_hosts, + } + + ::Openstacklib::Db::Mysql['vitrage'] ~> Exec<| title == 'vitrage-manage db_sync' |> +} diff --git a/manifests/db/postgresql.pp b/manifests/db/postgresql.pp new file mode 100644 index 0000000..ce67236 --- /dev/null +++ b/manifests/db/postgresql.pp @@ -0,0 +1,47 @@ +# == Class: vitrage::db::postgresql +# +# Class that configures postgresql for vitrage +# Requires the Puppetlabs postgresql module. +# +# === Parameters +# +# [*password*] +# (Required) Password to connect to the database. +# +# [*dbname*] +# (Optional) Name of the database. +# Defaults to 'vitrage'. +# +# [*user*] +# (Optional) User to connect to the database. +# Defaults to 'vitrage'. +# +# [*encoding*] +# (Optional) The charset to use for the database. +# Default to undef. +# +# [*privileges*] +# (Optional) Privileges given to the database user. +# Default to 'ALL' +# +class vitrage::db::postgresql( + $password, + $dbname = 'vitrage', + $user = 'vitrage', + $encoding = undef, + $privileges = 'ALL', +) { + + Class['vitrage::db::postgresql'] -> Service<| title == 'vitrage' |> + + ::openstacklib::db::postgresql { 'vitrage': + password_hash => postgresql_password($user, $password), + dbname => $dbname, + user => $user, + encoding => $encoding, + privileges => $privileges, + } + + ::Openstacklib::Db::Postgresql['vitrage'] ~> Exec<| title == 'vitrage-manage db_sync' |> + +} diff --git a/manifests/db/sync.pp b/manifests/db/sync.pp new file mode 100644 index 0000000..24185b3 --- /dev/null +++ b/manifests/db/sync.pp @@ -0,0 +1,23 @@ +# +# Class to execute vitrage-manage db_sync +# +# == Parameters +# +# [*extra_params*] +# (optional) String of extra command line parameters to append +# to the vitrage-dbsync command. +# Defaults to undef +# +class vitrage::db::sync( + $extra_params = undef, +) { + exec { 'vitrage-db-sync': + command => "vitrage-manage db_sync ${extra_params}", + path => '/usr/bin', + user => 'vitrage', + refreshonly => true, + subscribe => [Package['vitrage'], Vitrage_config['database/connection']], + } + + Exec['vitrage-manage db_sync'] ~> Service<| title == 'vitrage' |> +} diff --git a/manifests/init.pp b/manifests/init.pp new file mode 100644 index 0000000..8105b95 --- /dev/null +++ b/manifests/init.pp @@ -0,0 +1,11 @@ +# == Class: vitrage +# +# Full description of class vitrage here. +# +# === Parameters +# +class vitrage { + + include ::vitrage::params + +} diff --git a/manifests/keystone/auth.pp b/manifests/keystone/auth.pp new file mode 100644 index 0000000..0017e07 --- /dev/null +++ b/manifests/keystone/auth.pp @@ -0,0 +1,91 @@ +# == Class: vitrage::keystone::auth +# +# Configures vitrage user, service and endpoint in Keystone. +# +# === Parameters +# +# [*password*] +# (required) Password for vitrage user. +# +# [*auth_name*] +# Username for vitrage service. Defaults to 'vitrage'. +# +# [*email*] +# Email for vitrage user. Defaults to 'vitrage@localhost'. +# +# [*tenant*] +# Tenant for vitrage user. Defaults to 'services'. +# +# [*configure_endpoint*] +# Should vitrage endpoint be configured? Defaults to 'true'. +# +# [*configure_user*] +# (Optional) Should the service user be configured? +# Defaults to 'true'. +# +# [*configure_user_role*] +# (Optional) Should the admin role be configured for the service user? +# Defaults to 'true'. +# +# [*service_type*] +# Type of service. Defaults to 'root_cause_analysis_engine'. +# +# [*region*] +# Region for endpoint. Defaults to 'RegionOne'. +# +# [*service_name*] +# (optional) Name of the service. +# Defaults to the value of auth_name. +# +# [*public_url*] +# (optional) The endpoint's public url. (Defaults to 'http://127.0.0.1:8999/v1') +# This url should *not* contain any trailing '/'. +# +# [*admin_url*] +# (optional) The endpoint's admin url. (Defaults to 'http://127.0.0.1:8999/v1') +# This url should *not* contain any trailing '/'. +# +# [*internal_url*] +# (optional) The endpoint's internal url. (Defaults to 'http://127.0.0.1:8999/v1') +# +class vitrage::keystone::auth ( + $password, + $auth_name = 'vitrage', + $email = 'vitrage@localhost', + $tenant = 'services', + $configure_endpoint = true, + $configure_user = true, + $configure_user_role = true, + $service_name = undef, + $service_type = 'root_cause_analysis_engine', + $region = 'RegionOne', + $public_url = 'http://127.0.0.1:8999/v1', + $admin_url = 'http://127.0.0.1:8999/v1', + $internal_url = 'http://127.0.0.1:8999/v1', +) { + + $real_service_name = pick($service_name, $auth_name) + + if $configure_user_role { + Keystone_user_role["${auth_name}@${tenant}"] ~> Service <| name == 'vitrage-server' |> + } + Keystone_endpoint["${region}/${real_service_name}"] ~> Service <| name == 'vitrage-server' |> + + keystone::resource::service_identity { 'vitrage': + configure_user => $configure_user, + configure_user_role => $configure_user_role, + configure_endpoint => $configure_endpoint, + service_name => $real_service_name, + service_type => $service_type, + service_description => 'vitrage Root Cause Analysis engine Service', + region => $region, + auth_name => $auth_name, + password => $password, + email => $email, + tenant => $tenant, + public_url => $public_url, + internal_url => $internal_url, + admin_url => $admin_url, + } + +} diff --git a/manifests/logging.pp b/manifests/logging.pp new file mode 100644 index 0000000..83fe89b --- /dev/null +++ b/manifests/logging.pp @@ -0,0 +1,140 @@ +# Class vitrage::logging +# +# vitrage logging configuration +# +# === Parameters +# +# [*verbose*] +# (Optional) Should the daemons log verbose messages +# Defaults to $::os_service_default. +# +# [*debug*] +# (Optional) Should the daemons log debug messages +# Defaults to $::os_service_default. +# +# [*use_syslog*] +# Use syslog for logging. +# (Optional) Defaults to $::os_service_default. +# +# [*use_stderr*] +# (optional) Use stderr for logging +# Defaults to $::os_service_default +# +# [*log_facility*] +# Syslog facility to receive log lines. +# (Optional) Defaults to $::os_service_default. +# +# [*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/vitrage' +# +# [*logging_context_format_string*] +# (optional) Format string to use for log messages with context. +# Defaults to $::os_service_default. +# 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 $::os_service_default. +# 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 $::os_service_default. +# Example: '%(funcName)s %(pathname)s:%(lineno)d' +# +# [*logging_exception_prefix*] +# (optional) Prefix each line of exception output with this format. +# Defaults to $::os_service_default. +# 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 $::os_service_default. +# See https://docs.python.org/2/howto/logging.html +# +# [*default_log_levels*] +# (optional) Hash of logger (keys) and level (values) pairs. +# Defaults to $::os_service_default. +# 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 $::os_service_default (false if unconfigured). +# +# [*fatal_deprecations*] +# (optional) Make deprecations fatal (boolean value) +# Defaults to $::os_service_default (false if unconfigured). +# +# [*instance_format*] +# (optional) If an instance is passed with the log message, format it +# like this (string value). +# Defaults to $::os_service_default. +# 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 $::os_service_default. +# Example: instance_uuid_format='[instance: %(uuid)s] ' + +# [*log_date_format*] +# (optional) Format string for %%(asctime)s in log records. +# Defaults to $::os_service_default. +# Example: 'Y-%m-%d %H:%M:%S' +# + +class vitrage::logging( + $use_syslog = $::os_service_default, + $use_stderr = $::os_service_default, + $log_facility = $::os_service_default, + $log_dir = '/var/log/vitrage', + $verbose = $::os_service_default, + $debug = $::os_service_default, + $logging_context_format_string = $::os_service_default, + $logging_default_format_string = $::os_service_default, + $logging_debug_format_suffix = $::os_service_default, + $logging_exception_prefix = $::os_service_default, + $log_config_append = $::os_service_default, + $default_log_levels = $::os_service_default, + $publish_errors = $::os_service_default, + $fatal_deprecations = $::os_service_default, + $instance_format = $::os_service_default, + $instance_uuid_format = $::os_service_default, + $log_date_format = $::os_service_default, +) { + + if is_service_default($default_log_levels) { + $default_log_levels_real = $default_log_levels + } else { + $default_log_levels_real = join(sort(join_keys_to_values($default_log_levels, '=')), ',') + } + + vitrage_config { + 'DEFAULT/use_syslog': value => $use_syslog; + 'DEFAULT/use_stderr': value => $use_stderr; + 'DEFAULT/log_dir': value => $log_dir; + 'DEFAULT/verbose': value => $verbose; + 'DEFAULT/debug': value => $debug; + 'DEFAULT/syslog_log_facility': value => $log_facility; + 'DEFAULT/logging_context_format_string': value => $logging_context_format_string; + 'DEFAULT/logging_default_format_string': value => $logging_default_format_string; + 'DEFAULT/logging_debug_format_suffix': value => $logging_debug_format_suffix; + 'DEFAULT/logging_exception_prefix': value => $logging_exception_prefix; + 'DEFAULT/log_config_append': value => $log_config_append; + 'DEFAULT/default_log_levels': value => $default_log_levels_real; + 'DEFAULT/publish_errors': value => $publish_errors; + 'DEFAULT/fatal_deprecations': value => $fatal_deprecations; + 'DEFAULT/instance_format': value => $instance_format; + 'DEFAULT/instance_uuid_format': value => $instance_uuid_format; + 'DEFAULT/log_date_format': value => $log_date_format; + } + +} diff --git a/manifests/params.pp b/manifests/params.pp new file mode 100644 index 0000000..c092897 --- /dev/null +++ b/manifests/params.pp @@ -0,0 +1,17 @@ +# Parameters for puppet-vitrage +# +class vitrage::params { + + case $::osfamily { + 'RedHat': { + $sqlite_package_name = undef + } + 'Debian': { + $sqlite_package_name = 'python-pysqlite2' + } + default: { + fail("Unsupported osfamily: ${::osfamily} operatingsystem") + } + + } # Case $::osfamily +} diff --git a/manifests/policy.pp b/manifests/policy.pp new file mode 100644 index 0000000..f7a0bdf --- /dev/null +++ b/manifests/policy.pp @@ -0,0 +1,39 @@ +# == Class: vitrage::policy +# +# Configure the vitrage policies +# +# === Parameters +# +# [*policies*] +# (optional) Set of policies to configure for vitrage +# Example : +# { +# 'vitrage-context_is_admin' => { +# 'key' => 'context_is_admin', +# 'value' => 'true' +# }, +# 'vitrage-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/vitrage/policy.json +# +class vitrage::policy ( + $policies = {}, + $policy_path = '/etc/vitrage/policy.json', +) { + + validate_hash($policies) + + Openstacklib::Policy::Base { + file_path => $policy_path, + } + + create_resources('openstacklib::policy::base', $policies) + +} diff --git a/metadata.json b/metadata.json new file mode 100644 index 0000000..1cb6b14 --- /dev/null +++ b/metadata.json @@ -0,0 +1,34 @@ +{ + "name": "puppet-vitrage", + "version": "0.0.1", + "author": "OpenStack Contributors", + "summary": "Puppet module for OpenStack Vitrage", + "license": "Apache-2.0", + "source": "git://github.com/openstack/puppet-vitrage.git", + "project_page": "https://launchpad.net/puppet-vitrage", + "issues_url": "https://bugs.launchpad.net/puppet-vitrage", + "description": "Installs and configures OpenStack Vitrage.", + "operatingsystem_support": [ + { + "operatingsystem": "Debian", + "operatingsystemrelease": ["8"] + }, + { + "operatingsystem": "Fedora", + "operatingsystemrelease": ["21","22"] + }, + { + "operatingsystem": "RedHat", + "operatingsystemrelease": ["7"] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": ["14.04"] + } + ], + "dependencies": [ + { "name": "puppetlabs/inifile", "version_requirement": ">=1.0.0 <2.0.0" }, + { "name": "puppetlabs/stdlib", "version_requirement": ">= 4.2.0 <5.0.0" }, + { "name": "openstack/openstacklib", "version_requirement": ">=6.0.0 <7.0.0" } + ] +} diff --git a/spec/acceptance/nodesets/centos-70-x64.yml b/spec/acceptance/nodesets/centos-70-x64.yml new file mode 100644 index 0000000..5f097e9 --- /dev/null +++ b/spec/acceptance/nodesets/centos-70-x64.yml @@ -0,0 +1,11 @@ +HOSTS: + centos-server-70-x64: + roles: + - master + platform: el-7-x86_64 + box: puppetlabs/centos-7.0-64-nocm + box_url: https://vagrantcloud.com/puppetlabs/centos-7.0-64-nocm + hypervisor: vagrant +CONFIG: + log_level: debug + type: foss diff --git a/spec/acceptance/nodesets/default.yml b/spec/acceptance/nodesets/default.yml new file mode 100644 index 0000000..486b6a3 --- /dev/null +++ b/spec/acceptance/nodesets/default.yml @@ -0,0 +1,10 @@ +HOSTS: + ubuntu-server-14.04-amd64: + roles: + - master + platform: ubuntu-14.04-amd64 + box: puppetlabs/ubuntu-14.04-64-nocm + box_url: https://vagrantcloud.com/puppetlabs/ubuntu-14.04-64-nocm + hypervisor: vagrant +CONFIG: + type: foss diff --git a/spec/acceptance/nodesets/nodepool-centos7.yml b/spec/acceptance/nodesets/nodepool-centos7.yml new file mode 100644 index 0000000..c552874 --- /dev/null +++ b/spec/acceptance/nodesets/nodepool-centos7.yml @@ -0,0 +1,10 @@ +HOSTS: + centos-70-x64: + roles: + - master + platform: el-7-x86_64 + hypervisor: none + ip: 127.0.0.1 +CONFIG: + type: foss + set_env: false diff --git a/spec/acceptance/nodesets/nodepool-trusty.yml b/spec/acceptance/nodesets/nodepool-trusty.yml new file mode 100644 index 0000000..9fc624e --- /dev/null +++ b/spec/acceptance/nodesets/nodepool-trusty.yml @@ -0,0 +1,10 @@ +HOSTS: + ubuntu-14.04-amd64: + roles: + - master + platform: ubuntu-14.04-amd64 + hypervisor: none + ip: 127.0.0.1 +CONFIG: + type: foss + set_env: false diff --git a/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml b/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml new file mode 100644 index 0000000..8001929 --- /dev/null +++ b/spec/acceptance/nodesets/ubuntu-server-1404-x64.yml @@ -0,0 +1,11 @@ +HOSTS: + ubuntu-server-14.04-amd64: + roles: + - master + platform: ubuntu-14.04-amd64 + box: puppetlabs/ubuntu-14.04-64-nocm + box_url: https://vagrantcloud.com/puppetlabs/ubuntu-14.04-64-nocm + hypervisor: vagrant +CONFIG: + log_level: debug + type: foss diff --git a/spec/classes/vitrage_db_mysql_spec.rb b/spec/classes/vitrage_db_mysql_spec.rb new file mode 100644 index 0000000..8d25bcc --- /dev/null +++ b/spec/classes/vitrage_db_mysql_spec.rb @@ -0,0 +1,93 @@ +require 'spec_helper' + +describe 'vitrage::db::mysql' do + + let :pre_condition do + [ + 'include mysql::server', + 'include vitrage::db::sync' + ] + end + + let :facts do + @default_facts.merge({ :osfamily => 'Debian' }) + end + + let :params do + { + 'password' => 'fooboozoo_default_password', + } + end + + describe 'with only required params' do + it { is_expected.to contain_openstacklib__db__mysql('vitrage').with( + :user => 'vitrage', + :password_hash => '*3DDF34A86854A312A8E2C65B506E21C91800D206', + :dbname => 'vitrage', + :host => '127.0.0.1', + :charset => 'utf8', + :collate => 'utf8_general_ci', + )} + end + + describe "overriding allowed_hosts param to array" do + let :params do + { + :password => 'fooboozoo_default_password', + :allowed_hosts => ['127.0.0.1','%'], + } + end + + it { is_expected.to contain_openstacklib__db__mysql('vitrage').with( + :user => 'vitrage', + :password_hash => '*3DDF34A86854A312A8E2C65B506E21C91800D206', + :dbname => 'vitrage', + :host => '127.0.0.1', + :charset => 'utf8', + :collate => 'utf8_general_ci', + :allowed_hosts => ['127.0.0.1','%'], + )} + + end + + describe "overriding allowed_hosts param to string" do + let :params do + { + :password => 'fooboozoo_default_password', + :allowed_hosts => '192.168.1.1', + } + end + + it { is_expected.to contain_openstacklib__db__mysql('vitrage').with( + :user => 'vitrage', + :password_hash => '*3DDF34A86854A312A8E2C65B506E21C91800D206', + :dbname => 'vitrage', + :host => '127.0.0.1', + :charset => 'utf8', + :collate => 'utf8_general_ci', + :allowed_hosts => '192.168.1.1', + )} + + end + + describe "overriding allowed_hosts equal to host param" do + let :params do + { + :password => 'fooboozoo_default_password', + :allowed_hosts => '127.0.0.1', + } + end + + it { is_expected.to contain_openstacklib__db__mysql('vitrage').with( + :user => 'vitrage', + :password_hash => '*3DDF34A86854A312A8E2C65B506E21C91800D206', + :dbname => 'vitrage', + :host => '127.0.0.1', + :charset => 'utf8', + :collate => 'utf8_general_ci', + :allowed_hosts => '127.0.0.1', + )} + + end + +end diff --git a/spec/classes/vitrage_db_postgresql_spec.rb b/spec/classes/vitrage_db_postgresql_spec.rb new file mode 100644 index 0000000..bd9e5a3 --- /dev/null +++ b/spec/classes/vitrage_db_postgresql_spec.rb @@ -0,0 +1,58 @@ +require 'spec_helper' + +describe 'vitrage::db::postgresql' do + + let :req_params do + { :password => 'pw' } + end + + let :pre_condition do + 'include postgresql::server' + end + + context 'on a RedHat osfamily' do + let :facts do + @default_facts.merge({ + :osfamily => 'RedHat', + :operatingsystemrelease => '7.0', + :concat_basedir => '/var/lib/puppet/concat' + }) + end + + context 'with only required parameters' do + let :params do + req_params + end + + it { is_expected.to contain_postgresql__server__db('vitrage').with( + :user => 'vitrage', + :password => 'md58e3c14dceaf5be55c5982764df87003a' + )} + end + + end + + context 'on a Debian osfamily' do + let :facts do + @default_facts.merge({ + :operatingsystemrelease => '7.8', + :operatingsystem => 'Debian', + :osfamily => 'Debian', + :concat_basedir => '/var/lib/puppet/concat' + }) + end + + context 'with only required parameters' do + let :params do + req_params + end + + it { is_expected.to contain_postgresql__server__db('vitrage').with( + :user => 'vitrage', + :password => 'md58e3c14dceaf5be55c5982764df87003a' + )} + end + + end + +end diff --git a/spec/classes/vitrage_db_spec.rb b/spec/classes/vitrage_db_spec.rb new file mode 100644 index 0000000..f4c3cc4 --- /dev/null +++ b/spec/classes/vitrage_db_spec.rb @@ -0,0 +1,82 @@ +require 'spec_helper' + +describe 'vitrage::db' do + + shared_examples 'vitrage::db' do + context 'with default parameters' do + it { is_expected.to contain_vitrage_config('database/connection').with_value('mysql://vitrage:secrete@localhost:3306/vitrage') } + it { is_expected.to contain_vitrage_config('database/idle_timeout').with_value('') } + it { is_expected.to contain_vitrage_config('database/min_pool_size').with_value('') } + it { is_expected.to contain_vitrage_config('database/max_retries').with_value('') } + it { is_expected.to contain_vitrage_config('database/retry_interval').with_value('') } + it { is_expected.to contain_vitrage_config('database/max_pool_size').with_value('') } + it { is_expected.to contain_vitrage_config('database/max_overflow').with_value('') } + end + + context 'with specific parameters' do + let :params do + { :database_connection => 'mysql://vitrage:vitrage@localhost/vitrage', + :database_idle_timeout => '3601', + :database_min_pool_size => '2', + :database_max_retries => '11', + :database_retry_interval => '11', + :database_max_pool_size => '11', + :database_max_overflow => '21', + } + end + + it { is_expected.to contain_vitrage_config('database/connection').with_value('mysql://vitrage:vitrage@localhost/vitrage') } + it { is_expected.to contain_vitrage_config('database/idle_timeout').with_value('3601') } + it { is_expected.to contain_vitrage_config('database/min_pool_size').with_value('2') } + it { is_expected.to contain_vitrage_config('database/max_retries').with_value('11') } + it { is_expected.to contain_vitrage_config('database/retry_interval').with_value('11') } + it { is_expected.to contain_vitrage_config('database/max_pool_size').with_value('11') } + it { is_expected.to contain_vitrage_config('database/max_overflow').with_value('21') } + end + + context 'with postgresql backend' do + let :params do + { :database_connection => 'postgresql://vitrage:vitrage@localhost/vitrage', } + end + + it 'install the proper backend package' do + is_expected.to contain_package('python-psycopg2').with(:ensure => 'present') + end + + end + + context 'with incorrect database_connection string' do + let :params do + { :database_connection => 'redis://vitrage:vitrage@localhost/vitrage', } + end + + + + it_raises 'a Puppet::Error', /validate_re/ + end + end + + context 'on Debian platforms' do + let :facts do + @default_facts.merge({ + :osfamily => 'Debian', + :operatingsystem => 'Debian', + :operatingsystemrelease => 'jessie', + }) + end + + it_configures 'vitrage::db' + end + + context 'on Redhat platforms' do + let :facts do + @default_facts.merge({ + :osfamily => 'RedHat', + :operatingsystemrelease => '7.1', + }) + end + + it_configures 'vitrage::db' + end + +end diff --git a/spec/classes/vitrage_keystone_auth_spec.rb b/spec/classes/vitrage_keystone_auth_spec.rb new file mode 100644 index 0000000..521bd32 --- /dev/null +++ b/spec/classes/vitrage_keystone_auth_spec.rb @@ -0,0 +1,123 @@ +# +# Unit tests for vitrage::keystone::auth +# + +require 'spec_helper' + +describe 'vitrage::keystone::auth' do + + let :facts do + @default_facts.merge({ :osfamily => 'Debian' }) + end + + describe 'with default class parameters' do + let :params do + { :password => 'vitrage_password', + :tenant => 'foobar' } + end + + it { is_expected.to contain_keystone_user('vitrage').with( + :ensure => 'present', + :password => 'vitrage_password', + ) } + + it { is_expected.to contain_keystone_user_role('vitrage@foobar').with( + :ensure => 'present', + :roles => ['admin'] + )} + + it { is_expected.to contain_keystone_service('vitrage').with( + :ensure => 'present', + :type => 'root_cause_analysis_engine', + :description => 'vitrage Root Cause Analysis engine Service' + ) } + + it { is_expected.to contain_keystone_endpoint('RegionOne/vitrage').with( + :ensure => 'present', + :public_url => 'http://127.0.0.1:8999/v1', + :admin_url => 'http://127.0.0.1:8999/v1', + :internal_url => 'http://127.0.0.1:8999/v1', + ) } + end + + describe 'when overriding URL parameters' do + let :params do + { :password => 'vitrage_password', + :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 + + it { is_expected.to contain_keystone_endpoint('RegionOne/vitrage').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 auth name' do + let :params do + { :password => 'foo', + :auth_name => 'vitragey' } + end + + it { is_expected.to contain_keystone_user('vitragey') } + it { is_expected.to contain_keystone_user_role('vitragey@services') } + it { is_expected.to contain_keystone_service('vitragey') } + it { is_expected.to contain_keystone_endpoint('RegionOne/vitragey') } + end + + describe 'when overriding service name' do + let :params do + { :service_name => 'vitrage_service', + :auth_name => 'vitrage', + :password => 'vitrage_password' } + end + + it { is_expected.to contain_keystone_user('vitrage') } + it { is_expected.to contain_keystone_user_role('vitrage@services') } + it { is_expected.to contain_keystone_service('vitrage_service') } + it { is_expected.to contain_keystone_endpoint('RegionOne/vitrage_service') } + end + + describe 'when disabling user configuration' do + + let :params do + { + :password => 'vitrage_password', + :configure_user => false + } + end + + it { is_expected.not_to contain_keystone_user('vitrage') } + it { is_expected.to contain_keystone_user_role('vitrage@services') } + it { is_expected.to contain_keystone_service('vitrage').with( + :ensure => 'present', + :type => 'root_cause_analysis_engine', + :description => 'vitrage Root Cause Analysis engine Service' + ) } + + end + + describe 'when disabling user and user role configuration' do + + let :params do + { + :password => 'vitrage_password', + :configure_user => false, + :configure_user_role => false + } + end + + it { is_expected.not_to contain_keystone_user('vitrage') } + it { is_expected.not_to contain_keystone_user_role('vitrage@services') } + it { is_expected.to contain_keystone_service('vitrage').with( + :ensure => 'present', + :type => 'root_cause_analysis_engine', + :description => 'vitrage Root Cause Analysis engine Service' + ) } + + end + +end diff --git a/spec/classes/vitrage_logging_spec.rb b/spec/classes/vitrage_logging_spec.rb new file mode 100644 index 0000000..181316e --- /dev/null +++ b/spec/classes/vitrage_logging_spec.rb @@ -0,0 +1,144 @@ +require 'spec_helper' + +describe 'vitrage::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/vitrage/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', + :use_syslog => true, + :use_stderr => false, + :log_facility => 'LOG_FOO', + :log_dir => '/var/log', + :verbose => true, + :debug => true, + } + end + + shared_examples_for 'vitrage-logging' do + + context 'with basic logging options and default settings' do + it_configures 'basic default logging settings' + end + + context 'with basic logging options and non-default settings' do + before { params.merge!( log_params ) } + it_configures 'basic non-default logging settings' + end + + 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 'basic default logging settings' do + it 'configures vitrage logging settins with default values' do + is_expected.to contain_vitrage_config('DEFAULT/use_syslog').with(:value => '') + is_expected.to contain_vitrage_config('DEFAULT/use_stderr').with(:value => '') + is_expected.to contain_vitrage_config('DEFAULT/syslog_log_facility').with(:value => '') + is_expected.to contain_vitrage_config('DEFAULT/log_dir').with(:value => '/var/log/vitrage') + is_expected.to contain_vitrage_config('DEFAULT/verbose').with(:value => '') + is_expected.to contain_vitrage_config('DEFAULT/debug').with(:value => '') + end + end + + shared_examples 'basic non-default logging settings' do + it 'configures vitrage logging settins with non-default values' do + is_expected.to contain_vitrage_config('DEFAULT/use_syslog').with(:value => 'true') + is_expected.to contain_vitrage_config('DEFAULT/use_stderr').with(:value => 'false') + is_expected.to contain_vitrage_config('DEFAULT/syslog_log_facility').with(:value => 'LOG_FOO') + is_expected.to contain_vitrage_config('DEFAULT/log_dir').with(:value => '/var/log') + is_expected.to contain_vitrage_config('DEFAULT/verbose').with(:value => 'true') + is_expected.to contain_vitrage_config('DEFAULT/debug').with(:value => 'true') + end + end + + shared_examples_for 'logging params set' do + it 'enables logging params' do + is_expected.to contain_vitrage_config('DEFAULT/logging_context_format_string').with_value( + '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [%(request_id)s %(user_identity)s] %(instance)s%(message)s') + + is_expected.to contain_vitrage_config('DEFAULT/logging_default_format_string').with_value( + '%(asctime)s.%(msecs)03d %(process)d %(levelname)s %(name)s [-] %(instance)s%(message)s') + + is_expected.to contain_vitrage_config('DEFAULT/logging_debug_format_suffix').with_value( + '%(funcName)s %(pathname)s:%(lineno)d') + + is_expected.to contain_vitrage_config('DEFAULT/logging_exception_prefix').with_value( + '%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s') + + is_expected.to contain_vitrage_config('DEFAULT/log_config_append').with_value( + '/etc/vitrage/logging.conf') + is_expected.to contain_vitrage_config('DEFAULT/publish_errors').with_value( + true) + + is_expected.to contain_vitrage_config('DEFAULT/default_log_levels').with_value( + 'amqp=WARN,amqplib=WARN,boto=WARN,iso8601=WARN,qpid=WARN,requests.packages.urllib3.connectionpool=WARN,sqlalchemy=WARN,suds=INFO') + + is_expected.to contain_vitrage_config('DEFAULT/fatal_deprecations').with_value( + true) + + is_expected.to contain_vitrage_config('DEFAULT/instance_format').with_value( + '[instance: %(uuid)s] ') + + is_expected.to contain_vitrage_config('DEFAULT/instance_uuid_format').with_value( + '[instance: %(uuid)s] ') + + is_expected.to contain_vitrage_config('DEFAULT/log_date_format').with_value( + '%Y-%m-%d %H:%M:%S') + end + end + + + shared_examples_for 'logging params unset' do + [ :logging_context_format_string, :logging_default_format_string, + :logging_debug_format_suffix, :logging_exception_prefix, + :log_config_append, :publish_errors, + :default_log_levels, :fatal_deprecations, + :instance_format, :instance_uuid_format, + :log_date_format, ].each { |param| + it { is_expected.to contain_vitrage_config("DEFAULT/#{param}").with_value('') } + } + end + + context 'on Debian platforms' do + let :facts do + @default_facts.merge({ :osfamily => 'Debian' }) + end + + it_configures 'vitrage-logging' + end + + context 'on RedHat platforms' do + let :facts do + @default_facts.merge({ :osfamily => 'RedHat' }) + end + + it_configures 'vitrage-logging' + end + +end diff --git a/spec/classes/vitrage_policy_spec.rb b/spec/classes/vitrage_policy_spec.rb new file mode 100644 index 0000000..053419c --- /dev/null +++ b/spec/classes/vitrage_policy_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +describe 'vitrage::policy' do + + shared_examples_for 'vitrage policies' do + let :params do + { + :policy_path => '/etc/vitrage/policy.json', + :policies => { + 'context_is_admin' => { + 'key' => 'context_is_admin', + 'value' => 'foo:bar' + } + } + } + end + + it 'set up the policies' do + is_expected.to contain_openstacklib__policy__base('context_is_admin').with({ + :key => 'context_is_admin', + :value => 'foo:bar' + }) + end + end + + context 'on Debian platforms' do + let :facts do + @default_facts.merge({ :osfamily => 'Debian' }) + end + + it_configures 'vitrage policies' + end + + context 'on RedHat platforms' do + let :facts do + @default_facts.merge({ :osfamily => 'RedHat' }) + end + + it_configures 'vitrage policies' + end +end diff --git a/spec/shared_examples.rb b/spec/shared_examples.rb new file mode 100644 index 0000000..fec0eac --- /dev/null +++ b/spec/shared_examples.rb @@ -0,0 +1,5 @@ +shared_examples_for "a Puppet::Error" do |description| + it "with message matching #{description.inspect}" do + expect { is_expected.to have_class_count(1) }.to raise_error(Puppet::Error, description) + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..9bc7bcf --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,13 @@ +require 'puppetlabs_spec_helper/module_spec_helper' +require 'shared_examples' +require 'webmock/rspec' + +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.before :each do + @default_facts = { :os_service_default => '' } + end +end + +at_exit { RSpec::Puppet::Coverage.report! } diff --git a/spec/spec_helper_acceptance.rb b/spec/spec_helper_acceptance.rb new file mode 100644 index 0000000..429e807 --- /dev/null +++ b/spec/spec_helper_acceptance.rb @@ -0,0 +1,56 @@ +require 'beaker-rspec' +require 'beaker/puppet_install_helper' + +run_puppet_install_helper + +RSpec.configure do |c| + # Project root + proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) + modname = JSON.parse(open('metadata.json').read)['name'].split('-')[1] + + # Readable test descriptions + c.formatter = :documentation + + # Configure all nodes in nodeset + c.before :suite do + # Install module and dependencies + hosts.each do |host| + + # install git + install_package host, 'git' + + zuul_ref = ENV['ZUUL_REF'] + zuul_branch = ENV['ZUUL_BRANCH'] + zuul_url = ENV['ZUUL_URL'] + + repo = 'openstack/puppet-openstack-integration' + + # Start out with clean moduledir, don't trust r10k to purge it + on host, "rm -rf /etc/puppet/modules/*" + # Install dependent modules via git or zuul + r = on host, "test -e /usr/zuul-env/bin/zuul-cloner", { :acceptable_exit_codes => [0,1] } + if r.exit_code == 0 + zuul_clone_cmd = '/usr/zuul-env/bin/zuul-cloner ' + zuul_clone_cmd += '--cache-dir /opt/git ' + zuul_clone_cmd += "--zuul-ref #{zuul_ref} " + zuul_clone_cmd += "--zuul-branch #{zuul_branch} " + zuul_clone_cmd += "--zuul-url #{zuul_url} " + zuul_clone_cmd += "git://git.openstack.org #{repo}" + on host, zuul_clone_cmd + else + on host, "git clone https://git.openstack.org/#{repo} #{repo}" + end + + on host, "ZUUL_REF=#{zuul_ref} ZUUL_BRANCH=#{zuul_branch} ZUUL_URL=#{zuul_url} bash #{repo}/install_modules.sh" + + # Install the module being tested + on host, "rm -fr /etc/puppet/modules/#{modname}" + puppet_module_install(:source => proj_root, :module_name => modname) + + on host, "rm -fr #{repo}" + + # List modules installed to help with debugging + on host, puppet('module','list'), { :acceptable_exit_codes => 0 } + end + end +end diff --git a/spec/unit/provider/vitrage_config/ini_setting_spec.rb b/spec/unit/provider/vitrage_config/ini_setting_spec.rb new file mode 100644 index 0000000..5218cd8 --- /dev/null +++ b/spec/unit/provider/vitrage_config/ini_setting_spec.rb @@ -0,0 +1,68 @@ +# +# 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') +) +$LOAD_PATH.push( + File.join( + File.dirname(__FILE__), + '..', + '..', + '..', + 'fixtures', + 'modules', + 'openstacklib', + 'lib') +) +require 'spec_helper' +provider_class = Puppet::Type.type(:vitrage_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::Vitrage_config.new( + {:name => 'DEFAULT/foo', :value => 'bar'} + ) + provider = provider_class.new(resource) + expect(provider.section).to eq('DEFAULT') + expect(provider.setting).to eq('foo') + end + + it 'should allow setting to be set explicitly' do + resource = Puppet::Type::Vitrage_config.new( + {:name => 'dude/foo', :value => 'bar'} + ) + provider = provider_class.new(resource) + expect(provider.section).to eq('dude') + expect(provider.setting).to eq('foo') + end + + it 'should ensure absent when is specified as a value' do + resource = Puppet::Type::Vitrage_config.new( + {:name => 'dude/foo', :value => ''} + ) + provider = provider_class.new(resource) + provider.exists? + expect(resource[:ensure]).to eq :absent + end + + it 'should ensure absent when value matches ensure_absent_val' do + resource = Puppet::Type::Vitrage_config.new( + {:name => 'dude/foo', :value => 'foo', :ensure_absent_val => 'foo' } + ) + provider = provider_class.new(resource) + provider.exists? + expect(resource[:ensure]).to eq :absent + end + +end diff --git a/spec/unit/type/vitrage_config_spec.rb b/spec/unit/type/vitrage_config_spec.rb new file mode 100644 index 0000000..1d9e20a --- /dev/null +++ b/spec/unit/type/vitrage_config_spec.rb @@ -0,0 +1,64 @@ +require 'puppet' +require 'puppet/type/vitrage_config' +describe 'Puppet::Type.type(:vitrage_config)' do + before :each do + @vitrage_config = Puppet::Type.type(:vitrage_config).new(:name => 'DEFAULT/foo', :value => 'bar') + end + + it 'should require a name' do + expect { + Puppet::Type.type(:vitrage_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(:vitrage_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(:vitrage_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(:vitrage_config).new(:name => 'DEFAULT/foo', :ensure => :absent) + end + + it 'should accept a valid value' do + @vitrage_config[:value] = 'bar' + expect(@vitrage_config[:value]).to eq('bar') + end + + it 'should not accept a value with whitespace' do + @vitrage_config[:value] = 'b ar' + expect(@vitrage_config[:value]).to eq('b ar') + end + + it 'should accept valid ensure values' do + @vitrage_config[:ensure] = :present + expect(@vitrage_config[:ensure]).to eq(:present) + @vitrage_config[:ensure] = :absent + expect(@vitrage_config[:ensure]).to eq(:absent) + end + + it 'should not accept invalid ensure values' do + expect { + @vitrage_config[:ensure] = :latest + }.to raise_error(Puppet::Error, /Invalid value/) + end + + it 'should autorequire the package that install the file' do + catalog = Puppet::Resource::Catalog.new + package = Puppet::Type.type(:package).new(:name => 'vitrage') + catalog.add_resource package, @vitrage_config + dependency = @vitrage_config.autorequire + expect(dependency.size).to eq(1) + expect(dependency[0].target).to eq(@vitrage_config) + expect(dependency[0].source).to eq(package) + end + + +end diff --git a/tests/init.pp b/tests/init.pp new file mode 100644 index 0000000..bbb764f --- /dev/null +++ b/tests/init.pp @@ -0,0 +1,12 @@ +# The baseline for module testing used by Puppet Labs is that each manifest +# should have a corresponding test manifest that declares that class or defined +# type. +# +# Tests are then run by using puppet apply --noop (to check for compilation +# errors and view a log of events) or by fully applying the test in a virtual +# environment (to compare the resulting system state to the desired state). +# +# Learn more about module testing here: +# http://docs.puppetlabs.com/guides/tests_smoke.html +# +include ::vitrage