nagios-charmers team mailing list archive
-
nagios-charmers team
-
Mailing list archive
-
Message #00325
[Merge] ~woutervb/nagios-charm:master into nagios-charm:reactive
Wouter van Bommel has proposed merging ~woutervb/nagios-charm:master into nagios-charm:reactive.
Requested reviews:
Nagios Charm developers (nagios-charmers)
For more details, see:
https://code.launchpad.net/~woutervb/nagios-charm/+git/nagios-charm/+merge/364360
--
Your team Nagios Charm developers is requested to review the proposed merge of ~woutervb/nagios-charm:master into nagios-charm:reactive.
diff --git a/.gitignore b/.gitignore
index e650362..8f6789a 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,8 +1,19 @@
-*.pyc
-*.swp
-*~
+# Byte-compiled / optimized / DLL files
__pycache__/
-data/*.pem
-data/*.key
-data/*.crt
-data/*.csr
+*.py[cod]
+*$py.class
+
+# Log files
+*.log
+
+.tox/
+.coverage
+
+# vi
+.*.swp
+
+# pycharm
+.idea/
+
+# version data
+src/repo-info
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..55d5325
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,15 @@
+[submodule "layers/layer-basic"]
+ path = layers/layer-basic
+ url = https://github.com/juju-solutions/layer-basic.git
+[submodule "layers/layer-options"]
+ path = layers/layer-options
+ url = https://github.com/juju-solutions/layer-options.git
+[submodule "layers/juju-info"]
+ path = layers/juju-info
+ url = https://github.com/juju-solutions/interface-juju-info.git
+[submodule "layers/http"]
+ path = layers/http
+ url = https://github.com/juju-solutions/interface-http.git
+[submodule "src/lib/pynag"]
+ path = src/lib/pynag
+ url = https://github.com/netmarkjp/pynag.git
diff --git a/.isort.cfg b/.isort.cfg
new file mode 100644
index 0000000..8913d96
--- /dev/null
+++ b/.isort.cfg
@@ -0,0 +1,2 @@
+[settings]
+line_length=120
diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
new file mode 100644
index 0000000..62fb432
--- /dev/null
+++ b/.pre-commit-config.yaml
@@ -0,0 +1,49 @@
+repos:
+- repo: git://github.com/pre-commit/pre-commit-hooks
+ rev: v2.1.0
+ hooks:
+ - id: trailing-whitespace
+ exclude: cherrypy/test/static/index.html
+ - id: flake8
+ args:
+ # W503 ignored for https://github.com/PyCQA/pycodestyle/issues/498
+ - --ignore=W503
+ # E126 ignored, as yapf will give better identation
+ - --ignore=E126
+ - --max-line-length=120
+ - id: check-merge-conflict
+ - id: double-quote-string-fixer
+ - id: end-of-file-fixer
+ - id: check-ast
+ - id: check-added-large-files
+ - id: check-byte-order-marker
+ - id: check-case-conflict
+ - id: check-json
+# include: .mention-bot
+ - id: pretty-format-json
+ - id: check-symlinks
+ - id: check-yaml
+ - id: detect-private-key
+# exclude: cherrypy/test/test.pem
+ - id: requirements-txt-fixer
+
+
+- repo: git://github.com/Lucas-C/pre-commit-hooks
+ rev: v1.1.6
+ hooks:
+ - id: remove-tabs
+
+- repo: https://github.com/pre-commit/mirrors-yapf
+ rev: v0.26.0 # Use the sha / tag you want to point at
+ hooks:
+ - id: yapf
+
+- repo: https://github.com/pre-commit/mirrors-isort
+ rev: v4.3.12 # Use the sha / tag you want to point at
+ hooks:
+ - id: isort
+
+ #- repo: git://github.com/FalconSocial/pre-commit-mirrors-pep257
+ # rev: v0.3.3
+ # hooks:
+ # - id: pep257
diff --git a/.style.yapf b/.style.yapf
new file mode 100644
index 0000000..c480bf3
--- /dev/null
+++ b/.style.yapf
@@ -0,0 +1,263 @@
+[style]
+# Align closing bracket with visual indentation.
+align_closing_bracket_with_visual_indent=True
+
+# Allow dictionary keys to exist on multiple lines. For example:
+#
+# x = {
+# ('this is the first element of a tuple',
+# 'this is the second element of a tuple'):
+# value,
+# }
+allow_multiline_dictionary_keys=False
+
+# Allow lambdas to be formatted on more than one line.
+allow_multiline_lambdas=False
+
+# Allow splits before the dictionary value.
+allow_split_before_dict_value=True
+
+# Number of blank lines surrounding top-level function and class
+# definitions.
+blank_lines_around_top_level_definition=2
+
+# Insert a blank line before a class-level docstring.
+blank_line_before_class_docstring=False
+
+# Insert a blank line before a module docstring.
+blank_line_before_module_docstring=False
+
+# Insert a blank line before a 'def' or 'class' immediately nested
+# within another 'def' or 'class'. For example:
+#
+# class Foo:
+# # <------ this blank line
+# def method():
+# ...
+blank_line_before_nested_class_or_def=False
+
+# Do not split consecutive brackets. Only relevant when
+# dedent_closing_brackets is set. For example:
+#
+# call_func_that_takes_a_dict(
+# {
+# 'key1': 'value1',
+# 'key2': 'value2',
+# }
+# )
+#
+# would reformat to:
+#
+# call_func_that_takes_a_dict({
+# 'key1': 'value1',
+# 'key2': 'value2',
+# })
+coalesce_brackets=False
+
+# The column limit.
+column_limit=119
+
+# The style for continuation alignment. Possible values are:
+#
+# - SPACE: Use spaces for continuation alignment. This is default behavior.
+# - FIXED: Use fixed number (CONTINUATION_INDENT_WIDTH) of columns
+# (ie: CONTINUATION_INDENT_WIDTH/INDENT_WIDTH tabs) for continuation
+# alignment.
+# - LESS: Slightly left if cannot vertically align continuation lines with
+# indent characters.
+# - VALIGN-RIGHT: Vertically align continuation lines with indent
+# characters. Slightly right (one more indent character) if cannot
+# vertically align continuation lines with indent characters.
+#
+# For options FIXED, and VALIGN-RIGHT are only available when USE_TABS is
+# enabled.
+continuation_align_style=SPACE
+
+# Indent width used for line continuations.
+continuation_indent_width=4
+
+# Put closing brackets on a separate line, dedented, if the bracketed
+# expression can't fit in a single line. Applies to all kinds of brackets,
+# including function definitions and calls. For example:
+#
+# config = {
+# 'key1': 'value1',
+# 'key2': 'value2',
+# } # <--- this bracket is dedented and on a separate line
+#
+# time_series = self.remote_client.query_entity_counters(
+# entity='dev3246.region1',
+# key='dns.query_latency_tcp',
+# transform=Transformation.AVERAGE(window=timedelta(seconds=60)),
+# start_ts=now()-timedelta(days=3),
+# end_ts=now(),
+# ) # <--- this bracket is dedented and on a separate line
+dedent_closing_brackets=False
+
+# Disable the heuristic which places each list element on a separate line
+# if the list is comma-terminated.
+disable_ending_comma_heuristic=False
+
+# Place each dictionary entry onto its own line.
+each_dict_entry_on_separate_line=True
+
+# The regex for an i18n comment. The presence of this comment stops
+# reformatting of that line, because the comments are required to be
+# next to the string they translate.
+i18n_comment=
+
+# The i18n function call names. The presence of this function stops
+# reformattting on that line, because the string it has cannot be moved
+# away from the i18n comment.
+i18n_function_call=
+
+# Indent blank lines.
+indent_blank_lines=False
+
+# Indent the dictionary value if it cannot fit on the same line as the
+# dictionary key. For example:
+#
+# config = {
+# 'key1':
+# 'value1',
+# 'key2': value1 +
+# value2,
+# }
+indent_dictionary_value=False
+
+# The number of columns to use for indentation.
+indent_width=4
+
+# Join short lines into one line. E.g., single line 'if' statements.
+join_multiple_lines=True
+
+# Do not include spaces around selected binary operators. For example:
+#
+# 1 + 2 * 3 - 4 / 5
+#
+# will be formatted as follows when configured with "*,/":
+#
+# 1 + 2*3 - 4/5
+#
+no_spaces_around_selected_binary_operators=
+
+# Use spaces around default or named assigns.
+spaces_around_default_or_named_assign=False
+
+# Use spaces around the power operator.
+spaces_around_power_operator=False
+
+# The number of spaces required before a trailing comment.
+spaces_before_comment=2
+
+# Insert a space between the ending comma and closing bracket of a list,
+# etc.
+space_between_ending_comma_and_closing_bracket=True
+
+# Split before arguments
+split_all_comma_separated_values=False
+
+# Split before arguments if the argument list is terminated by a
+# comma.
+split_arguments_when_comma_terminated=False
+
+# Set to True to prefer splitting before '&', '|' or '^' rather than
+# after.
+split_before_bitwise_operator=True
+
+# Split before the closing bracket if a list or dict literal doesn't fit on
+# a single line.
+split_before_closing_bracket=True
+
+# Split before a dictionary or set generator (comp_for). For example, note
+# the split before the 'for':
+#
+# foo = {
+# variable: 'Hello world, have a nice day!'
+# for variable in bar if variable != 42
+# }
+split_before_dict_set_generator=True
+
+# Split before the '.' if we need to split a longer expression:
+#
+# foo = ('This is a really long string: {}, {}, {}, {}'.format(a, b, c, d))
+#
+# would reformat to something like:
+#
+# foo = ('This is a really long string: {}, {}, {}, {}'
+# .format(a, b, c, d))
+split_before_dot=False
+
+# Split after the opening paren which surrounds an expression if it doesn't
+# fit on a single line.
+split_before_expression_after_opening_paren=False
+
+# If an argument / parameter list is going to be split, then split before
+# the first argument.
+split_before_first_argument=False
+
+# Set to True to prefer splitting before 'and' or 'or' rather than
+# after.
+split_before_logical_operator=True
+
+# Split named assignments onto individual lines.
+split_before_named_assigns=True
+
+# Set to True to split list comprehensions and generators that have
+# non-trivial expressions and multiple clauses before each of these
+# clauses. For example:
+#
+# result = [
+# a_long_var + 100 for a_long_var in xrange(1000)
+# if a_long_var % 10]
+#
+# would reformat to something like:
+#
+# result = [
+# a_long_var + 100
+# for a_long_var in xrange(1000)
+# if a_long_var % 10]
+split_complex_comprehension=False
+
+# The penalty for splitting right after the opening bracket.
+split_penalty_after_opening_bracket=30
+
+# The penalty for splitting the line after a unary operator.
+split_penalty_after_unary_operator=10000
+
+# The penalty for splitting right before an if expression.
+split_penalty_before_if_expr=0
+
+# The penalty of splitting the line around the '&', '|', and '^'
+# operators.
+split_penalty_bitwise_operator=300
+
+# The penalty for splitting a list comprehension or generator
+# expression.
+split_penalty_comprehension=80
+
+# The penalty for characters over the column limit.
+split_penalty_excess_character=7000
+
+# The penalty incurred by adding a line split to the unwrapped line. The
+# more line splits added the higher the penalty.
+split_penalty_for_added_line_split=30
+
+# The penalty of splitting a list of "import as" names. For example:
+#
+# from a_very_long_or_indented_module_name_yada_yad import (long_argument_1,
+# long_argument_2,
+# long_argument_3)
+#
+# would reformat to something like:
+#
+# from a_very_long_or_indented_module_name_yada_yad import (
+# long_argument_1, long_argument_2, long_argument_3)
+split_penalty_import_names=0
+
+# The penalty of splitting the line around the 'and' and 'or'
+# operators.
+split_penalty_logical_operator=300
+
+# Use the Tab character for indentation.
+use_tabs=False
diff --git a/Makefile b/Makefile
index 9d48829..f45ed77 100644
--- a/Makefile
+++ b/Makefile
@@ -1,28 +1,50 @@
-#!/usr/bin/make
-PYTHON := /usr/bin/python3
-export PYTHONPATH := hooks
-
-default:
- echo Nothing to do
-
-# Primitive test runner. Someone please fix this.
-test:
- tests/00-setup
- tests/100-deploy
- tests/10-initial-test
- tests/15-nrpe-test
- tests/20-ssl-test
- tests/21-monitors-interface-test
- tests/22-extraconfig-test
- tests/23-livestatus-test
- tests/24-pagerduty-test
-
-bin/charm_helpers_sync.py:
- @mkdir -p bin
- @bzr cat lp:charm-helpers/tools/charm_helpers_sync/charm_helpers_sync.py \
- > bin/charm_helpers_sync.py
-
-sync: bin/charm_helpers_sync.py
- @$(PYTHON) bin/charm_helpers_sync.py -c charm-helpers.yaml
+ifndef JUJU_REPOSITORY
+ JUJU_REPOSITORY := $(shell pwd)
+ $(warning Warning JUJU_REPOSITORY was not set, defaulting to $(JUJU_REPOSITORY))
+endif
+help:
+ @echo "This project supports the following targets"
+ @echo ""
+ @echo " make help - show this text"
+ @echo " make submodules - make sure that the submodules are up-to-date"
+ @echo " make lint - run flake8"
+ @echo " make test - run the unittests and lint"
+ @echo " make unittest - run the tests defined in the unittest subdirectory"
+ @echo " make functional - run the tests defined in the functional subdirectory"
+ @echo " make release - build the charm"
+ @echo " make clean - remove unneeded files"
+ @echo ""
+submodules:
+ @echo "Cloning submodules"
+ @git submodule update --init --recursive
+
+lint:
+ @echo "Running flake8"
+ @cd src && tox -e lint
+
+test: unittest functional lint
+
+unittest:
+ @cd src && tox -e unit
+
+functional: build
+ @cd src && tox -e functional
+
+build:
+ @echo "Building charm to base directory $(JUJU_REPOSITORY)"
+ @-git describe --tags > ./src/repo-info
+ @CHARM_LAYERS_DIR=./layers CHARM_INTERFACES_DIR=./interfaces TERM=linux\
+ JUJU_REPOSITORY=$(JUJU_REPOSITORY) charm build ./src --force
+
+release: clean build
+ @echo "Charm is built at $(JUJU_REPOSITORY)/builds"
+
+clean:
+ @echo "Cleaning files"
+ @if [ -d src/.tox ] ; then rm -r src/.tox ; fi
+ @if [ -d src/.pytest_cache ] ; then rm -r src/.pytest_cache ; fi
+
+# The targets below don't depend on a file
+.PHONY: lint test unittest functional build release clean help submodules
diff --git a/interfaces/.empty b/interfaces/.empty
new file mode 100644
index 0000000..792d600
--- /dev/null
+++ b/interfaces/.empty
@@ -0,0 +1 @@
+#
diff --git a/interfaces/monitors/interface.yaml b/interfaces/monitors/interface.yaml
new file mode 100644
index 0000000..01e3d25
--- /dev/null
+++ b/interfaces/monitors/interface.yaml
@@ -0,0 +1,3 @@
+name: monitors
+summary: Monitoring link
+version: 1
diff --git a/interfaces/monitors/requires.py b/interfaces/monitors/requires.py
new file mode 100644
index 0000000..4bba8f8
--- /dev/null
+++ b/interfaces/monitors/requires.py
@@ -0,0 +1,50 @@
+#!/usr/bin/python
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import yaml
+from charms.reactive import RelationBase, hook, scopes
+
+
+class MonitorsClient(RelationBase):
+ scope = scopes.GLOBAL
+
+ auto_accessors = ['private_address']
+
+ @hook('{requires:monitors}-relation-{joined,changed}')
+ def changed(self):
+ self.set_state('{relation_name}.connected')
+ if self.private_address():
+ self.set_state('{relation_name}.available')
+
+ @hook('{requires:monitors}-relation-{broken, departed}')
+ def broken(self):
+ self.remove_state('{relation_name}.available')
+ self.remove_state('{relation_name}.connected')
+
+ def monitors(self):
+ """
+ Returns dict containing the information about the host to monitor, the how and the what parts.
+
+ {
+ 'monitors':
+ {
+ 'remote': {}
+ }
+ }
+
+ """
+ monitors = self.get_remote('monitors')
+ if monitors is not type(dict):
+ monitors = yaml.safe_load(monitors)
+
+ return monitors
diff --git a/layers/.empty b/layers/.empty
new file mode 100644
index 0000000..792d600
--- /dev/null
+++ b/layers/.empty
@@ -0,0 +1 @@
+#
diff --git a/layers/http b/layers/http
new file mode 160000
index 0000000..0614445
--- /dev/null
+++ b/layers/http
@@ -0,0 +1 @@
+Subproject commit 0614445f60f11422cc1bb36bdb2f4a87d2c3d0bc
diff --git a/layers/juju-info b/layers/juju-info
new file mode 160000
index 0000000..8495c8d
--- /dev/null
+++ b/layers/juju-info
@@ -0,0 +1 @@
+Subproject commit 8495c8d5e183ee57dffee939aefe92e246d5186b
diff --git a/layers/layer-basic b/layers/layer-basic
new file mode 160000
index 0000000..871cdfa
--- /dev/null
+++ b/layers/layer-basic
@@ -0,0 +1 @@
+Subproject commit 871cdfa33f120181f6267be2db5712984c760721
diff --git a/layers/layer-options b/layers/layer-options
new file mode 160000
index 0000000..fcdcea4
--- /dev/null
+++ b/layers/layer-options
@@ -0,0 +1 @@
+Subproject commit fcdcea4e5de3e1556c24e6704607862d0ba00a56
diff --git a/src/Makefile b/src/Makefile
new file mode 100644
index 0000000..cbd8b5c
--- /dev/null
+++ b/src/Makefile
@@ -0,0 +1,30 @@
+help:
+ @echo "This project supports the following targets"
+ @echo ""
+ @echo " make help - show this text"
+ @echo " make lint - run flake8"
+ @echo " make test - run the functional test and unittests"
+ @echo " make unittest - run the the unittest"
+ @echo " make functionaltest - run the functional tests"
+ @echo " make clean - remove unneeded files"
+ @echo ""
+
+lint:
+ @echo "Running flake8"
+ @tox -e lint
+
+test: unittest functionaltest lint
+
+unittest:
+ @tox -e unit
+
+functionaltest:
+ @tox -e functional
+
+clean:
+ @echo "Cleaning files"
+ @if [ -d ./.tox ] ; then rm -r ./.tox ; fi
+ @if [ -d ./.pytest_cache ] ; then rm -r ./.pytest_cache ; fi
+
+# The targets below don't depend on a file
+.PHONY: lint test unittest functionaltest clean help
diff --git a/src/actions.yaml b/src/actions.yaml
new file mode 100644
index 0000000..f1b2535
--- /dev/null
+++ b/src/actions.yaml
@@ -0,0 +1,2 @@
+example-action:
+ description: "This is just a test"
diff --git a/src/actions/example-action b/src/actions/example-action
new file mode 100755
index 0000000..459e59e
--- /dev/null
+++ b/src/actions/example-action
@@ -0,0 +1,6 @@
+#!/usr/local/sbin/charm-env python3
+
+from lib_nagios_charm import NagioscharmHelper
+
+helper = NagioscharmHelper()
+helper.action_function()
diff --git a/src/config.yaml b/src/config.yaml
new file mode 100644
index 0000000..23f0a59
--- /dev/null
+++ b/src/config.yaml
@@ -0,0 +1,186 @@
+options:
+ extraconfig:
+ type: string
+ default: ""
+ description: |
+ Any additional nagios configuration you would like to
+ add can be set into this element. It will be placed in
+ /etc/nagios3/conf.d/extra.cfg
+ ssl:
+ type: string
+ default: "off"
+ description: |
+ Enable SSL communication for Nagios. Possible values are
+ "on", "off", or "only". The "only" option disables
+ All HTTP communication in favor of HTTPS - may play havok with
+ existing nagios deployments.
+ ssl_cert:
+ type: string
+ default: None
+ description: |
+ base64 encoded server certificate. If left blank, the certificate
+ and key will be autogenerated as self-signed.
+ default: ''
+ ssl_key:
+ type: string
+ default: None
+ description: |
+ base64 encoded server certificate key. If ssl_cert is
+ blank, this is ignored.
+ default: ''
+ ssl_chain:
+ type: string
+ default: ''
+ description: |
+ base64 encoded chain certificates file. If ssl_cert is
+ blank, this will be ignored.
+ enable_livestatus:
+ type: boolean
+ default: false
+ description: |
+ Config variable to enable livestatus module or not.
+ livestatus_path:
+ type: string
+ default: "/var/lib/nagios3/livestatus/socket"
+ description: |
+ Default path to livestatus socket, if enabled via enable_livestatus
+ livestatus_args:
+ type: string
+ default: ""
+ description: |
+ Arguments to be passed to the livestatus module, defaults to empty.
+ nagios_user:
+ type: string
+ default: nagios
+ description: |
+ The effective user that nagios will run as.
+ nagios_group:
+ type: string
+ default: nagios
+ description: |
+ The effective group that nagios will run as.
+ check_external_commands:
+ type: int
+ default: 1
+ description: |
+ Config variable to enable checking external commands - 0 is disable, 1 is enable.
+ command_check_interval:
+ type: string
+ default: "-1"
+ description: |
+ How often to check for external commands.
+ command_file:
+ type: string
+ default: /var/lib/nagios3/rw/nagios.cmd
+ description: |
+ File that Nagios checks for external command requests.
+ debug_level:
+ type: int
+ default: 0
+ description: |
+ Specify the debug level for nagios. See the docs for more details.
+ debug_verbosity:
+ type: int
+ default: 1
+ description: |
+ How verbose will the debug logs be - 0 is brief, 1 is more detailed
+ and 2 is very detailed.
+ debug_file:
+ type: string
+ default: "/var/log/nagios3/nagios.debug"
+ description: |
+ Path for the debug file.
+ daemon_dumps_core:
+ type: int
+ default: 0
+ description:
+ Option to determine if Nagios is allowed to create a core dump.
+ admin_email:
+ type: string
+ default: root@localhost
+ description: |
+ Email address used for the admin, used by $ADMINEMAIL$ in notification
+ commands.
+ admin_pager:
+ type: string
+ default: pageroot@localhost
+ description: |
+ Email address used for the admin pager, used by $ADMINPAGER$ in
+ notification commands.
+ enable_pagerduty:
+ type: boolean
+ default: false
+ description: |
+ Config variable to enable pagerduty notifications or not.
+ pagerduty_key:
+ type: string
+ default: ""
+ description: |
+ Pagerduty API key to use for notifications
+ pagerduty_path:
+ type: string
+ default: "/var/lib/nagios3/pagerduty"
+ description: |
+ Path for Pagerduty notifications to be queued.
+ log_rotation_method:
+ type: string
+ default: "d"
+ description: |
+ Log rotation method that Nagios should use to rotate the main logfile.
+ log_archive_path:
+ type: string
+ default: "/var/log/nagios3/archives"
+ description: |
+ Path for archived log files
+ use_syslog:
+ type: int
+ default: 1
+ description: |
+ Log messages to syslog as well as main file.
+ password:
+ type: string
+ default: '/var/lib/juju/nagios.passwd'
+ description: |
+ Password to use for Nagios administrative access. If not
+ provided, a password will be generated (see documentation for
+ instructions on retrieving the generated password.)
+ ro-password:
+ type: string
+ default: ''
+ description: |
+ Password to use for read-only Nagios access. If left blank, the nagiosro account will not be created.
+ monitor_self:
+ type: boolean
+ default: true
+ description: |
+ If true, enable monitoring of the nagios unit itself.
+ nagios_host_context:
+ default: "juju"
+ type: string
+ description: |
+ a string that will be prepended to instance name to set the host name
+ in nagios. So for instance the hostname would be something like:
+ juju-postgresql-0
+ If you're running multiple environments with the same services in them
+ this allows you to differentiate between them.
+ load_monitor:
+ default: '5.0!4.0!3.0!10.0!6.0!4.0'
+ type: string
+ description: |
+ A string to pass to the Nagios load monitoring command. Default is
+ to report warning at 5.0, 4.0 and 3.0 averages, critical at 10.0,
+ 6.0 and 4.0.
+ pagerduty_notification_levels:
+ default: w,u,c,r
+ type: string
+ description: |
+ A string to use for the service_notification_options in the
+ pagerduty contact configuration. Remove w to avoid paging for
+ warning events.
+ check_timeout:
+ default: 10
+ type: int
+ description: |
+ A number of seconds before nrpe checks timeout from not being able
+ to connect to the client or finish execution of the command.
+ Raise this value to combat 'CHECK_NRPE Socket timeout alerts'
diff --git a/src/files/pagerduty_nagios.pl b/src/files/pagerduty_nagios.pl
new file mode 100755
index 0000000..afd18be
--- /dev/null
+++ b/src/files/pagerduty_nagios.pl
@@ -0,0 +1,289 @@
+#!/usr/bin/env perl
+
+
+# Nagios plugin that sends Nagios events to PagerDuty.
+#
+# Copyright (c) 2011, PagerDuty, Inc. <info@xxxxxxxxxxxxx>
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# * Neither the name of PagerDuty Inc nor the
+# names of its contributors may be used to endorse or promote products
+# derived from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+# DISCLAIMED. IN NO EVENT SHALL PAGERDUTY INC BE LIABLE FOR ANY
+# DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+# (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+# LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+use Pod::Usage;
+use Getopt::Long;
+use Sys::Syslog;
+use HTTP::Request::Common qw(POST);
+use HTTP::Status qw(is_client_error);
+use LWP::UserAgent;
+use File::Path;
+use Fcntl qw(:flock);
+
+
+=head1 NAME
+
+pagerduty_nagios -- Send Nagios events to the PagerDuty alert system
+
+=head1 SYNOPSIS
+
+pagerduty_nagios enqueue [options]
+
+pagerduty_nagios flush [options]
+
+=head1 DESCRIPTION
+
+ This script passes events from Nagios to the PagerDuty alert system. It's
+ meant to be run as a Nagios notification plugin. For more details, please see
+ the PagerDuty Nagios integration docs at:
+ http://www.pagerduty.com/docs/nagios-integration.
+
+ When called in the "enqueue" mode, the script loads a Nagios notification out
+ of the environment and into the event queue. It then tries to flush the
+ queue by sending any enqueued events to the PagerDuty server. The script is
+ typically invoked in this mode from a Nagios notification handler.
+
+ When called in the "flush" mode, the script simply tries to send any enqueued
+ events to the PagerDuty server. This mode is typically invoked by cron. The
+ purpose of this mode is to retry any events that couldn't be sent to the
+ PagerDuty server for whatever reason when they were initially enqueued.
+
+=head1 OPTIONS
+
+ --api-base URL
+ The base URL used to communicate with PagerDuty. The default option here
+ should be fine, but adjusting it may make sense if your firewall doesn't
+ pass HTTPS traffic for some reason. See the PagerDuty Nagios integration
+ docs for details.
+
+ --field KEY=VALUE
+ Add this key-value pair to the event being passed to PagerDuty. The script
+ automatically gathers Nagios macros out of the environment, so there's no
+ need to specify these explicitly. This option can be repeated as many
+ times as necessary to pass multiple key-value pairs. This option is only
+ useful when an event is being enqueued.0
+
+ --help
+ Display documentation for the script.
+
+ --queue-dir DIR
+ Path to the directory to use to store the event queue. By default, we use
+ /tmp/pagerduty_nagios.
+
+ --verbose
+ Turn on extra debugging information. Useful for debugging.
+
+ --proxy
+ Use a proxy for the connections like "--proxy http://127.0.0.1:8888/"
+
+=cut
+
+# This release tested on:
+# Debian Sarge (Perl 5.8.4)
+# Ubuntu 9.04 (Perl 5.10.0)
+
+my $opt_api_base = "https://events.pagerduty.com/nagios/2010-04-15";
+my %opt_fields;
+my $opt_help;
+my $opt_queue_dir = "/tmp/pagerduty_nagios";
+my $opt_verbose;
+my $opt_proxy;
+
+
+sub get_queue_from_dir {
+ my $dh;
+
+ unless (opendir($dh, $opt_queue_dir)) {
+ syslog(LOG_ERR, "opendir %s failed: %s", $opt_queue_dir, $!);
+ die $!;
+ }
+
+ my @files;
+ while (my $f = readdir($dh)) {
+ next unless $f =~ /^pd_(\d+)_\d+\.txt$/;
+ push @files, [int($1), $f];
+ }
+
+ closedir($dh);
+
+ @files = sort { @{$a}[0] <=> @{$b}[0] } @files;
+ return map { @{$_}[1] } @files;
+}
+
+
+sub flush_queue {
+ my @files = get_queue_from_dir();
+ my $ua = LWP::UserAgent->new;
+
+ # It's not a big deal if we don't get the message through the first time.
+ # It will get sent the next time cron fires.
+ $ua->timeout(15);
+
+ if ($opt_proxy) {
+ $ua->proxy (['http', 'https'], $opt_proxy);
+ }
+
+ foreach (@files) {
+ my $filename = "$opt_queue_dir/$_";
+ my $fd;
+ my %event;
+
+ print STDERR "==== Now processing: $filename\n" if $opt_verbose;
+
+ unless (open($fd, "<", $filename)) {
+ syslog(LOG_ERR, "open %s for read failed: %s", $filename, $!);
+ die $!;
+ }
+
+ while (<$fd>) {
+ chomp;
+ my @fields = split("=", $_, 2);
+ $event{$fields[0]} = $fields[1];
+ }
+
+ close($fd);
+
+ my $req = POST("$opt_api_base/create_event", \%event);
+
+ if ($opt_verbose) {
+ my $s = $req->as_string;
+ print STDERR "Request:\n$s\n";
+ }
+
+ my $resp = $ua->request($req);
+
+ if ($opt_verbose) {
+ my $s = $resp->as_string;
+ print STDERR "Response:\n$s\n";
+ }
+
+ if ($resp->is_success) {
+ syslog(LOG_INFO, "Nagios event in file %s ACCEPTED by the PagerDuty server.", $filename);
+ unlink($filename);
+ }
+ elsif (is_client_error($resp->code)) {
+ syslog(LOG_WARNING, "Nagios event in file %s REJECTED by the PagerDuty server. Server says: %s", $filename, $resp->content);
+ unlink($filename) if ($resp->content !~ /retry later/);
+ }
+ else {
+ # Something else went wrong.
+ syslog(LOG_WARNING, "Nagios event in file %s DEFERRED due to network/server problems.", $filename);
+ return 0;
+ }
+ }
+
+ # Everything that needed to be sent was sent.
+ return 1;
+}
+
+
+sub lock_and_flush_queue {
+ # Serialize access to the queue directory while we flush.
+ # (We don't want more than one flush at once.)
+
+ my $lock_filename = "$opt_queue_dir/lockfile";
+ my $lock_fd;
+
+ unless (open($lock_fd, ">", $lock_filename)) {
+ syslog(LOG_ERR, "open %s for write failed: %s", $lock_filename, $!);
+ die $!;
+ }
+
+ unless (flock($lock_fd, LOCK_EX)) {
+ syslog(LOG_ERR, "flock %s failed: %s", $lock_filename, $!);
+ die $!;
+ }
+
+ my $ret = flush_queue();
+
+ close($lock_fd);
+
+ return $ret;
+}
+
+
+sub enqueue_event {
+ my %event;
+
+ # Scoop all the Nagios related stuff out of the environment.
+ while ((my $k, my $v) = each %ENV) {
+ next unless $k =~ /^(ICINGA|NAGIOS)_(.*)$/;
+ $event{$2} = $v;
+ }
+
+ # Apply any other variables that were passed in.
+ %event = (%event, %opt_fields);
+
+ $event{"pd_version"} = "1.0";
+
+ # Right off the bat, enqueue the event. Nothing tiem consuming should come
+ # before here (i.e. no locks or remote connections), because we want to
+ # make sure we get the event written out within the Nagios notification
+ # timeout. If we get killed off after that, it isn't a big deal.
+
+ my $filename = sprintf("$opt_queue_dir/pd_%u_%u.txt", time(), $$);
+ my $fd;
+
+ unless (open($fd, ">", $filename)) {
+ syslog(LOG_ERR, "open %s for write failed: %s", $filename, $!);
+ die $!;
+ }
+
+ while ((my $k, my $v) = each %event) {
+ # "=" can't occur in the keyname, and "\n" can't occur anywhere.
+ # (Nagios follows this already, so I think we're safe)
+ print $fd "$k=$v\n";
+ }
+
+ close($fd);
+}
+
+###########
+
+GetOptions("api-base=s" => \$opt_api_base,
+ "field=s%" => \%opt_fields,
+ "help" => \$opt_help,
+ "queue-dir=s" => \$opt_queue_dir,
+ "verbose" => \$opt_verbose,
+ "proxy=s" => \$opt_proxy
+ ) || pod2usage(2);
+
+pod2usage(2) if @ARGV < 1 ||
+ (($ARGV[0] ne "enqueue") && ($ARGV[0] ne "flush"));
+
+pod2usage(-verbose => 3) if $opt_help;
+
+my @log_mode = ("nofatal", "pid");
+push(@log_mode, "perror") if $opt_verbose;
+
+openlog("pagerduty_nagios", join(",", @log_mode), LOG_LOCAL0);
+
+# This function automatically terminates the program on things like permission
+# errors.
+mkpath($opt_queue_dir);
+
+if ($ARGV[0] eq "enqueue") {
+ enqueue_event();
+ lock_and_flush_queue();
+}
+elsif ($ARGV[0] eq "flush") {
+ lock_and_flush_queue();
+}
diff --git a/src/icon.svg b/src/icon.svg
new file mode 100644
index 0000000..bcf3595
--- /dev/null
+++ b/src/icon.svg
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:cc="http://creativecommons.org/ns#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" width="96" height="96" id="svg6517" version="1.1" inkscape:version="0.91+devel r" sodipodi:docname="nagios01.svg" viewBox="0 0 96 96">
+ <defs id="defs6519">
+ <filter style="color-interpolation-filters:sRGB" inkscape:label="Inner Shadow" id="filter1121">
+ <feFlood flood-opacity="0.59999999999999998" flood-color="rgb(0,0,0)" result="flood" id="feFlood1123"/>
+ <feComposite in="flood" in2="SourceGraphic" operator="out" result="composite1" id="feComposite1125"/>
+ <feGaussianBlur in="composite1" stdDeviation="1" result="blur" id="feGaussianBlur1127"/>
+ <feOffset dx="0" dy="2" result="offset" id="feOffset1129"/>
+ <feComposite in="offset" in2="SourceGraphic" operator="atop" result="composite2" id="feComposite1131"/>
+ </filter>
+ <filter style="color-interpolation-filters:sRGB" inkscape:label="Drop Shadow" id="filter950">
+ <feFlood flood-opacity="0.25" flood-color="rgb(0,0,0)" result="flood" id="feFlood952"/>
+ <feComposite in="flood" in2="SourceGraphic" operator="in" result="composite1" id="feComposite954"/>
+ <feGaussianBlur in="composite1" stdDeviation="1" result="blur" id="feGaussianBlur956"/>
+ <feOffset dx="0" dy="1" result="offset" id="feOffset958"/>
+ <feComposite in="SourceGraphic" in2="offset" operator="over" result="composite2" id="feComposite960"/>
+ </filter>
+ <linearGradient id="Background">
+ <stop id="stop4178" offset="0" style="stop-color:#22779e;stop-opacity:1"/>
+ <stop id="stop4180" offset="1" style="stop-color:#2991c0;stop-opacity:1"/>
+ </linearGradient>
+ <clipPath clipPathUnits="userSpaceOnUse" id="clipPath873">
+ <g transform="matrix(0,-0.66666667,0.66604479,0,-258.25992,677.00001)" id="g875" inkscape:label="Layer 1" style="display:inline;fill:#ff00ff;fill-opacity:1;stroke:none">
+ <path style="display:inline;fill:#ff00ff;fill-opacity:1;stroke:none" d="M 46.702703,898.22775 H 97.297297 C 138.16216,898.22775 144,904.06497 144,944.92583 v 50.73846 c 0,40.86071 -5.83784,46.69791 -46.702703,46.69791 H 46.702703 C 5.8378378,1042.3622 0,1036.525 0,995.66429 v -50.73846 c 0,-40.86086 5.8378378,-46.69808 46.702703,-46.69808 z" id="path877" inkscape:connector-curvature="0" sodipodi:nodetypes="sssssssss"/>
+ </g>
+ </clipPath>
+ <style id="style867" type="text/css"><![CDATA[
+ .fil0 {fill:#1F1A17}
+ ]]></style>
+ </defs>
+ <sodipodi:namedview id="base" pagecolor="#ffffff" bordercolor="#666666" borderopacity="1.0" inkscape:pageopacity="0.0" inkscape:pageshadow="2" inkscape:zoom="5.0931702" inkscape:cx="51.311597" inkscape:cy="9.1743059" inkscape:document-units="px" inkscape:current-layer="layer1" showgrid="false" fit-margin-top="0" fit-margin-left="0" fit-margin-right="0" fit-margin-bottom="0" inkscape:window-width="1920" inkscape:window-height="1029" inkscape:window-x="0" inkscape:window-y="24" inkscape:window-maximized="1" showborder="true" showguides="true" inkscape:guide-bbox="true" inkscape:showpageshadow="false" inkscape:snap-global="false" inkscape:snap-bbox="true" inkscape:bbox-paths="true" inkscape:bbox-nodes="true" inkscape:snap-bbox-edge-midpoints="true" inkscape:snap-bbox-midpoints="true" inkscape:object-paths="true" inkscape:snap-intersection-paths="true" inkscape:object-nodes="true" inkscape:snap-smooth-nodes="true" inkscape:snap-midpoints="true" inkscape:snap-object-midpoints="true" inkscape:snap-center="true" inkscape:snap-text-baseline="true">
+ <inkscape:grid type="xygrid" id="grid821"/>
+ <sodipodi:guide orientation="1,0" position="16,48" id="guide823" inkscape:locked="false"/>
+ <sodipodi:guide orientation="0,1" position="64,80" id="guide825" inkscape:locked="false"/>
+ <sodipodi:guide orientation="1,0" position="80,40" id="guide827" inkscape:locked="false"/>
+ <sodipodi:guide orientation="0,1" position="64,16" id="guide829" inkscape:locked="false"/>
+ </sodipodi:namedview>
+ <metadata id="metadata6522">
+ <rdf:RDF>
+ <cc:Work rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
+ <dc:title/>
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <g inkscape:label="BACKGROUND" inkscape:groupmode="layer" id="layer1" transform="translate(268,-635.29076)" style="display:inline">
+ <path style="display:inline;fill:#383838;fill-opacity:1;stroke:none" d="M 48 0 A 48 48 0 0 0 0 48 A 48 48 0 0 0 48 96 A 48 48 0 0 0 96 48 A 48 48 0 0 0 48 0 z " transform="translate(-268,635.29076)" id="path6455"/>
+ <path style="opacity:1;fill:#ffffff;stroke-width:0.49836424" d="m -245.09662,711.72332 c 0.11462,-2.99034 3.05007,-3.91613 4.84239,-4.18797 1.71688,-0.26041 5.37891,0.68965 12.09436,0.58011 6.71546,-0.10955 12.86651,-0.84046 13.96291,-0.88947 1.9861,-0.0888 5.3861,0.76742 8.80105,1.10369 4.31039,0.42444 6.80977,-0.52091 9.2513,0.84518 1.61577,0.90407 1.08624,3.01777 -0.74659,4.38113 -1.33442,0.99261 -1.63017,1.00618 -10.21647,0.46871 -5.17466,-0.32392 -9.97919,-0.38052 -11.58328,-0.13645 -1.35912,0.2068 -6.41923,0.46913 -11.10369,0.29831 -2.63405,-0.096 -4.79303,-0.60312 -6.97952,-0.66401 -2.52649,-0.0704 -3.8034,0.41679 -4.70411,0.38205 -2.3943,-0.0924 -3.67838,-0.61513 -3.61835,-2.18128 z m 5.08818,-11.30155 c -2.22213,-1.35482 -2.60399,-2.66785 -2.60399,-8.95375 0,-1.80081 -0.61411,-3.70956 0,-5.40241 0.30925,-0.85248 1.16285,-1.39184 1.74428,-2.08776 1.99091,-2.38297 2.18499,-3.96166 0.73705,-5.99511 -2.15336,-3.02411 -2.55856,-5.26728 -2.5057,-13.87166 0.0276,-4.48536 0.36374,-8.50768 0.51938,-9.03208 0.39979,-1.34711 1.27377,-1.54835 3.07627,-1.29531 1.70445,0.23927 3.95595,-0.20898 5.39827,-0.90867 2.60236,-1.26243 3.2066,-0.51959 4.20906,0.37736 0.59637,0.5336 1.3041,1.99758 1.7922,3.12788 0.56626,1.31131 1.45544,2.99812 3.01987,3.48855 2.97891,0.93386 3.54465,3.48769 6.64802,8.00186 2.48359,3.61262 5.05929,7.14477 5.7238,7.84924 2.77866,2.94574 3.73548,0.83339 3.37029,-7.44054 -0.10452,-2.36805 -0.60796,-4.45632 -0.35748,-6.22263 0.44969,-3.17117 -0.064,-6.30696 1.06018,-8.13995 0.72523,-1.18253 2.25821,-0.84224 4.94907,-0.82731 5.87758,0.0326 7.51589,1.06692 8.04026,7.66048 0.17784,2.23625 -0.0448,5.06655 0.0935,8.77532 0.21258,5.69922 0.36565,9.89449 -0.19419,13.9542 -0.33257,2.4116 -0.23954,5.19203 0.11854,7.85689 0.65813,4.89781 0.10092,7.46463 -1.97891,9.11584 -1.22508,0.97261 -1.74021,1.04732 -5.2449,0.76061 -2.13752,-0.17486 -4.77629,-0.67399 -5.86393,-1.10918 -2.47417,-0.98996 -5.12777,-3.97168 -7.68278,-8.63275 -1.08686,-1.98272 -3.08563,-4.87223 -4.44173,-6.42113 -1.35609,-1.5489 -3.21923,-3.99357 -4.14032,-5.4326 -1.7631,-2.75454 -3.20325,-3.36232 -4.08098,-1.72228 -0.26319,0.49178 -0.61704,4.2482 -0.78633,8.3476 -0.0761,1.84209 0.29872,3.56974 0.0707,5.40334 -0.27023,2.17271 -1.51256,3.76156 -0.90944,4.81483 1.14113,1.99282 0.59074,2.41331 0.15055,3.26026 -0.85686,1.64863 -7.25181,2.33409 -9.93055,0.70086 z" id="path4279" inkscape:connector-curvature="0" sodipodi:nodetypes="sssssssssssssssssssssssssssssssssssssssssssssss"/>
+ </g>
+</svg>
diff --git a/src/layer.yaml b/src/layer.yaml
new file mode 100644
index 0000000..c680356
--- /dev/null
+++ b/src/layer.yaml
@@ -0,0 +1,11 @@
+includes:
+ - layer:basic
+ # Add additional layers and interfaces here
+ - interface:juju-info
+ - interface:monitors
+ - interface:http
+options:
+ basic:
+ use_venv: true
+ include_system_packages: true
+ packages: ['pwgen']
diff --git a/src/lib/lib_nagios_charm.py b/src/lib/lib_nagios_charm.py
new file mode 100644
index 0000000..80493a9
--- /dev/null
+++ b/src/lib/lib_nagios_charm.py
@@ -0,0 +1,459 @@
+import base64
+import datetime
+import grp
+import os
+import pwd
+import shutil
+import subprocess
+
+from charmhelpers.contrib import ssl
+from charmhelpers.core import hookenv, host, services, templating
+from charmhelpers.fetch import apt_install, apt_update
+
+
+def set_package_options(*args):
+ """This is a helper function that will use the parsed arguments, and feed them to debconf-set-selection."""
+
+ cmd = [
+ 'echo',
+ ] + list(args) + ['|', '/usr/bin/debconf-set-selections']
+ # we need the shell as we are using the pipe option, might add some input validation later
+ output = subprocess.check_output(cmd, shell=True, stderr=subprocess.PIPE).decode('utf-8')
+ hookenv.log(output, 'DEBUG')
+
+
+def set_package_stat_override(*args):
+ """A helper to set some package overrides using the dpkg-startoverride utility."""
+ cmd = [
+ '/usr/bin/dpkg-statoverride',
+ ] + list(args)
+ # we need the shell as we are using the pipe option, might add some input validation later, but we don't care
+ # about the exit status
+ output = subprocess.run(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE).stdout.decode('utf-8')
+ hookenv.log(output, 'DEBUG')
+
+
+class NagioscharmHelper:
+ """Helper class that does the basic heavy lifting of the charm."""
+
+ NAGIOS_CFG = '/etc/nagios3/nagios.cfg'
+ NAGIOS_CGI_CFG = '/etc/nagios3/cgi.cfg'
+ PAGERDUTY_CRON = '/etc/cron.d/nagios-pagerduty-flush'
+ PAGERDUTY_CFG = '/etc/nagios3/conf.d/pagerduty_nagios.cfg'
+ EXTRA_CFG = '/etc/nagios3/conf.d/extra.cfg'
+ PACKAGE_LIST = ['nagios3', 'nagios-plugins', 'nagios-nrpe-plugin']
+ ALLOWED_SSL_OPTIONS = ['on', 'only']
+
+ def __init__(self):
+ self.charm_config = hookenv.config()
+
+ @property
+ def password_file(self):
+ return self.charm_config['password']
+
+ @property
+ def cert_domain(self):
+ return hookenv.unit_get('public-address')
+
+ @property
+ def cert_file(self):
+ """This depends on some other charm parameters, so we can't make is static."""
+ return '/etc/ssl/certs/{}.pem'.format(self.cert_domain)
+
+ @property
+ def key_file(self):
+ """This depends on some other charm parameters, so we can't make is static."""
+ return '/etc/ssl/private/{}.key'.format(self.cert_domain)
+
+ @property
+ def chain_file(self):
+ """This depends on some other charm parameters, so we can't make is static."""
+ return '/etc/ssl/certs/{}.csr'.format(self.cert_domain)
+
+ def install_nagios(self):
+ """This function will install nagios3.
+
+ FUTURE: Make it an option to install nagios4, if the version changes via a config option, simply reset the
+ nagios.installed flag state.
+ """
+ hookenv.status_set('maintenance', 'Installing nagios')
+ apt_update()
+ self.check_handle_password()
+ apt_install(self.PACKAGE_LIST)
+
+ def check_handle_password(self):
+ """Make sure that the password file is written and used. This is a prerequisite to install nagios3 package.
+
+ :FUTURE: handle nagios4
+ """
+ hookenv.status_set('maintenance', 'Setting up password')
+
+ if not os.path.exists(self.password_file):
+ # The file does not exist, so we create it
+ cmd = 'pwgen 10 1'
+ hookenv.log('Command to execute [{}]'.format(cmd.split()), 'DEBUG')
+ output = subprocess.check_output(cmd.split(), shell=True).decode('utf-8')
+ # change the file to read-only for the current user
+ with open(self.password_file, 'w') as fh:
+ fh.write(output)
+ os.chmod(self.password_file, 0o0400)
+
+ with open(self.password_file, 'r') as fh:
+ password = fh.read()
+
+ set_package_options('nagios3-cgi', 'nagios3/adminpassword password', password)
+ set_package_options('nagios3-cgi', 'nagios3/adminpassword-repeat password', password)
+
+ self._update_password('nagiosadmin', password)
+
+ def setup_overrides(self):
+ """Set some variables other then the default for the nagios dpkgs.
+
+ :FUTURE: handle nagios4
+ """
+ self.stop_service_nagios()
+ set_package_stat_override('--update', '--add', 'nagios', 'www-data', '2710', '/var/lib/nagios3/rw')
+ set_package_stat_override('--update', '--add', 'nagios', 'nagios', '5751', '/var/lib/nagios3')
+ self.start_service_nagios()
+
+ @staticmethod
+ def stop_service_nagios():
+ """Stop the nagios service.
+
+ :FUTURE: handle nagios4
+ """
+ services.service_stop('nagios3')
+
+ def start_service_nagios(self):
+ """Currently an alias for restart as we lack the services option for a start."""
+ self.restart_service_nagios()
+
+ @staticmethod
+ def restart_service_nagios():
+ """Restart the nagios service.
+
+ :FUTURE: handle nagios4
+ """
+ services.service_restart('nagios3')
+
+ @staticmethod
+ def reload_service_nagios():
+ """Reload the nagios3 service."""
+ host.service_reload('nagios3', restart_on_failure=True)
+
+ @staticmethod
+ def reload_service_apache2():
+ """Reload the apache2 service."""
+ host.service_reload('apache2', restart_on_failure=True)
+
+ def setup_hostgroups(self):
+ """Make sure that the hostgroup is overwritten with our version, so we don't end up as being marked Debian."""
+ hookenv.status_set('maintenance', 'Setting up hostgroups')
+ context = {'today': datetime.datetime.now().isoformat()}
+ context.update(self.charm_config)
+ templating.render(
+ source='hostgroups_nagios2.cfg.j2',
+ target='/etc/nagios3/conf.d/hostgroups_nagios2.cfg',
+ owner='nagios',
+ perms=0o0644,
+ context=context,
+ )
+
+ remove_files = ['/etc/nagios3/conf.d/services_nagios2.cfg', '/etc/nagios3/conf.d/extinfo_nagios2.cfg']
+ for filename in remove_files:
+ if os.path.exists(filename):
+ os.unlink(filename)
+
+ def install_livestatus(self):
+ """Install the livestatus additions for nagios."""
+ hookenv.status_set('maintenance', 'Installing livestatus')
+ apt_install(['check-mk-livestatus'])
+ self.configure_livestatus_dir()
+
+ def configure_livestatus_dir(self):
+ """
+ Configure the directory where the livestatus dir sockets lives, so it can be accessed.
+
+ Should be called if either the location (livestatus_path) changes or when livestatus is enabled.
+ """
+ livestatus_dir = os.path.dirname(self.charm_config['livestatus_path'])
+ if not os.path.exists(livestatus_dir):
+ os.mkdir(livestatus_dir)
+ os.chmod(livestatus_dir, 0o2775)
+ os.chown(livestatus_dir, pwd.getpwnam('nagios').pw_uid, grp.getgrnam('www-data').gr_gid)
+
+ def install_http_redirect(self):
+ """Install a redirect file for apache, so that it will redirect to /nagios3."""
+ hookenv.status_set('maintenance', 'Installing redirect')
+ context = {'today': datetime.datetime.now().isoformat()}
+ context.update(self.charm_config)
+ templating.render(
+ source='index.html.j2',
+ target='/var/www/html/index.html',
+ context=context,
+ )
+
+ def setup_pagerduty(self):
+ """
+ Install and configure the pagerduty configuration. Depends on the following config options:
+
+ enable_pagerduty
+ pagerduty_key
+ pagerduty_path
+ pagerduty_notification_levels
+ admin_email
+ nagios_user
+ nagios_group
+ """
+
+ hookenv.status_set('maintenance', 'Configuring pagerduty')
+
+ if self.charm_config['enable_pagerduty']:
+ hookenv.log('pagerduty is enabled')
+ apt_install([
+ 'libhttp-parser-perl',
+ ])
+ env = os.environ
+ proxy = env.get('JUJU_CHARM_HTTPS_PROXY') or env.get('https_proxy') or env.get('HTTPS_PROXY')
+ proxy_switch = '--proxy {}'.format(proxy) if proxy else ''
+
+ template_values = {
+ 'today': datetime.datetime.now().isoformat(),
+ 'pagerduty_key': self.charm_config['pagerduty_key'],
+ 'pagerduty_path': self.charm_config['pagerduty_path'],
+ 'proxy_switch': proxy_switch,
+ 'notification_levels': self.charm_config['pagerduty_notification_levels']
+ }
+
+ # The nagios configuration
+ templating.render(
+ source='pagerduty_nagios.cfg.j2',
+ target=self.PAGERDUTY_CFG,
+ context=template_values,
+ )
+
+ # The crontab for the cleanup
+ templating.render(
+ source='nagios-pagerduty-flush-cron.j2',
+ target=self.PAGERDUTY_CRON,
+ context=template_values,
+ )
+
+ if not os.path.isfile('/usr/local/bin/pagerduty_nagios.pl'):
+ shutil.copy('files/pagerduty_nagios.pl', '/usr/local/bin/pagerduty_nagios.pl')
+
+ if not os.path.isdir(self.charm_config['pagerduty_path']):
+ os.makedirs(self.charm_config['pagerduty_path'])
+ os.chown(self.charm_config['pagerduty_path'],
+ pwd.getpwnam(self.charm_config['nagios_user']).pw_uid,
+ grp.getgrnam(self.charm_config['nagios_group']).gr_gid)
+
+ else:
+ # Remove the pagerduty file(s)
+ if os.path.isfile(self.PAGERDUTY_CFG):
+ os.remove(self.PAGERDUTY_CFG)
+ if os.path.isfile(self.PAGERDUTY_CRON):
+ os.remove(self.PAGERDUTY_CRON)
+
+ context = {
+ 'today': datetime.datetime.now().isoformat(),
+ 'enable_pagerduty': self.charm_config['enable_pagerduty'],
+ 'admin_email': self.charm_config['admin_email']
+ }
+ templating.render(source='contacts.cfg.j2', target='/etc/nagios3/conf.d/contacts_nagios2.cfg', context=context)
+
+ # let's restart after the update of the config
+ self.restart_service_nagios()
+
+ def setup_nagios_config(self):
+ """Setup the configuration of nagios.
+
+ As this is heavily templated we depend on most config options of the charm. So any change to the config would
+ be a valid reason to update the configs.
+ """
+
+ hookenv.status_set('maintenance', 'Writing nagios config')
+
+ host_context = self.charm_config['nagios_host_context']
+ principal_unitname = hookenv.principal_unit()
+
+ # Fallback to primary if it exists for the unitname
+ if principal_unitname:
+ local_host_name = principal_unitname
+ else:
+ local_host_name = hookenv.local_unit().replace('/', '-')
+
+ template_values = {'today': datetime.datetime.now().isoformat()}
+ for key in [
+ 'nagios_user', 'nagios_group', 'enable_livestatus', 'livestatus_path', 'livestatus_args',
+ 'check_external_commands', 'command_check_interval', 'command_file', 'debug_file', 'debug_verbosity',
+ 'debug_level', 'daemon_dumps_core', 'admin_email', 'admin_pager', 'log_rotation_method',
+ 'log_archive_path', 'use_syslog', 'monitor_self', 'load_monitor'
+ ]:
+ template_values.update({key: self.charm_config[key]})
+ template_values.update({'nagios_hostname': '{}-{}'.format(host_context, local_host_name)})
+
+ templating.render(source='nagios.cfg.j2', target=self.NAGIOS_CFG, context=template_values)
+
+ templating.render(
+ source='localhost_nagios.cfg.j2',
+ target='/etc/nagios3/conf.d/localhost_nagios.cfg',
+ context=template_values)
+
+ self.restart_service_nagios()
+
+ def setup_cgi_config(self):
+ """
+ Configure the cgi configuration, using the configuration from juju.
+
+ This function should be triggered on changes on any of the following config option; ro-password
+ """
+
+ hookenv.status_set('maintenance', 'Writing nagios-cgi config')
+
+ template_value = {
+ 'today': datetime.datetime.now().isoformat(),
+ 'ro_password': self.charm_config['ro-password'],
+ }
+
+ templating.render(source='nagios-cgi.cfg.j2', target=self.NAGIOS_CGI_CFG, context=template_value)
+
+ self.reload_service_nagios()
+ self.reload_service_apache2()
+
+ def setup_extra_config(self):
+ """Write the extra config attached to the charm to the nagios configuration directory."""
+
+ hookenv.status_set('maintenance', 'Writing extra configuration data.')
+
+ # Always remove the file, so we know that we end up in a state the user expects
+ if os.path.exists(self.EXTRA_CFG):
+ os.remove(self.EXTRA_CFG)
+
+ if self.charm_config['extraconfig'] is not None:
+ host.write_file(self.EXTRA_CFG, self.charm_config['extraconfig'])
+
+ def ssl_configured(self):
+ """Check if ssl is properly configured."""
+ return self.charm_config['ssl'].lower() in self.ALLOWED_SSL_OPTIONS
+
+ def enable_ssl(self):
+ """Setup apache to use ssl."""
+ if not self.charm_config['ssl_cert']:
+ # We are not given a certificate, see if we need to create one, or if we already did that
+ if os.path.exists(self.cert_file):
+ hookenv.log('Certificate key already exist at [{}], not creating new one'.format(self.cert_file),
+ 'WARNING')
+ return
+ hookenv.log('No Certificate currently exists at [{}], creating a self signed one'.format(self.cert_file),
+ 'WARNING')
+ # ssl is from charmhelpers
+ ssl.generate_selfsigned(self.key_file, self.cert_file, cn=self.cert_domain)
+ else:
+ hookenv.log('Decoding provided certificate files', 'INFO')
+ self.decode_cert_files()
+
+ def decode_cert_files(self):
+ """Get the certificate files from the charm config and write them to disk."""
+
+ hookenv.status_set('maintenance', 'Handling ssl files')
+
+ if self.charm_config['ssl_key']:
+ hookenv.log('Decoding and writing ssl_key to [{}]'.format(self.key_file))
+ with open(self.key_file, 'w') as fh:
+ fh.write(base64.b64decode(self.charm_config['ssl_key']))
+
+ if self.charm_config['ssl_cert']:
+ hookenv.log('Decoding and writing ssl_cert to [{}]'.format(self.cert_file))
+ with open(self.cert_file, 'w') as fh:
+ fh.write(base64.b64decode(self.charm_config['ssl_cert']))
+
+ if self.charm_config['ssl_chain']:
+ hookenv.log('Decoding and writing ssl_chain to [{}]'.format(self.chain_file))
+ with open(self.chain_file, 'w') as fh:
+ fh.write(base64.b64decode(self.charm_config['ssl_chain']))
+
+ def disable_ssl(self):
+ """Remove the ssl configuration parts from apache2."""
+ if os.path.exists(self.key_file):
+ os.remove(self.key_file)
+ if os.path.exists(self.cert_file):
+ os.remove(self.cert_file)
+ if os.path.exists(self.chain_file):
+ os.remove(self.chain_file)
+
+ def update_apache(self):
+ """Configure apache, based on the charm config."""
+
+ if os.path.exists(self.chain_file) and os.path.getsize(self.chain_file) > 0:
+ ssl_chain = self.chain_file
+ else:
+ ssl_chain = None
+
+ template_values = {
+ 'today': datetime.datetime.now().isoformat(),
+ 'ssl_chain': ssl_chain,
+ 'ssl_key': self.key_file,
+ 'ssl_cert': self.cert_file,
+ }
+
+ templating.render(
+ source='default-ssl.j2',
+ target='/etc/apache2/sites-available/default-ssl',
+ context=template_values,
+ )
+
+ # Process all the options we manipulate in every case to be sure we don't mis any if things are toggled
+ if self.charm_config['ssl'].lower() == 'on':
+ subprocess.call(['a2enmod', 'ssl'])
+ subprocess.call(['a2ensite', 'default-ssl'])
+ subprocess.call(['a2ensite', 'default'])
+ hookenv.open_port(80)
+ hookenv.open_port(443)
+ elif self.charm_config['ssl'].lower() == 'only':
+ subprocess.call(['a2enmod', 'ssl'])
+ subprocess.call(['a2ensite', 'default-ssl'])
+ subprocess.call(['a2dissite', 'default'])
+ hookenv.close_port(80)
+ hookenv.open_port(443)
+ else:
+ subprocess.call(['a2enmod', 'ssl'])
+ subprocess.call(['a2dissite', 'default-ssl'])
+ subprocess.call(['a2ensite', 'default'])
+ hookenv.open_port(80)
+ hookenv.close_port(443)
+
+ self.reload_service_apache2()
+
+ @staticmethod
+ def _update_password(account, password):
+ """The real code that changes the password(s)."""
+ account_file = os.path.join(['var', 'lib', 'juju', 'nagios.{}.passwd'.format(account)])
+
+ hookenv.log('Updating password for account [{}]', format(account), 'INFO')
+ if password:
+ with open(account_file, 'w') as fh:
+ fh.write(account_file)
+ subprocess.check_output(['htpasswd', '-b', '/etc/nagios3/htpasswd.users', account, password])
+ else:
+ if os.path.exists(account_file):
+ os.remove(account_file)
+ subprocess.check_output(['htpasswd', '-D', '/etc/nagios3/htpasswd.users', account])
+
+ def update_password(self):
+ """Figure out which password was changed and how, and act accordingly"""
+
+ hookenv.status_set('maintenance', 'Updating password(s)')
+
+ if self.charm_config['ro-password'] is not None:
+ self._update_password('nagiosro', self.charm_config['ro-password'])
+ else:
+ self._update_password('nagiosro', None)
+
+ # this is the same password as we set for the initial installation? Should that not mean we need to update
+ # the debian package installation defaults. While we could skip it, as it will prevent a prompt on
+ # (re)installtion
+ if self.charm_config['password'] is not None:
+ self._update_password('nagiosadmin', self.charm_config['nagiosadmin'])
+ else:
+ self._update_password('nagiosadmin', None)
diff --git a/src/lib/pynag b/src/lib/pynag
new file mode 160000
index 0000000..bcdbd43
--- /dev/null
+++ b/src/lib/pynag
@@ -0,0 +1 @@
+Subproject commit bcdbd435dd48f9bf791b5d41307da93683cb17b3
diff --git a/src/metadata.yaml b/src/metadata.yaml
new file mode 100644
index 0000000..537386f
--- /dev/null
+++ b/src/metadata.yaml
@@ -0,0 +1,23 @@
+name: nagios
+summary: Nagios Core 3 monitoring.
+maintainers:
+ - Marco Ceppi <marco@xxxxxxxxx>
+ - Nagios Charm Developers <nagios-charmers@xxxxxxxxxxxxxxxxxxx>
+description: |
+ Nagios is a monitoring and management system for hosts, services, and
+ networks.
+tags: ["monitoring"]
+series:
+ - xenial
+ - bionic
+ - trusty
+provides:
+ website:
+ interface: http
+requires:
+ nagios:
+ interface: juju-info
+ monitors:
+ interface: monitors
+extra-bindings:
+ public:
diff --git a/src/reactive/nagios_charm.py b/src/reactive/nagios_charm.py
new file mode 100644
index 0000000..51e1290
--- /dev/null
+++ b/src/reactive/nagios_charm.py
@@ -0,0 +1,157 @@
+from charmhelpers.core import hookenv
+from charms.reactive import clear_flag, hook, register_trigger, set_flag, when, when_any, when_not
+from lib_nagios_charm import NagioscharmHelper
+
+helper = NagioscharmHelper()
+
+# Make sure that we register changes in the livestatus
+register_trigger(when='config.changed.enable_livestatus', set_flag='nagios.livestatus.changed')
+
+
+@hook('upgrade-charm')
+def upgrade_charm():
+ """Make sure that the upgrade is handles as we expect it. We do this by basically resetting all the flags."""
+ install_flags = [
+ 'nagios.installed',
+ 'nagios.installed.hostgroup',
+ 'nagios.installed.overrides',
+ 'nagios.installed.redirect',
+ 'nagios.installed.livestatus',
+ ]
+ for flag in install_flags:
+ clear_flag(flag)
+
+
+@when_not('nagios.installed')
+def install_nagios_charm():
+ # Do your setup here.
+ #
+ # If your charm has other dependencies before it can install,
+ # add those as @when() clauses above., or as additional @when()
+ # decorated handlers below
+ #
+ # See the following for information about reactive charms:
+ #
+ # * https://jujucharms.com/docs/devel/developer-getting-started
+ # * https://github.com/juju-solutions/layer-basic#overview
+ #
+ helper.install_nagios()
+ set_flag('nagios.installed')
+
+ # The config sets this to false by default, but we don't want to mis it, so this is here as a safety precaution
+ if hookenv.config('enable_livestatus'):
+ set_flag('nagios.livestatus.changed')
+
+ update_pagerduty()
+ update_nagios_config()
+ update_nagios_cgi_config()
+ update_ssl_flags()
+ unit_ready()
+
+
+def unit_ready():
+ hookenv.status_set('active', 'unit ready')
+
+
+@when('nagios.installed')
+@when_not('nagios.installed.hostgroup')
+def setup_nagios_hostgroups():
+ helper.setup_hostgroups()
+ set_flag('nagios.installed.hostgroup')
+ unit_ready()
+
+
+@when('nagios.installed')
+@when_not('nagios.installed.overrides')
+def setup_nagios_overrides():
+ """Override some dpkg settings."""
+ helper.setup_overrides()
+ set_flag('nagios.installed.overrides')
+ unit_ready()
+
+
+@when('nagios.installed')
+@when_not('nagios.installed.redirect')
+def handle_redirect():
+ """Install our index.html so we have an redirect."""
+ helper.install_http_redirect()
+ set_flag('nagios.installed.redirect')
+ unit_ready()
+
+
+@when('nagios.installed')
+@when_not('nagios.installed.livestatus')
+@when('nagios.livestatus.changed')
+def setup_livestatus():
+ """Setup livestatus as we want it installed."""
+ if hookenv.config('enable_livestatus'):
+ helper.install_livestatus()
+ set_flag('nagios.installed.livestatus')
+ else:
+ clear_flag('nagios.installed.livestatus')
+
+ clear_flag('nagios.livestatus.changed')
+ unit_ready()
+
+
+@when('nagios.installed.livestatus')
+@when('config.changed.livestatus_path')
+def update_livestatus_path():
+ helper.configure_livestatus_dir()
+ unit_ready()
+
+
+@when('nagios.installed')
+@when_any(
+ 'config.changed.enable_pagerduty',
+ 'config.changed.pagerduty_key',
+ 'config.changed.pagerduty_path',
+ 'config.changed.pagerduty_notification_levels',
+ 'config.changed.admin_email',
+ 'config.changes.nagios_user',
+ 'config.changed.nagios_group',
+)
+def update_pagerduty():
+ helper.setup_pagerduty()
+ unit_ready()
+
+
+@when('nagios.installed')
+@when('config.changed')
+def update_nagios_config():
+ helper.setup_nagios_config()
+ unit_ready()
+
+
+@when('nagios.installed')
+@when('config.changed.ro-password')
+def update_nagios_cgi_config():
+ helper.setup_cgi_config()
+ unit_ready()
+
+
+@when('nagios.installed')
+@when('config.changed.extraconfig')
+def update_extra_config():
+ helper.setup_extra_config()
+ unit_ready()
+
+
+@when('nagios.installed')
+@when_any('config.changed.ssl_config', 'config.changed.ssl_cert', 'config.changed.ssl_chain', 'config.changed.ssl_key')
+def update_ssl_flags():
+ if helper.ssl_configured():
+ # We want to have ssl configured
+ helper.enable_ssl()
+ else:
+ helper.disable_ssl()
+
+ helper.update_apache()
+ unit_ready()
+
+
+@when('nagios.installed')
+@when_any('config.changed.ro-password', 'config.changed.password')
+def update_passwords():
+ helper.update_password()
+ unit_ready()
diff --git a/src/requirements.txt b/src/requirements.txt
new file mode 100644
index 0000000..8462291
--- /dev/null
+++ b/src/requirements.txt
@@ -0,0 +1 @@
+# Include python requirements here
diff --git a/src/templates/contacts.cfg.j2 b/src/templates/contacts.cfg.j2
new file mode 100644
index 0000000..9cdb64d
--- /dev/null
+++ b/src/templates/contacts.cfg.j2
@@ -0,0 +1,51 @@
+#------------------------------------------------
+# This file is juju managed
+# last update was on {{ today }}
+#------------------------------------------------
+
+###############################################################################
+# contacts.cfg
+###############################################################################
+
+
+
+###############################################################################
+###############################################################################
+#
+# CONTACTS
+#
+###############################################################################
+###############################################################################
+
+# In this simple config file, a single contact will receive all alerts.
+
+define contact{
+ contact_name root
+ alias Root
+ service_notification_period 24x7
+ host_notification_period 24x7
+ service_notification_options w,u,c,r
+ host_notification_options d,r
+ service_notification_commands notify-service-by-email
+ host_notification_commands notify-host-by-email
+ email {{ admin_email }}
+ }
+
+
+
+###############################################################################
+###############################################################################
+#
+# CONTACT GROUPS
+#
+###############################################################################
+###############################################################################
+
+# We only have one contact in this simple configuration file, so there is
+# no need to create more than one contact group.
+
+define contactgroup{
+ contactgroup_name admins
+ alias Nagios Administrators
+ members root{% if enable_pagerduty -%}, pagerduty{% endif %}
+ }
diff --git a/src/templates/default-ssl.j2 b/src/templates/default-ssl.j2
new file mode 100644
index 0000000..b33860c
--- /dev/null
+++ b/src/templates/default-ssl.j2
@@ -0,0 +1,181 @@
+# Default Apache SSL configuration - with template bits for SSL keyfile updates
+#
+# This file is maintained by JUJU
+# Written on: {{ today }}
+#
+<IfModule mod_ssl.c>
+<VirtualHost _default_:443>
+ ServerAdmin webmaster@localhost
+
+ DocumentRoot /var/www
+ <Directory />
+ Options FollowSymLinks
+ AllowOverride None
+ </Directory>
+ <Directory /var/www/>
+ Options Indexes FollowSymLinks MultiViews
+ AllowOverride None
+ Order allow,deny
+ allow from all
+ </Directory>
+
+ ScriptAlias /cgi-bin/ /usr/lib/cgi-bin/
+ <Directory "/usr/lib/cgi-bin">
+ AllowOverride None
+ Options +ExecCGI -MultiViews +SymLinksIfOwnerMatch
+ Order allow,deny
+ Allow from all
+ </Directory>
+
+ ErrorLog ${APACHE_LOG_DIR}/error.log
+
+ # Possible values include: debug, info, notice, warn, error, crit,
+ # alert, emerg.
+ LogLevel warn
+
+ CustomLog ${APACHE_LOG_DIR}/ssl_access.log combined
+
+ Alias /doc/ "/usr/share/doc/"
+ <Directory "/usr/share/doc/">
+ Options Indexes MultiViews FollowSymLinks
+ AllowOverride None
+ Order deny,allow
+ Deny from all
+ Allow from 127.0.0.0/255.0.0.0 ::1/128
+ </Directory>
+
+ # SSL Engine Switch:
+ # Enable/Disable SSL for this virtual host.
+ SSLEngine on
+
+ # A self-signed (snakeoil) certificate can be created by installing
+ # the ssl-cert package. See
+ # /usr/share/doc/apache2.2-common/README.Debian.gz for more info.
+ # If both key and certificate are stored in the same file, only the
+ # SSLCertificateFile directive is needed.
+ SSLCertificateFile {{ssl_cert}}
+ SSLCertificateKeyFile {{ssl_key}}
+
+ # Server Certificate Chain:
+ # Point SSLCertificateChainFile at a file containing the
+ # concatenation of PEM encoded CA certificates which form the
+ # certificate chain for the server certificate. Alternatively
+ # the referenced file can be the same as SSLCertificateFile
+ # when the CA certificates are directly appended to the server
+ # certificate for convinience.
+ #SSLCertificateChainFile /etc/apache2/ssl.crt/server-ca.crt
+{%if ssl_chain %}
+ SSLCertificateChainFile {{ssl_chain}}
+{% endif %}
+
+
+ # Certificate Authority (CA):
+ # Set the CA certificate verification path where to find CA
+ # certificates for client authentication or alternatively one
+ # huge file containing all of them (file must be PEM encoded)
+ # Note: Inside SSLCACertificatePath you need hash symlinks
+ # to point to the certificate files. Use the provided
+ # Makefile to update the hash symlinks after changes.
+ #SSLCACertificatePath /etc/ssl/certs/
+ #SSLCACertificateFile /etc/apache2/ssl.crt/ca-bundle.crt
+
+ # Certificate Revocation Lists (CRL):
+ # Set the CA revocation path where to find CA CRLs for client
+ # authentication or alternatively one huge file containing all
+ # of them (file must be PEM encoded)
+ # Note: Inside SSLCARevocationPath you need hash symlinks
+ # to point to the certificate files. Use the provided
+ # Makefile to update the hash symlinks after changes.
+ #SSLCARevocationPath /etc/apache2/ssl.crl/
+ #SSLCARevocationFile /etc/apache2/ssl.crl/ca-bundle.crl
+
+ # Client Authentication (Type):
+ # Client certificate verification type and depth. Types are
+ # none, optional, require and optional_no_ca. Depth is a
+ # number which specifies how deeply to verify the certificate
+ # issuer chain before deciding the certificate is not valid.
+ #SSLVerifyClient require
+ #SSLVerifyDepth 10
+
+ # Access Control:
+ # With SSLRequire you can do per-directory access control based
+ # on arbitrary complex boolean expressions containing server
+ # variable checks and other lookup directives. The syntax is a
+ # mixture between C and Perl. See the mod_ssl documentation
+ # for more details.
+ #<Location />
+ #SSLRequire ( %{SSL_CIPHER} !~ m/^(EXP|NULL)/ \
+ # and %{SSL_CLIENT_S_DN_O} eq "Snake Oil, Ltd." \
+ # and %{SSL_CLIENT_S_DN_OU} in {"Staff", "CA", "Dev"} \
+ # and %{TIME_WDAY} >= 1 and %{TIME_WDAY} <= 5 \
+ # and %{TIME_HOUR} >= 8 and %{TIME_HOUR} <= 20 ) \
+ # or %{REMOTE_ADDR} =~ m/^192\.76\.162\.[0-9]+$/
+ #</Location>
+
+ # SSL Engine Options:
+ # Set various options for the SSL engine.
+ # o FakeBasicAuth:
+ # Translate the client X.509 into a Basic Authorisation. This means that
+ # the standard Auth/DBMAuth methods can be used for access control. The
+ # user name is the `one line' version of the client's X.509 certificate.
+ # Note that no password is obtained from the user. Every entry in the user
+ # file needs this password: `xxj31ZMTZzkVA'.
+ # o ExportCertData:
+ # This exports two additional environment variables: SSL_CLIENT_CERT and
+ # SSL_SERVER_CERT. These contain the PEM-encoded certificates of the
+ # server (always existing) and the client (only existing when client
+ # authentication is used). This can be used to import the certificates
+ # into CGI scripts.
+ # o StdEnvVars:
+ # This exports the standard SSL/TLS related `SSL_*' environment variables.
+ # Per default this exportation is switched off for performance reasons,
+ # because the extraction step is an expensive operation and is usually
+ # useless for serving static content. So one usually enables the
+ # exportation for CGI and SSI requests only.
+ # o StrictRequire:
+ # This denies access when "SSLRequireSSL" or "SSLRequire" applied even
+ # under a "Satisfy any" situation, i.e. when it applies access is denied
+ # and no other module can change it.
+ # o OptRenegotiate:
+ # This enables optimized SSL connection renegotiation handling when SSL
+ # directives are used in per-directory context.
+ #SSLOptions +FakeBasicAuth +ExportCertData +StrictRequire
+ <FilesMatch "\.(cgi|shtml|phtml|php)$">
+ SSLOptions +StdEnvVars
+ </FilesMatch>
+ <Directory /usr/lib/cgi-bin>
+ SSLOptions +StdEnvVars
+ </Directory>
+
+ # SSL Protocol Adjustments:
+ # The safe and default but still SSL/TLS standard compliant shutdown
+ # approach is that mod_ssl sends the close notify alert but doesn't wait for
+ # the close notify alert from client. When you need a different shutdown
+ # approach you can use one of the following variables:
+ # o ssl-unclean-shutdown:
+ # This forces an unclean shutdown when the connection is closed, i.e. no
+ # SSL close notify alert is send or allowed to received. This violates
+ # the SSL/TLS standard but is needed for some brain-dead browsers. Use
+ # this when you receive I/O errors because of the standard approach where
+ # mod_ssl sends the close notify alert.
+ # o ssl-accurate-shutdown:
+ # This forces an accurate shutdown when the connection is closed, i.e. a
+ # SSL close notify alert is send and mod_ssl waits for the close notify
+ # alert of the client. This is 100% SSL/TLS standard compliant, but in
+ # practice often causes hanging connections with brain-dead browsers. Use
+ # this only for browsers where you know that their SSL implementation
+ # works correctly.
+ # Notice: Most problems of broken clients are also related to the HTTP
+ # keep-alive facility, so you usually additionally want to disable
+ # keep-alive for those clients, too. Use variable "nokeepalive" for this.
+ # Similarly, one has to force some clients to use HTTP/1.0 to workaround
+ # their broken HTTP/1.1 implementation. Use variables "downgrade-1.0" and
+ # "force-response-1.0" for this.
+ BrowserMatch "MSIE [2-6]" \
+ nokeepalive ssl-unclean-shutdown \
+ downgrade-1.0 force-response-1.0
+ # MSIE 7 and newer should be able to use keepalive
+ BrowserMatch "MSIE [17-9]" ssl-unclean-shutdown
+
+</VirtualHost>
+</IfModule>
diff --git a/src/templates/hostgroups_nagios2.cfg.j2 b/src/templates/hostgroups_nagios2.cfg.j2
new file mode 100644
index 0000000..dc855e3
--- /dev/null
+++ b/src/templates/hostgroups_nagios2.cfg.j2
@@ -0,0 +1,9 @@
+# Written by juju on: {{ today }}
+# Some generic hostgroup definitions
+
+# A simple wildcard hostgroup
+define hostgroup {
+ hostgroup_name all
+ alias All Servers
+ members *
+}
diff --git a/src/templates/index.html.j2 b/src/templates/index.html.j2
new file mode 100644
index 0000000..8828624
--- /dev/null
+++ b/src/templates/index.html.j2
@@ -0,0 +1,14 @@
+<!-- Written by juju on: {{ today }} -->
+<html lang="en-US">
+ <head>
+ <meta charset="UTF-8">
+ <meta http-equiv="refresh" content="1;url=nagios3/">
+ <script type="text/javascript">
+ window.location.href = "nagios3/"
+ </script>
+ <title>Nagios3</title>
+ </head>
+ <body>
+ If you are not redirected automatically, follow the <a href='nagios3/'>link to nagios3</a>.
+ </body>
+</html>
diff --git a/src/templates/localhost_nagios.cfg.j2 b/src/templates/localhost_nagios.cfg.j2
new file mode 100644
index 0000000..2d45c1c
--- /dev/null
+++ b/src/templates/localhost_nagios.cfg.j2
@@ -0,0 +1,70 @@
+#------------------------------------------------
+# This file is juju managed
+#------------------------------------------------
+{% if monitor_self -%}
+
+# A simple configuration file for monitoring the local host
+# This can serve as an example for configuring other servers;
+# Custom services specific to this host are added here, but services
+# defined in nagios2-common_services.cfg may also apply.
+#
+
+define host{
+ use generic-host ; Name of host template to use
+ host_name {{ nagios_hostname }}
+ alias {{ nagios_hostname }}
+ address 127.0.0.1
+ icon_image_alt Ubuntu Linux
+ statusmap_image base/ubuntu.gd2
+ vrml_image ubuntu.png
+ icon_image base/ubuntu.png
+ }
+
+# Define a service to check the disk space of the root partition
+# on the local machine. Warning if < 20% free, critical if
+# < 10% free space on partition.
+
+define service{
+ use generic-service ; Name of service template to use
+ host_name {{ nagios_hostname }}
+ service_description Disk Space
+ check_command check_all_disks!20%!10%
+ }
+
+
+
+# Define a service to check the number of currently logged in
+# users on the local machine. Warning if > 20 users, critical
+# if > 50 users.
+
+define service{
+ use generic-service ; Name of service template to use
+ host_name {{ nagios_hostname }}
+ service_description Current Users
+ check_command check_users!20!50
+ }
+
+
+# Define a service to check the number of currently running procs
+# on the local machine. Warning if > 250 processes, critical if
+# > 400 processes.
+
+define service{
+ use generic-service ; Name of service template to use
+ host_name {{ nagios_hostname }}
+ service_description Total Processes
+ check_command check_procs!250!400
+ }
+
+
+
+# Define a service to check the load on the local machine.
+
+define service{
+ use generic-service ; Name of service template to use
+ host_name {{ nagios_hostname }}
+ service_description Current Load
+ check_command check_load!{{ load_monitor }}
+ }
+
+{% endif %}
diff --git a/src/templates/nagios-cgi.cfg.j2 b/src/templates/nagios-cgi.cfg.j2
new file mode 100644
index 0000000..24410d5
--- /dev/null
+++ b/src/templates/nagios-cgi.cfg.j2
@@ -0,0 +1,380 @@
+#################################################################
+#
+# CGI.CFG - Sample CGI Configuration File for Nagios
+#
+#################################################################
+
+
+# MAIN CONFIGURATION FILE
+# This tells the CGIs where to find your main configuration file.
+# The CGIs will read the main and host config files for any other
+# data they might need.
+
+main_config_file=/etc/nagios3/nagios.cfg
+
+
+
+# PHYSICAL HTML PATH
+# This is the path where the HTML files for Nagios reside. This
+# value is used to locate the logo images needed by the statusmap
+# and statuswrl CGIs.
+
+physical_html_path=/usr/share/nagios3/htdocs
+
+
+
+# URL HTML PATH
+# This is the path portion of the URL that corresponds to the
+# physical location of the Nagios HTML files (as defined above).
+# This value is used by the CGIs to locate the online documentation
+# and graphics. If you access the Nagios pages with an URL like
+# http://www.myhost.com/nagios, this value should be '/nagios'
+# (without the quotes).
+
+url_html_path=/nagios3
+
+
+
+# CONTEXT-SENSITIVE HELP
+# This option determines whether or not a context-sensitive
+# help icon will be displayed for most of the CGIs.
+# Values: 0 = disables context-sensitive help
+# 1 = enables context-sensitive help
+
+show_context_help=1
+
+
+
+# PENDING STATES OPTION
+# This option determines what states should be displayed in the web
+# interface for hosts/services that have not yet been checked.
+# Values: 0 = leave hosts/services that have not been check yet in their original state
+# 1 = mark hosts/services that have not been checked yet as PENDING
+
+use_pending_states=1
+
+# NAGIOS PROCESS CHECK COMMAND
+# This is the full path and filename of the program used to check
+# the status of the Nagios process. It is used only by the CGIs
+# and is completely optional. However, if you don't use it, you'll
+# see warning messages in the CGIs about the Nagios process
+# not running and you won't be able to execute any commands from
+# the web interface. The program should follow the same rules
+# as plugins; the return codes are the same as for the plugins,
+# it should have timeout protection, it should output something
+# to STDIO, etc.
+#
+# Note: The command line for the check_nagios plugin below may
+# have to be tweaked a bit, as different versions of the plugin
+# use different command line arguments/syntaxes.
+
+nagios_check_command=/usr/lib/nagios/plugins/check_nagios /var/cache/nagios3/status.dat 5 '/usr/sbin/nagios3'
+
+
+# AUTHENTICATION USAGE
+# This option controls whether or not the CGIs will use any
+# authentication when displaying host and service information, as
+# well as committing commands to Nagios for processing.
+#
+# Read the HTML documentation to learn how the authorization works!
+#
+# NOTE: It is a really *bad* idea to disable authorization, unless
+# you plan on removing the command CGI (cmd.cgi)! Failure to do
+# so will leave you wide open to kiddies messing with Nagios and
+# possibly hitting you with a denial of service attack by filling up
+# your drive by continuously writing to your command file!
+#
+# Setting this value to 0 will cause the CGIs to *not* use
+# authentication (bad idea), while any other value will make them
+# use the authentication functions (the default).
+
+use_authentication=1
+
+
+
+
+# x509 CERT AUTHENTICATION
+# When enabled, this option allows you to use x509 cert (SSL)
+# authentication in the CGIs. This is an advanced option and should
+# not be enabled unless you know what you're doing.
+
+use_ssl_authentication=0
+
+
+
+
+# DEFAULT USER
+# Setting this variable will define a default user name that can
+# access pages without authentication. This allows people within a
+# secure domain (i.e., behind a firewall) to see the current status
+# without authenticating. You may want to use this to avoid basic
+# authentication if you are not using a secure server since basic
+# authentication transmits passwords in the clear.
+#
+# Important: Do not define a default username unless you are
+# running a secure web server and are sure that everyone who has
+# access to the CGIs has been authenticated in some manner! If you
+# define this variable, anyone who has not authenticated to the web
+# server will inherit all rights you assign to this user!
+
+#default_user_name=guest
+
+
+
+# SYSTEM/PROCESS INFORMATION ACCESS
+# This option is a comma-delimited list of all usernames that
+# have access to viewing the Nagios process information as
+# provided by the Extended Information CGI (extinfo.cgi). By
+# default, *no one* has access to this unless you choose to
+# not use authorization. You may use an asterisk (*) to
+# authorize any user who has authenticated to the web server.
+
+authorized_for_system_information=nagiosadmin
+
+
+
+# CONFIGURATION INFORMATION ACCESS
+# This option is a comma-delimited list of all usernames that
+# can view ALL configuration information (hosts, commands, etc).
+# By default, users can only view configuration information
+# for the hosts and services they are contacts for. You may use
+# an asterisk (*) to authorize any user who has authenticated
+# to the web server.
+
+authorized_for_configuration_information=nagiosadmin
+
+
+
+# SYSTEM/PROCESS COMMAND ACCESS
+# This option is a comma-delimited list of all usernames that
+# can issue shutdown and restart commands to Nagios via the
+# command CGI (cmd.cgi). Users in this list can also change
+# the program mode to active or standby. By default, *no one*
+# has access to this unless you choose to not use authorization.
+# You may use an asterisk (*) to authorize any user who has
+# authenticated to the web server.
+
+authorized_for_system_commands=nagiosadmin
+
+
+
+# GLOBAL HOST/SERVICE VIEW ACCESS
+# These two options are comma-delimited lists of all usernames that
+# can view information for all hosts and services that are being
+# monitored. By default, users can only view information
+# for hosts or services that they are contacts for (unless you
+# you choose to not use authorization). You may use an asterisk (*)
+# to authorize any user who has authenticated to the web server.
+
+
+{%if ro_password%}
+authorized_for_read_only=nagiosro
+authorized_for_all_services=nagiosadmin,nagiosro
+authorized_for_all_hosts=nagiosadmin,nagiosro
+{% else %}
+authorized_for_all_services=nagiosadmin
+authorized_for_all_hosts=nagiosadmin
+{% endif %}
+
+
+
+# GLOBAL HOST/SERVICE COMMAND ACCESS
+# These two options are comma-delimited lists of all usernames that
+# can issue host or service related commands via the command
+# CGI (cmd.cgi) for all hosts and services that are being monitored.
+# By default, users can only issue commands for hosts or services
+# that they are contacts for (unless you you choose to not use
+# authorization). You may use an asterisk (*) to authorize any
+# user who has authenticated to the web server.
+
+authorized_for_all_service_commands=nagiosadmin
+authorized_for_all_host_commands=nagiosadmin
+
+
+
+# READ-ONLY USERS
+# A comma-delimited list of usernames that have read-only rights in
+# the CGIs. This will block any service or host commands normally shown
+# on the extinfo CGI pages. It will also block comments from being shown
+# to read-only users.
+
+#authorized_for_read_only=user1,user2
+
+
+
+
+# STATUSMAP BACKGROUND IMAGE
+# This option allows you to specify an image to be used as a
+# background in the statusmap CGI. It is assumed that the image
+# resides in the HTML images path (i.e. /usr/local/nagios/share/images).
+# This path is automatically determined by appending "/images"
+# to the path specified by the 'physical_html_path' directive.
+# Note: The image file may be in GIF, PNG, JPEG, or GD2 format.
+# However, I recommend that you convert your image to GD2 format
+# (uncompressed), as this will cause less CPU load when the CGI
+# generates the image.
+
+#statusmap_background_image=smbackground.gd2
+
+
+
+
+# STATUSMAP TRANSPARENCY INDEX COLOR
+# These options set the r,g,b values of the background color used the statusmap CGI,
+# so normal browsers that can't show real png transparency set the desired color as
+# a background color instead (to make it look pretty).
+# Defaults to white: (R,G,B) = (255,255,255).
+
+#color_transparency_index_r=255
+#color_transparency_index_g=255
+#color_transparency_index_b=255
+
+
+
+
+# DEFAULT STATUSMAP LAYOUT METHOD
+# This option allows you to specify the default layout method
+# the statusmap CGI should use for drawing hosts. If you do
+# not use this option, the default is to use user-defined
+# coordinates. Valid options are as follows:
+# 0 = User-defined coordinates
+# 1 = Depth layers
+# 2 = Collapsed tree
+# 3 = Balanced tree
+# 4 = Circular
+# 5 = Circular (Marked Up)
+
+default_statusmap_layout=5
+
+
+
+# DEFAULT STATUSWRL LAYOUT METHOD
+# This option allows you to specify the default layout method
+# the statuswrl (VRML) CGI should use for drawing hosts. If you
+# do not use this option, the default is to use user-defined
+# coordinates. Valid options are as follows:
+# 0 = User-defined coordinates
+# 2 = Collapsed tree
+# 3 = Balanced tree
+# 4 = Circular
+
+default_statuswrl_layout=4
+
+
+
+# STATUSWRL INCLUDE
+# This option allows you to include your own objects in the
+# generated VRML world. It is assumed that the file
+# resides in the HTML path (i.e. /usr/local/nagios/share).
+
+#statuswrl_include=myworld.wrl
+
+
+
+# PING SYNTAX
+# This option determines what syntax should be used when
+# attempting to ping a host from the WAP interface (using
+# the statuswml CGI. You must include the full path to
+# the ping binary, along with all required options. The
+# $HOSTADDRESS$ macro is substituted with the address of
+# the host before the command is executed.
+# Please note that the syntax for the ping binary is
+# notorious for being different on virtually ever *NIX
+# OS and distribution, so you may have to tweak this to
+# work on your system.
+
+ping_syntax=/bin/ping -n -U -c 5 $HOSTADDRESS$
+
+
+
+# REFRESH RATE
+# This option allows you to specify the refresh rate in seconds
+# of various CGIs (status, statusmap, extinfo, and outages).
+
+refresh_rate=90
+
+# DEFAULT PAGE LIMIT
+# This option allows you to specify the default number of results
+# displayed on the status.cgi. This number can be adjusted from
+# within the UI after the initial page load. Setting this to 0
+# will show all results.
+
+result_limit=100
+
+
+# ESCAPE HTML TAGS
+# This option determines whether HTML tags in host and service
+# status output is escaped in the web interface. If enabled,
+# your plugin output will not be able to contain clickable links.
+
+escape_html_tags=1
+
+
+
+
+# SOUND OPTIONS
+# These options allow you to specify an optional audio file
+# that should be played in your browser window when there are
+# problems on the network. The audio files are used only in
+# the status CGI. Only the sound for the most critical problem
+# will be played. Order of importance (higher to lower) is as
+# follows: unreachable hosts, down hosts, critical services,
+# warning services, and unknown services. If there are no
+# visible problems, the sound file optionally specified by
+# 'normal_sound' variable will be played.
+#
+#
+# <varname>=<sound_file>
+#
+# Note: All audio files must be placed in the /media subdirectory
+# under the HTML path (i.e. /usr/local/nagios/share/media/).
+
+#host_unreachable_sound=hostdown.wav
+#host_down_sound=hostdown.wav
+#service_critical_sound=critical.wav
+#service_warning_sound=warning.wav
+#service_unknown_sound=warning.wav
+#normal_sound=noproblem.wav
+
+
+
+# URL TARGET FRAMES
+# These options determine the target frames in which notes and
+# action URLs will open.
+
+action_url_target=_blank
+notes_url_target=_blank
+
+
+
+
+# LOCK AUTHOR NAMES OPTION
+# This option determines whether users can change the author name
+# when submitting comments, scheduling downtime. If disabled, the
+# author names will be locked into their contact name, as defined in Nagios.
+# Values: 0 = allow editing author names
+# 1 = lock author names (disallow editing)
+
+lock_author_names=1
+
+
+
+
+# SPLUNK INTEGRATION OPTIONS
+# These options allow you to enable integration with Splunk
+# in the web interface. If enabled, you'll be presented with
+# "Splunk It" links in various places in the CGIs (log file,
+# alert history, host/service detail, etc). Useful if you're
+# trying to research why a particular problem occurred.
+# For more information on Splunk, visit http://www.splunk.com/
+
+# This option determines whether the Splunk integration is enabled
+# Values: 0 = disable Splunk integration
+# 1 = enable Splunk integration
+
+#enable_splunk_integration=1
+
+
+# This option should be the URL used to access your instance of Splunk
+
+#splunk_url=http://127.0.0.1:8000/
diff --git a/src/templates/nagios-pagerduty-flush-cron.j2 b/src/templates/nagios-pagerduty-flush-cron.j2
new file mode 100644
index 0000000..9213e97
--- /dev/null
+++ b/src/templates/nagios-pagerduty-flush-cron.j2
@@ -0,0 +1,7 @@
+#------------------------------------------------
+# This file is juju managed
+#------------------------------------------------
+
+# Flush the nagios pagerduty alerts every minute as per
+# http://www.pagerduty.com/docs/guides/nagios-perl-integration-guide/
+* * * * * nagios /usr/local/bin/pagerduty_nagios.pl flush {{ proxy_switch }} --queue-dir {{ pagerduty_path }}
diff --git a/src/templates/nagios.cfg.j2 b/src/templates/nagios.cfg.j2
new file mode 100644
index 0000000..afd3455
--- /dev/null
+++ b/src/templates/nagios.cfg.j2
@@ -0,0 +1,1359 @@
+#------------------------------------------------
+# This file is juju managed
+# File is written on: {{ today }}
+#------------------------------------------------
+
+##############################################################################
+#
+# NAGIOS.CFG - Sample Main Config File for Nagios
+#
+#
+##############################################################################
+
+
+# LOG FILE
+# This is the main log file where service and host events are logged
+# for historical purposes. This should be the first option specified
+# in the config file!!!
+
+log_file=/var/log/nagios3/nagios.log
+
+# Commands definitions
+cfg_file=/etc/nagios3/commands.cfg
+
+# Debian also defaults to using the check commands defined by the debian
+# nagios-plugins package
+cfg_dir=/etc/nagios-plugins/config
+
+# Debian uses by default a configuration directory where nagios3-common,
+# other packages and the local admin can dump or link configuration
+# files into.
+cfg_dir=/etc/nagios3/conf.d
+
+# OBJECT CONFIGURATION FILE(S)
+# These are the object configuration files in which you define hosts,
+# host groups, contacts, contact groups, services, etc.
+# You can split your object definitions across several config files
+# if you wish (as shown below), or keep them all in a single config file.
+
+# You can specify individual object config files as shown below:
+#cfg_file=/etc/nagios3/objects/commands.cfg
+#cfg_file=/etc/nagios3/objects/contacts.cfg
+#cfg_file=/etc/nagios3/objects/timeperiods.cfg
+#cfg_file=/etc/nagios3/objects/templates.cfg
+
+# Definitions for monitoring a Windows machine
+#cfg_file=/etc/nagios3/objects/windows.cfg
+
+# Definitions for monitoring a router/switch
+#cfg_file=/etc/nagios3/objects/switch.cfg
+
+# Definitions for monitoring a network printer
+#cfg_file=/etc/nagios3/objects/printer.cfg
+
+
+# You can also tell Nagios to process all config files (with a .cfg
+# extension) in a particular directory by using the cfg_dir
+# directive as shown below:
+
+#cfg_dir=/etc/nagios3/servers
+#cfg_dir=/etc/nagios3/printers
+#cfg_dir=/etc/nagios3/switches
+#cfg_dir=/etc/nagios3/routers
+
+
+
+
+# OBJECT CACHE FILE
+# This option determines where object definitions are cached when
+# Nagios starts/restarts. The CGIs read object definitions from
+# this cache file (rather than looking at the object config files
+# directly) in order to prevent inconsistencies that can occur
+# when the config files are modified after Nagios starts.
+
+object_cache_file=/var/cache/nagios3/objects.cache
+
+
+
+# PRE-CACHED OBJECT FILE
+# This options determines the location of the precached object file.
+# If you run Nagios with the -p command line option, it will preprocess
+# your object configuration file(s) and write the cached config to this
+# file. You can then start Nagios with the -u option to have it read
+# object definitions from this precached file, rather than the standard
+# object configuration files (see the cfg_file and cfg_dir options above).
+# Using a precached object file can speed up the time needed to (re)start
+# the Nagios process if you've got a large and/or complex configuration.
+# Read the documentation section on optimizing Nagios to find our more
+# about how this feature works.
+
+precached_object_file=/var/lib/nagios3/objects.precache
+
+
+
+# RESOURCE FILE
+# This is an optional resource file that contains $USERx$ macro
+# definitions. Multiple resource files can be specified by using
+# multiple resource_file definitions. The CGIs will not attempt to
+# read the contents of resource files, so information that is
+# considered to be sensitive (usernames, passwords, etc) can be
+# defined as macros in this file and restrictive permissions (600)
+# can be placed on this file.
+
+resource_file=/etc/nagios3/resource.cfg
+
+
+
+# STATUS FILE
+# This is where the current status of all monitored services and
+# hosts is stored. Its contents are read and processed by the CGIs.
+# The contents of the status file are deleted every time Nagios
+# restarts.
+
+status_file=/var/cache/nagios3/status.dat
+
+
+
+# STATUS FILE UPDATE INTERVAL
+# This option determines the frequency (in seconds) that
+# Nagios will periodically dump program, host, and
+# service status data.
+
+status_update_interval=10
+
+
+
+# NAGIOS USER
+# This determines the effective user that Nagios should run as.
+# You can either supply a username or a UID.
+
+nagios_user={{ nagios_user }}
+
+
+
+# NAGIOS GROUP
+# This determines the effective group that Nagios should run as.
+# You can either supply a group name or a GID.
+
+nagios_group={{ nagios_group }}
+
+
+
+# EXTERNAL COMMAND OPTION
+# This option allows you to specify whether or not Nagios should check
+# for external commands (in the command file defined below). By default
+# Nagios will *not* check for external commands, just to be on the
+# cautious side. If you want to be able to use the CGI command interface
+# you will have to enable this.
+# Values: 0 = disable commands, 1 = enable commands
+
+check_external_commands={{ check_external_commands }}
+
+
+
+# EXTERNAL COMMAND CHECK INTERVAL
+# This is the interval at which Nagios should check for external commands.
+# This value works of the interval_length you specify later. If you leave
+# that at its default value of 60 (seconds), a value of 1 here will cause
+# Nagios to check for external commands every minute. If you specify a
+# number followed by an "s" (i.e. 15s), this will be interpreted to mean
+# actual seconds rather than a multiple of the interval_length variable.
+# Note: In addition to reading the external command file at regularly
+# scheduled intervals, Nagios will also check for external commands after
+# event handlers are executed.
+# NOTE: Setting this value to -1 causes Nagios to check the external
+# command file as often as possible.
+
+#command_check_interval=15s
+command_check_interval={{ command_check_interval }}
+
+
+
+# EXTERNAL COMMAND FILE
+# This is the file that Nagios checks for external command requests.
+# It is also where the command CGI will write commands that are submitted
+# by users, so it must be writeable by the user that the web server
+# is running as (usually 'nobody'). Permissions should be set at the
+# directory level instead of on the file, as the file is deleted every
+# time its contents are processed.
+# Debian Users: In case you didn't read README.Debian yet, _NOW_ is the
+# time to do it.
+
+command_file={{ command_file }}
+
+
+
+# EXTERNAL COMMAND BUFFER SLOTS
+# This settings is used to tweak the number of items or "slots" that
+# the Nagios daemon should allocate to the buffer that holds incoming
+# external commands before they are processed. As external commands
+# are processed by the daemon, they are removed from the buffer.
+
+external_command_buffer_slots=4096
+
+
+
+# LOCK FILE
+# This is the lockfile that Nagios will use to store its PID number
+# in when it is running in daemon mode.
+
+lock_file=/var/run/nagios3/nagios3.pid
+
+
+
+# TEMP FILE
+# This is a temporary file that is used as scratch space when Nagios
+# updates the status log, cleans the comment file, etc. This file
+# is created, used, and deleted throughout the time that Nagios is
+# running.
+
+temp_file=/var/cache/nagios3/nagios.tmp
+
+
+
+# TEMP PATH
+# This is path where Nagios can create temp files for service and
+# host check results, etc.
+
+temp_path=/tmp
+
+
+
+# EVENT BROKER OPTIONS
+# Controls what (if any) data gets sent to the event broker.
+# Values: 0 = Broker nothing
+# -1 = Broker everything
+# <other> = See documentation
+
+event_broker_options=-1
+
+
+
+# EVENT BROKER MODULE(S)
+# This directive is used to specify an event broker module that should
+# by loaded by Nagios at startup. Use multiple directives if you want
+# to load more than one module. Arguments that should be passed to
+# the module at startup are seperated from the module path by a space.
+#
+#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+# WARNING !!! WARNING !!! WARNING !!! WARNING !!! WARNING !!! WARNING
+#!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
+#
+# Do NOT overwrite modules while they are being used by Nagios or Nagios
+# will crash in a fiery display of SEGFAULT glory. This is a bug/limitation
+# either in dlopen(), the kernel, and/or the filesystem. And maybe Nagios...
+#
+# The correct/safe way of updating a module is by using one of these methods:
+# 1. Shutdown Nagios, replace the module file, restart Nagios
+# 2. Delete the original module file, move the new module file into place, restart Nagios
+#
+# Example:
+#
+# broker_module=<modulepath> [moduleargs]
+
+#broker_module=/somewhere/module1.o
+#broker_module=/somewhere/module2.o arg1 arg2=3 debug=0
+{% if enable_livestatus -%}
+broker_module=/usr/lib/check_mk/livestatus.o {{ livestatus_path }} {{ livestatus_args }}
+{% endif %}
+
+
+# LOG ROTATION METHOD
+# This is the log rotation method that Nagios should use to rotate
+# the main log file. Values are as follows..
+# n = None - don't rotate the log
+# h = Hourly rotation (top of the hour)
+# d = Daily rotation (midnight every day)
+# w = Weekly rotation (midnight on Saturday evening)
+# m = Monthly rotation (midnight last day of month)
+
+log_rotation_method={{ log_rotation_method }}
+
+
+
+# LOG ARCHIVE PATH
+# This is the directory where archived (rotated) log files should be
+# placed (assuming you've chosen to do log rotation).
+
+log_archive_path={{ log_archive_path }}
+
+
+
+# LOGGING OPTIONS
+# If you want messages logged to the syslog facility, as well as the
+# Nagios log file set this option to 1. If not, set it to 0.
+
+use_syslog={{ use_syslog }}
+
+
+
+# NOTIFICATION LOGGING OPTION
+# If you don't want notifications to be logged, set this value to 0.
+# If notifications should be logged, set the value to 1.
+
+log_notifications=1
+
+
+
+# SERVICE RETRY LOGGING OPTION
+# If you don't want service check retries to be logged, set this value
+# to 0. If retries should be logged, set the value to 1.
+
+log_service_retries=1
+
+
+
+# HOST RETRY LOGGING OPTION
+# If you don't want host check retries to be logged, set this value to
+# 0. If retries should be logged, set the value to 1.
+
+log_host_retries=1
+
+
+
+# EVENT HANDLER LOGGING OPTION
+# If you don't want host and service event handlers to be logged, set
+# this value to 0. If event handlers should be logged, set the value
+# to 1.
+
+log_event_handlers=1
+
+
+
+# INITIAL STATES LOGGING OPTION
+# If you want Nagios to log all initial host and service states to
+# the main log file (the first time the service or host is checked)
+# you can enable this option by setting this value to 1. If you
+# are not using an external application that does long term state
+# statistics reporting, you do not need to enable this option. In
+# this case, set the value to 0.
+
+log_initial_states=0
+
+
+
+# EXTERNAL COMMANDS LOGGING OPTION
+# If you don't want Nagios to log external commands, set this value
+# to 0. If external commands should be logged, set this value to 1.
+# Note: This option does not include logging of passive service
+# checks - see the option below for controlling whether or not
+# passive checks are logged.
+
+log_external_commands=1
+
+
+
+# PASSIVE CHECKS LOGGING OPTION
+# If you don't want Nagios to log passive host and service checks, set
+# this value to 0. If passive checks should be logged, set
+# this value to 1.
+
+log_passive_checks=1
+
+
+
+# GLOBAL HOST AND SERVICE EVENT HANDLERS
+# These options allow you to specify a host and service event handler
+# command that is to be run for every host or service state change.
+# The global event handler is executed immediately prior to the event
+# handler that you have optionally specified in each host or
+# service definition. The command argument is the short name of a
+# command definition that you define in your host configuration file.
+# Read the HTML docs for more information.
+
+#global_host_event_handler=somecommand
+#global_service_event_handler=somecommand
+
+
+
+# SERVICE INTER-CHECK DELAY METHOD
+# This is the method that Nagios should use when initially
+# "spreading out" service checks when it starts monitoring. The
+# default is to use smart delay calculation, which will try to
+# space all service checks out evenly to minimize CPU load.
+# Using the dumb setting will cause all checks to be scheduled
+# at the same time (with no delay between them)! This is not a
+# good thing for production, but is useful when testing the
+# parallelization functionality.
+# n = None - don't use any delay between checks
+# d = Use a "dumb" delay of 1 second between checks
+# s = Use "smart" inter-check delay calculation
+# x.xx = Use an inter-check delay of x.xx seconds
+
+service_inter_check_delay_method=s
+
+
+
+# MAXIMUM SERVICE CHECK SPREAD
+# This variable determines the timeframe (in minutes) from the
+# program start time that an initial check of all services should
+# be completed. Default is 30 minutes.
+
+max_service_check_spread=30
+
+
+
+# SERVICE CHECK INTERLEAVE FACTOR
+# This variable determines how service checks are interleaved.
+# Interleaving the service checks allows for a more even
+# distribution of service checks and reduced load on remote
+# hosts. Setting this value to 1 is equivalent to how versions
+# of Nagios previous to 0.0.5 did service checks. Set this
+# value to s (smart) for automatic calculation of the interleave
+# factor unless you have a specific reason to change it.
+# s = Use "smart" interleave factor calculation
+# x = Use an interleave factor of x, where x is a
+# number greater than or equal to 1.
+
+service_interleave_factor=s
+
+
+
+# HOST INTER-CHECK DELAY METHOD
+# This is the method that Nagios should use when initially
+# "spreading out" host checks when it starts monitoring. The
+# default is to use smart delay calculation, which will try to
+# space all host checks out evenly to minimize CPU load.
+# Using the dumb setting will cause all checks to be scheduled
+# at the same time (with no delay between them)!
+# n = None - don't use any delay between checks
+# d = Use a "dumb" delay of 1 second between checks
+# s = Use "smart" inter-check delay calculation
+# x.xx = Use an inter-check delay of x.xx seconds
+
+host_inter_check_delay_method=s
+
+
+
+# MAXIMUM HOST CHECK SPREAD
+# This variable determines the timeframe (in minutes) from the
+# program start time that an initial check of all hosts should
+# be completed. Default is 30 minutes.
+
+max_host_check_spread=30
+
+
+
+# MAXIMUM CONCURRENT SERVICE CHECKS
+# This option allows you to specify the maximum number of
+# service checks that can be run in parallel at any given time.
+# Specifying a value of 1 for this variable essentially prevents
+# any service checks from being parallelized. A value of 0
+# will not restrict the number of concurrent checks that are
+# being executed.
+
+max_concurrent_checks=0
+
+
+
+# HOST AND SERVICE CHECK REAPER FREQUENCY
+# This is the frequency (in seconds!) that Nagios will process
+# the results of host and service checks.
+
+check_result_reaper_frequency=10
+
+
+
+
+# MAX CHECK RESULT REAPER TIME
+# This is the max amount of time (in seconds) that a single
+# check result reaper event will be allowed to run before
+# returning control back to Nagios so it can perform other
+# duties.
+
+max_check_result_reaper_time=30
+
+
+
+
+# CHECK RESULT PATH
+# This is directory where Nagios stores the results of host and
+# service checks that have not yet been processed.
+#
+# Note: Make sure that only one instance of Nagios has access
+# to this directory!
+
+check_result_path=/var/lib/nagios3/spool/checkresults
+
+
+
+
+# MAX CHECK RESULT FILE AGE
+# This option determines the maximum age (in seconds) which check
+# result files are considered to be valid. Files older than this
+# threshold will be mercilessly deleted without further processing.
+
+max_check_result_file_age=3600
+
+
+
+
+# CACHED HOST CHECK HORIZON
+# This option determines the maximum amount of time (in seconds)
+# that the state of a previous host check is considered current.
+# Cached host states (from host checks that were performed more
+# recently that the timeframe specified by this value) can immensely
+# improve performance in regards to the host check logic.
+# Too high of a value for this option may result in inaccurate host
+# states being used by Nagios, while a lower value may result in a
+# performance hit for host checks. Use a value of 0 to disable host
+# check caching.
+
+cached_host_check_horizon=15
+
+
+
+# CACHED SERVICE CHECK HORIZON
+# This option determines the maximum amount of time (in seconds)
+# that the state of a previous service check is considered current.
+# Cached service states (from service checks that were performed more
+# recently that the timeframe specified by this value) can immensely
+# improve performance in regards to predictive dependency checks.
+# Use a value of 0 to disable service check caching.
+
+cached_service_check_horizon=15
+
+
+
+# ENABLE PREDICTIVE HOST DEPENDENCY CHECKS
+# This option determines whether or not Nagios will attempt to execute
+# checks of hosts when it predicts that future dependency logic test
+# may be needed. These predictive checks can help ensure that your
+# host dependency logic works well.
+# Values:
+# 0 = Disable predictive checks
+# 1 = Enable predictive checks (default)
+
+enable_predictive_host_dependency_checks=1
+
+
+
+# ENABLE PREDICTIVE SERVICE DEPENDENCY CHECKS
+# This option determines whether or not Nagios will attempt to execute
+# checks of service when it predicts that future dependency logic test
+# may be needed. These predictive checks can help ensure that your
+# service dependency logic works well.
+# Values:
+# 0 = Disable predictive checks
+# 1 = Enable predictive checks (default)
+
+enable_predictive_service_dependency_checks=1
+
+
+
+# SOFT STATE DEPENDENCIES
+# This option determines whether or not Nagios will use soft state
+# information when checking host and service dependencies. Normally
+# Nagios will only use the latest hard host or service state when
+# checking dependencies. If you want it to use the latest state (regardless
+# of whether its a soft or hard state type), enable this option.
+# Values:
+# 0 = Don't use soft state dependencies (default)
+# 1 = Use soft state dependencies
+
+soft_state_dependencies=0
+
+
+
+# TIME CHANGE ADJUSTMENT THRESHOLDS
+# These options determine when Nagios will react to detected changes
+# in system time (either forward or backwards).
+
+#time_change_threshold=900
+
+
+
+# AUTO-RESCHEDULING OPTION
+# This option determines whether or not Nagios will attempt to
+# automatically reschedule active host and service checks to
+# "smooth" them out over time. This can help balance the load on
+# the monitoring server.
+# WARNING: THIS IS AN EXPERIMENTAL FEATURE - IT CAN DEGRADE
+# PERFORMANCE, RATHER THAN INCREASE IT, IF USED IMPROPERLY
+
+auto_reschedule_checks=0
+
+
+
+# AUTO-RESCHEDULING INTERVAL
+# This option determines how often (in seconds) Nagios will
+# attempt to automatically reschedule checks. This option only
+# has an effect if the auto_reschedule_checks option is enabled.
+# Default is 30 seconds.
+# WARNING: THIS IS AN EXPERIMENTAL FEATURE - IT CAN DEGRADE
+# PERFORMANCE, RATHER THAN INCREASE IT, IF USED IMPROPERLY
+
+auto_rescheduling_interval=30
+
+
+
+# AUTO-RESCHEDULING WINDOW
+# This option determines the "window" of time (in seconds) that
+# Nagios will look at when automatically rescheduling checks.
+# Only host and service checks that occur in the next X seconds
+# (determined by this variable) will be rescheduled. This option
+# only has an effect if the auto_reschedule_checks option is
+# enabled. Default is 180 seconds (3 minutes).
+# WARNING: THIS IS AN EXPERIMENTAL FEATURE - IT CAN DEGRADE
+# PERFORMANCE, RATHER THAN INCREASE IT, IF USED IMPROPERLY
+
+auto_rescheduling_window=180
+
+
+
+# SLEEP TIME
+# This is the number of seconds to sleep between checking for system
+# events and service checks that need to be run.
+
+sleep_time=0.25
+
+
+
+# TIMEOUT VALUES
+# These options control how much time Nagios will allow various
+# types of commands to execute before killing them off. Options
+# are available for controlling maximum time allotted for
+# service checks, host checks, event handlers, notifications, the
+# ocsp command, and performance data commands. All values are in
+# seconds.
+
+service_check_timeout=60
+host_check_timeout=30
+event_handler_timeout=30
+notification_timeout=30
+ocsp_timeout=5
+perfdata_timeout=5
+
+
+
+# RETAIN STATE INFORMATION
+# This setting determines whether or not Nagios will save state
+# information for services and hosts before it shuts down. Upon
+# startup Nagios will reload all saved service and host state
+# information before starting to monitor. This is useful for
+# maintaining long-term data on state statistics, etc, but will
+# slow Nagios down a bit when it (re)starts. Since its only
+# a one-time penalty, I think its well worth the additional
+# startup delay.
+
+retain_state_information=1
+
+
+
+# STATE RETENTION FILE
+# This is the file that Nagios should use to store host and
+# service state information before it shuts down. The state
+# information in this file is also read immediately prior to
+# starting to monitor the network when Nagios is restarted.
+# This file is used only if the retain_state_information
+# variable is set to 1.
+
+state_retention_file=/var/lib/nagios3/retention.dat
+
+
+
+# RETENTION DATA UPDATE INTERVAL
+# This setting determines how often (in minutes) that Nagios
+# will automatically save retention data during normal operation.
+# If you set this value to 0, Nagios will not save retention
+# data at regular interval, but it will still save retention
+# data before shutting down or restarting. If you have disabled
+# state retention, this option has no effect.
+
+retention_update_interval=60
+
+
+
+# USE RETAINED PROGRAM STATE
+# This setting determines whether or not Nagios will set
+# program status variables based on the values saved in the
+# retention file. If you want to use retained program status
+# information, set this value to 1. If not, set this value
+# to 0.
+
+use_retained_program_state=1
+
+
+
+# USE RETAINED SCHEDULING INFO
+# This setting determines whether or not Nagios will retain
+# the scheduling info (next check time) for hosts and services
+# based on the values saved in the retention file. If you
+# If you want to use retained scheduling info, set this
+# value to 1. If not, set this value to 0.
+
+use_retained_scheduling_info=1
+
+
+
+# RETAINED ATTRIBUTE MASKS (ADVANCED FEATURE)
+# The following variables are used to specify specific host and
+# service attributes that should *not* be retained by Nagios during
+# program restarts.
+#
+# The values of the masks are bitwise ANDs of values specified
+# by the "MODATTR_" definitions found in include/common.h.
+# For example, if you do not want the current enabled/disabled state
+# of flap detection and event handlers for hosts to be retained, you
+# would use a value of 24 for the host attribute mask...
+# MODATTR_EVENT_HANDLER_ENABLED (8) + MODATTR_FLAP_DETECTION_ENABLED (16) = 24
+
+# This mask determines what host attributes are not retained
+retained_host_attribute_mask=0
+
+# This mask determines what service attributes are not retained
+retained_service_attribute_mask=0
+
+# These two masks determine what process attributes are not retained.
+# There are two masks, because some process attributes have host and service
+# options. For example, you can disable active host checks, but leave active
+# service checks enabled.
+retained_process_host_attribute_mask=0
+retained_process_service_attribute_mask=0
+
+# These two masks determine what contact attributes are not retained.
+# There are two masks, because some contact attributes have host and
+# service options. For example, you can disable host notifications for
+# a contact, but leave service notifications enabled for them.
+retained_contact_host_attribute_mask=0
+retained_contact_service_attribute_mask=0
+
+
+
+# INTERVAL LENGTH
+# This is the seconds per unit interval as used in the
+# host/contact/service configuration files. Setting this to 60 means
+# that each interval is one minute long (60 seconds). Other settings
+# have not been tested much, so your mileage is likely to vary...
+
+interval_length=60
+
+
+
+# CHECK FOR UPDATES
+# This option determines whether Nagios will automatically check to
+# see if new updates (releases) are available. It is recommend that you
+# enable this option to ensure that you stay on top of the latest critical
+# patches to Nagios. Nagios is critical to you - make sure you keep it in
+# good shape. Nagios will check once a day for new updates. Data collected
+# by Nagios Enterprises from the update check is processed in accordance
+# with our privacy policy - see http://api.nagios.org for details.
+
+check_for_updates=1
+
+
+
+# BARE UPDATE CHECK
+# This option deterines what data Nagios will send to api.nagios.org when
+# it checks for updates. By default, Nagios will send information on the
+# current version of Nagios you have installed, as well as an indicator as
+# to whether this was a new installation or not. Nagios Enterprises uses
+# this data to determine the number of users running specific version of
+# Nagios. Enable this option if you do not want this information to be sent.
+
+bare_update_check=0
+
+
+
+# AGGRESSIVE HOST CHECKING OPTION
+# If you don't want to turn on aggressive host checking features, set
+# this value to 0 (the default). Otherwise set this value to 1 to
+# enable the aggressive check option. Read the docs for more info
+# on what aggressive host check is or check out the source code in
+# base/checks.c
+
+use_aggressive_host_checking=0
+
+
+
+# SERVICE CHECK EXECUTION OPTION
+# This determines whether or not Nagios will actively execute
+# service checks when it initially starts. If this option is
+# disabled, checks are not actively made, but Nagios can still
+# receive and process passive check results that come in. Unless
+# you're implementing redundant hosts or have a special need for
+# disabling the execution of service checks, leave this enabled!
+# Values: 1 = enable checks, 0 = disable checks
+
+execute_service_checks=1
+
+
+
+# PASSIVE SERVICE CHECK ACCEPTANCE OPTION
+# This determines whether or not Nagios will accept passive
+# service checks results when it initially (re)starts.
+# Values: 1 = accept passive checks, 0 = reject passive checks
+
+accept_passive_service_checks=1
+
+
+
+# HOST CHECK EXECUTION OPTION
+# This determines whether or not Nagios will actively execute
+# host checks when it initially starts. If this option is
+# disabled, checks are not actively made, but Nagios can still
+# receive and process passive check results that come in. Unless
+# you're implementing redundant hosts or have a special need for
+# disabling the execution of host checks, leave this enabled!
+# Values: 1 = enable checks, 0 = disable checks
+
+execute_host_checks=1
+
+
+
+# PASSIVE HOST CHECK ACCEPTANCE OPTION
+# This determines whether or not Nagios will accept passive
+# host checks results when it initially (re)starts.
+# Values: 1 = accept passive checks, 0 = reject passive checks
+
+accept_passive_host_checks=1
+
+
+
+# NOTIFICATIONS OPTION
+# This determines whether or not Nagios will sent out any host or
+# service notifications when it is initially (re)started.
+# Values: 1 = enable notifications, 0 = disable notifications
+
+enable_notifications=1
+
+
+
+# EVENT HANDLER USE OPTION
+# This determines whether or not Nagios will run any host or
+# service event handlers when it is initially (re)started. Unless
+# you're implementing redundant hosts, leave this option enabled.
+# Values: 1 = enable event handlers, 0 = disable event handlers
+
+enable_event_handlers=1
+
+
+
+# PROCESS PERFORMANCE DATA OPTION
+# This determines whether or not Nagios will process performance
+# data returned from service and host checks. If this option is
+# enabled, host performance data will be processed using the
+# host_perfdata_command (defined below) and service performance
+# data will be processed using the service_perfdata_command (also
+# defined below). Read the HTML docs for more information on
+# performance data.
+# Values: 1 = process performance data, 0 = do not process performance data
+
+process_performance_data=0
+
+
+
+# HOST AND SERVICE PERFORMANCE DATA PROCESSING COMMANDS
+# These commands are run after every host and service check is
+# performed. These commands are executed only if the
+# enable_performance_data option (above) is set to 1. The command
+# argument is the short name of a command definition that you
+# define in your host configuration file. Read the HTML docs for
+# more information on performance data.
+
+#host_perfdata_command=process-host-perfdata
+#service_perfdata_command=process-service-perfdata
+
+
+
+# HOST AND SERVICE PERFORMANCE DATA FILES
+# These files are used to store host and service performance data.
+# Performance data is only written to these files if the
+# enable_performance_data option (above) is set to 1.
+
+#host_perfdata_file=/tmp/host-perfdata
+#service_perfdata_file=/tmp/service-perfdata
+
+
+
+# HOST AND SERVICE PERFORMANCE DATA FILE TEMPLATES
+# These options determine what data is written (and how) to the
+# performance data files. The templates may contain macros, special
+# characters (\t for tab, \r for carriage return, \n for newline)
+# and plain text. A newline is automatically added after each write
+# to the performance data file. Some examples of what you can do are
+# shown below.
+
+#host_perfdata_file_template=[HOSTPERFDATA]\t$TIMET$\t$HOSTNAME$\t$HOSTEXECUTIONTIME$\t$HOSTOUTPUT$\t$HOSTPERFDATA$
+#service_perfdata_file_template=[SERVICEPERFDATA]\t$TIMET$\t$HOSTNAME$\t$SERVICEDESC$\t$SERVICEEXECUTIONTIME$\t$SERVICELATENCY$\t$SERVICEOUTPUT$\t$SERVICEPERFDATA$
+
+
+
+# HOST AND SERVICE PERFORMANCE DATA FILE MODES
+# This option determines whether or not the host and service
+# performance data files are opened in write ("w") or append ("a")
+# mode. If you want to use named pipes, you should use the special
+# pipe ("p") mode which avoid blocking at startup, otherwise you will
+# likely want the defult append ("a") mode.
+
+#host_perfdata_file_mode=a
+#service_perfdata_file_mode=a
+
+
+
+# HOST AND SERVICE PERFORMANCE DATA FILE PROCESSING INTERVAL
+# These options determine how often (in seconds) the host and service
+# performance data files are processed using the commands defined
+# below. A value of 0 indicates the files should not be periodically
+# processed.
+
+#host_perfdata_file_processing_interval=0
+#service_perfdata_file_processing_interval=0
+
+
+
+# HOST AND SERVICE PERFORMANCE DATA FILE PROCESSING COMMANDS
+# These commands are used to periodically process the host and
+# service performance data files. The interval at which the
+# processing occurs is determined by the options above.
+
+#host_perfdata_file_processing_command=process-host-perfdata-file
+#service_perfdata_file_processing_command=process-service-perfdata-file
+
+
+
+# HOST AND SERVICE PERFORMANCE DATA PROCESS EMPTY RESULTS
+# THese options determine wether the core will process empty perfdata
+# results or not. This is needed for distributed monitoring, and intentionally
+# turned on by default.
+# If you don't require empty perfdata - saving some cpu cycles
+# on unwanted macro calculation - you can turn that off. Be careful!
+# Values: 1 = enable, 0 = disable
+
+#host_perfdata_process_empty_results=1
+#service_perfdata_process_empty_results=1
+
+
+# OBSESS OVER SERVICE CHECKS OPTION
+# This determines whether or not Nagios will obsess over service
+# checks and run the ocsp_command defined below. Unless you're
+# planning on implementing distributed monitoring, do not enable
+# this option. Read the HTML docs for more information on
+# implementing distributed monitoring.
+# Values: 1 = obsess over services, 0 = do not obsess (default)
+
+obsess_over_services=0
+
+
+
+# OBSESSIVE COMPULSIVE SERVICE PROCESSOR COMMAND
+# This is the command that is run for every service check that is
+# processed by Nagios. This command is executed only if the
+# obsess_over_services option (above) is set to 1. The command
+# argument is the short name of a command definition that you
+# define in your host configuration file. Read the HTML docs for
+# more information on implementing distributed monitoring.
+
+#ocsp_command=somecommand
+
+
+
+# OBSESS OVER HOST CHECKS OPTION
+# This determines whether or not Nagios will obsess over host
+# checks and run the ochp_command defined below. Unless you're
+# planning on implementing distributed monitoring, do not enable
+# this option. Read the HTML docs for more information on
+# implementing distributed monitoring.
+# Values: 1 = obsess over hosts, 0 = do not obsess (default)
+
+obsess_over_hosts=0
+
+
+
+# OBSESSIVE COMPULSIVE HOST PROCESSOR COMMAND
+# This is the command that is run for every host check that is
+# processed by Nagios. This command is executed only if the
+# obsess_over_hosts option (above) is set to 1. The command
+# argument is the short name of a command definition that you
+# define in your host configuration file. Read the HTML docs for
+# more information on implementing distributed monitoring.
+
+#ochp_command=somecommand
+
+
+
+# TRANSLATE PASSIVE HOST CHECKS OPTION
+# This determines whether or not Nagios will translate
+# DOWN/UNREACHABLE passive host check results into their proper
+# state for this instance of Nagios. This option is useful
+# if you have distributed or failover monitoring setup. In
+# these cases your other Nagios servers probably have a different
+# "view" of the network, with regards to the parent/child relationship
+# of hosts. If a distributed monitoring server thinks a host
+# is DOWN, it may actually be UNREACHABLE from the point of
+# this Nagios instance. Enabling this option will tell Nagios
+# to translate any DOWN or UNREACHABLE host states it receives
+# passively into the correct state from the view of this server.
+# Values: 1 = perform translation, 0 = do not translate (default)
+
+translate_passive_host_checks=0
+
+
+
+# PASSIVE HOST CHECKS ARE SOFT OPTION
+# This determines whether or not Nagios will treat passive host
+# checks as being HARD or SOFT. By default, a passive host check
+# result will put a host into a HARD state type. This can be changed
+# by enabling this option.
+# Values: 0 = passive checks are HARD, 1 = passive checks are SOFT
+
+passive_host_checks_are_soft=0
+
+
+
+# ORPHANED HOST/SERVICE CHECK OPTIONS
+# These options determine whether or not Nagios will periodically
+# check for orphaned host service checks. Since service checks are
+# not rescheduled until the results of their previous execution
+# instance are processed, there exists a possibility that some
+# checks may never get rescheduled. A similar situation exists for
+# host checks, although the exact scheduling details differ a bit
+# from service checks. Orphaned checks seem to be a rare
+# problem and should not happen under normal circumstances.
+# If you have problems with service checks never getting
+# rescheduled, make sure you have orphaned service checks enabled.
+# Values: 1 = enable checks, 0 = disable checks
+
+check_for_orphaned_services=1
+check_for_orphaned_hosts=1
+
+
+
+# SERVICE FRESHNESS CHECK OPTION
+# This option determines whether or not Nagios will periodically
+# check the "freshness" of service results. Enabling this option
+# is useful for ensuring passive checks are received in a timely
+# manner.
+# Values: 1 = enabled freshness checking, 0 = disable freshness checking
+
+check_service_freshness=1
+
+
+
+# SERVICE FRESHNESS CHECK INTERVAL
+# This setting determines how often (in seconds) Nagios will
+# check the "freshness" of service check results. If you have
+# disabled service freshness checking, this option has no effect.
+
+service_freshness_check_interval=60
+
+
+
+# SERVICE CHECK TIMEOUT STATE
+# This setting determines the state Nagios will report when a
+# service check times out - that is does not respond within
+# service_check_timeout seconds. This can be useful if a
+# machine is running at too high a load and you do not want
+# to consider a failed service check to be critical (the default).
+# Valid settings are:
+# c - Critical (default)
+# u - Unknown
+# w - Warning
+# o - OK
+
+service_check_timeout_state=c
+
+
+
+# HOST FRESHNESS CHECK OPTION
+# This option determines whether or not Nagios will periodically
+# check the "freshness" of host results. Enabling this option
+# is useful for ensuring passive checks are received in a timely
+# manner.
+# Values: 1 = enabled freshness checking, 0 = disable freshness checking
+
+check_host_freshness=0
+
+
+
+# HOST FRESHNESS CHECK INTERVAL
+# This setting determines how often (in seconds) Nagios will
+# check the "freshness" of host check results. If you have
+# disabled host freshness checking, this option has no effect.
+
+host_freshness_check_interval=60
+
+
+
+
+# ADDITIONAL FRESHNESS THRESHOLD LATENCY
+# This setting determines the number of seconds that Nagios
+# will add to any host and service freshness thresholds that
+# it calculates (those not explicitly specified by the user).
+
+additional_freshness_latency=15
+
+
+
+
+# FLAP DETECTION OPTION
+# This option determines whether or not Nagios will try
+# and detect hosts and services that are "flapping".
+# Flapping occurs when a host or service changes between
+# states too frequently. When Nagios detects that a
+# host or service is flapping, it will temporarily suppress
+# notifications for that host/service until it stops
+# flapping. Flap detection is very experimental, so read
+# the HTML documentation before enabling this feature!
+# Values: 1 = enable flap detection
+# 0 = disable flap detection (default)
+
+enable_flap_detection=1
+
+
+
+# FLAP DETECTION THRESHOLDS FOR HOSTS AND SERVICES
+# Read the HTML documentation on flap detection for
+# an explanation of what this option does. This option
+# has no effect if flap detection is disabled.
+
+low_service_flap_threshold=5.0
+high_service_flap_threshold=20.0
+low_host_flap_threshold=5.0
+high_host_flap_threshold=20.0
+
+
+
+# DATE FORMAT OPTION
+# This option determines how short dates are displayed. Valid options
+# include:
+# us (MM-DD-YYYY HH:MM:SS)
+# euro (DD-MM-YYYY HH:MM:SS)
+# iso8601 (YYYY-MM-DD HH:MM:SS)
+# strict-iso8601 (YYYY-MM-DDTHH:MM:SS)
+#
+
+date_format=iso8601
+
+
+
+
+# TIMEZONE OFFSET
+# This option is used to override the default timezone that this
+# instance of Nagios runs in. If not specified, Nagios will use
+# the system configured timezone.
+#
+# NOTE: In order to display the correct timezone in the CGIs, you
+# will also need to alter the Apache directives for the CGI path
+# to include your timezone. Example:
+#
+# <Directory "/usr/local/nagios/sbin/">
+# SetEnv TZ "Australia/Brisbane"
+# ...
+# </Directory>
+
+#use_timezone=US/Mountain
+#use_timezone=Australia/Brisbane
+
+
+
+
+# P1.PL FILE LOCATION
+# This value determines where the p1.pl perl script (used by the
+# embedded Perl interpreter) is located. If you didn't compile
+# Nagios with embedded Perl support, this option has no effect.
+
+p1_file=/usr/lib/nagios3/p1.pl
+
+
+
+# EMBEDDED PERL INTERPRETER OPTION
+# This option determines whether or not the embedded Perl interpreter
+# will be enabled during runtime. This option has no effect if Nagios
+# has not been compiled with support for embedded Perl.
+# Values: 0 = disable interpreter, 1 = enable interpreter
+
+enable_embedded_perl=1
+
+
+
+# EMBEDDED PERL USAGE OPTION
+# This option determines whether or not Nagios will process Perl plugins
+# and scripts with the embedded Perl interpreter if the plugins/scripts
+# do not explicitly indicate whether or not it is okay to do so. Read
+# the HTML documentation on the embedded Perl interpreter for more
+# information on how this option works.
+
+use_embedded_perl_implicitly=1
+
+
+
+# ILLEGAL OBJECT NAME CHARACTERS
+# This option allows you to specify illegal characters that cannot
+# be used in host names, service descriptions, or names of other
+# object types.
+
+illegal_object_name_chars=`~!$%^&*|'"<>?,()=
+
+
+
+# ILLEGAL MACRO OUTPUT CHARACTERS
+# This option allows you to specify illegal characters that are
+# stripped from macros before being used in notifications, event
+# handlers, etc. This DOES NOT affect macros used in service or
+# host check commands.
+# The following macros are stripped of the characters you specify:
+# $HOSTOUTPUT$
+# $HOSTPERFDATA$
+# $HOSTACKAUTHOR$
+# $HOSTACKCOMMENT$
+# $SERVICEOUTPUT$
+# $SERVICEPERFDATA$
+# $SERVICEACKAUTHOR$
+# $SERVICEACKCOMMENT$
+
+illegal_macro_output_chars=`~$&|'"<>
+
+
+
+# REGULAR EXPRESSION MATCHING
+# This option controls whether or not regular expression matching
+# takes place in the object config files. Regular expression
+# matching is used to match host, hostgroup, service, and service
+# group names/descriptions in some fields of various object types.
+# Values: 1 = enable regexp matching, 0 = disable regexp matching
+
+use_regexp_matching=0
+
+
+
+# "TRUE" REGULAR EXPRESSION MATCHING
+# This option controls whether or not "true" regular expression
+# matching takes place in the object config files. This option
+# only has an effect if regular expression matching is enabled
+# (see above). If this option is DISABLED, regular expression
+# matching only occurs if a string contains wildcard characters
+# (* and ?). If the option is ENABLED, regexp matching occurs
+# all the time (which can be annoying).
+# Values: 1 = enable true matching, 0 = disable true matching
+
+use_true_regexp_matching=0
+
+
+
+# ADMINISTRATOR EMAIL/PAGER ADDRESSES
+# The email and pager address of a global administrator (likely you).
+# Nagios never uses these values itself, but you can access them by
+# using the $ADMINEMAIL$ and $ADMINPAGER$ macros in your notification
+# commands.
+
+admin_email={{ admin_email }}
+admin_pager={{ admin_pager }}
+
+
+
+# DAEMON CORE DUMP OPTION
+# This option determines whether or not Nagios is allowed to create
+# a core dump when it runs as a daemon. Note that it is generally
+# considered bad form to allow this, but it may be useful for
+# debugging purposes. Enabling this option doesn't guarantee that
+# a core file will be produced, but that's just life...
+# Values: 1 - Allow core dumps
+# 0 - Do not allow core dumps (default)
+
+daemon_dumps_core={{ daemon_dumps_core }}
+
+
+
+# LARGE INSTALLATION TWEAKS OPTION
+# This option determines whether or not Nagios will take some shortcuts
+# which can save on memory and CPU usage in large Nagios installations.
+# Read the documentation for more information on the benefits/tradeoffs
+# of enabling this option.
+# Values: 1 - Enabled tweaks
+# 0 - Disable tweaks (default)
+
+use_large_installation_tweaks=0
+
+
+
+# ENABLE ENVIRONMENT MACROS
+# This option determines whether or not Nagios will make all standard
+# macros available as environment variables when host/service checks
+# and system commands (event handlers, notifications, etc.) are
+# executed. Enabling this option can cause performance issues in
+# large installations, as it will consume a bit more memory and (more
+# importantly) consume more CPU.
+# Values: 1 - Enable environment variable macros (default)
+# 0 - Disable environment variable macros
+
+enable_environment_macros=1
+
+
+
+# CHILD PROCESS MEMORY OPTION
+# This option determines whether or not Nagios will free memory in
+# child processes (processed used to execute system commands and host/
+# service checks). If you specify a value here, it will override
+# program defaults.
+# Value: 1 - Free memory in child processes
+# 0 - Do not free memory in child processes
+
+#free_child_process_memory=1
+
+
+
+# CHILD PROCESS FORKING BEHAVIOR
+# This option determines how Nagios will fork child processes
+# (used to execute system commands and host/service checks). Normally
+# child processes are fork()ed twice, which provides a very high level
+# of isolation from problems. Fork()ing once is probably enough and will
+# save a great deal on CPU usage (in large installs), so you might
+# want to consider using this. If you specify a value here, it will
+# program defaults.
+# Value: 1 - Child processes fork() twice
+# 0 - Child processes fork() just once
+
+#child_processes_fork_twice=1
+
+
+
+# DEBUG LEVEL
+# This option determines how much (if any) debugging information will
+# be written to the debug file. OR values together to log multiple
+# types of information.
+# Values:
+# -1 = Everything
+# 0 = Nothing
+# 1 = Functions
+# 2 = Configuration
+# 4 = Process information
+# 8 = Scheduled events
+# 16 = Host/service checks
+# 32 = Notifications
+# 64 = Event broker
+# 128 = External commands
+# 256 = Commands
+# 512 = Scheduled downtime
+# 1024 = Comments
+# 2048 = Macros
+
+debug_level={{ debug_level }}
+
+
+
+# DEBUG VERBOSITY
+# This option determines how verbose the debug log out will be.
+# Values: 0 = Brief output
+# 1 = More detailed
+# 2 = Very detailed
+
+debug_verbosity={{ debug_verbosity }}
+
+
+
+# DEBUG FILE
+# This option determines where Nagios should write debugging information.
+
+debug_file={{ debug_file }}
+
+
+
+# MAX DEBUG FILE SIZE
+# This option determines the maximum size (in bytes) of the debug file. If
+# the file grows larger than this size, it will be renamed with a .old
+# extension. If a file already exists with a .old extension it will
+# automatically be deleted. This helps ensure your disk space usage doesn't
+# get out of control when debugging Nagios.
+
+max_debug_file_size=1000000
diff --git a/src/templates/pagerduty_nagios.cfg.j2 b/src/templates/pagerduty_nagios.cfg.j2
new file mode 100644
index 0000000..3dfd0fe
--- /dev/null
+++ b/src/templates/pagerduty_nagios.cfg.j2
@@ -0,0 +1,26 @@
+#------------------------------------------------
+# This file is juju managed
+# File created on: {{ today }}
+#------------------------------------------------
+
+define contact {
+ contact_name pagerduty
+ alias PagerDuty Pseudo-Contact
+ service_notification_period 24x7
+ host_notification_period 24x7
+ service_notification_options {{ notification_levels }}
+ host_notification_options d,r
+ service_notification_commands notify-service-by-pagerduty
+ host_notification_commands notify-host-by-pagerduty
+ pager {{ pagerduty_key }}
+}
+
+define command {
+ command_name notify-service-by-pagerduty
+ command_line /usr/local/bin/pagerduty_nagios.pl enqueue -f pd_nagios_object=service -q {{ pagerduty_path }}
+}
+
+define command {
+ command_name notify-host-by-pagerduty
+ command_line /usr/local/bin/pagerduty_nagios.pl enqueue -f pd_nagios_object=host -q {{ pagerduty_path }}
+}
diff --git a/src/tests/functional/requirements.txt b/src/tests/functional/requirements.txt
new file mode 100644
index 0000000..f76bfbb
--- /dev/null
+++ b/src/tests/functional/requirements.txt
@@ -0,0 +1,6 @@
+flake8
+juju
+mock
+pytest
+pytest-asyncio
+requests
diff --git a/src/tests/functional/test_deploy.py b/src/tests/functional/test_deploy.py
new file mode 100644
index 0000000..51b4f2e
--- /dev/null
+++ b/src/tests/functional/test_deploy.py
@@ -0,0 +1,59 @@
+import os
+
+import pytest
+from juju.model import Model
+
+# Treat tests as coroutines
+pytestmark = pytest.mark.asyncio
+
+series = ['xenial', 'bionic']
+juju_repository = os.getenv('JUJU_REPOSITORY', '.').rstrip('/')
+
+
+@pytest.fixture
+async def model():
+ model = Model()
+ await model.connect_current()
+ yield model
+ await model.disconnect()
+
+
+@pytest.fixture
+async def apps(model):
+ apps = []
+ for entry in series:
+ app = model.applications['nagios-charm-{}'.format(entry)]
+ apps.append(app)
+ return apps
+
+
+@pytest.fixture
+async def units(apps):
+ units = []
+ for app in apps:
+ units.extend(app.units)
+ return units
+
+
+@pytest.mark.parametrize('series', series)
+async def test_nagioscharm_deploy(model, series):
+ # Starts a deploy for each series
+ await model.deploy(
+ '{}/builds/nagios-charm'.format(juju_repository),
+ series=series,
+ application_name='nagios-charm-{}'.format(series))
+ assert True
+
+
+async def test_nagioscharm_status(apps, model):
+ # Verifies status for all deployed series of the charm
+ for app in apps:
+ await model.block_until(lambda: app.status == 'active')
+ assert True
+
+
+async def test_example_action(units):
+ for unit in units:
+ action = await unit.run_action('example-action')
+ action = await action.wait()
+ assert action.status == 'completed'
diff --git a/src/tests/unit/conftest.py b/src/tests/unit/conftest.py
new file mode 100644
index 0000000..b557434
--- /dev/null
+++ b/src/tests/unit/conftest.py
@@ -0,0 +1,70 @@
+#!/usr/bin/python3
+import mock
+import pytest
+
+
+# If layer options are used, add this to nagioscharm
+# and import layer in lib_nagios_charm
+@pytest.fixture
+def mock_layers(monkeypatch):
+ import sys
+ sys.modules['charms.layer'] = mock.Mock()
+ sys.modules['reactive'] = mock.Mock()
+
+ # Mock any functions in layers that need to be mocked here
+
+ def options(layer):
+ # mock options for layers here
+ if layer == 'example-layer':
+ options = {'port': 9999}
+ return options
+ else:
+ return None
+
+ monkeypatch.setattr('lib_nagios_charm.layer.options', options)
+
+
+@pytest.fixture
+def mock_hookenv_config(monkeypatch):
+ import yaml
+
+ def mock_config():
+ cfg = {}
+ yml = yaml.load(open('./config.yaml'))
+
+ # Load all defaults
+ for key, value in yml['options'].items():
+ cfg[key] = value['default']
+
+ # Manually add cfg from other layers
+ # cfg['my-other-layer'] = 'mock'
+ return cfg
+
+ monkeypatch.setattr('lib_nagios_charm.hookenv.config', mock_config)
+
+
+@pytest.fixture
+def mock_remote_unit(monkeypatch):
+ monkeypatch.setattr('lib_nagios_charm.hookenv.remote_unit', lambda: 'unit-mock/0')
+
+
+@pytest.fixture
+def mock_charm_dir(monkeypatch):
+ monkeypatch.setattr('lib_nagios_charm.hookenv.charm_dir', lambda: '/mock/charm/dir')
+
+
+@pytest.fixture
+def nagioscharm(tmpdir, mock_hookenv_config, mock_charm_dir, monkeypatch):
+ from lib_nagios_charm import NagioscharmHelper
+ helper = NagioscharmHelper()
+
+ # Example config file patching
+ cfg_file = tmpdir.join('example.cfg')
+ with open('./tests/unit/example.cfg', 'r') as src_file:
+ cfg_file.write(src_file.read())
+ helper.example_config_file = cfg_file.strpath
+
+ # Any other functions that load helper will get this version
+ monkeypatch.setattr('lib_nagios_charm.NagioscharmHelper', lambda: helper)
+
+ return helper
diff --git a/src/tests/unit/example.cfg b/src/tests/unit/example.cfg
new file mode 100644
index 0000000..81b1e94
--- /dev/null
+++ b/src/tests/unit/example.cfg
@@ -0,0 +1 @@
+This is an example config file included with the unit tests
diff --git a/src/tests/unit/requirements.txt b/src/tests/unit/requirements.txt
new file mode 100644
index 0000000..9c685e5
--- /dev/null
+++ b/src/tests/unit/requirements.txt
@@ -0,0 +1,5 @@
+charmhelpers
+charms.reactive
+mock
+pytest
+pytest-cov
diff --git a/src/tests/unit/test_actions.py b/src/tests/unit/test_actions.py
new file mode 100644
index 0000000..a181707
--- /dev/null
+++ b/src/tests/unit/test_actions.py
@@ -0,0 +1,12 @@
+import imp
+
+import mock
+
+
+class TestActions():
+ def test_example_action(self, nagioscharm, monkeypatch):
+ mock_function = mock.Mock()
+ monkeypatch.setattr(nagioscharm, 'action_function', mock_function)
+ assert mock_function.call_count == 0
+ imp.load_source('action_function', './actions/example-action')
+ assert mock_function.call_count == 1
diff --git a/src/tests/unit/test_lib.py b/src/tests/unit/test_lib.py
new file mode 100644
index 0000000..cefcdd1
--- /dev/null
+++ b/src/tests/unit/test_lib.py
@@ -0,0 +1,12 @@
+#!/usr/bin/python3
+
+
+class TestLib():
+ def test_pytest(self):
+ assert True
+
+ def test_nagioscharm(self, nagioscharm):
+ ''' See if the helper fixture works to load charm configs '''
+ assert isinstance(nagioscharm.charm_config, dict)
+
+ # Include tests for functions in lib_nagios_charm
diff --git a/src/tox.ini b/src/tox.ini
new file mode 100644
index 0000000..f1e64f7
--- /dev/null
+++ b/src/tox.ini
@@ -0,0 +1,37 @@
+[tox]
+skipsdist=True
+envlist = unit, functional
+skip_missing_interpreters = True
+
+[testenv]
+basepython = python3
+setenv =
+ PYTHONPATH = .
+
+[testenv:unit]
+commands = pytest -v --ignore {toxinidir}/tests/functional --cov=lib --cov=reactive --cov=actions --cov-report=term
+deps = -r{toxinidir}/tests/unit/requirements.txt
+ -r{toxinidir}/requirements.txt
+setenv = PYTHONPATH={toxinidir}/lib
+
+[testenv:functional]
+passenv =
+ HOME
+ JUJU_REPOSITORY
+ PATH
+commands = pytest -v --ignore {toxinidir}/tests/unit
+deps = -r{toxinidir}/tests/functional/requirements.txt
+ -r{toxinidir}/requirements.txt
+
+[testenv:lint]
+commands = flake8
+deps = flake8
+
+[flake8]
+exclude =
+ .git,
+ __pycache__,
+ .tox,
+ lib/pynag
+max-line-length = 120
+max-complexity = 10
Follow ups