diff --git a/.fixtures.yml b/.fixtures.yml new file mode 100644 index 0000000..3525154 --- /dev/null +++ b/.fixtures.yml @@ -0,0 +1,13 @@ +fixtures: + repositories: + 'concat': + 'repo': 'git://github.com/puppetlabs/puppetlabs-concat.git' + 'ref': '1.2.2' + 'inifile': 'git://github.com/puppetlabs/puppetlabs-inifile' + 'keystone': 'git://github.com/openstack/puppet-keystone.git' + 'mysql': 'git://github.com/puppetlabs/puppetlabs-mysql.git' + 'openstacklib': 'git://github.com/openstack/puppet-openstacklib.git' + 'postgresql': 'git://github.com/puppetlabs/puppetlabs-postgresql.git' + 'stdlib': 'git://github.com/puppetlabs/puppetlabs-stdlib.git' + symlinks: + mistral: "#{source_dir}" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4dd84f0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,10 @@ +pkg/ +Gemfile.lock +vendor/ +spec/fixtures/ +.vagrant/ +.bundle/ +coverage/ +.idea/ +*.swp +*.iml diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..6d4ce9a --- /dev/null +++ b/Gemfile @@ -0,0 +1,36 @@ +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' +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..b09d105 --- /dev/null +++ b/README.md @@ -0,0 +1,54 @@ +mistral +====== + +#### Table of Contents + +1. [Overview - What is the mistral module?](#overview) +2. [Module Description - What does the module do?](#module-description) +3. [Setup - The basics of getting started with mistral](#setup) +4. [Implementation - An under-the-hood peek at what the module is doing](#implementation) +5. [Development - Guide for contributing to the module](#development) +6. [Contributors - Those with commits](#contributors) + +Overview +-------- + +The Mistral module itself is a workflow service for OpenStack cloud. + +Module Description +------------------ + +The mistral module is an attempt to make Puppet capable of managing the +entirety of mistral. + +Setup +----- + +### Beginning with mistral + +To use the mistral module's functionality you will need to declare multiple +resources. This is not an exhaustive list of all the components needed; we +recommend you consult and understand the +[core of openstack](http://docs.openstack.org) documentation. + + +Implementation +-------------- + +### mistral + +puppet-mistral is a combination of Puppet manifests and ruby code to deliver +configuration and extra functionality through types and providers. + + +Development +----------- + +Developer documentation for the entire puppet-openstack project. + +* https://wiki.openstack.org/wiki/Puppet#Developer_documentation + +Contributors +------------ + +* https://github.com/openstack/puppet-mistral/graphs/contributors diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..bc08f43 --- /dev/null +++ b/Rakefile @@ -0,0 +1,21 @@ +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' +require 'puppet-syntax/tasks/puppet-syntax' + +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", "class_parameter_defaults", "only_variable_string"] +end + +desc "Run acceptance tests" +RSpec::Core::RakeTask.new(:acceptance) do |t| + t.pattern = 'spec/acceptance' +end diff --git a/lib/puppet/provider/mistral_config/ini_setting.rb b/lib/puppet/provider/mistral_config/ini_setting.rb new file mode 100644 index 0000000..560b2dd --- /dev/null +++ b/lib/puppet/provider/mistral_config/ini_setting.rb @@ -0,0 +1,27 @@ +Puppet::Type.type(:mistral_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/mistral/mistral.conf' + end + + # added for backwards compatibility with older versions of inifile + def file_path + self.class.file_path + end + +end diff --git a/lib/puppet/type/mistral_config.rb b/lib/puppet/type/mistral_config.rb new file mode 100644 index 0000000..90b7620 --- /dev/null +++ b/lib/puppet/type/mistral_config.rb @@ -0,0 +1,42 @@ +Puppet::Type.newtype(:mistral_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from /etc/mistral/mistral.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/manifests/client.pp b/manifests/client.pp new file mode 100644 index 0000000..4fb064f --- /dev/null +++ b/manifests/client.pp @@ -0,0 +1,20 @@ +# == Class: mistral::client +# +# Installs mistral python client. +# +# === Parameters +# +# [*package_ensure*] +# Ensure state for package. Defaults to 'present'. +# +class mistral::client( + $package_ensure = 'present' +) { + + include ::mistral::params + + package { 'python-mistralclient': + ensure => $package_ensure, + name => $::mistral::params::client_package, + } +} diff --git a/manifests/config.pp b/manifests/config.pp new file mode 100644 index 0000000..c00504f --- /dev/null +++ b/manifests/config.pp @@ -0,0 +1,30 @@ +# == Class: mistral::config +# +# This class is used to manage arbitrary mistral configurations. +# +# === Parameters +# +# [*mistral_config*] +# (optional) Allow configuration of arbitrary mistral configurations. +# The value is an hash of mistral_config resources. Example: +# { 'DEFAULT/foo' => { value => 'fooValue'}, +# 'DEFAULT/bar' => { value => 'barValue'} +# } +# In yaml format, Example: +# mistral_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 mistral::config ( + $mistral_config = {}, +) { + + validate_hash($mistral_config) + + create_resources('mistral_config', $mistral_config) +} diff --git a/manifests/db/mysql.pp b/manifests/db/mysql.pp new file mode 100644 index 0000000..f210654 --- /dev/null +++ b/manifests/db/mysql.pp @@ -0,0 +1,73 @@ +# The mistral::db::mysql class implements mysql backend for mistral +# +# This class can be used to create tables, users and grant +# privelege for a mysql mistral database. +# +# == parameters +# +# [*password*] +# (Mandatory) Password to connect to the database. +# Defaults to 'false'. +# +# [*dbname*] +# (Optional) Name of the database. +# Defaults to 'mistral'. +# +# [*user*] +# (Optional) User to connect to the database. +# Defaults to 'mistral'. +# +# [*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' +# +# [*listening_service*] +# The name that will be called from the mysql machine +# Defaults to 'mistral_db'. +# +# == Dependencies +# Class['mysql::server'] +# +# == Examples +# +# == Authors +# +# == Copyright +# +class mistral::db::mysql( + $password, + $listening_service = 'mistral_db', + $dbname = 'mistral', + $user = 'mistral', + $host = '127.0.0.1', + $charset = 'utf8', + $collate = 'utf8_general_ci', + $allowed_hosts = undef +) { + + validate_string($password) + + ::openstacklib::db::mysql { 'mistral': + user => $user, + password_hash => mysql_password($password), + dbname => $dbname, + host => $host, + charset => $charset, + collate => $collate, + allowed_hosts => $allowed_hosts, + } + +} diff --git a/manifests/db/postgresql.pp b/manifests/db/postgresql.pp new file mode 100644 index 0000000..241c3eb --- /dev/null +++ b/manifests/db/postgresql.pp @@ -0,0 +1,55 @@ +# == Class: mistral::db::postgresql +# +# Class that configures postgresql for mistral +# Requires the Puppetlabs postgresql module. +# +# === Parameters +# +# [*password*] +# (Required) Password to connect to the database. +# +# [*dbname*] +# (Optional) Name of the database. +# Defaults to 'mistral'. +# +# [*user*] +# (Optional) User to connect to the database. +# Defaults to 'mistral'. +# +# [*encoding*] +# (Optional) The charset to use for the database. +# Default to undef. +# +# [*privileges*] +# (Optional) Privileges given to the database user. +# Default to 'ALL' +# +# == Dependencies +# +# == Examples +# +# == Authors +# +# == Copyright +# +class mistral::db::postgresql( + $password, + $dbname = 'mistral', + $user = 'mistral', + $encoding = undef, + $privileges = 'ALL', +) { + + Class['mistral::db::postgresql'] -> Service<| title == 'mistral' |> + + ::openstacklib::db::postgresql { 'mistral': + password_hash => postgresql_password($user, $password), + dbname => $dbname, + user => $user, + encoding => $encoding, + privileges => $privileges, + } + + ::Openstacklib::Db::Postgresql['mistral'] ~> Exec<| title == 'mistral-dbsync' |> + +} diff --git a/manifests/db/sync.pp b/manifests/db/sync.pp new file mode 100644 index 0000000..038bfaa --- /dev/null +++ b/manifests/db/sync.pp @@ -0,0 +1,15 @@ +# +# Class to execute "mistral-dbsync" +# +class mistral::db::sync { + + exec { 'mistral-dbsync': + command => $::mistral::params::dbsync_command, + path => '/usr/bin', + user => 'mistral', + logoutput => on_failure, + subscribe => File[$::mistral::params::mistral_conf], + } + + Exec['mistral-dbsync'] ~> Service<| title == 'mistral' |> +} diff --git a/manifests/init.pp b/manifests/init.pp new file mode 100644 index 0000000..cc409f3 --- /dev/null +++ b/manifests/init.pp @@ -0,0 +1,277 @@ +# == Class: mistral +# +# Full description of class mistral here. +# +# === Parameters +# [*qpid_hostname*] +# The name/ip of qpid. Defult 'localhost' +# +# [*qpid_port*] +# The port of qpid. Defult '5671' +# +# [*qpid_username*] +# User name for qpid. Defult 'guest' +# +# [*qpid_password*] +# password for qpid. Defult 'guest' +# +# [*qpid_protocol*] +# protocol for qpid. Defult 'ssl' +# +# [*qpid_tcp_nodelay*] +# Shuld tcp be no deply at qpid? defult 'true' +# +# [*rpc_backend*] +# The rpc backend defult 'qpid' +# +# [*auth_uri*] +# Keystone url. Defult 'http://localhost:5000/v2.0/' +# +# [*admin_user*] +# The user name from 'mistral::keystone::auth'. Defult 'mistral' +# +# [*admin_tenant_name*] +# The tenant name from 'mistral::keystone::auth'. Defult 'service' +# +# [*admin_password*] +# The password from 'mistral::keystone::auth'. Defult 'password' +# +# [*log_dir*] +# Path to the log dir. Defult '$::mistral::params::log_dir' +# +# [*mysql_vip*] +# ip for the my sql DB. Defult '127.0.0.1' +# +# [*mistral_db_pass*] +# password for thr DB. Shulde be the same as mistral::db::mysql. +# Defult 'password' +# +# [*auth_version*] +# Keystone Api versioh. Defult 'v2.0' +# +# [*rabbit_hostname*] +# The name/ip of rabbit. Defult 'localhost' +# +# [*rabbit_userid*] +# User id for rabbit. Defult 'guest' +# +# [*rabbit_password*] +# password for rabbit. Defult 'guest' +# +# [*rabbit_port*] +# The port of rabbit. Defult '5671' +# +# [*auth_protocol*] +# Keystone protocol +# +class mistral( + $qpid_hostname = 'localhost', + $qpid_port = 5671, + $qpid_username = 'guest', + $qpid_password = 'guest', + $qpid_protocol = 'ssl', + $qpid_tcp_nodelay = true, + $rpc_backend = 'qpid', + $auth_uri = 'http://localhost:5000/v2.0/', + $admin_user = 'mistral', + $admin_tenant_name = 'services', + $admin_password = 'password', + $log_dir = $::mistral::params::log_dir, + $mysql_vip = '127.0.0.1', + $mistral_db_pass = 'password', + $auth_version = 'v2.0', + $auth_protocol = 'http', + $rabbit_hostname = 'localhost', + $rabbit_userid = 'guest', + $rabbit_password = 'guest', + $rabbit_port = 5671 +){ + include ::mistral::params + + group { 'mistral': + ensure => 'present', + name => 'mistral', + } + + file { '/home/mistral' : + ensure => directory, + owner => 'mistral', + group => 'mistral', + mode => '0750', + } + + user { 'mistral': + name => 'mistral', + gid => 'mistral', + groups => ['mistral'], + home => '/home/mistral', + system => true + } + + + package { 'MySQL-python': + ensure => installed, + name => 'MySQL-python', + } + + package { 'python-devel': + ensure => installed, + name => 'python-devel', + } + + package { 'python-pip': + ensure => installed, + name => 'python-pip', + } + + package { 'python-keystonemiddleware': + ensure => latest, + name => 'python-keystonemiddleware', + } + + package { 'python-oslo-utils': + ensure => latest, + name => 'python-oslo-utils', + } + + package { 'python-oslo-db': + ensure => latest, + name => 'python-oslo-db', + } + + package { 'python-oslo-log': + ensure => latest, + name => 'python-oslo-log', + } + + package { 'python-oslo-service': + ensure => latest, + name => 'python-oslo-service', + } + + package { 'python-oslo-i18n': + ensure => latest, + name => 'python-oslo-i18n', + } + + package { 'python-oslo-config': + ensure => latest, + name => 'python-oslo-config', + } + + package { 'python-oslo-messaging': + ensure => latest, + name => 'python-oslo-messaging', + } + + package { 'python-oslo-context': + ensure => latest, + name => 'python-oslo-context', + } + + package { 'python-oslo-serialization': + ensure => latest, + name => 'python-oslo-serialization', + } + + package { 'python-novaclient': + ensure => latest, + name => 'python-novaclient', + } + + package { 'python-eventlet': + ensure => latest, + name => 'python-eventlet', + } + + + package { 'yaql': + ensure => installed, + name => 'yaql', + } + + package { 'python-pecan': + ensure => latest, + name => 'python-pecan', + } + + package { 'python-ply': + ensure => installed, + name => 'python-ply', + } + + package { 'python-jsonschema': + ensure => installed, + name => 'python-jsonschema', + } + + package { 'python-croniter': + ensure => installed, + name => 'python-croniter', + } + + package { 'python-networkx': + ensure => installed, + name => 'python-networkx', + } + + package { 'python-warlock': + ensure => installed, + name => 'python-warlock', + } + + package { 'python-cliff': + ensure => installed, + name => 'python-cliff', + } + + package { 'python-wsme': + ensure => installed, + name => 'python-wsme', + } + + package { 'python-paramiko': + ensure => installed, + name => 'python-paramiko', + } + + package { 'mistral': + ensure => latest, + name => 'mistral', + } + + $auth_uri_with_version = "${auth_uri}${auth_version}/" + $database_connection = "mysql://mistral:${mistral_db_pass}@${mysql_vip}/mistral" + mistral_config { + 'DEFAULT/log_dir' : value => $log_dir; + 'DEFAULT/rpc_backend' : value => $rpc_backend; + 'keystone_authtoken/auth_uri' : value => + $auth_uri_with_version; + 'keystone_authtoken/auth_version' : value => $auth_version; + 'keystone_authtoken/auth_protocol' : value => $auth_protocol; + 'keystone_authtoken/identity_uri' : value => $auth_uri; + 'keystone_authtoken/admin_user' : value => $admin_user; + 'keystone_authtoken/admin_password' : value => $admin_password; + 'keystone_authtoken/admin_tenant_name' : value => $admin_tenant_name; + 'database/connection' : value => $database_connection; + } + if $rpc_backend == 'qpid' { + mistral_config { + 'oslo_messaging_qpid/qpid_hostname' : value => $qpid_hostname; + 'oslo_messaging_qpid/qpid_port' : value => $qpid_port; + 'oslo_messaging_qpid/qpid_username' : value => $qpid_username; + 'oslo_messaging_qpid/qpid_password' : value => $qpid_password; + 'oslo_messaging_qpid/qpid_protocol' : value => $qpid_protocol; + 'oslo_messaging_qpid/qpid_tcp_nodelay' : value => $qpid_tcp_nodelay; + } + } + if $rpc_backend == 'rabbit' { + mistral_config { + 'oslo_messaging_rabbit/rabbit_host' : value => $rabbit_hostname; + 'oslo_messaging_rabbit/rabbit_port' : value => $rabbit_port; + 'oslo_messaging_rabbit/rabbit_userid' : value => $rabbit_userid; + 'oslo_messaging_rabbit/rabbit_password' : value => $rabbit_password; + } + } +} + diff --git a/manifests/keystone/auth.pp b/manifests/keystone/auth.pp new file mode 100644 index 0000000..2830fd0 --- /dev/null +++ b/manifests/keystone/auth.pp @@ -0,0 +1,150 @@ +# == Class: mistral::keystone::auth +# +# Configures mistral user, service and endpoint in Keystone. +# +# === Parameters +# +# [*password*] +# (required) Password for mistral user. +# +# [*auth_name*] +# Username for mistral service. Defaults to 'mistral'. +# +# [*email*] +# Email for mistral user. Defaults to 'mistral@localhost'. +# +# [*tenant*] +# Tenant for mistral user. Defaults to 'services'. +# +# [*configure_endpoint*] +# Should mistral endpoint be configured? Defaults to 'true'. +# +# [*configure_user*] +# (Optional) Should the service user be configured? +# Defaults to 'true'. +# +# [*service_type*] +# Type of service. Defaults to 'workflow'. +# +# [*public_url*] +# (optional) The endpoint's public url. +# (Defaults to 'http://127.0.0.1:8989:/v2') +# +# [*internal_url*] +# (optional) The endpoint's internal url. +# (Defaults to 'http://127.0.0.1:8989/v2') +# +# [*admin_url*] +# (optional) The endpoint's admin url. +# (Defaults to 'http://127.0.0.1:8989/v2') +# +# [*region*] +# Region for endpoint. Defaults to 'RegionOne'. +# +# [*service_name*] +# (optional) Name of the service. +# Defaults to the value of auth_name. +# +# +# [*configure_service*] +# Should mistral service be configured? Defaults to 'true'. +# +# [*service_description*] +# (optional) Description for keystone service. +# Defaults to 'Openstack workflow Service'. + +# [*configure_user_role*] +# (optional) Whether to configure the admin role for the service user. +# Defaults to true +# +# [*version*] +# (optional) DEPRECATED: Use public_url, internal_url and admin_url instead. +# API version endpoint. (Defaults to 'v2') +# Setting this parameter overrides public_url, internal_url and admin_url parameters. +# +# [*port*] +# (optional) DEPRECATED: Use public_url, internal_url and admin_url instead. +# Default port for endpoints. (Defaults to 8989) +# Setting this parameter overrides public_url, internal_url and admin_url parameters. +# +# [*public_port*] +# (optional) DEPRECATED: Use public_url, internal_url and admin_url instead. +# Default public port for endpoints. (Defaults to 8989) +# Setting this parameter overrides public_url, internal_url and admin_url parameters. +# +# [*public_protocol*] +# (optional) DEPRECATED: Use public_url instead. +# Protocol for public endpoint. (Defaults to 'http') +# Setting this parameter overrides public_url parameter. +# +# [*public_address*] +# (optional) DEPRECATED: Use public_url instead. +# Public address for endpoint. (Defaults to '127.0.0.1') +# Setting this parameter overrides public_url parameter. +# +# [*internal_protocol*] +# (optional) DEPRECATED: Use internal_url instead. +# Protocol for internal endpoint. (Defaults to 'http') +# Setting this parameter overrides internal_url parameter. +# +# [*internal_address*] +# (optional) DEPRECATED: Use internal_url instead. +# Internal address for endpoint. (Defaults to '127.0.0.1') +# Setting this parameter overrides internal_url parameter. +# +# [*admin_protocol*] +# (optional) DEPRECATED: Use admin_url instead. +# Protocol for admin endpoint. (Defaults to 'http') +# Setting this parameter overrides admin_url parameter. +# +# [*admin_address*] +# (optional) DEPRECATED: Use admin_url instead. +# Admin address for endpoint. (Defaults to '127.0.0.1') +# Setting this parameter overrides admin_url parameter. +# === Deprecation notes +# +# If any value is provided for public_protocol, public_address or port parameters, +# public_url will be completely ignored. The same applies for internal and admin parameters. +# +class mistral::keystone::auth( + $password, + $email = 'mistral@localhost', + $auth_name = 'mistral', + $service_name = undef, + $service_type = 'workflow', + $public_url = 'http://127.0.0.1:8989/v2', + $admin_url = 'http://127.0.0.1:8989/v2', + $internal_url = 'http://127.0.0.1:8989/v2', + $region = 'RegionOne', + $tenant = 'services', + $configure_endpoint = true, + $configure_service = true, + $configure_user = true, + $configure_user_role = true, + $service_description = 'Openstack workflow Service', +) { + + validate_string($password) + + if $service_name == undef { + $real_service_name = $auth_name + } else { + $real_service_name = $service_name + } + + keystone::resource::service_identity { $auth_name: + configure_user => $configure_user, + configure_user_role => $configure_user_role, + configure_endpoint => $configure_endpoint, + service_type => $service_type, + service_description => $service_description, + service_name => $real_service_name, + region => $region, + password => $password, + email => $email, + tenant => $tenant, + public_url => $public_url, + admin_url => $admin_url, + internal_url => $internal_url, + } +} diff --git a/manifests/keystone/keystone_config_listener.pp b/manifests/keystone/keystone_config_listener.pp new file mode 100644 index 0000000..91d2ec3 --- /dev/null +++ b/manifests/keystone/keystone_config_listener.pp @@ -0,0 +1,120 @@ +# == Class: mistral::keystone::keystone_config_listener +# +# Listener for the keystone. this class will call mistral::keystone::auth when keystone will be up +# +# === Parameters +# +#[*listening_service*] +# (required) The name that will be called from keystone +# +# [*password*] +# (required) Password for mistral user. +# +# [*auth_name*] +# Username for mistral service. Defaults to 'mistral'. +# +# +# [*email*] +# Email for mistral user. Defaults to 'mistral@localhost'. +# +# [*tenant*] +# Tenant for mistral user. Defaults to 'services'. +# +# [*configure_endpoint*] +# Should mistral endpoint be configured? Defaults to 'true'. +# +# [*configure_user*] +# (Optional) Should the service user be configured? +# Defaults to 'true'. +# +# [*service_type*] +# Type of service. Defaults to 'workflow'. +# +# [*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 '8989'. +# +# [*public_port*] +# Port for public endpoint. Defaults to $port. +# +# [*region*] +# Region for endpoint. Defaults to 'RegionOne'. +# +# [*service_name*] +# (optional) Name of the service. +# Defaults to the value of auth_name. +# +# [*configure_service*] +# Should mistral service be configured? Defaults to 'true'. +# +# [*unique_name*] +# (optional) This name is for mistral in HA +# Defaults is '${::fqdn}_${auth_name}' +# +# [*service_description*] +# (optional) This description os the service +# Defaults is 'Openstack workflow Service' +# +define mistral::keystone::keystone_config_listener( + $listening_service, + $password = false, + $email = 'mistral@localhost', + $auth_name = 'mistral', + $service_name = undef, + $service_type = 'workflow', + $service_description = 'Openstack workflow Service', + $public_address = '127.0.0.1', + $admin_address = '127.0.0.1', + $internal_address = '127.0.0.1', + $port = '8989', + $region = 'RegionOne', + $tenant = 'services', + $public_protocol = 'http', + $admin_protocol = 'http', + $internal_protocol = 'http', + $configure_endpoint = true, + $configure_service = true, + $configure_user = true, + $unique_name = "${::fqdn}_${auth_name}" +){ + + if ! defined(mistral::keystone::auth[$unique_name]){ + mistral::keystone::auth { $unique_name: + password => $password, + email => $email, + auth_name => $auth_name, + service_name => $service_name, + service_type => $service_type, + public_address => $public_address, + admin_address => $admin_address, + internal_address => $internal_address, + port => $port, + region => $region, + tenant => $tenant, + public_protocol => $public_protocol, + admin_protocol => $admin_protocol, + internal_protocol => $internal_protocol, + configure_endpoint => $configure_endpoint, + configure_service => $configure_service, + configure_user => $configure_user, + unique_name => $unique_name + } + } +} diff --git a/manifests/logging.pp b/manifests/logging.pp new file mode 100644 index 0000000..c454a8d --- /dev/null +++ b/manifests/logging.pp @@ -0,0 +1,211 @@ +# Class mistral::logging +# +# mistral 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', 'mistralmiddleware' => '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 mistral::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 { + mistral_config { + 'DEFAULT/logging_context_format_string' : + value => $logging_context_format_string; + } + } + else { + mistral_config { + 'DEFAULT/logging_context_format_string' : ensure => absent; + } + } + + if $logging_default_format_string { + mistral_config { + 'DEFAULT/logging_default_format_string' : + value => $logging_default_format_string; + } + } + else { + mistral_config { + 'DEFAULT/logging_default_format_string' : ensure => absent; + } + } + + if $logging_debug_format_suffix { + mistral_config { + 'DEFAULT/logging_debug_format_suffix' : + value => $logging_debug_format_suffix; + } + } + else { + mistral_config { + 'DEFAULT/logging_debug_format_suffix' : ensure => absent; + } + } + + if $logging_exception_prefix { + mistral_config { + 'DEFAULT/logging_exception_prefix' : value => $logging_exception_prefix; + } + } + else { + mistral_config { + 'DEFAULT/logging_exception_prefix' : ensure => absent; + } + } + + if $log_config_append { + mistral_config { + 'DEFAULT/log_config_append' : value => $log_config_append; + } + } + else { + mistral_config { + 'DEFAULT/log_config_append' : ensure => absent; + } + } + + if $default_log_levels { + mistral_config { + 'DEFAULT/default_log_levels' : + value => join(sort(join_keys_to_values($default_log_levels, '=')), ','); + } + } + else { + mistral_config { + 'DEFAULT/default_log_levels' : ensure => absent; + } + } + + if $publish_errors { + mistral_config { + 'DEFAULT/publish_errors' : value => $publish_errors; + } + } + else { + mistral_config { + 'DEFAULT/publish_errors' : ensure => absent; + } + } + + if $fatal_deprecations { + mistral_config { + 'DEFAULT/fatal_deprecations' : value => $fatal_deprecations; + } + } + else { + mistral_config { + 'DEFAULT/fatal_deprecations' : ensure => absent; + } + } + + if $instance_format { + mistral_config { + 'DEFAULT/instance_format' : value => $instance_format; + } + } + else { + mistral_config { + 'DEFAULT/instance_format' : ensure => absent; + } + } + + if $instance_uuid_format { + mistral_config { + 'DEFAULT/instance_uuid_format' : value => $instance_uuid_format; + } + } + else { + mistral_config { + 'DEFAULT/instance_uuid_format' : ensure => absent; + } + } + + if $log_date_format { + mistral_config { + 'DEFAULT/log_date_format' : value => $log_date_format; + } + } + else { + mistral_config { + 'DEFAULT/log_date_format' : ensure => absent; + } + } + + +} diff --git a/manifests/params.pp b/manifests/params.pp new file mode 100644 index 0000000..10597c2 --- /dev/null +++ b/manifests/params.pp @@ -0,0 +1,10 @@ +# +class mistral::params { + $mistral_conf_dir = '/etc/mistral' + $mistral_conf = "${mistral_conf_dir}/mistral.conf" + $package_name = 'mistral' + $client_package = 'python-mistralclient' + $log_dir ='/var/log/mistral' + $dbsync_command = "/usr/bin/python /usr/bin/mistral-db-manage --config-file=${mistral_conf} populate" + $update_service_command = '/usr/bin/systemctl daemon-reload' +} diff --git a/manifests/policy.pp b/manifests/policy.pp new file mode 100644 index 0000000..7305827 --- /dev/null +++ b/manifests/policy.pp @@ -0,0 +1,39 @@ +# == Class: mistral::policy +# +# Configure the mistral policies +# +# === Parameters +# +# [*policies*] +# (optional) Set of policies to configure for mistral +# Example : +# { +# 'mistral-context_is_admin' => { +# 'key' => 'context_is_admin', +# 'value' => 'true' +# }, +# 'mistral-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/mistral/policy.json +# +class mistral::policy ( + $policies = {}, + $policy_path = '/etc/mistral/policy.json', +) { + + validate_hash($policies) + + Openstacklib::Policy::Base { + file_path => $policy_path, + } + + create_resources('openstacklib::policy::base', $policies) + +} diff --git a/manifests/services.pp b/manifests/services.pp new file mode 100644 index 0000000..2f815df --- /dev/null +++ b/manifests/services.pp @@ -0,0 +1,97 @@ +# == Class: mistral::services +# +# Start mistral services +# +# === Parameters +# +# [*is_engine*] +# start mistral engine? Defaults to 'true'. +# +# [*is_api*] +# start mistral api? Defaults to 'true'. +# +# [*is_executor*] +# start mistral executor? Defaults to 'true'. +# +# [*conf_file*] +# path to the conf file. Defaults '$::mistral::params::mistral_conf' +# +class mistral::services( + $is_engine = true, + $is_api = true, + $is_executor = true, + $conf_file = $::mistral::params::mistral_conf +) { + + if $is_engine { + notify { 'Start mistral-engine': } + + file { 'openstack-mistral-engine': + path => '/usr/lib/systemd/system/openstack-mistral-engine + .service', + owner => 'mistral', + group => 'mistral', + mode => '0644', + content => template('mistral/openstack-mistral-engine.service.erb'), + require => Package['mistral'] + } + + service { 'openstack-mistral-engine': + ensure => running, + enable => true, + require => File['openstack-mistral-engine'], + subscribe => File[$::mistral::params::mistral_conf] + } + } + + if $is_api { + notify { 'Start mistral-api': } + + file { 'openstack-mistral-api': + path => '/usr/lib/systemd/system/openstack-mistral-api.service', + owner => 'mistral', + group => 'mistral', + mode => '0644', + content => template('mistral/openstack-mistral-api.service.erb'), + require => Package['mistral'] + } + + service { 'openstack-mistral-api': + ensure => running, + enable => true, + require => File['openstack-mistral-api'], + subscribe => File[$::mistral::params::mistral_conf] + } + } + + if $is_executor { + notify { 'Start mistral-executor': } + + file { 'openstack-mistral-executor': + path => '/usr/lib/systemd/system/openstack-mistral-executor + .service', + owner => 'mistral', + group => 'mistral', + mode => '0644', + content => template('mistral/openstack-mistral-executor.service.erb'), + require => Package['mistral'] + } + + service { 'openstack-mistral-executor': + ensure => running, + enable => true, + require => File['openstack-mistral-executor'], + subscribe => File[$::mistral::params::mistral_conf] + } + } + + exec { 'update-service': + command => $::mistral::params::update_service_command, + path => '/usr/bin', + user => 'root', + logoutput => on_failure, + subscribe => [File['openstack-mistral-executor'], + File['openstack-mistral-api'], File['openstack-mistral-engine']] + } + +} diff --git a/metadata.json b/metadata.json new file mode 100644 index 0000000..f2c53dc --- /dev/null +++ b/metadata.json @@ -0,0 +1,34 @@ +{ + "name": "puppet-mistral", + "version": "0.0.1", + "author": "OpenStack Contributors", + "summary": "Puppet module for OpenStack mistral", + "license": "Apache-2.0", + "source": "git://github.com/openstack/puppet-mistral.git", + "project_page": "https://launchpad.net/puppet-mistral", + "issues_url": "https://bugs.launchpad.net/puppet-mistral", + "description": "Installs and configures OpenStack mistral.", + "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.0.0 <5.0.0" }, + { "name": "stackforge/openstacklib", "version_requirement": ">=5.0.0 <6.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..3bb3e62 --- /dev/null +++ b/spec/acceptance/nodesets/default.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/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..7f503ca --- /dev/null +++ b/spec/acceptance/nodesets/nodepool-trusty.yml @@ -0,0 +1,10 @@ +HOSTS: + ubuntu-1404-x64: + 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..3bb3e62 --- /dev/null +++ b/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/spec/classes/mistral_config_spec.rb b/spec/classes/mistral_config_spec.rb new file mode 100644 index 0000000..ad012a1 --- /dev/null +++ b/spec/classes/mistral_config_spec.rb @@ -0,0 +1,20 @@ +require 'spec_helper' + +describe 'mistral::config' do + + let :params do + { :mistral_config => { + 'DEFAULT/foo' => { 'value' => 'fooValue' }, + 'DEFAULT/bar' => { 'value' => 'barValue' }, + 'DEFAULT/baz' => { 'ensure' => 'absent' } + } + } + end + + it 'configures arbitrary mistral configurations' do + is_expected.to contain_mistral_config('DEFAULT/foo').with_value('fooValue') + is_expected.to contain_mistral_config('DEFAULT/bar').with_value('barValue') + is_expected.to contain_mistral_config('DEFAULT/baz').with_ensure('absent') + end + +end \ No newline at end of file diff --git a/spec/classes/mistral_db_mysql_spec.rb b/spec/classes/mistral_db_mysql_spec.rb new file mode 100644 index 0000000..110a336 --- /dev/null +++ b/spec/classes/mistral_db_mysql_spec.rb @@ -0,0 +1,62 @@ +require 'spec_helper' + +describe 'mistral::db::mysql' do + + let :pre_condition do + [ + 'include mysql::server', + 'include mistral::db::sync' + ] + end + + let :facts do + { :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('mistral').with( + 'user' => 'mistral', + 'password_hash' => '*3DDF34A86854A312A8E2C65B506E21C91800D206', + 'dbname' => 'mistral', + 'host' => '127.0.0.1', + 'charset' => 'utf8', + :collate => 'utf8_general_ci', + )} + end + + describe "overriding allowed_hosts param to array" do + let :params do + { + :password => 'mistralpass', + :allowed_hosts => ['127.0.0.1','%'] + } + end + + end + describe "overriding allowed_hosts param to string" do + let :params do + { + :password => 'mistralpass2', + :allowed_hosts => '192.168.1.1' + } + end + + end + + describe "overriding allowed_hosts param equals to host param " do + let :params do + { + :password => 'mistralpass2', + :allowed_hosts => '127.0.0.1' + } + end + + end + +end diff --git a/spec/classes/mistral_db_postgresql_spec.rb b/spec/classes/mistral_db_postgresql_spec.rb new file mode 100644 index 0000000..495a340 --- /dev/null +++ b/spec/classes/mistral_db_postgresql_spec.rb @@ -0,0 +1,58 @@ +require 'spec_helper' + +describe 'mistral::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 + { + :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('mistral').with( + :user => 'mistral', + :password => 'md56cc4a9db977897a441d3a498a5d94fce' + )} + end + + end + + context 'on a Debian osfamily' do + let :facts do + { + :operatingsystemrelease => '7.8', + :operatingsystem => 'Debian', + :osfamily => 'Debian', + :concat_basedir => '/var/lib/puppet/concat' + } + end + + context 'with only required parameters' do + let :params do + req_params + end + + it { is_expected.to contain_postgresql__server__db('mistral').with( + :user => 'mistral', + :password => 'md56cc4a9db977897a441d3a498a5d94fce' + )} + end + + end + +end diff --git a/spec/classes/mistral_keystone_auth_spec.rb b/spec/classes/mistral_keystone_auth_spec.rb new file mode 100644 index 0000000..bedbf55 --- /dev/null +++ b/spec/classes/mistral_keystone_auth_spec.rb @@ -0,0 +1,108 @@ +# +# Unit tests for mistral::keystone::auth +# + +require 'spec_helper' + +describe 'mistral::keystone::auth' do + + let :facts do + { :osfamily => 'Debian' } + end + + describe 'with default class parameters' do + let :params do + { :password => 'mistral_password', + :tenant => 'services' } + end + + it { is_expected.to contain_keystone_user('mistral').with( + :ensure => 'present', + :password => 'mistral_password', + :tenant => 'services' + ) } + + it { is_expected.to contain_keystone_user_role('mistral@services').with( + :ensure => 'present', + :roles => ['admin'] + )} + + it { is_expected.to contain_keystone_service('mistral').with( + :ensure => 'present', + :type => 'workflow', + :description => 'Openstack workflow Service' + ) } + + it { is_expected.to contain_keystone_endpoint('RegionOne/mistral').with( + :ensure => 'present', + :public_url => "http://127.0.0.1:8989/v2", + :admin_url => "http://127.0.0.1:8989/v2", + :internal_url => "http://127.0.0.1:8989/v2" + ) } + end + + describe 'when overriding auth name' do + let :params do + { :password => 'foo', + :auth_name => 'mistraly' } + end + + it { is_expected.to contain_keystone_user('mistraly') } + it { is_expected.to contain_keystone_user_role('mistraly@services') } + it { is_expected.to contain_keystone_service('mistraly') } + it { is_expected.to contain_keystone_endpoint('RegionOne/mistraly') } + end + + describe 'when overriding service name' do + let :params do + { :service_name => 'mistral_service', + :auth_name => 'mistral', + :password => 'mistral_password' } + end + + it { is_expected.to contain_keystone_user('mistral') } + it { is_expected.to contain_keystone_user_role('mistral@services') } + it { is_expected.to contain_keystone_service('mistral_service') } + it { is_expected.to contain_keystone_endpoint('RegionOne/mistral_service') } + end + + describe 'when disabling user configuration' do + + let :params do + { + :password => 'mistral_password', + :configure_user => false + } + end + + it { is_expected.not_to contain_keystone_user('mistral') } + it { is_expected.to contain_keystone_user_role('mistral@services') } + it { is_expected.to contain_keystone_service('mistral').with( + :ensure => 'present', + :type => 'workflow', + :description => 'Openstack workflow Service' + ) } + + end + + describe 'when disabling user and user role configuration' do + + let :params do + { + :password => 'mistral_password', + :configure_user => false, + :configure_user_role => false + } + end + + it { is_expected.not_to contain_keystone_user('mistral') } + it { is_expected.not_to contain_keystone_user_role('mistral@services') } + it { is_expected.to contain_keystone_service('mistral').with( + :ensure => 'present', + :type => 'workflow', + :description => 'Openstack workflow Service' + ) } + + end + +end diff --git a/spec/classes/mistral_logging_spec.rb b/spec/classes/mistral_logging_spec.rb new file mode 100644 index 0000000..de04985 --- /dev/null +++ b/spec/classes/mistral_logging_spec.rb @@ -0,0 +1,107 @@ +require 'spec_helper' + +describe 'mistral::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/mistral/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 'mistral-logging' do + + context 'with extended logging options' do + before { params.merge!( log_params ) } + it_configures 'logging params set' + end + + context 'without extended logging options' do + it_configures 'logging params unset' + end + + end + + shared_examples_for 'logging params set' do + it 'enables logging params' do + is_expected.to contain_mistral_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_mistral_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_mistral_config('DEFAULT/logging_debug_format_suffix').with_value( + '%(funcName)s %(pathname)s:%(lineno)d') + + is_expected.to contain_mistral_config('DEFAULT/logging_exception_prefix').with_value( + '%(asctime)s.%(msecs)03d %(process)d TRACE %(name)s %(instance)s') + + is_expected.to contain_mistral_config('DEFAULT/log_config_append').with_value( + '/etc/mistral/logging.conf') + is_expected.to contain_mistral_config('DEFAULT/publish_errors').with_value( + true) + + is_expected.to contain_mistral_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_mistral_config('DEFAULT/fatal_deprecations').with_value( + true) + + is_expected.to contain_mistral_config('DEFAULT/instance_format').with_value( + '[instance: %(uuid)s] ') + + is_expected.to contain_mistral_config('DEFAULT/instance_uuid_format').with_value( + '[instance: %(uuid)s] ') + + is_expected.to contain_mistral_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_mistral_config("DEFAULT/#{param}").with_ensure('absent') } + } + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'mistral-logging' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'mistral-logging' + end + +end diff --git a/spec/classes/mistral_policy_spec.rb b/spec/classes/mistral_policy_spec.rb new file mode 100644 index 0000000..09c1a58 --- /dev/null +++ b/spec/classes/mistral_policy_spec.rb @@ -0,0 +1,41 @@ +require 'spec_helper' + +describe 'mistral::policy' do + + shared_examples_for 'mistral policies' do + let :params do + { + :policy_path => '/etc/mistral/policy.json', + :policies => { + 'context_is_admin' => { + 'key' => 'context_is_admin', + 'value' => 'foo:bar' + } + } + } + end + + it 'set up the policies' do + is_expected.to contain_openstacklib__policy__base('context_is_admin').with({ + :key => 'context_is_admin', + :value => 'foo:bar' + }) + end + end + + context 'on Debian platforms' do + let :facts do + { :osfamily => 'Debian' } + end + + it_configures 'mistral policies' + end + + context 'on RedHat platforms' do + let :facts do + { :osfamily => 'RedHat' } + end + + it_configures 'mistral 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..3df4ced --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,10 @@ +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' +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/mistral_config/ini_setting_spec.rb b/spec/unit/provider/mistral_config/ini_setting_spec.rb new file mode 100644 index 0000000..2797578 --- /dev/null +++ b/spec/unit/provider/mistral_config/ini_setting_spec.rb @@ -0,0 +1,37 @@ +# 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(:mistral_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::Mistral_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::Mistral_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 +end diff --git a/spec/unit/type/mistral_config_spec.rb b/spec/unit/type/mistral_config_spec.rb new file mode 100644 index 0000000..7e21a3f --- /dev/null +++ b/spec/unit/type/mistral_config_spec.rb @@ -0,0 +1,52 @@ +require 'puppet' +require 'puppet/type/mistral_config' +describe 'Puppet::Type.type(:mistral_config)' do + before :each do + @mistral_config = Puppet::Type.type(:mistral_config).new(:name => 'DEFAULT/foo', :value => 'bar') + end + + it 'should require a name' do + expect { + Puppet::Type.type(:mistral_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(:mistral_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(:mistral_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(:mistral_config).new(:name => 'DEFAULT/foo', :ensure => :absent) + end + + it 'should accept a valid value' do + @mistral_config[:value] = 'bar' + expect(@mistral_config[:value]).to eq('bar') + end + + it 'should not accept a value with whitespace' do + @mistral_config[:value] = 'b ar' + expect(@mistral_config[:value]).to eq('b ar') + end + + it 'should accept valid ensure values' do + @mistral_config[:ensure] = :present + expect(@mistral_config[:ensure]).to eq(:present) + @mistral_config[:ensure] = :absent + expect(@mistral_config[:ensure]).to eq(:absent) + end + + it 'should not accept invalid ensure values' do + expect { + @mistral_config[:ensure] = :latest + }.to raise_error(Puppet::Error, /Invalid value/) + end +end diff --git a/templates/openstack-mistral-api.service.erb b/templates/openstack-mistral-api.service.erb new file mode 100644 index 0000000..e2fca34 --- /dev/null +++ b/templates/openstack-mistral-api.service.erb @@ -0,0 +1,12 @@ +[Unit] +Description=OpenStack workflow service (code-named Mistral) +After=syslog.target network.target + +[Service] +Type=simple +Restart=always +User=mistral +ExecStart=/usr/bin/python /usr/lib/python2.7/site-packages/mistral/cmd/launch.py --server api --config-file <%= @conf_file %> + +[Install] +WantedBy=multi-user.target diff --git a/templates/openstack-mistral-engine.service.erb b/templates/openstack-mistral-engine.service.erb new file mode 100644 index 0000000..3066948 --- /dev/null +++ b/templates/openstack-mistral-engine.service.erb @@ -0,0 +1,12 @@ +[Unit] +Description=OpenStack workflow service (code-named Mistral) +After=syslog.target network.target + +[Service] +Type=simple +Restart=always +User=mistral +ExecStart=/usr/bin/python /usr/lib/python2.7/site-packages/mistral/cmd/launch.py --server engine --config-file <%= @conf_file %> + +[Install] +WantedBy=multi-user.target diff --git a/templates/openstack-mistral-executor.service.erb b/templates/openstack-mistral-executor.service.erb new file mode 100644 index 0000000..aef1aba --- /dev/null +++ b/templates/openstack-mistral-executor.service.erb @@ -0,0 +1,12 @@ +[Unit] +Description=OpenStack workflow service (code-named Mistral) +After=syslog.target network.target + +[Service] +Type=simple +Restart=always +User=mistral +ExecStart=/usr/bin/python /usr/lib/python2.7/site-packages/mistral/cmd/launch.py --server executor --config-file <%= @conf_file %> + +[Install] +WantedBy=multi-user.target diff --git a/tests/init.pp b/tests/init.pp new file mode 100644 index 0000000..a121f5e --- /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 ::mistral