diff --git a/.fixtures.yml b/.fixtures.yml new file mode 100644 index 0000000..6f8234f --- /dev/null +++ b/.fixtures.yml @@ -0,0 +1,14 @@ +fixtures: + repositories: + 'inifile': 'git://github.com/puppetlabs/puppetlabs-inifile' + 'keystone': 'git://github.com/stackforge/puppet-keystone.git' + 'mysql': + repo: 'git://github.com/puppetlabs/puppetlabs-mysql.git' + ref: 'origin/2.2.x' + 'openstacklib': 'git://github.com/stackforge/puppet-openstacklib.git' + 'postgresql': + repo: 'git://github.com/puppetlabs/puppet-postgresql.git' + ref: '2.5.0' + 'stdlib': 'git://github.com/puppetlabs/puppetlabs-stdlib.git' + symlinks: + 'trove': "#{source_dir}" diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..da42381 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.swp +spec/fixtures/modules/* +spec/fixtures/manifests/site.pp +Gemfile.lock +.vendor +.bundle/ +vendor/ diff --git a/.gitreview b/.gitreview new file mode 100644 index 0000000..4db59a6 --- /dev/null +++ b/.gitreview @@ -0,0 +1,4 @@ +[gerrit] +host=review.openstack.org +port=29418 +project=stackforge/puppet-tuskar.git diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..d965fa9 --- /dev/null +++ b/Gemfile @@ -0,0 +1,18 @@ +source 'https://rubygems.org' + +group :development, :test do + gem 'puppetlabs_spec_helper', :require => false + gem 'puppet-lint', '~> 0.3.2' + gem 'rake', '10.1.1' + gem 'rspec', '< 2.99' + gem 'json' + gem 'webmock' +end + +if puppetversion = ENV['PUPPET_GEM_VERSION'] + gem 'puppet', puppetversion, :require => false +else + gem 'puppet', :require => false +end + +# vim:ft=ruby diff --git a/LICENSE b/LICENSE index e06d208..68c771a 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,5 @@ -Apache License + + Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ @@ -173,30 +174,3 @@ Apache License incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - diff --git a/README.md b/README.md index 5ac8417..88a9ddb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,54 @@ puppet-tuskar ============= -OpenStack Tuskar Puppet Module http://openstack.org +#### Table of Contents + +1. [Overview - What is the tuskar module?](#overview) +2. [Module Description - What does the module do?](#module-description) +3. [Setup - The basics of getting started with tuskar](#setup) +4. [Implementation - An under-the-hood peek at what the module is doing](#implementation) +5. [Limitations - OS compatibility, etc.](#limitations) +6. [Development - Guide for contributing to the module](#development) +7. [Contributors - Those with commits](#contributors) +8. [Release Notes - Notes on the most recent updates to the module](#release-notes) + +Overview +-------- + +The tuskar module is a part of [Stackforge](https://github.com/stackforge), an effort by the Openstack infrastructure team to provide continuous integration testing and code review for Openstack and Openstack community projects not part of the core software. The module itself is used to flexibly configure and manage the database service for Openstack. + +Module Description +------------------ + +Setup +----- + +**What the tuskar module affects:** + +* tuskar, the management service for Openstack. + +Implementation +-------------- + +### tuskar + +tuskar is a combination of Puppet manifest and ruby code to delivery configuration and extra functionality through types and providers. + +Limitations +----------- + +Development +----------- + +Developer documentation for the entire puppet-openstack project. + +* https://wiki.openstack.org/wiki/Puppet-openstack#Developer_documentation + +Contributors +------------ + +* https://github.com/enovance/puppet-tuskar/graphs/contributors + +Release Notes +------------- -Work in progress for now. diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..84c9a70 --- /dev/null +++ b/Rakefile @@ -0,0 +1,9 @@ +require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' + +PuppetLint.configuration.fail_on_warnings = true +PuppetLint.configuration.send('disable_80chars') +PuppetLint.configuration.send('disable_class_parameter_defaults') + +task(:default).clear +task :default => [:spec, :lint] diff --git a/examples/site.pp b/examples/site.pp new file mode 100644 index 0000000..e7cc999 --- /dev/null +++ b/examples/site.pp @@ -0,0 +1,27 @@ +# This is an example of site.pp to deploy Tuskar + +class { 'tuskar::client': } + +class { 'tuskar::keystone::auth': + admin_address => '10.0.0.1', + internal_address => '10.0.0.1', + public_address => '10.0.0.1', + password => 'verysecrete', + region => 'OpenStack' +} + +class { 'tuskar::db::mysql': + password => 'dbpass', + host => '10.0.0.1', + allowed_hosts => '10.0.0.1' +} + +class { 'tuskar': + database_connection => 'mysql://tuskar:secrete@10.0.0.1/tuskar?charset=utf8', +} + +class { 'tuskar::api': + bind_host => '10.0.0.1', + identity_uri => 'https://identity.openstack.org:35357', + keystone_password => 'verysecrete' +} diff --git a/lib/puppet/provider/tuskar.rb b/lib/puppet/provider/tuskar.rb new file mode 100644 index 0000000..63c9d7d --- /dev/null +++ b/lib/puppet/provider/tuskar.rb @@ -0,0 +1,113 @@ +require 'json' +require 'puppet/util/inifile' + +class Puppet::Provider::Tuskar < Puppet::Provider + + def self.conf_filename + '/etc/tuskar/tuskar.conf' + end + + def self.withenv(hash, &block) + saved = ENV.to_hash + hash.each do |name, val| + ENV[name.to_s] = val + end + + yield + ensure + ENV.clear + saved.each do |name, val| + ENV[name] = val + end + end + + def self.tuskar_credentials + @tuskar_credentials ||= get_tuskar_credentials + end + + def self.get_tuskar_credentials + auth_keys = ['auth_host', 'auth_port', 'auth_protocol', + 'admin_tenant_name', 'admin_user', 'admin_password'] + conf = tuskar_conf + if conf and conf['keystone_authtoken'] and + auth_keys.all?{|k| !conf['keystone_authtoken'][k].nil?} + return Hash[ auth_keys.map \ + { |k| [k, conf['keystone_authtoken'][k].strip] } ] + else + raise(Puppet::Error, "File: #{conf_filename} does not contain all \ +required sections. Tuskar types will not work if tuskar is not \ +correctly configured.") + end + end + + def tuskar_credentials + self.class.tuskar_credentials + end + + def self.auth_endpoint + @auth_endpoint ||= get_auth_endpoint + end + + def self.get_auth_endpoint + q = tuskar_credentials + "#{q['auth_protocol']}://#{q['auth_host']}:#{q['auth_port']}/v2.0/" + end + + def self.tuskar_conf + return @tuskar_conf if @tuskar_conf + @tuskar_conf = Puppet::Util::IniConfig::File.new + @tuskar_conf.read(conf_filename) + @tuskar_conf + end + + def self.auth_tuskar(*args) + q = tuskar_credentials + authenv = { + :OS_AUTH_URL => self.auth_endpoint, + :OS_USERNAME => q['admin_user'], + :OS_TENANT_NAME => q['admin_tenant_name'], + :OS_PASSWORD => q['admin_password'] + } + begin + withenv authenv do + tuskar(args) + end + rescue Exception => e + if (e.message =~ /\[Errno 111\] Connection refused/) or + (e.message =~ /\(HTTP 400\)/) + sleep 10 + withenv authenv do + tuskar(args) + end + else + raise(e) + end + end + end + + def auth_tuskar(*args) + self.class.auth_tuskar(args) + end + + def tuskar_manage(*args) + cmd = args.join(" ") + output = `#{cmd}` + $?.exitstatus + end + + def self.reset + @tuskar_conf = nil + @tuskar_credentials = nil + end + + def self.list_tuskar_resources(type, *args) + json = auth_tuskar("--json", "#{type}-list", *args) + return JSON.parse(json) + end + + def self.get_tuskar_resource_attrs(type, id) + json = auth_tuskar("--json", "#{type}-show", id) + return JSON.parse(json) + end + +end diff --git a/lib/puppet/provider/tuskar_config/ini_setting.rb b/lib/puppet/provider/tuskar_config/ini_setting.rb new file mode 100644 index 0000000..4bd0867 --- /dev/null +++ b/lib/puppet/provider/tuskar_config/ini_setting.rb @@ -0,0 +1,27 @@ +Puppet::Type.type(:tuskar_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/tuskar/tuskar.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/tuskar_config.rb b/lib/puppet/type/tuskar_config.rb new file mode 100644 index 0000000..d78cc9e --- /dev/null +++ b/lib/puppet/type/tuskar_config.rb @@ -0,0 +1,42 @@ +Puppet::Type.newtype(:tuskar_config) do + + ensurable + + newparam(:name, :namevar => true) do + desc 'Section/setting name to manage from /etc/tuskar/tuskar.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/api.pp b/manifests/api.pp new file mode 100644 index 0000000..1aeb5b5 --- /dev/null +++ b/manifests/api.pp @@ -0,0 +1,186 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Class tuskar::api +# +# Configure API service in tuskar +# +# == Parameters +# +# [*manage_service*] +# (optional) Whether to start/stop the service +# Defaults to true +# +# [*ensure_package*] +# (optional) Whether the tuskar api package will be installed +# Defaults to 'present' +# +# [*keystone_password*] +# (required) Password used to authentication. +# +# [*verbose*] +# (optional) Rather to log the tuskar api service at verbose level. +# Default: false +# +# [*debug*] +# (optional) Rather to log the tuskar api service at debug level. +# Default: false +# +# [*bind_host*] +# (optional) The address of the host to bind to. +# Default: 0.0.0.0 +# +# [*bind_port*] +# (optional) The port the server should bind to. +# Default: 8585 +# +# [*log_file*] +# (optional) The path of file used for logging +# If set to boolean false, it will not log to any file. +# Default: /var/log/tuskar/tuskar-api.log +# +# [*log_dir*] +# (optional) directory to which tuskar logs are sent. +# If set to boolean false, it will not log to any directory. +# Defaults to '/var/log/tuskar' +# +# [*keystone_tenant*] +# (optional) Tenant to authenticate to. +# Defaults to services. +# +# [*keystone_user*] +# (optional) User to authenticate as with keystone. +# Defaults to 'tuskar'. + +# [*enabled*] +# (optional) Whether to enable services. +# Defaults to true. +# +# [*use_syslog*] +# (optional) Use syslog for logging. +# Defaults to false. +# +# [*log_facility*] +# (optional) Syslog facility to receive log lines. +# Defaults to 'LOG_USER'. +# +# [*purge_config*] +# (optional) Whether to set only the specified config options +# in the api config. +# Defaults to false. +# +# [*identity_uri*] +# (optional) Complete admin Identity API endpoint. +# Defaults to 'http://127.0.0.1:35357'. +# +class tuskar::api( + $keystone_password, + $verbose = false, + $debug = false, + $bind_host = '0.0.0.0', + $bind_port = '8585', + $log_file = '/var/log/tuskar/tuskar-api.log', + $log_dir = '/var/log/tuskar', + $keystone_tenant = 'services', + $keystone_user = 'tuskar', + $identity_uri = 'http://127.0.0.1:35357', + $enabled = true, + $use_syslog = false, + $log_facility = 'LOG_USER', + $purge_config = false, + $manage_service = true, + $ensure_package = 'present', +) inherits tuskar { + + require keystone::python + include tuskar::params + + Tuskar_config<||> ~> Exec['post-tuskar_config'] + Tuskar_config<||> ~> Service['tuskar-api'] + Package['tuskar-api'] -> Tuskar_config<||> + + if $::tuskar::database_connection { + if($::tuskar::database_connection =~ /mysql:\/\/\S+:\S+@\S+\/\S+/) { + require 'mysql::bindings' + require 'mysql::bindings::python' + } elsif($::tuskar::database_connection =~ /postgresql:\/\/\S+:\S+@\S+\/\S+/) { + + } elsif($::tuskar::database_connection =~ /sqlite:\/\//) { + + } else { + fail("Invalid db connection ${::tuskar::database_connection}") + } + tuskar_config { + 'database/sql_connection': value => $::tuskar::database_connection; + 'database/sql_idle_timeout': value => $::tuskar::database_idle_timeoutl; + } + } + + # basic service config + tuskar_config { + 'DEFAULT/verbose': value => $verbose; + 'DEFAULT/debug': value => $debug; + 'DEFAULT/tuskar_api_bind_ip': value => $bind_host; + 'DEFAULT/tuskar_api_port': value => $bind_port; + 'keystone_authtoken/identity_uri' value => $identity_uri; + } + + # Logging + if $log_file { + tuskar_config { + 'DEFAULT/log_file': value => $log_file; + } + } else { + tuskar_config { + 'DEFAULT/log_file': ensure => absent; + } + } + + if $log_dir { + tuskar_config { + 'DEFAULT/log_dir': value => $log_dir; + } + } else { + tuskar_config { + 'DEFAULT/log_dir': ensure => absent; + } + } + + # Syslog + if $use_syslog { + tuskar_config { + 'DEFAULT/use_syslog' : value => true; + 'DEFAULT/syslog_log_facility' : value => $log_facility; + } + } else { + tuskar_config { + 'DEFAULT/use_syslog': value => false; + } + } + + resources { 'tuskar_config': + purge => $purge_config, + } + + tuskar::generic_service { 'api': + enabled => $enabled, + manage_service => $manage_service, + ensure_package => $ensure_package, + package_name => $::tuskar::params::api_package_name, + service_name => $::tuskar::params::api_service_name, + } +} diff --git a/manifests/client.pp b/manifests/client.pp new file mode 100644 index 0000000..7cafb86 --- /dev/null +++ b/manifests/client.pp @@ -0,0 +1,40 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# tuskar::client +# +# Manages the tuskar client package on systems +# +# === Parameters: +# +# [*package_ensure*] +# (optional) The state of the package +# Defaults to present +# +# +class tuskar::client ( + $package_ensure = present +) { + + include tuskar::params + + package { 'python-tuskarclient': + ensure => $package_ensure, + name => $::tuskar::params::client_package_name, + } + +} diff --git a/manifests/db/mysql.pp b/manifests/db/mysql.pp new file mode 100644 index 0000000..a130192 --- /dev/null +++ b/manifests/db/mysql.pp @@ -0,0 +1,83 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Class: tuskar::db::mysql +# +# The tuskar::db::mysql class creates a MySQL database for tuskar. +# It must be used on the MySQL server +# +# === Parameters +# +# [*password*] +# (required) Password that will be used for the tuskar db user. +# +# [*dbname*] +# (optional) Name of tuskar database. +# Defaults to tuskar +# +# [*user*] +# (optional) Name of tuskar user. +# Defaults to tuskar +# +# [*host*] +# (optional) Host where user should be allowed all privileges for database. +# Defaults to 127.0.0.1 +# +# [*allowed_hosts*] +# (optional) Hosts allowed to use the database +# Defaults to undef. +# +# [*charset*] +# (optional) Charset of tuskar database +# Defaults 'utf8'. +# +# [*collate*] +# (optional) Charset collate of tuskar database +# Defaults 'utf8_unicode_ci'. +# +# [*mysql_module*] +# (optional) Deprecated. Does nothing +# +class tuskar::db::mysql( + $password, + $dbname = 'tuskar', + $user = 'tuskar', + $host = '127.0.0.1', + $allowed_hosts = undef, + $charset = 'utf8', + $collate = 'utf8_unicode_ci', + $mysql_module = undef, +) { + + if $mysql_module { + warning('The mysql_module parameter is deprecated. The latest 2.x mysql module will be used.') + } + + validate_string($password) + + ::openstacklib::db::mysql { 'tuskar': + user => $user, + password_hash => mysql_password($password), + dbname => $dbname, + host => $host, + charset => $charset, + collate => $collate, + allowed_hosts => $allowed_hosts, + } + + ::Openstacklib::Db::Mysql['tuskar'] ~> Exec<| title == 'tuskar-dbsync' |> +} diff --git a/manifests/db/postgresql.pp b/manifests/db/postgresql.pp new file mode 100644 index 0000000..3a20c95 --- /dev/null +++ b/manifests/db/postgresql.pp @@ -0,0 +1,36 @@ +# == Class: tuskar::db::postgresql +# +# Manage the tuskar postgresql database +# +# === Parameters: +# +# [*password*] +# (required) Password that will be used for the tuskar db user. +# +# [*dbname*] +# (optionnal) Name of tuskar database. +# Defaults to tuskar +# +# [*user*] +# (optionnal) Name of tuskar user. +# Defaults to tuskar +# +class tuskar::db::postgresql( + $password, + $dbname = 'tuskar', + $user = 'tuskar' +) { + + require postgresql::python + + Class['tuskar::db::postgresql'] -> Service<| title == 'tuskar' |> + Postgresql::Db[$dbname] ~> Exec<| title == 'tuskar-dbsync' |> + Package['python-psycopg2'] -> Exec<| title == 'tuskar-dbsync' |> + + + postgresql::db { $dbname: + user => $user, + password => $password, + } + +} diff --git a/manifests/db/sync.pp b/manifests/db/sync.pp new file mode 100644 index 0000000..d8b39e6 --- /dev/null +++ b/manifests/db/sync.pp @@ -0,0 +1,28 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# Class to execute "tuskar-dbsync" +# +class tuskar::db::sync { + exec { 'tuskar-dbsync': + path => '/usr/bin', + user => 'tuskar', + refreshonly => true, + subscribe => [Package['tuskar'], Keystone_config['DEFAULT/sql_connection']], + require => User['tuskar'], + } +} diff --git a/manifests/generic_service.pp b/manifests/generic_service.pp new file mode 100644 index 0000000..916d4d2 --- /dev/null +++ b/manifests/generic_service.pp @@ -0,0 +1,71 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# == Define: tuskar::generic_service +# +# This defined type implements basic tuskar services. +# It is introduced to attempt to consolidate +# common code. +# +# It also allows users to specify ad-hoc services +# as needed +# +# This define creates a service resource with title tuskar-${name} and +# conditionally creates a package resource with title tuskar-${name} +# +define tuskar::generic_service( + $package_name, + $service_name, + $enabled = false, + $manage_service = true, + $ensure_package = 'present' +) { + + include tuskar::params + include tuskar::db::sync + + $tuskar_title = "tuskar-${name}" + Exec['post-tuskar_config'] ~> Service<| title == $tuskar_title |> + Exec<| title == 'tuskar-dbsync' |> ~> Service<| title == $tuskar_title |> + + if ($package_name) { + if !defined(Package[$package_name]) { + package { $tuskar_title: + ensure => $ensure_package, + name => $package_name, + notify => Service[$tuskar_title], + } + } + } + + if $service_name { + if $manage_service { + if $enabled { + $service_ensure = 'running' + } else { + $service_ensure = 'stopped' + } + } + + service { $tuskar_title: + ensure => $service_ensure, + name => $service_name, + enable => $enabled, + hasstatus => true, + } + } +} diff --git a/manifests/init.pp b/manifests/init.pp new file mode 100644 index 0000000..05840a9 --- /dev/null +++ b/manifests/init.pp @@ -0,0 +1,43 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# tuskar::init +# +# Tuskar base config +# +# == Parameters +# +# [*database_connection*] +# (optional) Connection url to connect to tuskar database. +# Defaults to 'sqlite:////var/lib/tuskar/tuskar.sqlite' +# +# [*database_idle_timeout*] +# (optional) Timeout before idle db connections are reaped. +# Defaults to 3600 +# +class tuskar( + $database_connection = 'sqlite:////var/lib/tuskar/tuskar.sqlite', + $database_idle_timeout = 3600, +) { + include tuskar::params + + exec { 'post-tuskar_config': + command => '/bin/echo "Tuskar config has changed"', + refreshonly => true, + } + +} diff --git a/manifests/keystone/auth.pp b/manifests/keystone/auth.pp new file mode 100644 index 0000000..1eb1c12 --- /dev/null +++ b/manifests/keystone/auth.pp @@ -0,0 +1,122 @@ +# +# Copyright (C) 2014 eNovance SAS +# +# Author: Emilien Macchi +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# +# tuskar::keystone::auth +# +# Configures Tuskar user, service and endpoint in Keystone. +# +# === Parameters +# +# [*password*] +# (required) Password for Tuskar user. +# +# [*auth_name*] +# Username for Tuskar service. Defaults to 'tuskar'. +# +# [*email*] +# Email for Tuskar user. Defaults to 'tuskar@localhost'. +# +# [*tenant*] +# Tenant for Tuskar user. Defaults to 'services'. +# +# [*configure_endpoint*] +# Should Tuskar endpoint be configured? Defaults to 'true'. +# +# [*service_type*] +# Type of service. Defaults to 'management'. +# +# [*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 '8585'. +# +# [*public_port*] +# Port for public endpoint. Defaults to $port. +# +# [*region*] +# Region for endpoint. Defaults to 'RegionOne'. +# +# +class tuskar::keystone::auth ( + $password, + $auth_name = 'tuskar', + $email = 'tuskar@localhost', + $tenant = 'services', + $configure_endpoint = true, + $service_type = 'management', + $public_protocol = 'http', + $public_address = '127.0.0.1', + $admin_protocol = 'http', + $admin_address = '127.0.0.1', + $internal_protocol = 'http', + $internal_address = '127.0.0.1', + $port = '8585', + $public_port = undef, + $region = 'RegionOne' +) { + + Keystone_user_role["${auth_name}@${tenant}"] ~> Service <| name == 'tuskar-api' |> + Keystone_endpoint["${region}/${auth_name}"] ~> Service <| name == 'tuskar-api' |> + + if ! $public_port { + $real_public_port = $port + } else { + $real_public_port = $public_port + } + + keystone_user { $auth_name: + ensure => present, + password => $password, + email => $email, + tenant => $tenant, + } + keystone_user_role { "${auth_name}@${tenant}": + ensure => present, + roles => 'admin', + } + keystone_service { $auth_name: + ensure => present, + type => $service_type, + description => 'Tuskar Management Service', + } + + if $configure_endpoint { + keystone_endpoint { "${region}/${auth_name}": + ensure => present, + public_url => "${public_protocol}://${public_address}:${real_public_port}", + internal_url => "${internal_protocol}://${internal_address}:${port}", + admin_url => "${admin_protocol}://${admin_address}:${port}", + } + + } +} diff --git a/manifests/params.pp b/manifests/params.pp new file mode 100644 index 0000000..6472bc5 --- /dev/null +++ b/manifests/params.pp @@ -0,0 +1,21 @@ +# Parameters for puppet-tuskar +# +class tuskar::params { + + case $::osfamily { + 'RedHat': { + $client_package_name = 'openstack-tuskar' + $api_package_name = 'openstack-tuskar-api' + $api_service_name = 'openstack-tuskar-api' + } + 'Debian': { + $client_package_name = 'python-tuskarclient' + $api_package_name = 'tuskar-api' + $api_service_name = 'tuskar-api' + } + default: { + fail("Unsupported osfamily: ${::osfamily} operatingsystem") + } + + } # Case $::osfamily +} diff --git a/metadata.json b/metadata.json new file mode 100644 index 0000000..7406184 --- /dev/null +++ b/metadata.json @@ -0,0 +1,39 @@ +{ + "name": "stackforge-tuskar", + "version": "5.0.0", + "author": "eNovance and StackForge Contributors", + "summary": "Puppet module for OpenStack Tuskar", + "license": "Apache License 2.0", + "source": "git://github.com/stackforge/puppet-tuskar.git", + "project_page": "https://launchpad.net/puppet-tuskar", + "issues_url": "https://bugs.launchpad.net/puppet-tuskar", + "requirements": [ + { "name": "pe","version_requirement": "3.x" }, + { "name": "puppet","version_requirement": "3.x" } + ], + "operatingsystem_support": [ + { + "operatingsystem": "Debian", + "operatingsystemrelease": ["7"] + }, + { + "operatingsystem": "Fedora", + "operatingsystemrelease": ["20"] + }, + { + "operatingsystem": "RedHat", + "operatingsystemrelease": ["6.5","7"] + }, + { + "operatingsystem": "Ubuntu", + "operatingsystemrelease": ["12.04","14.04"] + } + ], + "description": "Installs and configures OpenStack Tuskar (Management service).", + "dependencies": [ + { "name": "puppetlabs/inifile", "version_requirement": ">=1.0.0 <2.0.0" }, + { "name": "stackforge/keystone", "version_requirement": ">=5.0.0 <6.0.0" }, + { "name": "puppetlabs/stdlib", "version_requirement": ">=4.0.0 <5.0.0" }, + { "name": "stackforge/openstacklib", "version_requirement": ">=5.0.0" } + ] +} diff --git a/spec/shared_examples.rb b/spec/shared_examples.rb new file mode 100644 index 0000000..d0c2fe9 --- /dev/null +++ b/spec/shared_examples.rb @@ -0,0 +1,56 @@ +shared_examples_for "a Puppet::Error" do |description| + it "with message matching #{description.inspect}" do + expect { should have_class_count(1) }.to raise_error(Puppet::Error, description) + end +end + +shared_examples 'generic Tuskar service' do |service| + + context 'with default parameters' do + it 'installs package and service' do + should contain_package(service[:name]).with({ + :name => service[:package_name], + :ensure => 'present', + :notify => "Service[#{service[:name]}]" + }) + should contain_service(service[:name]).with({ + :name => service[:service_name], + :ensure => 'stopped', + :hasstatus => true, + :enable => false + }) + end + end + + context 'with overridden parameters' do + let :params do + { :enabled => true, + :ensure_package => '2014.1-1' } + end + + it 'installs package and service' do + should contain_package(service[:name]).with({ + :name => service[:package_name], + :ensure => '2014.1-1', + :notify => "Service[#{service[:name]}]" + }) + should contain_service(service[:name]).with({ + :name => service[:service_name], + :ensure => 'running', + :hasstatus => true, + :enable => true + }) + end + end + + context 'while not managing service state' do + let :params do + { :enabled => false, + :manage_service => false } + end + + it 'does not control service state' do + should contain_service(service[:name]).without_ensure + end + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..53d4dd0 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,7 @@ +require 'puppetlabs_spec_helper/module_spec_helper' +require 'shared_examples' + +RSpec.configure do |c| + c.alias_it_should_behave_like_to :it_configures, 'configures' + c.alias_it_should_behave_like_to :it_raises, 'raises' +end