diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0bbb03c --- /dev/null +++ b/.gitignore @@ -0,0 +1,122 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a packager +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.kitchen +.kitchen.local.yml +kitchen.local.yml +junit-*.xml + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# dotenv +.env + +# virtualenv +.venv +venv/ +ENV/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ + +# Bundler +Gemfile.lock + +# copied `.md` files used for conversion to `.rst` using `m2r` +docs/*.md + +# Vim +*.sw? + +## Collected when centralising formulas (check and sort) +# `collectd-formula` +.pytest_cache/ +/.idea/ +Dockerfile.*_* +ignore/ +tmp/ diff --git a/.rubocop.yml b/.rubocop.yml new file mode 100644 index 0000000..bdae9aa --- /dev/null +++ b/.rubocop.yml @@ -0,0 +1,10 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +# General overrides used across formulas in the org +Metrics/LineLength: + # Increase from default of `80` + # Based on https://github.com/PyCQA/flake8-bugbear#opinionated-warnings (`B950`) + Max: 88 + +# Any offenses that should be fixed, e.g. collected via. `rubocop --auto-gen-config` diff --git a/.salt-lint b/.salt-lint new file mode 100644 index 0000000..f3f4da0 --- /dev/null +++ b/.salt-lint @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +exclude_paths: [] +rules: + 206: # Jinja variables should have spaces before and after + ignore: | + icinga2/files/xmpp.conf.jinja +skip_list: + # Using `salt-lint` for linting other files as well, such as Jinja macros/templates + - 205 # Use ".sls" as a Salt State file extension + # Skipping `207` and `208` because `210` is sufficient, at least for the time-being + # I.e. Allows 3-digit unquoted codes to still be used, such as `644` and `755` + - 207 # File modes should always be encapsulated in quotation marks + - 208 # File modes should always contain a leading zero +tags: [] +verbosity: 1 diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..fb4406d --- /dev/null +++ b/.travis.yml @@ -0,0 +1,116 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +## Machine config +os: 'linux' +arch: 'amd64' +dist: 'bionic' +version: '~> 1.0' + +## Language and cache config +language: 'ruby' +cache: 'bundler' + +## Services config +services: + - docker + +## Script to run for the test stage +script: + - bin/kitchen verify "${INSTANCE}" + +## Stages and jobs matrix +stages: + - test + - name: 'release' + if: 'branch = master AND type != pull_request' +jobs: + include: + ## Define the test stage that runs the linters (and testing matrix, if applicable) + + # Run all of the linters in a single job + - language: 'node_js' + node_js: 'lts/*' + env: 'Lint' + name: 'Lint: salt-lint, yamllint, rubocop, shellcheck & commitlint' + before_install: 'skip' + script: + # Install and run `salt-lint` + - pip install --user salt-lint + - git ls-files -- '*.sls' '*.jinja' '*.j2' '*.tmpl' '*.tst' + | xargs salt-lint + # Install and run `yamllint` + # Need at least `v1.17.0` for the `yaml-files` setting + - pip install --user yamllint>=1.17.0 + - yamllint -s . + # Install and run `rubocop` + - gem install rubocop + - rubocop -d + # Run `shellcheck` (already pre-installed in Travis) + - shellcheck --version + - git ls-files -- '*.sh' '*.bash' '*.ksh' + | xargs shellcheck + # Install and run `commitlint` + - npm i -D @commitlint/config-conventional + @commitlint/travis-cli + - commitlint-travis + + ## Define the rest of the matrix based on Kitchen testing + # Make sure the instances listed below match up with + # the `platforms` defined in `kitchen.yml` + - env: INSTANCE=default-debian-10-master-py3 + - env: INSTANCE=default-ubuntu-1804-master-py3 + # - env: INSTANCE=default-centos-8-master-py3 + # - env: INSTANCE=default-fedora-31-master-py3 + # - env: INSTANCE=default-opensuse-leap-151-master-py3 + # - env: INSTANCE=default-amazonlinux-2-master-py2 + # - env: INSTANCE=default-arch-base-latest-master-py2 + # - env: INSTANCE=default-debian-10-2019-2-py3 + - env: INSTANCE=default-debian-9-2019-2-py3 + - env: INSTANCE=default-ubuntu-1804-2019-2-py3 + # - env: INSTANCE=default-centos-8-2019-2-py3 + # - env: INSTANCE=default-fedora-31-2019-2-py3 + # - env: INSTANCE=default-opensuse-leap-151-2019-2-py3 + # - env: INSTANCE=default-centos-7-2019-2-py2 + # - env: INSTANCE=default-amazonlinux-2-2019-2-py2 + # - env: INSTANCE=default-arch-base-latest-2019-2-py2 + # - env: INSTANCE=default-fedora-30-2018-3-py3 + - env: INSTANCE=default-debian-9-2018-3-py2 + # - env: INSTANCE=default-ubuntu-1604-2018-3-py2 + # - env: INSTANCE=default-centos-7-2018-3-py2 + # - env: INSTANCE=default-opensuse-leap-151-2018-3-py2 + # - env: INSTANCE=default-amazonlinux-2-2018-3-py2 + # - env: INSTANCE=default-arch-base-latest-2018-3-py2 + # - env: INSTANCE=default-debian-8-2017-7-py2 + - env: INSTANCE=default-ubuntu-1604-2017-7-py2 + # - env: INSTANCE=default-centos-6-2017-7-py2 + # - env: INSTANCE=default-fedora-30-2017-7-py2 + # - env: INSTANCE=default-opensuse-leap-151-2017-7-py2 + # - env: INSTANCE=default-amazonlinux-2-2017-7-py2 + # - env: INSTANCE=default-arch-base-latest-2017-7-py2 + + ## Define the release stage that runs `semantic-release` + - stage: 'release' + language: 'node_js' + node_js: 'lts/*' + env: 'Release' + name: 'Run semantic-release inc. file updates to AUTHORS, CHANGELOG & FORMULA' + before_install: 'skip' + script: + # Update `AUTHORS.md` + - export MAINTAINER_TOKEN=${GH_TOKEN} + - go get github.com/myii/maintainer + - maintainer contributor + + # Install all dependencies required for `semantic-release` + - npm i -D @semantic-release/changelog@3 + @semantic-release/exec@3 + @semantic-release/git@7 + deploy: + provider: 'script' + # Opt-in to `dpl v2` to complete the Travis build config validation (beta) + # * https://docs.travis-ci.com/user/build-config-validation + # Deprecated `skip_cleanup` can now be avoided, `cleanup: false` is by default + edge: true + # Run `semantic-release` + script: 'npx semantic-release@15' diff --git a/.yamllint b/.yamllint new file mode 100644 index 0000000..f83d156 --- /dev/null +++ b/.yamllint @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +# Extend the `default` configuration provided by `yamllint` +extends: default + +# Files to ignore completely +# 1. All YAML files under directory `node_modules/`, introduced during the Travis run +# 2. Any SLS files under directory `test/`, which are actually state files +# 3. Any YAML files under directory `.kitchen/`, introduced during local testing +ignore: | + node_modules/ + test/**/states/**/*.sls + .kitchen/ + icinga2/osfamilymap.yaml + +yaml-files: + # Default settings + - '*.yaml' + - '*.yml' + - .salt-lint + - .yamllint + # SaltStack Formulas additional settings + - '*.example' + - test/**/*.sls + +rules: + empty-values: + forbid-in-block-mappings: true + forbid-in-flow-mappings: true + line-length: + # Increase from default of `80` + # Based on https://github.com/PyCQA/flake8-bugbear#opinionated-warnings (`B950`) + max: 88 + octal-values: + forbid-implicit-octal: true + forbid-explicit-octal: true diff --git a/FORMULA b/FORMULA new file mode 100644 index 0000000..b19e875 --- /dev/null +++ b/FORMULA @@ -0,0 +1,9 @@ +name: icinga2 +os: Debian, Ubuntu, Raspbian, RedHat, Fedora, CentOS, Suse, openSUSE, FreeBSD, OpenBSD, Windows +os_family: Debian, RedHat, Suse, FreeBSD, OpenBSDWindows, MacOS +version: 0.7.1 +release: 1 +minimum_version: 2017.7 +summary: icinga2 formula +description: Formula to install and configure icinga2 +top_level_dir: icinga2 diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..5a232b6 --- /dev/null +++ b/Gemfile @@ -0,0 +1,7 @@ +# frozen_string_literal: true + +source 'https://rubygems.org' + +gem 'kitchen-docker', '>= 2.9' +gem 'kitchen-inspec', '>= 1.1' +gem 'kitchen-salt', '>= 0.6.0' diff --git a/README.rst b/README.rst deleted file mode 100644 index 67f6e34..0000000 --- a/README.rst +++ /dev/null @@ -1,101 +0,0 @@ -=============== -icinga2-formula -=============== - -A salt formula that installs and configures icinga2, currently on Debian and Ubuntu only, but other -installation source can be easily added. Configuration via pillar currently for hosts and -services only. - -.. note:: - -Suggestions, pull-requests, bug reports and comments are welcome. - - -Available states -================ - -.. contents:: - :local: - - -``icinga2`` ------------ - -Installs and configures the icinga2 package. -Includes ``icinga.repositories``. - - -``icinga2.icinga-web2`` ------------------------ - -Includes: - -- ``icinga2.icinga-web2-core`` -- ``icinga2.icinga-web2-database`` -- ``icinga2.pgsql-ido`` -- ``icinga2.postgresql-client`` -- ``icinga2.postgresql-server`` - - -``icinga2.nrpe-server`` (DEPRECATED) ------------------------------------- - -Installs and configures the nrpe-server to perform checks on non-local hosts. - - -States which are independent (reusable) building blocks -======================================================= - -.. contents:: - :local: - - -``icinga2.icinga-web2-database`` ------------------------ - -Creates the DB user and the DB itself. -(Makes only sense if the DB shall run on the same host as Icinga2) - - -``icinga2.icinga-web2-core`` ------------------------ - -Installs the (new) Icinga Web UI. - - -``icinga2.pgsql-ido`` ---------------------- - -Installs and configures ``icinga2-ido-pgsql``. -You may want to add ``icinga2.postgresql-client`` - - -``icinga2.postgresql-client`` ----------------------- - -Installs PostgreSQL client. - - -``icinga2.postgresql-server`` ----------------------- - -Installs PostgreSQL server. - - -``icinga2.repositories`` ------------------------- - -Adds the Debian / Ubuntu repository to get Icinga2 packages from if (and only if) -the machine happens to run one of the mentioned operating systems. - - -``icinga2.check_command.openvpn`` ------------------------------ - -Sets up CheckCommand ``openvpn`` using ``. - -``icinga2.notification.xmpp`` ------------------------------ - -Sets up notification via XMPP using `slixmpp -`_. diff --git a/bin/kitchen b/bin/kitchen new file mode 100755 index 0000000..dcfdb4c --- /dev/null +++ b/bin/kitchen @@ -0,0 +1,32 @@ +#!/usr/bin/env ruby +# frozen_string_literal: true + +# +# This file was generated by Bundler. +# +# The application 'kitchen' is installed as part of a gem, and +# this file is here to facilitate running it. +# + +require 'pathname' +ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../Gemfile', + Pathname.new(__FILE__).realpath) + +bundle_binstub = File.expand_path('bundle', __dir__) + +if File.file?(bundle_binstub) + if File.read(bundle_binstub, 300) =~ /This file was generated by Bundler/ + load(bundle_binstub) + else + abort( + 'Your `bin/bundle` was not generated by Bundler, '\ + 'so this binstub cannot run. Replace `bin/bundle` by running '\ + '`bundle binstubs bundler --force`, then run this command again.' + ) + end +end + +require 'rubygems' +require 'bundler/setup' + +load Gem.bin_path('test-kitchen', 'kitchen') diff --git a/commitlint.config.js b/commitlint.config.js new file mode 100644 index 0000000..2f9d1aa --- /dev/null +++ b/commitlint.config.js @@ -0,0 +1,3 @@ +module.exports = { + extends: ['@commitlint/config-conventional'], +}; diff --git a/docs/README.rst b/docs/README.rst new file mode 100644 index 0000000..444857f --- /dev/null +++ b/docs/README.rst @@ -0,0 +1,186 @@ +.. _readme: + +icinga2-formula +=============== + +|img_travis| |img_sr| + +.. |img_travis| image:: https://travis-ci.com/saltstack-formulas/icinga2-formula.svg?branch=master + :alt: Travis CI Build Status + :scale: 100% + :target: https://travis-ci.com/saltstack-formulas/icinga2-formula +.. |img_sr| image:: https://img.shields.io/badge/%20%20%F0%9F%93%A6%F0%9F%9A%80-semantic--release-e10079.svg + :alt: Semantic Release + :scale: 100% + :target: https://github.com/semantic-release/semantic-release + +A salt formula that installs and configures icinga2, currently on Debian and Ubuntu only, but other +installation source can be easily added. Configuration via pillar currently for hosts and +services only. + +.. note:: + +Suggestions, pull-requests, bug reports and comments are welcome. + +.. contents:: **Table of Contents** + +General notes +------------- + +See the full `SaltStack Formulas installation and usage instructions +`_. + +If you are interested in writing or contributing to formulas, please pay attention to the `Writing Formula Section +`_. + +If you want to use this formula, please pay attention to the ``FORMULA`` file and/or ``git tag``, +which contains the currently released version. This formula is versioned according to `Semantic Versioning `_. + +See `Formula Versioning Section `_ for more details. + +If you need (non-default) configuration, please pay attention to the ``pillar.example`` file and/or `Special notes`_ section. + +Contributing to this repo +------------------------- + +**Commit message formatting is significant!!** + +Please see `How to contribute `_ for more details. + +Special notes +------------- + +None + +Available states +---------------- + +.. contents:: + :local: + +``icinga2`` +^^^^^^^^^^^ + +Installs and configures the icinga2 package. +Includes ``icinga.repositories``. + + +``icinga2.icinga-web2`` +^^^^^^^^^^^^^^^^^^^^^^^ + +Includes: + +- ``icinga2.icinga-web2-core`` +- ``icinga2.icinga-web2-database`` +- ``icinga2.pgsql-ido`` +- ``icinga2.postgresql-client`` +- ``icinga2.postgresql-server`` + + +``icinga2.nrpe-server`` (DEPRECATED) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Installs and configures the nrpe-server to perform checks on non-local hosts. + + +States which are independent (reusable) building blocks +------------------------------------------------------- + +.. contents:: + :local: + + +``icinga2.icinga-web2-database`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Creates the DB user and the DB itself. +(Makes only sense if the DB shall run on the same host as Icinga2) + + +``icinga2.icinga-web2-core`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Installs the (new) Icinga Web UI. + + +``icinga2.pgsql-ido`` +^^^^^^^^^^^^^^^^^^^^^ + +Installs and configures ``icinga2-ido-pgsql``. +You may want to add ``icinga2.postgresql-client`` + + +``icinga2.postgresql-client`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Installs PostgreSQL client. + + +``icinga2.postgresql-server`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Installs PostgreSQL server. + + +``icinga2.repositories`` +^^^^^^^^^^^^^^^^^^^^^^^^ + +Adds the Debian / Ubuntu repository to get Icinga2 packages from if (and only if) +the machine happens to run one of the mentioned operating systems. + + +``icinga2.check_command.openvpn`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Sets up CheckCommand ``openvpn`` using ``. + +``icinga2.notification.xmpp`` +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Sets up notification via XMPP using `slixmpp +`_. + +Testing +------- + +Linux testing is done with ``kitchen-salt``. + +Requirements +^^^^^^^^^^^^ + +* Ruby +* Docker + +.. code-block:: bash + + $ gem install bundler + $ bundle install + $ bin/kitchen test [platform] + +Where ``[platform]`` is the platform name defined in ``kitchen.yml``, +e.g. ``debian-9-2019-2-py3``. + +``bin/kitchen converge`` +^^^^^^^^^^^^^^^^^^^^^^^^ + +Creates the docker instance and runs the ``template`` main state, ready for testing. + +``bin/kitchen verify`` +^^^^^^^^^^^^^^^^^^^^^^ + +Runs the ``inspec`` tests on the actual instance. + +``bin/kitchen destroy`` +^^^^^^^^^^^^^^^^^^^^^^^ + +Removes the docker instance. + +``bin/kitchen test`` +^^^^^^^^^^^^^^^^^^^^ + +Runs all of the stages above in one go: i.e. ``destroy`` + ``converge`` + ``verify`` + ``destroy``. + +``bin/kitchen login`` +^^^^^^^^^^^^^^^^^^^^^ + +Gives you SSH access to the instance for manual testing. diff --git a/icinga2/config.sls b/icinga2/config.sls index 4f2221f..aa46995 100644 --- a/icinga2/config.sls +++ b/icinga2/config.sls @@ -3,13 +3,13 @@ {%- macro printconfig(type, object, name, config, applyto="") %} {{ type }} {{ object }} "{{ name }}" {% if applyto !="" %}to {% endif %}{{ applyto }}{% if applyto !="" %} {% endif %}{ -{%- for key, value in config.items()%} +{%- for key, value in config.items() %} {%- if key == "import" %} - {{key}} "{{ value }}" + {{ key }} "{{ value }}" {%- endif %} {%- endfor %} -{%- for key, value in config.items()%} +{%- for key, value in config.items() %} {%- if key == "import" %} {%- elif key == "vars" %} {%- for varkey, varvalue in config.vars.items() %} @@ -52,7 +52,7 @@ {%- endif %} {%- endfor %} } -{%-endmacro%} +{%- endmacro %} include: - .directories @@ -104,7 +104,7 @@ include: {{ printconfig("object", "Host", host, hostconf) }} {%- if hostconf.services is defined %} -{{ path}}: +{{ path }}: file.directory {%- for service, serviceconf in hostconf.services.items() %} @@ -157,7 +157,7 @@ include: - contents: | {{ printconfig("template", templateinfo["type"], template, templateinfo["conf"]) }} -{%- endfor%} +{%- endfor %} {%- endif %} ### End template configuration @@ -178,7 +178,7 @@ include: - contents: | {{ printconfig("object", "User", user, userinfo) }} -{%- endfor%} +{%- endfor %} {%- endif %} ### End user configuration @@ -199,7 +199,7 @@ include: - contents: | {{ printconfig("object", "UserGroup", group, groupinfo) }} -{%- endfor%} +{%- endfor %} {%- endif %} ### End user group configuration @@ -224,10 +224,10 @@ include: - contents: | {{ printconfig("apply", applyinfo.get("type", objecttype), apply, applyinfo.get("conf", {}), applyto) }} -{%- endfor%} +{%- endfor %} {%- endif %} -{%- endfor%} +{%- endfor %} ### End apply configuration {% endif %} diff --git a/icinga2/defaults.yaml b/icinga2/defaults.yaml index 00108e1..8ac7f63 100644 --- a/icinga2/defaults.yaml +++ b/icinga2/defaults.yaml @@ -1,3 +1,6 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- icinga2: config_dir: /etc/icinga2 confd_dir: /etc/icinga2/conf.d @@ -11,13 +14,13 @@ icinga2: postgresql_pkgs: - postgresql-client service: icinga2 - configure_repositories: True + configure_repositories: true ido: db: name: icinga user: icinga2ido # None => lets the state fail which is desired! - password: + password: ~ host: 127.0.0.1 port: 5432 schema_path: /usr/share/icinga2-ido-pgsql/schema/pgsql.sql @@ -31,7 +34,7 @@ icinga2: name: icinga2web user: icinga2web # None => lets the state fail which is desired! - password: + password: ~ host: 127.0.0.1 port: 5432 pkgs: @@ -48,17 +51,17 @@ icinga2: - php-gd - php-imagick features: - api: False - command: True - debuglog: False - gelf: False - graphite: False - influxdb: False - livestatus: False - opentsdb: False - perfdata: False - statusdata: False - syslog: False + api: false + command: true + debuglog: false + gelf: false + graphite: false + influxdb: false + livestatus: false + opentsdb: false + perfdata: false + statusdata: false + syslog: false check_command: openvpn: diff --git a/icinga2/files/xmpp.conf.jinja b/icinga2/files/xmpp.conf.jinja index a445490..4e56e60 100644 --- a/icinga2/files/xmpp.conf.jinja +++ b/icinga2/files/xmpp.conf.jinja @@ -1,12 +1,12 @@ template NotificationCommand "xmpp-notification-template" { import "plugin-notification-command" - + command = [ "{{ sender }}", "$xmpp_recipient$", "$xmpp_message$" ] - + vars.xmpp_recipient = "$jabber$" // Hide credentials from 'ps' & Co. @@ -18,39 +18,39 @@ template NotificationCommand "xmpp-notification-template" { XMPP_PASSWORD = "$xmpp_password$" } } - + template NotificationCommand "xmpp-host-notification-template" { import "xmpp-notification-template" - + vars.xmpp_message = {{ "{{{" }}$host.display_name$ is $host.state$ Date/Time: $icinga.long_date_time$ - + Host: $host.display_name$ Address: $address$ State: $host.state$ - + Notification Type: $notification.type$ - + Additional Info: $host.output$ - + Comment: [$notification.author$] $notification.comment${{ "}}}" }} } - + template NotificationCommand "xmpp-service-notification-template" { import "xmpp-notification-template" - + vars.xmpp_message = {{ "{{{" }}$service.name$ on $host.display_name$ is $service.state$ Date/Time: $icinga.long_date_time$ - + Service: $service.name$ Host: $host.display_name$ Address: $address$ State: $service.state$ - + Notification Type: $notification.type$ - + Additional Info: $service.output$ - + Comment: [$notification.author$] $notification.comment${{ "}}}" }} } diff --git a/icinga2/map.jinja b/icinga2/map.jinja index 97463a0..911d618 100644 --- a/icinga2/map.jinja +++ b/icinga2/map.jinja @@ -3,7 +3,7 @@ {% import_yaml "icinga2/osmap.yaml" as osmap %} {%- set icinga2 = salt['grains.filter_by']( - defaults, + defaults, merge=salt['grains.filter_by']( osfamilymap, grain='os_family', diff --git a/icinga2/nrpe-server.sls b/icinga2/nrpe-server.sls index bcc3e7f..b16f18e 100644 --- a/icinga2/nrpe-server.sls +++ b/icinga2/nrpe-server.sls @@ -1,5 +1,5 @@ {# keep backwards compatibility #} -{% set nrpe = salt['pillar.get']('nrpe', salt['pillar.get']('icinga2:lookup::nrpe', {}))%} +{% set nrpe = salt['pillar.get']('nrpe', salt['pillar.get']('icinga2:lookup::nrpe', {})) %} include: diff --git a/icinga2/osfamilymap.yaml b/icinga2/osfamilymap.yaml index a517a1c..b607e79 100644 --- a/icinga2/osfamilymap.yaml +++ b/icinga2/osfamilymap.yaml @@ -1,8 +1,11 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- Debian: {} FreeBSD: user: icinga group: icinga - configure_repositories: False + configure_repositories: false config_dir: /usr/local/etc/icinga2 check_command_dir: /usr/local/etc/icinga2/conf.d/check_command confd_dir: /usr/local/etc/icinga2/conf.d @@ -14,17 +17,17 @@ FreeBSD: pkgs: - icingaweb2 required_pkgs: -{%- set phpng_version = salt['pillar.get']('php:ng:version', '7.2')|string %} -{%- set freebsd_phpng_version = phpng_version.replace('.', '') %} - - mod_php{{ freebsd_phpng_version }} - - php{{ freebsd_phpng_version }} - - php{{ freebsd_phpng_version }}-gd - - php{{ freebsd_phpng_version }}-intl - - php{{ freebsd_phpng_version }}-pgsql - - php{{ freebsd_phpng_version }}-gd + {%- set php_version = salt['pillar.get']('php:version', '7.2')|string %} + {%- set freebsd_php_version = php_version.replace('.', '') %} + - mod_php{{ freebsd_php_version }} + - php{{ freebsd_php_version }} + - php{{ freebsd_php_version }}-gd + - php{{ freebsd_php_version }}-intl + - php{{ freebsd_php_version }}-pgsql + - php{{ freebsd_php_version }}-gd ido: # In FreeBSD IDO is included in the icinga2 package. - pkg: False + pkg: false schema_path: /usr/local/share/icinga2-ido-pgsql/schema/pgsql.sql notification: xmpp: diff --git a/icinga2/osmap.yaml b/icinga2/osmap.yaml index e30de6b..5e4e409 100644 --- a/icinga2/osmap.yaml +++ b/icinga2/osmap.yaml @@ -1,2 +1,28 @@ -Debian: {} -Ubuntu: {} +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +# os_family: Debian +Debian: + repo: 'debian' +Ubuntu: + repo: 'ubuntu' +Raspbian: + repo: 'raspbian' + +# os_family: RedHat +Fedora: + repo: 'fedora' +CentOS: + repo: 'epel' +Amazon: + repo: 'epel' + +# os_family: Suse +SUSE: + repo: 'SUSE' +openSUSE: + repo: 'openSUSE' + +# os_family: Windows +Windows: + repo: 'windows' diff --git a/icinga2/pgsql-ido.sls b/icinga2/pgsql-ido.sls index 8a403de..c525c6a 100644 --- a/icinga2/pgsql-ido.sls +++ b/icinga2/pgsql-ido.sls @@ -6,6 +6,8 @@ include: {% if grains['os_family'] == 'Debian' %} debconf_pgsql_ido: + pkg.installed: + - name: debconf-utils debconf.set: - name: "{{ icinga2.ido.pkg }}" - data: @@ -16,6 +18,8 @@ debconf_pgsql_ido: '{{ icinga2.ido.pkg }}/db/dbport': {'type': 'string', 'value': "{{ icinga2.ido.db.port }}"} '{{ icinga2.ido.pkg }}/db/dbserver': {'type': 'string', 'value': "{{ icinga2.ido.db.host }}"} '{{ icinga2.ido.pkg }}/enable': {'type': 'boolean', 'value': true} + - require: + - pkg: debconf_pgsql_ido - require_in: - pkg: icinga2ido-pkg @@ -38,7 +42,7 @@ icinga2ido-pkg: icinga2ido-config: file.managed: - - name: "{{ icinga2.config_dir}}/features-available/ido-pgsql.conf" + - name: "{{ icinga2.config_dir }}/features-available/ido-pgsql.conf" - template: jinja - source: salt://icinga2/files/ido-pgsql.conf.jinja - watch_in: diff --git a/icinga2/postgresql-server.sls b/icinga2/postgresql-server.sls index 9212382..be72bd3 100644 --- a/icinga2/postgresql-server.sls +++ b/icinga2/postgresql-server.sls @@ -1,3 +1,5 @@ +{% from "icinga2/map.jinja" import icinga2 with context %} + {% if salt['pillar.get']('icinga2:postgres:use_formula', False) %} include: - postgres.server diff --git a/icinga2/repositories.sls b/icinga2/repositories.sls index 435cdeb..35d52e2 100644 --- a/icinga2/repositories.sls +++ b/icinga2/repositories.sls @@ -1,3 +1,5 @@ +{% from "icinga2/map.jinja" import icinga2 with context %} + {% if grains['os'] == 'Debian' %} icinga_repo_required_packages: pkg.installed: @@ -10,9 +12,32 @@ debmon: pkgrepo.absent: [] {% endif %} +{#- Source: http://packages.icinga.com/ #} +{#- Preparing the basic structure here for all of the available platforms #} +{#- But only configuring for Debian for now #} +{%- set dist = '' %} +{%- set ocn = grains.get('oscodename', '') %} +{%- set omr = grains.get('osmajorrelease', '0')|string %} +{%- if grains.os_family == 'Debian' %} +{%- set dist = 'icinga-{0} main'.format(ocn) %} +{#- elif grains.os_family == 'RedHat' #} +{#- set dist = '7' if grains.os == 'Amazon' else omr #} +{#- elif grains.os_family == 'Suse' #} +{#- set dist = grains.osrelease #} +{%- endif %} + +{%- if icinga2.repo and dist %} +{%- if grains.osfinger == 'Debian-9' %} +icinga_deps_repo_for_stretch: + pkgrepo.managed: + - humanname: Stretch Backports + - name: deb http://http.debian.net/debian stretch-backports main + - dist: stretch-backports +{%- endif %} icinga_repo: pkgrepo.managed: - humanname: icinga_official - - name: deb http://packages.icinga.org/ubuntu icinga-{{ grains['lsb_distrib_codename'] }} main + - name: deb http://packages.icinga.org/{{ icinga2.repo }} {{ dist }} - file: /etc/apt/sources.list.d/icinga.list - key_url: http://packages.icinga.org/icinga.key +{%- endif %} diff --git a/kitchen.yml b/kitchen.yml new file mode 100644 index 0000000..aa3bcca --- /dev/null +++ b/kitchen.yml @@ -0,0 +1,198 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +# For help on this file's format, see https://kitchen.ci/ +driver: + name: docker + use_sudo: false + privileged: true + run_command: /lib/systemd/systemd + +# Make sure the platforms listed below match up with +# the `env.matrix` instances defined in `.travis.yml` +platforms: + ## SALT `master` + - name: debian-10-master-py3 + driver: + image: netmanagers/salt-master-py3:debian-10 + provision_command: + - curl -o bootstrap-salt.sh -L https://bootstrap.saltstack.com + - sh bootstrap-salt.sh -XdPbfrq -x python3 git master + - name: ubuntu-1804-master-py3 + driver: + image: netmanagers/salt-master-py3:ubuntu-18.04 + provision_command: + - curl -o bootstrap-salt.sh -L https://bootstrap.saltstack.com + - sh bootstrap-salt.sh -XdPbfrq -x python3 git master + - name: centos-8-master-py3 + driver: + image: netmanagers/salt-master-py3:centos-8 + provision_command: + - curl -o bootstrap-salt.sh -L https://bootstrap.saltstack.com + - sh bootstrap-salt.sh -XdPbfrq -x python3 git master + - name: fedora-31-master-py3 + driver: + image: netmanagers/salt-master-py3:fedora-31 + provision_command: + - curl -o bootstrap-salt.sh -L https://bootstrap.saltstack.com + - sh bootstrap-salt.sh -XdPbfrq -x python3 git master + - name: opensuse-leap-151-master-py3 + driver: + image: netmanagers/salt-master-py3:opensuse-leap-15.1 + provision_command: + - curl -o bootstrap-salt.sh -L https://bootstrap.saltstack.com + - sh bootstrap-salt.sh -XdPbfrq -x python3 git master + run_command: /usr/lib/systemd/systemd + # Workaround to avoid intermittent failures on `opensuse-leap-15.1`: + # => SCP did not finish successfully (255): (Net::SCP::Error) + transport: + max_ssh_sessions: 1 + # Use the `develop` image temporarily until the `master` image is available + # Not changing the name to minimise disruption across all of the formulas + - name: amazonlinux-2-master-py2 + driver: + image: netmanagers/salt-develop-py2:amazonlinux-2 + provision_command: + - curl -o bootstrap-salt.sh -L https://bootstrap.saltstack.com + - sh bootstrap-salt.sh -XdPbfrq -x python2 git develop + - name: arch-base-latest-master-py2 + driver: + image: netmanagers/salt-master-py2:arch-base-latest + provision_command: + - curl -o bootstrap-salt.sh -L https://bootstrap.saltstack.com + - sh bootstrap-salt.sh -XdPbfrq -x python2 git master + run_command: /usr/lib/systemd/systemd + + ## SALT `2019.2` + - name: debian-10-2019-2-py3 + driver: + image: netmanagers/salt-2019.2-py3:debian-10 + - name: debian-9-2019-2-py3 + driver: + image: netmanagers/salt-2019.2-py3:debian-9 + - name: ubuntu-1804-2019-2-py3 + driver: + image: netmanagers/salt-2019.2-py3:ubuntu-18.04 + - name: centos-8-2019-2-py3 + driver: + image: netmanagers/salt-2019.2-py3:centos-8 + - name: fedora-31-2019-2-py3 + driver: + image: netmanagers/salt-2019.2-py3:fedora-31 + - name: opensuse-leap-151-2019-2-py3 + driver: + image: netmanagers/salt-2019.2-py3:opensuse-leap-15.1 + run_command: /usr/lib/systemd/systemd + # Workaround to avoid intermittent failures on `opensuse-leap-15.1`: + # => SCP did not finish successfully (255): (Net::SCP::Error) + transport: + max_ssh_sessions: 1 + - name: centos-7-2019-2-py2 + driver: + image: netmanagers/salt-2019.2-py2:centos-7 + - name: amazonlinux-2-2019-2-py2 + driver: + image: netmanagers/salt-2019.2-py2:amazonlinux-2 + - name: arch-base-latest-2019-2-py2 + driver: + image: netmanagers/salt-2019.2-py2:arch-base-latest + run_command: /usr/lib/systemd/systemd + + ## SALT `2018.3` + - name: fedora-30-2018-3-py3 + driver: + image: netmanagers/salt-2018.3-py3:fedora-30 + - name: debian-9-2018-3-py2 + driver: + image: netmanagers/salt-2018.3-py2:debian-9 + - name: ubuntu-1604-2018-3-py2 + driver: + image: netmanagers/salt-2018.3-py2:ubuntu-16.04 + - name: centos-7-2018-3-py2 + driver: + image: netmanagers/salt-2018.3-py2:centos-7 + - name: opensuse-leap-151-2018-3-py2 + driver: + image: netmanagers/salt-2018.3-py2:opensuse-leap-15.1 + run_command: /usr/lib/systemd/systemd + # Workaround to avoid intermittent failures on `opensuse-leap-15.1`: + # => SCP did not finish successfully (255): (Net::SCP::Error) + transport: + max_ssh_sessions: 1 + - name: amazonlinux-2-2018-3-py2 + driver: + image: netmanagers/salt-2018.3-py2:amazonlinux-2 + - name: arch-base-latest-2018-3-py2 + driver: + image: netmanagers/salt-2018.3-py2:arch-base-latest + run_command: /usr/lib/systemd/systemd + + ## SALT `2017.7` + - name: debian-8-2017-7-py2 + driver: + image: netmanagers/salt-2017.7-py2:debian-8 + - name: ubuntu-1604-2017-7-py2 + driver: + image: netmanagers/salt-2017.7-py2:ubuntu-16.04 + - name: centos-6-2017-7-py2 + driver: + image: netmanagers/salt-2017.7-py2:centos-6 + run_command: /sbin/init + - name: fedora-30-2017-7-py2 + driver: + image: netmanagers/salt-2017.7-py2:fedora-30 + - name: opensuse-leap-151-2017-7-py2 + driver: + image: netmanagers/salt-2017.7-py2:opensuse-leap-15.1 + run_command: /usr/lib/systemd/systemd + # Workaround to avoid intermittent failures on `opensuse-leap-15.1`: + # => SCP did not finish successfully (255): (Net::SCP::Error) + transport: + max_ssh_sessions: 1 + - name: amazonlinux-2-2017-7-py2 + driver: + image: netmanagers/salt-2017.7-py2:amazonlinux-2 + - name: arch-base-latest-2017-7-py2 + driver: + image: netmanagers/salt-2017.7-py2:arch-base-latest + run_command: /usr/lib/systemd/systemd + +provisioner: + name: salt_solo + log_level: debug + salt_install: none + require_chef: false + formula: icinga2 + salt_copy_filter: + - .kitchen + - .git + +verifier: + # https://www.inspec.io/ + name: inspec + sudo: true + # cli, documentation, html, progress, json, json-min, json-rspec, junit + reporter: + - cli + +suites: + - name: default + provisioner: + state_top: + base: + '*': + - icinga2.icinga-web2 + pillars: + top.sls: + base: + '*': + - icinga2 + pillars_from_files: + icinga2.sls: test/salt/pillar/default.sls + dependencies: + - name: postgres + repo: git + source: https://github.com/saltstack-formulas/postgres-formula.git + verifier: + inspec_tests: + - path: test/integration/default diff --git a/pillar.example b/pillar.example index b4d5a1d..78445d6 100644 --- a/pillar.example +++ b/pillar.example @@ -1,9 +1,12 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- icinga2: lookup: # See defaults.yaml and map.jinja for a better overview service: icinga2 pkgs: - icinga2 - #- nagios-nrpe-plugin + # - nagios-nrpe-plugin ido: db: # MUST BE SET when using icinga2.pgsql-ido @@ -17,13 +20,13 @@ icinga2: required_pkgs: - ... features: - api: False # disable - command: True # enable - gelf: True - graphite: True - opentsdb: True - perfdata: True - statusdata: True + api: false # disable + command: true # enable + gelf: true + graphite: true + opentsdb: true + perfdata: true + statusdata: true # ... notification: @@ -33,7 +36,7 @@ icinga2: ca_file: /etc/ssl/certs/ca-certificates.crt postgres: - use_formula: False # set to True if you are using postgres-formula + use_formula: false # set to true if you are using postgres-formula nrpe: # deprecated config: @@ -100,13 +103,13 @@ icinga2: # Minimalistic, supply only hostname example2.test: {} - # sets - # address: example2.test - # import: generic-host + # # sets + # address: example2.test + # import: generic-host # Removes this host from Icinga deprecated.example.com: - remove: True + remove: true notifications: 'xmpp-host': @@ -120,11 +123,11 @@ icinga2: assign: - 'true' - downtimes: - # see 'notifications' above + downtimes: {} + # see 'notifications' above - services: - # see 'notifications' above + services: {} + # see 'notifications' above notification: xmpp: diff --git a/pre-commit_semantic-release.sh b/pre-commit_semantic-release.sh new file mode 100755 index 0000000..ba80535 --- /dev/null +++ b/pre-commit_semantic-release.sh @@ -0,0 +1,30 @@ +#!/bin/sh + +############################################################################### +# (A) Update `FORMULA` with `${nextRelease.version}` +############################################################################### +sed -i -e "s_^\(version:\).*_\1 ${1}_" FORMULA + + +############################################################################### +# (B) Use `m2r` to convert automatically produced `.md` docs to `.rst` +############################################################################### + +# Install `m2r` +sudo -H pip install m2r + +# Copy and then convert the `.md` docs +cp ./*.md docs/ +cd docs/ || exit +m2r --overwrite ./*.md + +# Change excess `H1` headings to `H2` in converted `CHANGELOG.rst` +sed -i -e '/^=.*$/s/=/-/g' CHANGELOG.rst +sed -i -e '1,4s/-/=/g' CHANGELOG.rst + +# Use for debugging output, when required +# cat AUTHORS.rst +# cat CHANGELOG.rst + +# Return back to the main directory +cd .. diff --git a/release-rules.js b/release-rules.js new file mode 100644 index 0000000..c63c850 --- /dev/null +++ b/release-rules.js @@ -0,0 +1,18 @@ +// No release is triggered for the types commented out below. +// Commits using these types will be incorporated into the next release. +// +// NOTE: Any changes here must be reflected in `CONTRIBUTING.md`. +module.exports = [ + {breaking: true, release: 'major'}, + // {type: 'build', release: 'patch'}, + // {type: 'chore', release: 'patch'}, + // {type: 'ci', release: 'patch'}, + {type: 'docs', release: 'patch'}, + {type: 'feat', release: 'minor'}, + {type: 'fix', release: 'patch'}, + {type: 'perf', release: 'patch'}, + {type: 'refactor', release: 'patch'}, + {type: 'revert', release: 'patch'}, + {type: 'style', release: 'patch'}, + {type: 'test', release: 'patch'}, +]; diff --git a/release.config.js b/release.config.js new file mode 100644 index 0000000..6af7aa8 --- /dev/null +++ b/release.config.js @@ -0,0 +1,106 @@ +module.exports = { + branch: 'master', + plugins: [ + ['@semantic-release/commit-analyzer', { + preset: 'angular', + releaseRules: './release-rules.js', + }], + '@semantic-release/release-notes-generator', + ['@semantic-release/changelog', { + changelogFile: 'CHANGELOG.md', + changelogTitle: '# Changelog', + }], + ['@semantic-release/exec', { + prepareCmd: 'sh ./pre-commit_semantic-release.sh ${nextRelease.version}', + }], + ['@semantic-release/git', { + assets: ['*.md', 'docs/*.rst', 'FORMULA'], + }], + '@semantic-release/github', + ], + generateNotes: { + preset: 'angular', + writerOpts: { + // Required due to upstream bug preventing all types being displayed. + // Bug: https://github.com/conventional-changelog/conventional-changelog/issues/317 + // Fix: https://github.com/conventional-changelog/conventional-changelog/pull/410 + transform: (commit, context) => { + const issues = [] + + commit.notes.forEach(note => { + note.title = `BREAKING CHANGES` + }) + + // NOTE: Any changes here must be reflected in `CONTRIBUTING.md`. + if (commit.type === `feat`) { + commit.type = `Features` + } else if (commit.type === `fix`) { + commit.type = `Bug Fixes` + } else if (commit.type === `perf`) { + commit.type = `Performance Improvements` + } else if (commit.type === `revert`) { + commit.type = `Reverts` + } else if (commit.type === `docs`) { + commit.type = `Documentation` + } else if (commit.type === `style`) { + commit.type = `Styles` + } else if (commit.type === `refactor`) { + commit.type = `Code Refactoring` + } else if (commit.type === `test`) { + commit.type = `Tests` + } else if (commit.type === `build`) { + commit.type = `Build System` + // } else if (commit.type === `chore`) { + // commit.type = `Maintenance` + } else if (commit.type === `ci`) { + commit.type = `Continuous Integration` + } else { + return + } + + if (commit.scope === `*`) { + commit.scope = `` + } + + if (typeof commit.hash === `string`) { + commit.shortHash = commit.hash.substring(0, 7) + } + + if (typeof commit.subject === `string`) { + let url = context.repository + ? `${context.host}/${context.owner}/${context.repository}` + : context.repoUrl + if (url) { + url = `${url}/issues/` + // Issue URLs. + commit.subject = commit.subject.replace(/#([0-9]+)/g, (_, issue) => { + issues.push(issue) + return `[#${issue}](${url}${issue})` + }) + } + if (context.host) { + // User URLs. + commit.subject = commit.subject.replace(/\B@([a-z0-9](?:-?[a-z0-9/]){0,38})/g, (_, username) => { + if (username.includes('/')) { + return `@${username}` + } + + return `[@${username}](${context.host}/${username})` + }) + } + } + + // remove references that already appear in the subject + commit.references = commit.references.filter(reference => { + if (issues.indexOf(reference.issue) === -1) { + return true + } + + return false + }) + + return commit + }, + }, + }, +}; diff --git a/test/integration/default/README.md b/test/integration/default/README.md new file mode 100644 index 0000000..37cf963 --- /dev/null +++ b/test/integration/default/README.md @@ -0,0 +1,50 @@ +# InSpec Profile: `default` + +This shows the implementation of the `default` InSpec [profile](https://github.com/inspec/inspec/blob/master/docs/profiles.md). + +## Verify a profile + +InSpec ships with built-in features to verify a profile structure. + +```bash +$ inspec check default +Summary +------- +Location: default +Profile: profile +Controls: 4 +Timestamp: 2019-06-24T23:09:01+00:00 +Valid: true + +Errors +------ + +Warnings +-------- +``` + +## Execute a profile + +To run all **supported** controls on a local machine use `inspec exec /path/to/profile`. + +```bash +$ inspec exec default +.. + +Finished in 0.0025 seconds (files took 0.12449 seconds to load) +8 examples, 0 failures +``` + +## Execute a specific control from a profile + +To run one control from the profile use `inspec exec /path/to/profile --controls name`. + +```bash +$ inspec exec default --controls package +. + +Finished in 0.0025 seconds (files took 0.12449 seconds to load) +1 examples, 0 failures +``` + +See an [example control here](https://github.com/inspec/inspec/blob/master/examples/profile/controls/example.rb). diff --git a/test/integration/default/controls/config_spec.rb b/test/integration/default/controls/config_spec.rb new file mode 100644 index 0000000..6bf3814 --- /dev/null +++ b/test/integration/default/controls/config_spec.rb @@ -0,0 +1,186 @@ +# frozen_string_literal: true + +control 'icinga2 `features-available/ido-pgsql.conf` configuration' do + title 'should match desired lines' + + describe file('/etc/icinga2/features-available/ido-pgsql.conf') do + it { should be_file } + it { should be_owned_by 'nagios' } + it { should be_grouped_into 'nagios' } + its('mode') { should cmp '0600' } + its('content') { should include 'password = "SomeSecurePassword"' } + end +end + +control 'icinga2 `conf.d/hosts/example.com.conf` configuration' do + title 'should match desired lines' + + describe file('/etc/icinga2/conf.d/hosts/example.com.conf') do + it { should be_file } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + its('mode') { should cmp '0644' } + its('content') { should include 'object Host "example.com"' } + its('content') { should include 'import "generic-host"' } + its('content') { should include 'address = "1.2.3.4"' } + its('content') { should include 'vars.sla = "24x7"' } + end +end + +control 'icinga2 `conf.d/hosts/example.com/http.conf` configuration' do + title 'should match desired lines' + + describe file('/etc/icinga2/conf.d/hosts/example.com/http.conf') do + it { should be_file } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + its('mode') { should cmp '0644' } + its('content') { should include 'object Service "http"' } + its('content') { should include 'import "generic-service"' } + its('content') { should include 'host_name = "example.com"' } + its('content') { should include 'check_command = "http"' } + its('content') { should include 'vars.sla = "24x7"' } + end +end + +control 'icinga2 `conf.d/hosts/example.com/ssh.conf` configuration' do + title 'should match desired lines' + + describe file('/etc/icinga2/conf.d/hosts/example.com/ssh.conf') do + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + its('mode') { should cmp '0644' } + its('content') { should include 'object Service "ssh"' } + its('content') { should include 'import "generic-service"' } + its('content') { should include 'host_name = "example.com"' } + its('content') { should include 'check_command = "ssh"' } + its('content') { should include 'vars.sla = "24x7"' } + end +end + +control 'icinga2 `conf.d/hosts/example.com/ssh_alt.conf` configuration' do + title 'should match desired lines' + + describe file('/etc/icinga2/conf.d/hosts/example.com/ssh_alt.conf') do + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + its('mode') { should cmp '0644' } + its('content') { should include 'object Service "ssh_alt"' } + its('content') { should include 'import "generic-service"' } + its('content') { should include 'host_name = "example.com"' } + its('content') { should include 'check_command = "ssh"' } + its('content') { should include 'vars.ssh_port = "43"' } + its('content') { should include 'vars.sla = "24x7"' } + end +end + +control 'icinga2 `conf.d/hosts/example2.test.conf` configuration' do + title 'should match desired lines' + + describe file('/etc/icinga2/conf.d/hosts/example2.test.conf') do + it { should be_file } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + its('mode') { should cmp '0644' } + its('content') { should include 'object Host "example2.test"' } + its('content') { should include 'import "generic-host"' } + its('content') { should include 'address = "example2.test"' } + end +end + +control 'icinga2 `conf.d/templates/special-host.conf` configuration' do + title 'should match desired lines' + + describe file('/etc/icinga2/conf.d/templates/special-host.conf') do + it { should be_file } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + its('mode') { should cmp '0644' } + its('content') { should include 'template Host "special-host"' } + its('content') { should include 'vars.sla = "24x5"' } + end +end + +control 'icinga2 `conf.d/templates/special-downtime.conf` configuration' do + title 'should match desired lines' + + describe file('/etc/icinga2/conf.d/templates/special-downtime.conf') do + it { should be_file } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + its('mode') { should cmp '0644' } + its('content') { should include 'template ScheduledDowntime "special-downtime"' } + its('content') { should include 'ranges =' } + its('content') { should include 'monday = "02:00-03:00"' } + end +end + +control 'icinga2 `conf.d/templates/special-notification.conf` configuration' do + title 'should match desired lines' + + describe file('/etc/icinga2/conf.d/templates/special-notification.conf') do + it { should be_file } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + its('mode') { should cmp '0644' } + its('content') { should include 'template Notification "special-notification"' } + its('content') { should include 'types = [ FlappingStart,FlappingEnd ]' } + end +end + +control 'icinga2 `conf.d/users/alice.conf` configuration' do + title 'should match desired lines' + + describe file('/etc/icinga2/conf.d/users/alice.conf') do + it { should be_file } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + its('mode') { should cmp '0644' } + its('content') { should include 'object User "alice"' } + its('content') { should include 'email = "alice@example.test"' } + its('content') { should include 'groups = [ "icingaadmins" ]' } + its('content') { should include 'vars.jabber = "alice@jabber.example.test"' } + end +end + +control 'icinga2 `conf.d/user_groups/icingaadmins_alt.conf` configuration' do + title 'should match desired lines' + + describe file('/etc/icinga2/conf.d/user_groups/icingaadmins_alt.conf') do + it { should be_file } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + its('mode') { should cmp '0644' } + its('content') { should include 'object UserGroup "icingaadmins_alt"' } + its('content') { should include 'display_name = "Icinga 2 Admin Group (alt)"' } + end +end + +control 'icinga2 directories configuration' do + title 'should match desired settings' + + %w[ + /etc/icinga2/conf.d/downtimes + /etc/icinga2/conf.d/services + /etc/icinga2/conf.d/check_command + /etc/icinga2/scripts + ].each do |d| + describe file(d) do + it { should be_directory } + it { should be_owned_by 'root' } + it { should be_grouped_into 'root' } + its('mode') { should cmp '0755' } + end + end +end + +control 'icingaweb2 directory configuration' do + title 'should match desired settings' + + describe file('/etc/icingaweb2') do + it { should be_directory } + it { should be_owned_by 'www-data' } + it { should be_grouped_into 'icingaweb2' } + its('mode') { should cmp '0750' } + end +end diff --git a/test/integration/default/controls/packages_spec.rb b/test/integration/default/controls/packages_spec.rb new file mode 100644 index 0000000..7cf33bc --- /dev/null +++ b/test/integration/default/controls/packages_spec.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +control 'icinga2 packages' do + title 'should be installed' + + %w[ + icinga2-ido-pgsql + icinga2 + icingaweb2 + icingaweb2-module-doc + icingaweb2-module-monitoring + ].each do |p| + describe package(p) do + it { should be_installed } + end + end +end diff --git a/test/integration/default/controls/services_spec.rb b/test/integration/default/controls/services_spec.rb new file mode 100644 index 0000000..c45efad --- /dev/null +++ b/test/integration/default/controls/services_spec.rb @@ -0,0 +1,12 @@ +# frozen_string_literal: true + +control 'icinga2 service' do + impact 0.5 + title 'should be installed, running and enabled' + + describe service('icinga2') do + it { should be_installed } + it { should be_enabled } + it { should be_running } + end +end diff --git a/test/integration/default/inspec.yml b/test/integration/default/inspec.yml new file mode 100644 index 0000000..b6faf12 --- /dev/null +++ b/test/integration/default/inspec.yml @@ -0,0 +1,18 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +name: default +title: icinga2 formula +maintainer: SaltStack Formulas +license: Apache-2.0 +summary: Verify that the icinga2 formula is setup and configured correctly +supports: + - platform-name: debian + - platform-name: ubuntu + - platform-name: centos + - platform-name: fedora + - platform-name: opensuse + - platform-name: suse + - platform-name: freebsd + - platform-name: amazon + - platform-name: arch diff --git a/test/salt/pillar/default.sls b/test/salt/pillar/default.sls new file mode 100644 index 0000000..8b60d60 --- /dev/null +++ b/test/salt/pillar/default.sls @@ -0,0 +1,137 @@ +# -*- coding: utf-8 -*- +# vim: ft=yaml +--- +icinga2: + lookup: # See defaults.yaml and map.jinja for a better overview + service: icinga2 + pkgs: + - icinga2 + # - nagios-nrpe-plugin + ido: + db: + # MUST BE SET when using icinga2.pgsql-ido + password: SomeSecurePassword + icinga_web2: + db: + # MUST BE SET when using icinga2.icinga-web2-database + password: AnotherSecurePassword + # pkgs: + # - ... + # required_pkgs: + # - ... + features: + api: false # disable + command: true # enable + gelf: true + graphite: true + opentsdb: true + perfdata: true + statusdata: true + # ... + + notification: + xmpp: + pkg: python3-slixmpp + python_executable: python3 + ca_file: /etc/ssl/certs/ca-certificates.crt + + postgres: + use_formula: true # set to true if you are using postgres-formula + + nrpe: # deprecated + config: + server_port: 5666 + commands: + check_users: /usr/lib/nagios/plugins/check_users -w 5 -c 10 + defaults: + DAEMON_OPTS: "\"--no-ssl\"" + + conf: + users: + alice: + email: alice@example.test + groups: + - icingaadmins + vars: + jabber: alice@jabber.example.test + user_groups: + # Using `alt` because only want this in `users.conf`, as shown in the docs: + # - https://icinga.com/docs/icinga2/latest/doc/04-configuration/#usersconf + icingaadmins_alt: + display_name: "Icinga 2 Admin Group (alt)" + templates: + special-host: + type: Host + conf: + vars: + sla: "24x5" + special-downtime: + type: ScheduledDowntime + conf: + ranges: + monday: "02:00-03:00" + special-notification: + type: Notification + conf: + types: + - FlappingStart + - FlappingEnd + hosts: + example.com: + import: generic-host + address: 1.2.3.4 + vars: + sla: "24x7" + services: + http: + import: generic-service + host_name: example.com + check_command: http + vars: + sla: "24x7" + ssh: + import: generic-service + host_name: example.com + check_command: ssh + vars: + sla: "24x7" + ssh_alt: + import: generic-service + host_name: example.com + check_command: ssh + vars: + ssh_port: 43 + sla: "24x7" + + # Minimalistic, supply only hostname + example2.test: {} + # # sets + # address: example2.test + # import: generic-host + + # Removes this host from Icinga + deprecated.example.com: + remove: true + + # notifications: + # 'xmpp-host': + # # opt-in to trigger application + # apply_to: Host + # conf: + # users: + # - alice + # # defined by icinga.notification.xmpp + # command: 'xmpp-host-notification' + # assign: + # - 'true' + + downtimes: {} + # see 'notifications' above + + services: {} + # see 'notifications' above + + notification: + xmpp: + jid: icinga@jabber.example.test + password: supersecurerandomizeduniquepassword