diff --git a/README.md b/README.md index 40a8efd..4e02df5 100644 --- a/README.md +++ b/README.md @@ -1,634 +1,635 @@ [![Build Status](https://travis-ci.org/Icinga/puppet-icinga2.svg?branch=master)](https://travis-ci.org/Icinga/puppet-icinga2) # Icinga 2 Puppet Module ![Icinga Logo](https://www.icinga.com/wp-content/uploads/2014/06/icinga_logo.png) #### Table of Contents 1. [Overview](#overview) 2. [Module Description - What the module does and why it is useful](#module-description) 3. [Setup - The basics of getting started with icinga2](#setup) 4. [Usage - Configuration options and additional functionality](#usage) * [Installing Icinga](#installing-icinga) * [Clustering Icinga](#clustering-icinga) * [Config Objects](#config-objects) * [Reading objects from hiera](#Reading-objects-from-hiera) * [Apply Rules](#apply-rules) * [Custom configuration](#custom-configuration) 5. [How Configuration is parsed](#how-configuration-is-parsed) 6. [Reference](#reference) 7. [Release Notes](#release-notes) ## Overview Icinga 2 is a widely used open source monitoring software. This Puppet module helps with installing and managing configuration of Icinga 2 on multiple operating systems. ### What's new in version 3.0.0 * The current version now uses the icinga :: repos class from the new `icinga` module for the configuration of repositories including EPEL on RedHat and Backports on Debian. (see https://github.com/icinga/puppet-icinga) * `manage_repos` will replace `manage_repo` in the future +* `manage_packages` will replace `manage_package` in the future * Since Icinga v2.12.0 the fingerprint to validate certificates is a sha256 instead of a sha1. Both is supported now. ## Module Description This module installs and configures Icinga 2 on your Linux or Windows hosts. By default it uses packages provided by your distribution's repository or [Chocolatey] on Windows. The module can also be configured to use [packages.icinga.com] as the primary repository, which enables you to install Icinga 2 versions that are newer than the ones provided by your distribution's vendor. All features and objects available in Icinga 2 can be enabled and configured with this module. ## Setup ### What the Icinga 2 Puppet module supports * Installation of packages * Configuration of features * Configuration of objects (also apply rules) * Service * MySQL / PostgreSQL Database Schema Import * Repository Management * Certification Authority ### Dependencies This module supports: -* [puppet] >= 4.10 < 7.0.0 +* [puppet] >= 4.10 < 8.0.0 And depends on: -* [puppetlabs/stdlib] >= 4.16.0 < 7.0.0 +* [puppetlabs/stdlib] >= 5.0.0 < 8.0.0 * If Puppet 6 is used a stdlib 5.1 or higher is required, see https://github.com/Icinga/puppet-icinga2/issues/505 -* [puppetlabs/concat] >= 2.1.0 < 7.0.0 -* [icinga/icinga] >= 1.0.0 < 2.0.0 +* [puppetlabs/concat] >= 2.1.0 < 8.0.0 +* [icinga/icinga] >= 1.0.0 < 3.0.0 * needed if `manage_repos` is set to `true` ### Limitations This module has been tested on: * Ruby >= 1.9 * Debian 8, 9, 10 * Ubuntu 16.04, 18.04, 20.04 * CentOS/RHEL 6, 7, 8 * Fedora 31 * FreeBSD 10, 11 * SLES 12, 15 -* Windows Server 2012 R2, 2016 +* Windows Server 2016 Other operating systems or versions may work but have not been tested. ## Usage ### Installing Icinga The default class `icinga2` installs and configures a basic installation of Icinga 2. The features `checker`, `mainlog` and `notification` are enabled by default. By default, your distribution's packages are used to install Icinga 2. On Windows systems we use the [Chocolatey] package manager. Use the `manage_repos` parameter to configure repositories by default the official and stable [packages.icinga.com]. To configure your own repositories, or use the official testing or nightly snapshot stage, see https://github.com/icinga/puppet-icinga. ``` puppet class { '::icinga2': manage_repos => true, } ``` If you want to manage the version of Icinga 2, you have to disable the package management of this module and handle packages in your own Puppet code. The attribute `manage_repos` is disabled by default and you have to manage a repository within icinga in front of the package resource. You can combine this one with the section before about repositories. ``` puppet # class of extra module icinga/icinga include ::icinga::repos package { 'icinga2': ensure => latest, notify => Class['icinga2'], } class { '::icinga2': manage_package => false, } ``` Note: Be careful with this option: Setting `manage_package` to false means that this module will not install any package at all, including IDO packages! ### Clustering Icinga Icinga 2 can run in three different roles: * in a master zone which is on top of the hierarchy * in a satellite zone which is a child of a satellite or master zone * a standalone client node/zone which works as an agent connected to master and/or satellite zones To learn more about Icinga 2 Clustering, follow the official docs on [distributed monitoring]. The following examples show how these roles can be configured using this Puppet module. #### Master A Master zone has no parent and is usually also the place where you enable the IDO and notification features. A master sends configurations over the Icinga 2 protocol to satellites and/or clients. More detailed examples can be found in the [examples] directory. This example creates the configuration for a master that has one satellite connected. A global zone is created for templates, and all features of a typical master are enabled. ``` puppet class { '::icinga2': confd => false, constants => { 'ZoneName' => 'master', 'TicketSalt' => '5a3d695b8aef8f18452fc494593056a4', }, } class { '::icinga2::feature::api': pki => 'none', accept_commands => true, # when having multiple masters, you have to enable: accept_config => true, endpoints => { 'master.example.org' => {}, 'satellite.example.org' => { 'host' => '172.16.2.11' }, }, zones => { 'master' => { 'endpoints' => ['master.example.org'], }, 'dmz' => { 'endpoints' => ['satellite.example.org'], 'parent' => 'master', }, } } # to enable a CA on this instance you have to declare. Only one instance is allowed to be a CA: include ::icinga2::pki::ca icinga2::object::zone { 'global-templates': global => true, } ``` #### Satellite A satellite has a parent zone and one or multiple child zones. Satellites are usually created to distribute the monitoring load or to reach delimited zones in the network. A satellite either executes checks itself or delegates them to a client. The satellite has fewer features enabled, but executes checks similar to a master. It connects to a master zone, and to a satellite or client below in the hierarchy. As parent acts either the master zone, or another satellite zone. ``` puppet class { '::icinga2': confd => false, # setting dedicated feature list to disable notification features => ['checker','mainlog'], constants => { 'ZoneName' => 'dmz', }, } class { '::icinga2::feature::api': accept_config => true, accept_commands => true, ca_host => '172.16.1.11', ticket_salt => '5a3d695b8aef8f18452fc494593056a4', # to increase your security set fingerprint to validate the certificate of ca_host # fingerprint => 'D8:98:82:1B:14:8A:6A:89:4B:7A:40:32:50:68:01:D8:98:82:1B:14:8A:6A:89:4B:7A:40:32:99:3D:96:72:72', endpoints => { 'satellite.example.org' => {}, 'master.example.org' => { 'host' => '172.16.1.11', }, }, zones => { 'master' => { 'endpoints' => ['master.example.org'], }, 'dmz' => { 'endpoints' => ['satellite.example.org'], 'parent' => 'master', }, } } icinga2::object::zone { 'global-templates': global => true, } ``` #### Agent Icinga 2 runs as a client usually on each of your servers. It receives config or commands from a satellite or master zones and runs the checks that have to be executed locally. The client is connected to the satellite, which is the direct parent zone. ``` puppet class { '::icinga2': confd => false, features => ['mainlog'], } class { '::icinga2::feature::api': accept_config => true, accept_commands => true, ticket_salt => '5a3d695b8aef8f18452fc494593056a4', # to increase your security set fingerprint to validate the certificate of ca_host # fingerprint => 'D8:98:82:1B:14:8A:6A:89:4B:7A:40:32:50:68:01:D8:98:82:1B:14:8A:6A:89:4B:7A:40:32:99:3D:96:72:72', endpoints => { 'NodeName' => {}, 'satellite.example.org' => { 'host' => '172.16.2.11', }, }, zones => { 'ZoneName' => { 'endpoints' => ['NodeName'], 'parent' => 'dmz', }, 'dmz' => { 'endpoints' => ['satellite.example.org'], }, } } icinga2::object::zone { 'global-templates': global => true, } ``` The parameter `fingerprint` is optional and new since v2.1.0. It's used to validate the certificate of the CA host. You can get the fingerprint via `openssl x509 -noout -fingerprint -sha256 -inform pem -in master.crt` on the master host. (Icinga2 versions before 2.12.0 require '-sha1' as digest algorithm.) ### Config Objects With this module you can create almost every object that Icinga 2 knows about. When creating objects some parameters are required. This module sets the same requirements as Icinga 2 does. When creating an object you must set a target for the configuration. Here are some examples for some object types: #### Host ``` puppet icinga2::object::host { 'srv-web1.fqdn.com': display_name => 'srv-web1.fqdn.com', address => '127.0.0.1', address6 => '::1', check_command => 'hostalive', target => '/etc/icinga2/conf.d/srv-web1.fqdn.com.conf', } ``` #### Service ``` puppet icinga2::object::service { 'uptime': host_name => 'srv-web1.fqdn.com', display_name => 'Uptime', check_command => 'check_uptime', check_interval => '600m', groups => ['uptime', 'linux'], target => '/etc/icinga2/conf.d/uptime.conf', } ``` #### Hostgroup ``` puppet icinga2::object::hostgroup { 'monitoring-hosts': display_name => 'Linux Servers', groups => [ 'linux-servers' ], target => '/etc/icinga2/conf.d/groups2.conf', assign => [ 'host.vars.os == linux' ], } ``` ### Reading objects from hiera The following example shows how icinga2 objects can be read from a hiera datastore. See also examples/objects_from_hiera.pp. ``` class { 'icinga2': manage_repos => true, } $defaults = lookup('monitoring::defaults', undef, undef, {}) lookup('monitoring::objects').each |String $object_type, Hash $content| { $content.each |String $object_name, Hash $object_config| { ensure_resource( $object_type, $object_name, deep_merge($defaults[$object_type], $object_config)) } } ``` The datastore could be like: ``` --- monitoring::objects: 'icinga2::object::host': centos7.localdomain: address: 127.0.0.1 vars: os: Linux 'icinga2::object::service': ping4: check_command: ping4 apply: true assign: - host.address ssh: check_command: ssh apply: true assign: - host.address && host.vars.os == Linux monitoring::defaults: 'icinga2::object::host': import: - generic-host target: /etc/icinga2/conf.d/hosts.conf 'icinga2::object::service': import: - generic-service target: /etc/icinga2/conf.d/services.conf ``` ### Apply Rules Some objects can be applied to other objects. To create a simple apply rule you must set the `apply` parameter to `true`. If this parameter is set to a string, this string will be used to build an `apply for` loop. A service object always targets a host object. All other objects need to explicitly set an `apply_target` Apply a SSH service to all Linux hosts: ``` icinga2::object::service { 'SSH': target => '/etc/icinga2/conf.d/test.conf', apply => true, assign => [ 'host.vars.os == Linux' ], ignore => [ 'host.vars.os == Windows' ], display_name => 'Test Service', check_command => 'ssh', } ``` Apply notifications to services: ``` icinga2::object::notification { 'testnotification': target => '/etc/icinga2/conf.d/test.conf', apply => true, apply_target => 'Service', assign => [ 'host.vars.os == Linux' ], ignore => [ 'host.vars.os == Windows' ], user_groups => ['icingaadmins'] } ``` Assign all Linux hosts to a hostgroup: ``` icinga2::object::hostgroup { 'monitoring-hosts': display_name => 'Linux Servers', groups => [ 'linux-servers' ], target => '/etc/icinga2/conf.d/groups2.conf', assign => [ 'host.vars.os == linux' ], } ``` A loop to create HTTP services for all vHosts of a host object: ``` icinga2::object::service { 'HTTP': target => '/etc/icinga2/conf.d/http.conf', apply => 'http_vhost => config in host.vars_http_vhost', assign => [ 'host.vars.os == Linux' ], display_name => 'HTTP Service', check_command => 'http', } ``` ### Custom Configuration Sometimes it's necessary to cover very special configurations, that you cannot handle with this module. In this case you can use the `icinga2::config::file` tag on your file resource. The module collects all file resource types with this tag and triggers a reload of Icinga 2 on a file change. ``` include ::icinga2 file { '/etc/icinga2/conf.d/for-loop.conf': ensure => file, source => '...', tag => 'icinga2::config::file', } ``` ## How Configuration is parsed To generate a valid Icinga 2 configuration all object attributes are parsed. This simple parsing algorithm takes a decision for each attribute, whether part of the string is to be quoted or not, and how an array or dictionary is to be formatted. Parsing of a single attribute can be disabled by tagging it with -: at the front of the string. ``` attr => '-:"unparsed string with quotes"' ``` An array, a hash or a string can be assigned to an object attribute. True and false are also valid values. Hashes and arrays are created recursively, and all parts – such as single items of an array, keys and its values are parsed separately as strings. Strings are parsed in chunks, by splitting the original string into separate substrings at specific keywords (operators) such as `+`, `-`, `in`, `&&`, `||`, etc. **NOTICE**: This splitting only works for keywords that are surrounded by whitespace, e.g.: ``` attr => 'string1 + string2 - string3' ``` The algorithm will loop over the parameter and start by splitting it into 'string1' and 'string2 - string3'. 'string1' will be passed to the sub function 'value_types' and then the algorithm will continue parsing the rest of the string ('string2 - string3'), splitting it, passing it to value_types, etc. Brackets are parsed for expressions: ``` attr => '3 * (value1 - value2) / 2' ``` The parser also detects function calls and will parse all parameters separately. ``` attr => 'function(param1, param2, ...)' ``` True and false can be used as either booleans or strings. ``` attrs => true or attr => 'true' ``` In Icinga you can write your own lambda functions with {{ ... }}. For Puppet use: ``` attrs => '{{ ... }}' ``` The parser analyzes which parts of the string have to be quoted and which do not. As a general rule, all fragments are quoted except for the following: * Boolean: `true`, `false` * Numbers: `3` or `2.5` * Time Intervals: `3m` or `2.5h` (s = seconds, m = minutes, h = hours, d = days) * Functions: `{{ ... }}` or function `()` `{}` * All constants, which are declared in the constants parameter in main class `icinga2` * `NodeName` * Names of attributes that belong to the same type of object: * e.g. `name` and `check_command` for a host object * All attributes or variables (custom attributes) from the host, service or user contexts: * `host.name`, `service.check_command`, `user.groups`, ... Assignment with += and -=: Now it's possible to build an Icinga DSL code snippet like ``` vars += config ``` simply use a string with the prefix '+ ', e.g. ``` vars => '+ config', ``` The blank between + and the proper string 'config' is imported for the parser because numbers ``` attr => '+ -14', ``` are also possible now. For numbers -= can be built, too: ``` attr => '- -14', ``` Arrays can also be marked to merge with '+' or reduce by '-' as the first item of the array: ``` attr => [ '+', item1, item2, ... ] ``` Result: attr += [ item1, item2, ... ] ``` attr => [ '-', item1, item2, ... ] ``` Result: attr -= [ item1, item2, ... ] That all works for attributes and custom attributes! Finally dictionaries can be merged when a key '+' is set: ``` attr => { '+' => true, 'key1' => 'val1', } ``` Result: ``` attr += { "key1" = "val1" } ``` If 'attr' is a custom attribute this just works since level 3 of the dictionary: ``` vars => { 'level1' => { 'level2' => { 'level3' => { '+' => true, ... }, }, }, }, ``` Parsed to: ``` vars.level1["level2"] += level3 ``` Now it's also possible to add multiple custom attributes: ``` vars => [ { 'a' => '1', 'b' => '2', }, 'config', { 'c' => { 'd' => { '+' => true, 'e' => '5', }, }, }, ], ``` And you'll get: ``` vars.a = "1" vars.b = "2" vars += config vars.c["d"] += { "e" = "5" } ``` Note: Using an Array always means merge '+=' all items to vars. ##### What isn't supported? It's not currently possible to use dictionaries in a string WITH nested array or hash, like ``` attr1 => 'hash1 + { item1 => value1, item2 => [ value1, value2 ], ... ]' attr2 => 'hash2 + { item1 => value1, item2 => { ... },... }' ``` ## Reference See [REFERENCE.md](https://github.com/Icinga/puppet-icinga2/blob/master/REFERENCE.md) ## Release Notes When releasing new versions we refer to [SemVer 1.0.0] for version numbers. All steps required when creating a new release are described in [RELEASE.md](https://github.com/Icinga/puppet-icinga2/blob/master/RELEASE.md) See also [CHANGELOG.md](https://github.com/Icinga/puppet-icinga2/blob/master/CHANGELOG.md) [distributed monitoring]: http://docs.icinga.com/icinga2/latest/doc/module/icinga2/chapter/distributed-monitoring [puppetlabs/stdlib]: https://github.com/puppetlabs/puppetlabs-stdlib [puppetlabs/concat]: https://github.com/puppetlabs/puppetlabs-concat [puppetlabs/apt]: https://github.com/puppetlabs/puppetlabs-apt [puppetlabs/chocolatey]: https://github.com/puppetlabs/puppetlabs-chocolatey [puppet/zypprepo]: https://forge.puppet.com/puppet/zypprepo [puppetlabs/mysql]: https://github.com/puppetlabs/puppetlabs-mysql [puppetlabs/puppetlabs-postgresql]: https://github.com/puppetlabs/puppetlabs-postgresql [puppet-icinga2]: https://github.com/icinga/puppet-icinga2 [packages.icinga.com]: https://packages.icinga.com [Chocolatey]: https://chocolatey.org [SemVer 1.0.0]: http://semver.org/spec/v1.0.0.html [CONTRIBUTING.md]: CONTRIBUTING.md [TESTING.md]: TESTING.md [RELEASE.md]: RELEASE.md [CHANGELOG.md]: CHANGELOG.md [AUTHORS]: AUTHORS diff --git a/examples/init_package.pp b/examples/init_package.pp index 3930527..9af5ff4 100644 --- a/examples/init_package.pp +++ b/examples/init_package.pp @@ -1,10 +1,10 @@ include ::icinga2::repo package { 'icinga2': ensure => latest, notify => Class['icinga2'], } class { '::icinga2': - manage_package => false, + manage_packages => false, } diff --git a/examples/init_package_idomysql.pp b/examples/init_package_idomysql.pp index e9fd21e..db7f6b8 100644 --- a/examples/init_package_idomysql.pp +++ b/examples/init_package_idomysql.pp @@ -1,12 +1,12 @@ include ::icinga2::repo package { ['icinga2', 'icinga2-ido-mysql']: ensure => latest, notify => Class['icinga2'], } class { 'icinga2': - manage_package => false, + manage_packages => false, } include icinga2::feature::idomysql diff --git a/examples/init_package_idopgsql.pp b/examples/init_package_idopgsql.pp index 97596d6..b06e67b 100644 --- a/examples/init_package_idopgsql.pp +++ b/examples/init_package_idopgsql.pp @@ -1,18 +1,18 @@ include ::icinga2::repo package { ['icinga2', 'icinga2-ido-pgsql']: ensure => latest, notify => Class['icinga2'], } class{ 'icinga2': - manage_package => false, + manage_packages => false, } class{ 'icinga2::feature::idopgsql': host => "127.0.0.1", user => "icinga2", password => "icinga2", database => "icinga2", import_schema => true } diff --git a/manifests/feature/idomysql.pp b/manifests/feature/idomysql.pp index 283dc8a..02e8a5c 100644 --- a/manifests/feature/idomysql.pp +++ b/manifests/feature/idomysql.pp @@ -1,330 +1,331 @@ # @summary # Installs and configures the Icinga 2 feature ido-mysql. # # @example The ido-mysql featue requires an existing database and a user with permissions. This example uses the [puppetlabs/mysql](https://forge.puppet.com/puppetlabs/mysql) module. # include mysql::server # # mysql::db { 'icinga2': # user => 'icinga2', # password => 'supersecret', # host => 'localhost', # grant => ['SELECT', 'INSERT', 'UPDATE', 'DELETE', 'DROP', 'CREATE VIEW', 'CREATE', 'INDEX', 'EXECUTE', 'ALTER'], # } # # class{ 'icinga2::feature::idomysql': # user => "icinga2", # password => "supersecret", # database => "icinga2", # import_schema => true, # require => Mysql::Db['icinga2'] # } # # @param [Enum['absent', 'present']] ensure # Set to present enables the feature ido-mysql, absent disables it. # # @param [Stdlib::Host] host # MySQL database host address. # # @param [Optional[Stdlib::Port::Unprivileged]] port # MySQL database port. # # @param [Optional[Stdlib::Absolutepath]] socket_path # MySQL socket path. # # @param [String] user # MySQL database user with read/write permission to the icinga database. # # @param [String] password # MySQL database user's password. The password parameter isn't parsed anymore. # # @param [String] database # MySQL database name. # # @param [Boolean] enable_ssl # Either enable or disable SSL/TLS. Other SSL parameters are only affected if this is set to 'true'. # # @param [Optional[Stdlib::Absolutepath]] ssl_key_path # Location of the private key. Only valid if ssl is enabled. # # @param [Optional[Stdlib::Absolutepath]] ssl_cert_path # Location of the certificate. Only valid if ssl is enabled. # # @param [Optional[Stdlib::Absolutepath]] ssl_cacert_path # Location of the CA certificate. Only valid if ssl is enabled. # # @param [Optional[Stdlib::Base64]] ssl_key # The private key in a base64 encoded string to store in spicified ssl_key_path file. # Only valid if ssl is enabled. # # @param [Optional[tdlib::Base64]] ssl_cert # The certificate in a base64 encoded string to store in spicified ssl_cert_path file. # Only valid if ssl is enabled. # # @param [Optional[tdlib::Base64]] ssl_cacert # The CA root certificate in a base64 encoded string to store in spicified ssl_cacert_path file. # Only valid if ssl is enabled. # # @param [Optional[Stdlib::Absolutepath]] ssl_capath # MySQL SSL trusted SSL CA certificates in PEM format directory path. Only valid if ssl is enabled. # # @param [Optional[String]] ssl_cipher # MySQL SSL list of allowed ciphers. Only valid if ssl is enabled. # # @param [Optional[String]] table_prefix # MySQL database table prefix. # # @param [Optional[String]] instance_name # Unique identifier for the local Icinga 2 instance. # # @param [Optional[String]] instance_description # Description for the Icinga 2 instance. # # @param [Optional[Boolean]] enable_ha # Enable the high availability functionality. Only valid in a cluster setup. # # @param [Optional[Icinga2::Interval]] failover_timeout # Set the failover timeout in a HA cluster. Must not be lower than 60s. # # @param [Optional[Hash[String,Icinga2::Interval]]] cleanup # Hash with items for historical table cleanup. # # @param [Optional[Array]] categories # Array of information types that should be written to the database. # # @param [Boolean] import_schema # Whether to import the MySQL schema or not. # class icinga2::feature::idomysql( String $password, Enum['absent', 'present'] $ensure = present, Stdlib::Host $host = 'localhost', Optional[Stdlib::Port::Unprivileged] $port = undef, Optional[Stdlib::Absolutepath] $socket_path = undef, String $user = 'icinga', String $database = 'icinga', Boolean $enable_ssl = false, Optional[Stdlib::Absolutepath] $ssl_key_path = undef, Optional[Stdlib::Absolutepath] $ssl_cert_path = undef, Optional[Stdlib::Absolutepath] $ssl_cacert_path = undef, Optional[Stdlib::Base64] $ssl_key = undef, Optional[Stdlib::Base64] $ssl_cert = undef, Optional[Stdlib::Base64] $ssl_cacert = undef, Optional[Stdlib::Absolutepath] $ssl_capath = undef, Optional[String] $ssl_cipher = undef, Optional[String] $table_prefix = undef, Optional[String] $instance_name = undef, Optional[String] $instance_description = undef, Optional[Boolean] $enable_ha = undef, Optional[Icinga2::Interval] $failover_timeout = undef, Optional[Hash[String,Icinga2::Interval]] $cleanup = undef, Optional[Array] $categories = undef, Boolean $import_schema = false, ) { if ! defined(Class['::icinga2']) { fail('You must include the icinga2 base class before using any icinga2 feature class!') } $owner = $::icinga2::globals::user $group = $::icinga2::globals::group $conf_dir = $::icinga2::globals::conf_dir $ssl_dir = $::icinga2::globals::cert_dir $ido_mysql_package_name = $::icinga2::globals::ido_mysql_package_name $ido_mysql_schema = $::icinga2::globals::ido_mysql_schema $manage_package = $::icinga2::manage_package + $manage_packages = $::icinga2::manage_packages $_ssl_key_mode = $::osfamily ? { 'windows' => undef, default => '0600', } $_notify = $ensure ? { 'present' => Class['::icinga2::service'], default => undef, } # to build mysql exec command to import schema if $import_schema { $_mysql_options = join(any2array(delete_undef_values({ '-h' => $host ? { /localhost/ => undef, default => $host, }, '-P' => $port, '-u' => $user, })), ' ') } File { owner => $owner, group => $group, } if $enable_ssl { # Set defaults for certificate stuff if $ssl_key { if $ssl_key_path { $_ssl_key_path = $ssl_key_path } else { $_ssl_key_path = "${ssl_dir}/IdoMysqlConnection_ido-mysql.key" } $_ssl_key = $::osfamily ? { 'windows' => regsubst($ssl_key, '\n', "\r\n", 'EMG'), default => $ssl_key, } file { $_ssl_key_path: ensure => file, mode => $_ssl_key_mode, content => $ssl_key, tag => 'icinga2::config::file', } } else { $_ssl_key_path = $ssl_key_path } if $ssl_cert { if $ssl_cert_path { $_ssl_cert_path = $ssl_cert_path } else { $_ssl_cert_path = "${ssl_dir}/IdoMysqlConnection_ido-mysql.crt" } $_ssl_cert = $::osfamily ? { 'windows' => regsubst($ssl_cert, '\n', "\r\n", 'EMG'), default => $ssl_cert, } file { $_ssl_cert_path: ensure => file, content => $ssl_cert, tag => 'icinga2::config::file', } } else { $_ssl_cert_path = $ssl_cert_path } if $ssl_cacert { if $ssl_cacert_path { $_ssl_cacert_path = $ssl_cacert_path } else { $_ssl_cacert_path = "${ssl_dir}/IdoMysqlConnection_ido-mysql_ca.crt" } $_ssl_cacert = $::osfamily ? { 'windows' => regsubst($ssl_cacert, '\n', "\r\n", 'EMG'), default => $ssl_cacert, } file { $_ssl_cacert_path: ensure => file, content => $ssl_cacert, tag => 'icinga2::config::file', } } else { $_ssl_cacert_path = $ssl_cacert_path } if $import_schema { $_ssl_options = join(any2array(delete_undef_values({ '--ssl-ca' => $_ssl_cacert_path, '--ssl-cert' => $_ssl_cert_path, '--ssl-key' => $_ssl_key_path, '--ssl-capath' => $ssl_capath, '--ssl-cipher' => $ssl_cipher, })), ' ') # set cli options for mysql connection via tls $_mysql_command = "mysql ${_mysql_options} -p'${password}' ${_ssl_options} ${database}" } $attrs_ssl = { enable_ssl => $enable_ssl, ssl_ca => $_ssl_cacert_path, ssl_cert => $_ssl_cert_path, ssl_key => $_ssl_key_path, ssl_capath => $ssl_capath, ssl_cipher => $ssl_cipher, } } # enable_ssl else { # set cli options for mysql connection if $import_schema { $_mysql_command = "mysql ${_mysql_options} -p'${password}' ${database}" } $attrs_ssl = { enable_ssl => $enable_ssl } } $attrs = { host => $host, port => $port, socket_path => $socket_path, user => $user, password => "-:\"${password}\"", # The password parameter isn't parsed anymore. database => $database, table_prefix => $table_prefix, instance_name => $instance_name, instance_description => $instance_description, enable_ha => $enable_ha, failover_timeout => $failover_timeout, cleanup => $cleanup, categories => $categories, } # install additional package - if $ido_mysql_package_name and $manage_package { + if $ido_mysql_package_name and ($manage_package or $manage_packages) { if $::osfamily == 'debian' { ensure_resources('file', { '/etc/dbconfig-common' => { ensure => directory, owner => 'root', group => 'root' } }) file { "/etc/dbconfig-common/${ido_mysql_package_name}.conf": ensure => file, content => "dbc_install='false'\ndbc_upgrade='false'\ndbc_remove='false'\n", owner => 'root', group => 'root', mode => '0600', before => Package[$ido_mysql_package_name], } } # Debian package { $ido_mysql_package_name: ensure => installed, before => Icinga2::Feature['ido-mysql'], } } # import db schema if $import_schema { - if $ido_mysql_package_name and $manage_package { + if $ido_mysql_package_name and ($manage_package or $manage_packages) { Package[$ido_mysql_package_name] -> Exec['idomysql-import-schema'] } exec { 'idomysql-import-schema': user => 'root', path => $::path, command => "${_mysql_command} < \"${ido_mysql_schema}\"", unless => "${_mysql_command} -Ns -e 'select version from icinga_dbversion'", } } # create object icinga2::object { 'icinga2::object::IdoMysqlConnection::ido-mysql': object_name => 'ido-mysql', object_type => 'IdoMysqlConnection', attrs => delete_undef_values(merge($attrs, $attrs_ssl)), attrs_list => concat(keys($attrs), keys($attrs_ssl)), target => "${conf_dir}/features-available/ido-mysql.conf", order => 10, notify => $_notify, } # import library concat::fragment { 'icinga2::feature::ido-mysql': target => "${conf_dir}/features-available/ido-mysql.conf", content => "library \"db_ido_mysql\"\n\n", order => '05', } icinga2::feature { 'ido-mysql': ensure => $ensure, } } diff --git a/manifests/feature/idopgsql.pp b/manifests/feature/idopgsql.pp index 774fbcb..1b734dc 100644 --- a/manifests/feature/idopgsql.pp +++ b/manifests/feature/idopgsql.pp @@ -1,163 +1,164 @@ # @summary # Installs and configures the Icinga 2 feature ido-pgsql. # # @example The ido-pgsql featue requires an existing database and a user with permissions. This example uses the [puppetlab/postgresql](https://forge.puppet.com/puppetlabs/postgresql) module. # include icinga2 # include postgresql::server # # postgresql::server::db { 'icinga2': # user => 'icinga2', # password => postgresql_password('icinga2', 'supersecret'), # } # # class{ 'icinga2::feature::idopgsql': # user => 'icinga2', # password => 'supersecret', # database => 'icinga2', # import_schema => true, # require => Postgresql::Server::Db['icinga2'] # } # # @param [Enum['absent', 'present']] ensure # Set to present enables the feature ido-pgsql, absent disables it. # # @param [Stdlib::Host] host # PostgreSQL database host address. # # @param [Stdlib::Port::Unprivileged] port # PostgreSQL database port. # # @param [String] user # PostgreSQL database user with read/write permission to the icinga database. # # @param [String] password # PostgreSQL database user's password. The password parameter isn't parsed anymore. # # @param [String] database # PostgreSQL database name. # # @param [Optional[String]] table_prefix # PostgreSQL database table prefix. # # @param [Optional[String]] instance_name # Unique identifier for the local Icinga 2 instance. # # @param [Optional[String]] instance_description # Description of the Icinga 2 instance. # # @param [Optional[Boolean]] enable_ha # Enable the high availability functionality. Only valid in a cluster setup. # # @param [Optional[Icinga2::Interval]] failover_timeout # Set the failover timeout in a HA cluster. Must not be lower than 60s. # # @param [Optional[Hash]] cleanup # Hash with items for historical table cleanup. # # @param [Optional[Array]] categories # Array of information types that should be written to the database. # # @param [Boolean] import_schema # Whether to import the PostgreSQL schema or not. # class icinga2::feature::idopgsql( String $password, Enum['absent', 'present'] $ensure = present, Stdlib::Host $host = 'localhost', Stdlib::Port::Unprivileged $port = 5432, String $user = 'icinga', String $database = 'icinga', Optional[String] $table_prefix = undef, Optional[String] $instance_name = undef, Optional[String] $instance_description = undef, Optional[Boolean] $enable_ha = undef, Optional[Icinga2::Interval] $failover_timeout = undef, Optional[Hash] $cleanup = undef, Optional[Array] $categories = undef, Boolean $import_schema = false, ) { if ! defined(Class['::icinga2']) { fail('You must include the icinga2 base class before using any icinga2 feature class!') } $conf_dir = $::icinga2::globals::conf_dir $ido_pgsql_package_name = $::icinga2::globals::ido_pgsql_package_name $ido_pgsql_schema = $::icinga2::globals::ido_pgsql_schema $manage_package = $::icinga2::manage_package + $manage_packages = $::icinga2::manage_packages $_notify = $ensure ? { 'present' => Class['::icinga2::service'], default => undef, } $attrs = { host => $host, port => $port, user => $user, password => "-:\"${password}\"", # The password parameter isn't parsed anymore. database => $database, table_prefix => $table_prefix, instance_name => $instance_name, instance_description => $instance_description, enable_ha => $enable_ha, failover_timeout => $failover_timeout, cleanup => $cleanup, categories => $categories, } # install additional package - if $ido_pgsql_package_name and $manage_package { + if $ido_pgsql_package_name and ($manage_package or $manage_packages) { if $::osfamily == 'debian' { ensure_resources('file', { '/etc/dbconfig-common' => { ensure => directory, owner => 'root', group => 'root' } }) file { "/etc/dbconfig-common/${ido_pgsql_package_name}.conf": ensure => file, content => "dbc_install='false'\ndbc_upgrade='false'\ndbc_remove='false'\n", owner => 'root', group => 'root', mode => '0600', before => Package[$ido_pgsql_package_name], } } # Debian package { $ido_pgsql_package_name: ensure => installed, before => Icinga2::Feature['ido-pgsql'], } } # import db schema if $import_schema { - if $ido_pgsql_package_name and $manage_package { + if $ido_pgsql_package_name and ($manage_package or $manage_packages) { Package[$ido_pgsql_package_name] -> Exec['idopgsql-import-schema'] } exec { 'idopgsql-import-schema': user => 'root', path => $::path, environment => ["PGPASSWORD=${password}"], command => "psql -h '${host}' -U '${user}' -p '${port}' -d '${database}' -w -f \"${ido_pgsql_schema}\"", unless => "psql -h '${host}' -U '${user}' -p '${port}' -d '${database}' -w -c 'select version from icinga_dbversion'", } } # create object icinga2::object { 'icinga2::object::IdoPgsqlConnection::ido-pgsql': object_name => 'ido-pgsql', object_type => 'IdoPgsqlConnection', attrs => delete_undef_values($attrs), attrs_list => keys($attrs), target => "${conf_dir}/features-available/ido-pgsql.conf", order => 10, notify => $_notify, } # import library concat::fragment { 'icinga2::feature::ido-pgsql': target => "${conf_dir}/features-available/ido-pgsql.conf", content => "library \"db_ido_pgsql\"\n\n", order => '05', } icinga2::feature { 'ido-pgsql': ensure => $ensure, } } diff --git a/manifests/init.pp b/manifests/init.pp index d316054..6861419 100644 --- a/manifests/init.pp +++ b/manifests/init.pp @@ -1,171 +1,179 @@ # @summary # This module installs and configures Icinga 2. # # @example Declare icinga2 with all defaults. Keep in mind that your operating system may not have Icinga 2 in its package repository. # # include ::icinga2 # # @example If you want to use the module icinga/puppet-icinga, e.g. to use the official Icinga Project repositories, enable the manage_repos parameter. # class { 'icinga2': # manage_repos => true, # } # # @example If you don't want to manage the Icinga 2 service with puppet, you can dissable this behaviour with the manage_service parameter. When set to false no service refreshes will be triggered. # class { 'icinga2': # manage_service => false, # } # # @example To manage the version of Icinga 2 binaries you can do it by disable package management: # package { 'icinga2': # ensure => latest, # notifiy => Class['icinga2'], # } # # class { '::icinga2': -# manage_package => false, +# manage_packages => false, # } # -# @note Setting manage_package to false means that all package aren't handeld by the module included the IDO packages. +# @note Setting manage_packages to false means that all package aren't handeld by the module included the IDO packages. # # @example To set constants in etc/icinga2/constants.conf use the constants parameter and as value a hash, every key will be set as constant and assigned by it's value. Defaults can be overwritten. # class { 'icinga2': # ... # constants => { # 'key1' => 'value1', # 'key2' => 'value2', # 'PluginContirbDir' => '/usr/local/nagios/plugins', # } # } # # @example Enabling features with there defaults or loading parameters via Hiera: # class { '::icinga2': # manage_repos => true, # features => ['checker', 'mainlog', 'command'], # } # # @example The ITL contains several CheckCommand definitions to load, set these in the array of the plugins parameter, i.e. for a master or satellite do the following and disbale the load of the configuration in conf.d. # class { 'icinga': # ... # plugins => [ 'plugins', 'contrib-plugins', 'nscp', 'windows-plugins' ], # confd => false, # } # # @example Sometimes it's necessary to cover very special configurations that you cannot handle with this module. In this case you can use the icinga2::config::file tag on your file resource. This module collects all file resource types with this tag and triggers a reload of Icinga 2 on a file change. # include ::icinga2 # # file { '/etc/icinga2/conf.d/foo.conf': # ensure => file, # owner => icinga, # ... # tag => 'icinga2::config::file', # ... # } # # @example To use a different directory for your configuration, create the directory as file resource with tag icinga2::config::file. # file { '/etc/icinga2/local.d': # ensure => directory, # tag => 'icinga2::config::file' # } # class { 'icinga2': # ... # confd => 'local.d', # } # # @param [Stdlib::Ensure::Service] ensure # Manages if the service should be stopped or running. # # @param [Boolean] enable # If set to true the Icinga 2 service will start on boot. # # @param [Boolean] manage_repo # Deprecated, use manage_repos. # # @param [Boolean] manage_repos # When set to true this module will use the module icinga/puppet-icinga to manage repositories, # e.g. the release repo on packages.icinga.com repository by default, the EPEL repository or Backports. # For more information, see http://github.com/icinga/puppet-icinga. # # @param [Boolean] manage_package +# Deprecated, use manage_packages. +# +# @param [Boolean] manage_packages # If set to false packages aren't managed. # # @param [Boolean] manage_selinux # If set to true the icinga selinux package is installed. Requires a `selinux_package_name` (icinga2::globals) -# and `manage_package` has to be set to true. +# and `manage_packages` has to be set to true. # # @param [Boolean] manage_service # If set to true the service is managed otherwise the service also # isn't restarted if a config file changed. # # @param [Array] features # List of features to activate. Defaults to [checker, mainlog, notification]. # # @param [Boolean] purge_features # Define if configuration files for features not managed by Puppet should be purged. # # @param [Hash] constants # Hash of constants. Defaults are set in the params class. Your settings will be merged with the defaults. # # @param [Array] plugins # A list of the ITL plugins to load. Defaults to [ 'plugins', 'plugins-contrib', 'windows-plugins', 'nscp' ]. # # @param [Variant[Boolean, String]] confd # `conf.d` is the directory where Icinga 2 stores its object configuration by default. To disable it, # set this parameter to `false`. By default this parameter is `true`. It's also possible to assign your # own directory. This directory must be managed outside of this module as file resource # with tag icinga2::config::file. # class icinga2 ( Array $features, Array $plugins, - Stdlib::Ensure::Service $ensure = running, - Boolean $enable = true, - Boolean $manage_repo = false, - Boolean $manage_repos = false, - Boolean $manage_package = true, - Boolean $manage_selinux = false, - Boolean $manage_service = true, - Boolean $purge_features = true, - Hash $constants = {}, - Variant[Boolean, String] $confd = true, + Stdlib::Ensure::Service $ensure = running, + Boolean $enable = true, + Boolean $manage_repo = false, + Boolean $manage_repos = false, + Boolean $manage_package = false, + Boolean $manage_packages = true, + Boolean $manage_selinux = false, + Boolean $manage_service = true, + Boolean $purge_features = true, + Hash $constants = {}, + Variant[Boolean, String] $confd = true, ) { require ::icinga2::globals # load reserved words $_reserved = $::icinga2::globals::reserved # merge constants with defaults $_constants = merge($::icinga2::globals::constants, $constants) # validate confd, boolean or string if $confd =~ Boolean { if $confd { $_confd = 'conf.d' } else { $_confd = undef } } else { $_confd = $confd } Class['::icinga2::config'] -> Concat <| tag == 'icinga2::config::file' |> ~> Class['::icinga2::service'] + if $manage_package { + deprecation('manage_package', 'manage_package is deprecated and will be replaced by manage_packages in the future.') + } + if $manage_repos or $manage_repo { require ::icinga::repos if $manage_repo { deprecation('manage_repo', 'manage_repo is deprecated and will be replaced by manage_repos in the future.') } } anchor { '::icinga2::begin': notify => Class['::icinga2::service'], } -> class { '::icinga2::install': } -> File <| ensure == 'directory' and tag == 'icinga2::config::file' |> -> class { '::icinga2::config': notify => Class['::icinga2::service'] } -> File <| ensure != 'directory' and tag == 'icinga2::config::file' |> ~> class { '::icinga2::service': } -> anchor { '::icinga2::end': subscribe => Class['::icinga2::config'], } include prefix($features, '::icinga2::feature::') } diff --git a/manifests/install.pp b/manifests/install.pp index 1ae8825..8f89643 100644 --- a/manifests/install.pp +++ b/manifests/install.pp @@ -1,42 +1,43 @@ # @summary # This class handles the installation of the Icinga 2 package. # On Windows only chocolatey is supported as installation source. # # @api private # class icinga2::install { assert_private() $package_name = $::icinga2::globals::package_name $manage_package = $::icinga2::manage_package + $manage_packages = $::icinga2::manage_packages $selinux_package_name = $::icinga2::globals::selinux_package_name $manage_selinux = $::icinga2::manage_selinux $cert_dir = $::icinga2::globals::cert_dir $conf_dir = $::icinga2::globals::conf_dir $user = $::icinga2::globals::user $group = $::icinga2::globals::group - if $manage_package { + if $manage_package or $manage_packages { if $::osfamily == 'windows' { Package { provider => chocolatey, } } package { $package_name: ensure => installed, before => File[$cert_dir, $conf_dir], } if str2bool($manage_selinux) and $selinux_package_name { package { $selinux_package_name: ensure => installed, require => Package[$package_name], } } } file { [$conf_dir, $cert_dir]: ensure => directory, owner => $user, group => $group, } } diff --git a/spec/classes/icinga2_spec.rb b/spec/classes/icinga2_spec.rb index caf530b..fff2e22 100644 --- a/spec/classes/icinga2_spec.rb +++ b/spec/classes/icinga2_spec.rb @@ -1,172 +1,172 @@ require 'spec_helper' describe('icinga2', :type => :class) do on_supported_os.each do |os, facts| context "on #{os}" do let(:facts) do facts end before(:each) do case facts[:kernel] when 'windows' @icinga2_conf_dir = 'C:/ProgramData/icinga2/etc/icinga2' when 'FreeBSD' @icinga2_conf_dir = '/usr/local/etc/icinga2' else @icinga2_conf_dir = '/etc/icinga2' end end context 'with defaults' do it { is_expected.to contain_package('icinga2') .with({ 'ensure' => 'installed' }) } it { is_expected.to contain_service('icinga2') .with({ 'ensure' => 'running', 'enable' => true }) } it { is_expected.to contain_file("#{@icinga2_conf_dir}/features-enabled") .with({ 'ensure' => 'directory', 'purge' => true, 'recurse' => true, }) } it { is_expected.to contain_icinga2__feature('checker') .with({'ensure' => 'present'}) } it { is_expected.to contain_icinga2__feature('mainlog') .with({'ensure' => 'present'}) } it { is_expected.to contain_icinga2__feature('notification') .with({'ensure' => 'present'}) } end - context "with manage_package => false" do + context "with manage_packages => false" do let(:params) do - {:manage_package => false} + {:manage_packages => false} end it { is_expected.not_to contain_package('icinga2').with({ 'ensure' => 'installed' }) } end context "with manage_selinux => true" do let(:params) do {:manage_selinux => true} end case facts[:osfamily] when 'RedHat' it { is_expected.to contain_package('icinga2-selinux').with({ 'ensure' => 'installed' }) } end end context "with confd => false" do let(:params) do {:confd => false} end it { is_expected.to contain_file("#{@icinga2_conf_dir}/icinga2.conf") .without_content %r{^include_recursive \"conf.d\"} } end context "with confd => example.d" do let(:params) do {:confd => "#{@icinga2_conf_dir}/example.d"} end case facts[:kernel] when 'windows' let(:pre_condition) do [ "file { 'C:/ProgramData/icinga2/etc/icinga2/example.d': ensure => directory, tag => 'icinga2::config::file' }", "file { 'C:/ProgramData/icinga2/etc/icinga2/example.d/foo': ensure => file, tag => 'icinga2::config::file' }", ] end it { is_expected.to contain_file("#{@icinga2_conf_dir}/icinga2.conf") .with_content %r{^include_recursive \"C:/ProgramData/icinga2/etc/icinga2/example.d\"} } when 'FreeBSD' let(:pre_condition) do [ "file { '/usr/local/etc/icinga2/example.d': ensure => directory, tag => 'icinga2::config::file' }", "file { '/usr/local/etc/icinga2/example.d/foo': ensure => file, tag => 'icinga2::config::file' }", ] end it { is_expected.to contain_file("#{@icinga2_conf_dir}/icinga2.conf") .with_content %r{^include_recursive \"/usr/local/etc/icinga2/example.d\"} } else let(:pre_condition) do [ "file { '/etc/icinga2/example.d': ensure => directory, tag => 'icinga2::config::file' }", "file { '/etc/icinga2/example.d/foo': ensure => file, tag => 'icinga2::config::file' }", ] end it { is_expected.to contain_file("#{@icinga2_conf_dir}/icinga2.conf") .with_content %r{^include_recursive \"/etc/icinga2/example.d\"} } end it { is_expected.to contain_file("#{@icinga2_conf_dir}/example.d") .with({ 'ensure' => 'directory', 'tag' => 'icinga2::config::file', }) } it { is_expected.to contain_file("#{@icinga2_conf_dir}/example.d/foo") .with({ 'ensure' => 'file', 'tag' => 'icinga2::config::file', }) .that_notifies('Class[icinga2::service]') } end context "with constants => { foo => bar }" do let(:params) do { :constants => {'foo' => 'bar'} } end it { is_expected.to contain_file("#{@icinga2_conf_dir}/constants.conf") .with_content(/^const foo = \"bar\"/) } end context "with plugins => [ foo, bar ]" do let(:params) do { :plugins => ['foo', 'bar'] } end it { is_expected.to contain_file("#{@icinga2_conf_dir}/icinga2.conf") .with_content(/^include /) .with_content(/^include /) } end context "with ensure => stopped, enable => false" do let(:params) do { :ensure => 'stopped', :enable => false } end it { is_expected.to contain_service('icinga2') .with({ 'ensure' => 'stopped', 'enable' => false, }) } end context "with manage_service => false" do let(:params) do { :manage_service => false } end it { is_expected.not_to contain_service('icinga2') } end end end end diff --git a/spec/classes/idomysql_spec.rb b/spec/classes/idomysql_spec.rb index f74d2da..1dad067 100644 --- a/spec/classes/idomysql_spec.rb +++ b/spec/classes/idomysql_spec.rb @@ -1,206 +1,206 @@ require 'spec_helper' describe('icinga2::feature::idomysql', :type => :class) do let(:pre_condition) do [ "class { 'icinga2': features => [], constants => {'NodeName' => 'host.example.org'} }" ] end on_supported_os.each do |os, facts| context "on #{os}" do let(:facts) do case facts[:kernel] when 'windows' facts.merge({ :icinga2_puppet_hostcert => 'C:/ProgramData/PuppetLabs/puppet/ssl/certs/host.example.org.pem', :icinga2_puppet_hostprivkey => 'C:/ProgramData/PuppetLabs/puppet/ssl/private_keys/host.example.org.pem', :icinga2_puppet_localcacert => 'C:/ProgramData/PuppetLabs/var/lib/puppet/ssl/certs/ca.pem', }) else facts.merge({ :icinga2_puppet_hostcert => '/etc/puppetlabs/puppet/ssl/certs/host.example.org.pem', :icinga2_puppet_hostprivkey => '/etc/puppetlabs/puppet/ssl/private_keys/host.example.org.pem', :icinga2_puppet_localcacert => '/etc/lib/puppetlabs/puppet/ssl/certs/ca.pem', }) end end before(:each) do case facts[:kernel] when 'windows' @icinga2_conf_dir = 'C:/ProgramData/icinga2/etc/icinga2' @icinga2_pki_dir = 'C:/ProgramData/icinga2/var/lib/icinga2/certs' @ido_mysql_schema_dir = 'C:/Program Files/icinga2/usr/share/icinga2-ido-mysql/schema' @icinga2_sslkey_mode = nil @icinga2_user = nil @icinga2_group = nil when 'FreeBSD' @icinga2_conf_dir = '/usr/local/etc/icinga2' @icinga2_pki_dir = '/var/lib/icinga2/certs' @ido_mysql_schema_dir = '/usr/local/share/icinga2-ido-mysql/schema' @icinga2_sslkey_mode = '0600' @icinga2_user = 'icinga' @icinga2_group = 'icinga' else @icinga2_conf_dir = '/etc/icinga2' @icinga2_pki_dir = '/var/lib/icinga2/certs' @ido_mysql_schema_dir = '/usr/share/icinga2-ido-mysql/schema' @icinga2_sslkey_mode = '0600' case facts[:osfamily] when 'Debian' @icinga2_user = 'nagios' @icinga2_group = 'nagios' else @icinga2_user = 'icinga' @icinga2_group = 'icinga' end end end context "with defaults" do let(:params) do { :password => 'foo' } end if facts[:kernel] == 'Linux' it { is_expected.to contain_package('icinga2-ido-mysql').with({ 'ensure' => 'installed' }) } end if facts[:osfamily] == 'Debian' it { is_expected.to contain_file('/etc/dbconfig-common/icinga2-ido-mysql.conf') .with({ 'ensure' => 'file', 'owner' => 'root', 'group' => 'root', }) } end it { is_expected.to contain_icinga2__feature('ido-mysql').with({'ensure' => 'present'}) } it { is_expected.to contain_icinga2__object('icinga2::object::IdoMysqlConnection::ido-mysql') .with({ 'target' => "#{@icinga2_conf_dir}/features-available/ido-mysql.conf" }) .that_notifies('Class[icinga2::service]') } it { is_expected.to contain_concat__fragment('icinga2::feature::ido-mysql') .with({ 'target' => "#{@icinga2_conf_dir}/features-available/ido-mysql.conf", 'order' => '05', }) .with_content(/library \"db_ido_mysql\"$/) } end context "with ensure => absent" do let(:params) do { :ensure => 'absent', :password => 'foo' } end it { is_expected.to contain_icinga2__feature('ido-mysql').with({'ensure' => 'absent'}) } end context "with import_schema => true" do let(:params) do { :import_schema => true, :password => 'foo' } end it { is_expected.to contain_exec('idomysql-import-schema') .with({ 'user' => 'root', 'command' => "mysql -u icinga -p'foo' icinga < \"#{@ido_mysql_schema_dir}/mysql.sql\"", }) } end if facts[:kernel] == 'Linux' - context "with icinga2::manage_package => false" do + context "with icinga2::manage_packages => false" do let(:params) do { :password => 'foo' } end let(:pre_condition) do [ - "class { 'icinga2': features => [], manage_package => false }" + "class { 'icinga2': features => [], manage_packages => false }" ] end it { is_expected.not_to contain_package('icinga2').with({ 'ensure' => 'installed' }) } it { is_expected.not_to contain_package('icinga2-ido-mysql').with({ 'ensure' => 'installed' }) } end end context "with enable_ssl => true, host => 127.0.0.1, port => 3306, import_schema => true, ssl_key => foo, ssl_cert => bar, ssl_cacert => baz" do let(:params) do { :enable_ssl => true, :ssl_key => 'foo', :ssl_cert => 'bar', :ssl_cacert => 'baz', :host => '127.0.0.1', :port => 3306, :import_schema => true, :password => 'foo' } end it { is_expected.to contain_file("#{@icinga2_pki_dir}/IdoMysqlConnection_ido-mysql.key") .with({ 'mode' => @icinga2_sslkey_mode, 'owner' => @icinga2_user, 'group' => @icinga2_group, }) .with_content(/^foo/) } it { is_expected.to contain_file("#{@icinga2_pki_dir}/IdoMysqlConnection_ido-mysql.crt") .with({ 'owner' => @icinga2_user, 'group' => @icinga2_group, }) .with_content(/^bar$/) } it { is_expected.to contain_file("#{@icinga2_pki_dir}/IdoMysqlConnection_ido-mysql_ca.crt") .with({ 'owner' => @icinga2_user, 'group' => @icinga2_group, }) .with_content(/^baz$/) } it { is_expected.to contain_exec('idomysql-import-schema') .with({ 'user' => 'root', 'command' => "mysql -h 127.0.0.1 -P 3306 -u icinga -p'foo' --ssl-ca #{@icinga2_pki_dir}/IdoMysqlConnection_ido-mysql_ca.crt --ssl-cert #{@icinga2_pki_dir}/IdoMysqlConnection_ido-mysql.crt --ssl-key #{@icinga2_pki_dir}/IdoMysqlConnection_ido-mysql.key icinga < \"#{@ido_mysql_schema_dir}/mysql.sql\"", }) } end context "with enable_ssl => true, import_schema => true, ssl_key_path, ssl_cert_path and ssl_cacert_path set" do let(:params) do { :enable_ssl => true, :ssl_key_path => "#{@icinga2_pki_dir}/IdoMysqlConnection_ido-mysql.key", :ssl_cert_path => "#{@icinga2_pki_dir}/IdoMysqlConnection_ido-mysql.crt", :ssl_cacert_path => "#{@icinga2_pki_dir}/IdoMysqlConnection_ido-mysql_ca.crt", :import_schema => true, :password => 'foo' } end it { is_expected.to contain_concat__fragment('icinga2::object::IdoMysqlConnection::ido-mysql') .with_content %r{ssl_key = "#{@icinga2_pki_dir}/IdoMysqlConnection_ido-mysql.key"} } it { is_expected.to contain_concat__fragment('icinga2::object::IdoMysqlConnection::ido-mysql') .with_content %r{ssl_cert = "#{@icinga2_pki_dir}/IdoMysqlConnection_ido-mysql.crt"} } it { is_expected.to contain_concat__fragment('icinga2::object::IdoMysqlConnection::ido-mysql') .with_content %r{ssl_ca = "#{@icinga2_pki_dir}/IdoMysqlConnection_ido-mysql_ca.crt"} } it { is_expected.to contain_exec('idomysql-import-schema') .with({ 'user' => 'root', 'command' => "mysql -u icinga -p'foo' --ssl-ca #{@icinga2_pki_dir}/IdoMysqlConnection_ido-mysql_ca.crt --ssl-cert #{@icinga2_pki_dir}/IdoMysqlConnection_ido-mysql.crt --ssl-key #{@icinga2_pki_dir}/IdoMysqlConnection_ido-mysql.key icinga < \"#{@ido_mysql_schema_dir}/mysql.sql\"", }) } end end end end diff --git a/spec/classes/idopgsql_spec.rb b/spec/classes/idopgsql_spec.rb index 36fe774..255c55b 100644 --- a/spec/classes/idopgsql_spec.rb +++ b/spec/classes/idopgsql_spec.rb @@ -1,121 +1,121 @@ require 'spec_helper' describe('icinga2::feature::idopgsql', :type => :class) do let(:pre_condition) do [ "class { 'icinga2': features => [], }" ] end on_supported_os.each do |os, facts| context "on #{os}" do let(:facts) do facts end before(:each) do case facts[:kernel] when 'windows' @icinga2_conf_dir = 'C:/ProgramData/icinga2/etc/icinga2' @icinga2_pki_dir = 'C:/ProgramData/icinga2/var/lib/icinga2/certs' @ido_pgsql_schema_dir = 'C:/Program Files/icinga2/usr/share/icinga2-ido-pgsql/schema' @icinga2_sslkey_mode = nil @icinga2_user = nil @icinga2_group = nil when 'FreeBSD' @icinga2_conf_dir = '/usr/local/etc/icinga2' @icinga2_pki_dir = '/var/lib/icinga2/certs' @ido_pgsql_schema_dir = '/usr/local/share/icinga2-ido-pgsql/schema' @icinga2_sslkey_mode = '0600' @icinga2_user = 'icinga' @icinga2_group = 'icinga' else @icinga2_conf_dir = '/etc/icinga2' @icinga2_pki_dir = '/var/lib/icinga2/certs' @ido_pgsql_schema_dir = '/usr/share/icinga2-ido-pgsql/schema' @icinga2_sslkey_mode = '0600' case facts[:osfamily] when 'Debian' @icinga2_user = 'nagios' @icinga2_group = 'nagios' else @icinga2_user = 'icinga' @icinga2_group = 'icinga' end end end context "with defaults" do let(:params) do { :password => 'foo' } end if facts[:kernel] == 'Linux' it { is_expected.to contain_package('icinga2-ido-pgsql').with({ 'ensure' => 'installed' }) } end if facts[:osfamily] == 'Debian' it { is_expected.to contain_file('/etc/dbconfig-common/icinga2-ido-pgsql.conf') .with({ 'ensure' => 'file', 'owner' => 'root', 'group' => 'root', }) } end it { is_expected.to contain_icinga2__feature('ido-pgsql').with({'ensure' => 'present'}) } it { is_expected.to contain_concat__fragment('icinga2::object::IdoPgsqlConnection::ido-pgsql') .with({ 'target' => "#{@icinga2_conf_dir}/features-available/ido-pgsql.conf" }) } end context "with ensure => absent" do let(:params) do { :ensure => 'absent', :password => 'foo' } end it { is_expected.to contain_icinga2__feature('ido-pgsql').with({'ensure' => 'absent'}) } end context "with import_schema => true" do let(:params) do { :import_schema => true, :password => 'foo' } end it { is_expected.to contain_exec('idopgsql-import-schema') .with({ 'user' => 'root', 'environment' => ["PGPASSWORD=foo"], 'command' => "psql -h 'localhost' -U 'icinga' -p '5432' -d 'icinga' -w -f \"#{@ido_pgsql_schema_dir}/pgsql.sql\"" }) } end if facts[:kernel] == 'Linux' - context "with manage_package => false" do + context "with manage_packages => false" do let(:params) do { :password => 'foo' } end let(:pre_condition) do [ - "class { 'icinga2': features => [], manage_package => false }" + "class { 'icinga2': features => [], manage_packages => false }" ] end it { is_expected.not_to contain_package('icinga2').with({ 'ensure' => 'installed' }) } it { is_expected.not_to contain_package('icinga2-ido-pgsql').with({ 'ensure' => 'installed' }) } end end end end end