From 6a469562d06f7c368b7bb169366d813e9b6ce10a Mon Sep 17 00:00:00 2001 From: Marius Rieder Date: Wed, 5 Jun 2024 18:43:18 +0200 Subject: [PATCH 01/10] Update from template for Checkmk 23 --- .devcontainer/Dockerfile | 4 ++-- .devcontainer/build.sh | 10 +-------- .devcontainer/devcontainer.json | 2 +- .devcontainer/symlink.sh | 2 ++ .github/workflows/build-release.yml | 21 ++++++++++++------ .github/workflows/build.yml | 20 +++++++++++------ .github/workflows/lint.yml | 9 ++++---- .github/workflows/pytest.yml | 33 ++++++++++++----------------- 8 files changed, 53 insertions(+), 48 deletions(-) diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile index f58ff84..205fc34 100644 --- a/.devcontainer/Dockerfile +++ b/.devcontainer/Dockerfile @@ -1,7 +1,7 @@ # See here for image contents: https://github.com/microsoft/vscode-dev-containers/tree/v0.155.1/containers/ubuntu/.devcontainer/base.Dockerfile -# [Choice] CheckMK version: 2.2.0-latest -ARG VARIANT="2.2.0-latest" +# [Choice] CheckMK version: 2.3.0-latest +ARG VARIANT="2.3.0-latest" FROM checkmk/check-mk-raw:${VARIANT} RUN /docker-entrypoint.sh /bin/true diff --git a/.devcontainer/build.sh b/.devcontainer/build.sh index 62901f1..ad9915a 100755 --- a/.devcontainer/build.sh +++ b/.devcontainer/build.sh @@ -2,8 +2,7 @@ NAME=$(python3 -c 'print(eval(open("package").read())["name"])') VERSION=$(python3 -c 'print(eval(open("package").read())["version"])') -rm -f $NAME-$VERSION.mkp \ - /omd/sites/cmk/var/cat check_mk/packages/${NAME}-*.mkp \ +rm /omd/sites/cmk/var/check_mk/packages/${NAME} \ /omd/sites/cmk/var/check_mk/packages_local/${NAME}-*.mkp ||: mkp -v package package 2>&1 | sed '/Installing$/Q' ||: @@ -11,10 +10,3 @@ mkp -v package package 2>&1 | sed '/Installing$/Q' ||: cp /omd/sites/cmk/var/check_mk/packages_local/$NAME-$VERSION.mkp . mkp inspect $NAME-$VERSION.mkp - -# Set Outputs for GitHub Workflow steps -if [ -n "$GITHUB_WORKSPACE" ]; then - echo "pkgfile=${NAME}-${VERSION}.mkp" >> $GITHUB_OUTPUT - echo "pkgname=${NAME}" >> $GITHUB_OUTPUT - echo "pkgversion=$VERSION" >> $GITHUB_OUTPUT -fi \ No newline at end of file diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index b68ca48..ec92da1 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -5,7 +5,7 @@ "build": { "dockerfile": "Dockerfile", // Update 'VARIANT' to pick an Ubuntu version: focal, bionic - "args": { "VARIANT": "2.2.0-latest" } + "args": { "VARIANT": "2.3.0-latest" } }, "customizations": { diff --git a/.devcontainer/symlink.sh b/.devcontainer/symlink.sh index 18d6cf6..2c755f2 100755 --- a/.devcontainer/symlink.sh +++ b/.devcontainer/symlink.sh @@ -1,4 +1,6 @@ #!/bin/bash +PKGNAME=$(python3 -c 'print(eval(open("package").read())["name"])') +ln -sv $WORKSPACE $OMD_ROOT/local/lib/python3/cmk_addons/plugins/$PKGNAME for DIR in 'agents' 'checkman' 'checks' 'doc' 'inventory' 'notifications' 'pnp-templates' 'web'; do rm -rfv $OMD_ROOT/local/share/check_mk/$DIR diff --git a/.github/workflows/build-release.yml b/.github/workflows/build-release.yml index 1c3aa3e..94499de 100644 --- a/.github/workflows/build-release.yml +++ b/.github/workflows/build-release.yml @@ -11,7 +11,7 @@ jobs: name: Build Release Package runs-on: ubuntu-latest container: - image: checkmk/check-mk-raw:2.2.0-latest + image: checkmk/check-mk-raw:2.3.0-latest permissions: contents: write @@ -24,17 +24,24 @@ jobs: steps: - name: Initialize Checkmk Site run: /docker-entrypoint.sh /bin/true - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + - name: Parse Package File + run: | + NAME=$(python3 -c 'print(eval(open("package").read())["name"])') + VERSION=$(python3 -c 'print(eval(open("package").read())["version"])') + echo "CMKPKG_NAME=$NAME" >> "$GITHUB_ENV" + echo "CMKPKG_VERSION=$VERSION" >> "$GITHUB_ENV" - name: Setup links run: .devcontainer/symlink.sh - - name: Update GITHUB_PATH - run: echo "/omd/sites/cmk/bin" >> $GITHUB_PATH - name: Build Extension - run: .devcontainer/build.sh + run: | + chown -R cmk:cmk $GITHUB_WORKSPACE + su -l -c "mkp -v package $GITHUB_WORKSPACE/package" cmk + cp /omd/sites/cmk/var/check_mk/packages_local/${CMKPKG_NAME}-${CMKPKG_VERSION}.mkp . + echo "pkgfile=${CMKPKG_NAME}-${CMKPKG_VERSION}.mkp" >> $GITHUB_OUTPUT id: cmkpkg - - name: Create Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 with: release_name: Release ${{ github.ref }} draft: false diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 18bcb70..d0026e0 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -13,7 +13,7 @@ jobs: name: Build Checkmk package runs-on: ubuntu-latest container: - image: checkmk/check-mk-raw:2.2.0-latest + image: checkmk/check-mk-raw:2.3.0-latest env: OMD_ROOT: /omd/sites/cmk @@ -24,16 +24,24 @@ jobs: steps: - name: Initialize Checkmk Site run: /docker-entrypoint.sh /bin/true - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 + - name: Parse Package File + run: | + NAME=$(python3 -c 'print(eval(open("package").read())["name"])') + VERSION=$(python3 -c 'print(eval(open("package").read())["version"])') + echo "CMKPKG_NAME=$NAME" >> "$GITHUB_ENV" + echo "CMKPKG_VERSION=$VERSION" >> "$GITHUB_ENV" - name: Setup links run: .devcontainer/symlink.sh - - name: Update GITHUB_PATH - run: echo "/omd/sites/cmk/bin" >> $GITHUB_PATH - name: Build Extension - run: .devcontainer/build.sh + run: | + chown -R cmk:cmk $GITHUB_WORKSPACE + su -l -c "mkp -v package $GITHUB_WORKSPACE/package" cmk + cp /omd/sites/cmk/var/check_mk/packages_local/${CMKPKG_NAME}-${CMKPKG_VERSION}.mkp . + echo "pkgfile=${CMKPKG_NAME}-${CMKPKG_VERSION}.mkp" >> $GITHUB_OUTPUT id: cmkpkg - name: Upload artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: ${{ steps.cmkpkg.outputs.pkgfile }} path: ${{ steps.cmkpkg.outputs.pkgfile }} diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 91c978a..fb58819 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -4,6 +4,7 @@ on: push: paths: - '**.py' + - .github/workflows/lint.yml jobs: flake8_py3: @@ -11,11 +12,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 - - name: Set up Python 3.9 - uses: actions/setup-python@v4 + - uses: actions/checkout@v4 + - name: Set up Python 3.12 + uses: actions/setup-python@v5 with: - python-version: 3.9 + python-version: '3.12' - name: Install flake8 run: pip install flake8 - name: Run flake8 diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 695fba6..801bdce 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -1,30 +1,25 @@ name: pytest on: - push: [] + push: + paths: + - '**.py' + - .github/workflows/pytest.yml jobs: pytest: runs-on: ubuntu-latest container: - image: checkmk/check-mk-raw:2.2.0-latest - - env: - OMD_ROOT: /omd/sites/cmk - OMD_SITE: cmk - CMK_SITE_ID: cmk - WORKSPACE: ${{ github.workspace }} + image: checkmk/check-mk-raw:2.3.0-latest steps: - - name: Initialize Checkmk Site - run: /docker-entrypoint.sh /bin/true - - uses: actions/checkout@v3 - - name: Setup links - run: ./.devcontainer/symlink.sh - - name: Install pytest - run: su -l -c "REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt pip3 install -r $GITHUB_WORKSPACE/.devcontainer/requirements.txt" cmk - - name: Update GITHUB_PATH - run: echo "/omd/sites/cmk/bin" >> $GITHUB_PATH - - name: Run pytest - run: python3 -m pytest \ No newline at end of file + - name: Initialize Checkmk Site + run: /docker-entrypoint.sh /bin/true + - uses: actions/checkout@v4 + - name: Setup links + run: .devcontainer/symlink.sh + - name: Install pytest + run: su -l -c "REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt pip3 install -r $GITHUB_WORKSPACE/.devcontainer/requirements.txt" cmk + - name: Run pytest + run: su -l -c "python3 -m pytest" cmk \ No newline at end of file From aa626f6df558c096273cd5e407e7f944b3c592b6 Mon Sep 17 00:00:00 2001 From: Marius Rieder Date: Wed, 5 Jun 2024 17:28:17 +0000 Subject: [PATCH 02/10] Convert to rulesets --- rulesets/agent_config.py | 58 ++++++++ rulesets/check_parameters.py | 221 +++++++++++++++++++++++++++++++ rulesets/discovery_parameters.py | 57 ++++++++ 3 files changed, 336 insertions(+) create mode 100644 rulesets/agent_config.py create mode 100644 rulesets/check_parameters.py create mode 100644 rulesets/discovery_parameters.py diff --git a/rulesets/agent_config.py b/rulesets/agent_config.py new file mode 100644 index 0000000..74dc4bc --- /dev/null +++ b/rulesets/agent_config.py @@ -0,0 +1,58 @@ +#!/usr/bin/env python +# -*- encoding: utf-8; py-indent-offset: 4 -*- +# +# Copyright (C) 2020 Marius Rieder +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +from cmk.rulesets.v1 import Title, Help +from cmk.rulesets.v1.form_specs import ( + DictElement, + Dictionary, + DefaultValue, + SingleChoice, + SingleChoiceElement, +) +from cmk.rulesets.v1.rule_specs import AgentConfig, Topic + + +def _parameter_form_veeam_o365_bakery(): + return Dictionary( + elements={ + 'agent': DictElement( + parameter_form=SingleChoice( + title=Title('Veeam for Office 365'), + help_text=Help('This will deploy the agent plugin veeam_o365_status ' + 'for checking Veeam for Office 365 status.'), + elements=[ + SingleChoiceElement(name='deploy', title=Title('Deploy Veeam for Office 365 plugin')), + SingleChoiceElement(name='do_not_deploy', title=Title('Do not deploy Veeam for Office 365 plugin')), + ], + prefill=DefaultValue('deploy'), + ), + required=True, + ) + }, + ) + + +rule_spec_veeam_o365_bakery = AgentConfig( + title=Title('Veeam for Office 365'), + name='veeam_o365', + parameter_form=_parameter_form_veeam_o365_bakery, + topic=Topic.APPLICATIONS, + help_text=Help('This will deploy the agent plugin veeam_o365_status ' + 'for checking Veeam for Office 365 status.'), +) diff --git a/rulesets/check_parameters.py b/rulesets/check_parameters.py new file mode 100644 index 0000000..5ea5542 --- /dev/null +++ b/rulesets/check_parameters.py @@ -0,0 +1,221 @@ +#!/usr/bin/env python +# -*- encoding: utf-8; py-indent-offset: 4 -*- +# +# Copyright (C) 2020-2024 Marius Rieder +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +from cmk.rulesets.v1 import Help, Title, Message, Label +from cmk.rulesets.v1.form_specs import ( + DictElement, + Dictionary, + InputHint, + LevelDirection, + migrate_to_integer_simple_levels, + migrate_to_float_simple_levels, + SimpleLevels, + CascadingSingleChoice, + CascadingSingleChoiceElement, + TimeMagnitude, + TimeSpan, + Integer, + Percentage, + FixedValue, + validators, + ServiceState, + DefaultValue, +) +from cmk.rulesets.v1.rule_specs import CheckParameters, Topic, HostAndItemCondition + + +def crit_lower_then_warn(value): + if value['crit'] >= value['warn']: + raise validators.ValidationError(Message("The critical level needs to be less or equal then the warning.")) + + +def migrate_to_level_dict(value): + if isinstance(value, tuple): + return dict(warn=value[0], crit=value[1]) + return value + + +def _parameter_form_veeam_o365jobs(): + return Dictionary( + elements={ + 'duration': DictElement( + parameter_form=SimpleLevels( + title=Title('Duration'), + help_text=Help('Thresholds for duration of the job.'), + level_direction=LevelDirection.UPPER, + form_spec_template=TimeSpan( + displayed_magnitudes=[TimeMagnitude.DAY, TimeMagnitude.HOUR, TimeMagnitude.MINUTE] + ), + migrate=migrate_to_float_simple_levels, + prefill_fixed_levels=InputHint(value=(1800, 3600)), + ), + required=False, + ), + 'states': DictElement( + parameter_form=Dictionary( + title=Title('State mapping'), + help=Help('Remap the job stat to different monitoring states.'), + elements={ + 'Success': DictElement( + parameter_form=ServiceState( + title=Title('Success'), + prefill=DefaultValue(0), + ), + required=True, + ), + 'Warning': DictElement( + parameter_form=ServiceState( + title=Title('Warning'), + prefill=DefaultValue(1), + ), + required=True, + ), + 'Stopped': DictElement( + parameter_form=ServiceState( + title=Title('Stopped'), + prefill=DefaultValue(1), + ), + required=True, + ), + 'Failed': DictElement( + parameter_form=ServiceState( + title=Title('Failed'), + prefill=DefaultValue(2), + ), + required=True, + ), + } + ), + required=False, + ) + } + ) + + +rule_spec_veeam_o365jobs = CheckParameters( + name='veeam_o365jobs', + topic=Topic.APPLICATIONS, + parameter_form=_parameter_form_veeam_o365jobs, + title=Title('Veeam for Office 365 Job Levels'), + help_text=Help('This rule configures thresholds Veeam for Office 365 jobs.'), + condition=HostAndItemCondition(item_title=Title('Veeam for Office365 Job name')), +) + + +def _parameter_form_veeam_o365licenses(): + return Dictionary( + elements={ + 'validity': DictElement( + parameter_form=SimpleLevels( + title=Title('License term'), + help_text=Help('Days until expiry of the license'), + level_direction=LevelDirection.UPPER, + form_spec_template=TimeSpan( + displayed_magnitudes=[TimeMagnitude.DAY] + ), + migrate=migrate_to_integer_simple_levels, + prefill_fixed_levels=InputHint(value=(30, 20)), + ), + required=False, + ), + 'licenses': DictElement( + parameter_form=CascadingSingleChoice( + title=Title("Levels for Number of Licenses"), + elements=[ + CascadingSingleChoiceElement( + name="absolute", + title=Title('Absolute levels for unused licenses'), + parameter_form=Dictionary( + elements={ + "warn": DictElement( + parameter_form=Integer( + label=Label('Warning below'), + unit_symbol='unused license', + prefill=InputHint(5), + ), + required=True, + ), + "crit": DictElement( + parameter_form=Integer( + label=Label('Critical below'), + unit_symbol='unused license', + prefill=InputHint(0), + ), + required=True, + ) + }, + custom_validate=[ + crit_lower_then_warn + ], + migrate=migrate_to_level_dict, + ) + ), + CascadingSingleChoiceElement( + name="percentage", + title=Title('Percentual levels for unused licenses'), + parameter_form=Dictionary( + elements={ + "warn": DictElement( + parameter_form=Percentage( + label=Label('Warning below'), + prefill=InputHint(10.0), + ), + required=True, + ), + "crit": DictElement( + parameter_form=Percentage( + label=Label('Critical below'), + prefill=InputHint(0.0), + ), + required=True, + ) + }, + custom_validate=[ + crit_lower_then_warn + ], + migrate=migrate_to_level_dict, + ) + ), + CascadingSingleChoiceElement( + name='always_ok', + title=Title('Always be OK'), + parameter_form=FixedValue(value=False), + ), + CascadingSingleChoiceElement( + name='crit_on_all', + title=Title('Go critical if all licenses are used'), + parameter_form=FixedValue(value=None), + ), + ], + prefill='crit_on_all', + ), + required=True, + ), + }, + ) + + +rule_spec_veeam_o365licenses = CheckParameters( + name='veeam_o365licenses', + topic=Topic.APPLICATIONS, + parameter_form=_parameter_form_veeam_o365licenses, + title=Title('Veeam for Office 365 licenses'), + help_text=Help('This rule configures thresholds Veeam for Office 365 Licenses.'), + condition=HostAndItemCondition(item_title=Title('Veeam for Office365 Licenses number')), +) diff --git a/rulesets/discovery_parameters.py b/rulesets/discovery_parameters.py new file mode 100644 index 0000000..90fed89 --- /dev/null +++ b/rulesets/discovery_parameters.py @@ -0,0 +1,57 @@ +#!/usr/bin/env python +# -*- encoding: utf-8; py-indent-offset: 4 -*- +# +# Copyright (C) 2020-2024 Marius Rieder +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +from cmk.rulesets.v1 import Help, Title +from cmk.rulesets.v1.form_specs import ( + DefaultValue, + Dictionary, + SingleChoice, + SingleChoiceElement, +) +from cmk.rulesets.v1.rule_specs import DiscoveryParameters, Topic, HostCondition + + +def _parameter_form_veeam_o365jobs_discovery(): + return Dictionary( + elements={ + 'item_appearance': SingleChoice( + title=Title('Appearance of job'), + help_text=Help('This option lets Check_MK use either only the job name, ' + 'prepend it with the shortend org oder the full org.'), + elements=[ + SingleChoiceElement(name='name', title=Title('Use only the job name')), + SingleChoiceElement(name='short', title=Title('Use the shortend org and the name')), + SingleChoiceElement(name='full', title=Title('Use the full org and the name')), + ], + prefill=DefaultValue('name'), + ) + }, + ) + + +rule_spec_inventory_veeam_o365jobs_rules = DiscoveryParameters( + name='veeam_o365jobs', + topic=Topic.APPLICATIONS, + parameter_form=_parameter_form_veeam_o365jobs_discovery, + title=Title('Veeam for Office 365 Job Discovery'), + help_text=Help('This rule can be used to control the inventory for Veeam for ' + 'Office 365 Jobs. You can configure the service name to include' + 'the Organisation.'), + condition=HostCondition(), +) From 39b098489ad1c9cf96b48c6a52a4869e6a0606f7 Mon Sep 17 00:00:00 2001 From: Marius Rieder Date: Wed, 5 Jun 2024 18:25:49 +0000 Subject: [PATCH 03/10] Rework for Checkmk 2.3.0 --- .devcontainer/build.sh | 4 +- agent_based/veeam_o365jobs.py | 21 ++- agent_based/veeam_o365licenses.py | 74 ++++------ bakery/veeam_o365.py | 3 +- graphing/veeam_o365.py | 136 ++++++++++++++++++ package | 29 ++-- .../agent_based/test_veeam_o356jobs.py | 6 +- .../agent_based/test_veeam_o356licenses.py | 16 +-- 8 files changed, 204 insertions(+), 85 deletions(-) create mode 100644 graphing/veeam_o365.py rename tests/unit/{cmk/base/plugins => }/agent_based/test_veeam_o356jobs.py (98%) rename tests/unit/{cmk/base/plugins => }/agent_based/test_veeam_o356licenses.py (83%) diff --git a/.devcontainer/build.sh b/.devcontainer/build.sh index ad9915a..6625ef5 100755 --- a/.devcontainer/build.sh +++ b/.devcontainer/build.sh @@ -1,12 +1,14 @@ #!/bin/bash +set -e NAME=$(python3 -c 'print(eval(open("package").read())["name"])') VERSION=$(python3 -c 'print(eval(open("package").read())["version"])') rm /omd/sites/cmk/var/check_mk/packages/${NAME} \ /omd/sites/cmk/var/check_mk/packages_local/${NAME}-*.mkp ||: -mkp -v package package 2>&1 | sed '/Installing$/Q' ||: +mkp -v package package +rm $NAME-$VERSION.mkp cp /omd/sites/cmk/var/check_mk/packages_local/$NAME-$VERSION.mkp . mkp inspect $NAME-$VERSION.mkp diff --git a/agent_based/veeam_o365jobs.py b/agent_based/veeam_o365jobs.py index 0228045..df808eb 100644 --- a/agent_based/veeam_o365jobs.py +++ b/agent_based/veeam_o365jobs.py @@ -21,15 +21,14 @@ # 01234567-89ab-cdef-0123-456789abcdef cmk.onmicrosoft.com Outlook Online Success 29.05.2020 16:45:46 29.05.2020 16:47:55 128.7511818 191 142 # 12345678-9abc-def0-1234-56789abcdef0 cmk.onmicrosoft.com Outlook Online2 Failed 29.05.2020 16:45:46 29.05.2020 16:47:55 128.7511818 -from dataclasses import dataclass -from typing import Optional -from .agent_based_api.v1 import ( +from cmk.agent_based.v2 import ( Service, Result, State, check_levels, render, - register, + CheckPlugin, + RuleSetType, ) from .agent_based_api.v1.type_defs import StringTable @@ -136,7 +135,7 @@ def check_veeam_o365jobs(item, params, section): yield from check_levels( float(job.duration), metric_name='duration', - levels_upper=params.get('duration', None), + levels_upper=params.get('duration', ('no_levels', None)), label='Backup duration', render_func=render.timespan, ) @@ -152,14 +151,14 @@ def check_veeam_o365jobs(item, params, section): ) -register.check_plugin( - name = 'veeam_o365jobs', +check_plugin_veeam_o365jobs = CheckPlugin( + name='veeam_o365jobs', service_name = 'VEEAM O365 Job %s', - discovery_ruleset_name='inventory_veeam_o365jobs_rules', - discovery_ruleset_type=register.RuleSetType.MERGED, + discovery_function=discovery_veeam_o365jobs, + discovery_ruleset_name='veeam_o365jobs', + discovery_ruleset_type=RuleSetType.MERGED, discovery_default_parameters={}, - discovery_function = discovery_veeam_o365jobs, - check_function = check_veeam_o365jobs, + check_function=discovery_veeam_o365jobs, check_ruleset_name='veeam_o365jobs', check_default_parameters=VEEAM_O365JOBS_CHECK_DEFAULT_PARAMETERS, ) diff --git a/agent_based/veeam_o365licenses.py b/agent_based/veeam_o365licenses.py index 372a304..2a49392 100644 --- a/agent_based/veeam_o365licenses.py +++ b/agent_based/veeam_o365licenses.py @@ -20,14 +20,13 @@ # <<>> # Valid 28.06.2020 02:00:00 2592000 42 50000 -from .agent_based_api.v1 import ( +from cmk.agent_based.v2 import ( Service, Result, State, check_levels, render, - Metric, - register, + CheckPlugin, ) @@ -50,54 +49,37 @@ def check_veeam_o365licenses(item, params, section): yield from check_levels( float(license_validity), - levels_lower=params.get('validity', (0, 0)), + levels_lower=params.get('validity', ('fixed', (0, 0))), label='Period of validity' if float(license_validity) > 0 else 'Expired since', render_func=lambda f: render.timespan(f if f > 0 else -f), ) - license_params = params.get('licenses', None) - - if license_params is False: - license_warn = None - license_crit = None - elif not license_params: - license_warn = int(license_total) - license_crit = int(license_total) - elif isinstance(license_params[0], int): - license_warn = max(0, int(license_total) - license_params[0]) - license_crit = max(0, int(license_total) - license_params[1]) - else: - license_warn = int(license_total) * (1 - license_params[0] / 100.0) - license_crit = int(license_total) * (1 - license_params[1] / 100.0) - - yield Metric('licenses', - int(license_used), - levels=(license_warn, license_crit), - boundaries=(0, int(license_total))) - - if int(license_used) <= int(license_total): - infotext = 'used %d out of %d licenses' % (int(license_used), int(license_total)) - else: - infotext = 'used %d licenses, but you have only %d' % (int(license_used), int(license_total)) - - if license_crit is not None and int(license_used) >= license_crit: - status = State.CRIT - elif license_warn is not None and int(license_used) >= license_warn: - status = State.WARN - else: - status = State.OK - - if license_crit is not None: - infotext += ' (warn/crit at %d/%d)' % (license_warn, license_crit) - - yield Result(state=status, summary=infotext) - - -register.check_plugin( - name = 'veeam_o365licenses', + license_used = int(license_used) + license_total = int(license_total) + + match params.get('licenses', None): + case ('always_ok', None): + levels = ('no_levels', None) + case ('absolute', {'warn': warn, 'crit': crit}): + levels = ('fixed', (license_total - warn, license_total - crit)) + case ('percentage', {'warn': warn, 'crit': crit}): + levels = ('fixed', (int(license_total * (100 - warn) / 100), int(license_total * (100 - crit) / 100))) + case _: + levels = ('fixed', (int(license_total), int(license_total))) + + yield from check_levels(license_used, + label="used", + render_func=lambda v: f"{v:d}", + levels_upper=levels, + metric_name='licenses', + boundaries=(0, int(license_total))) + + +check_plugin_veeam_o365jobs = CheckPlugin( + name='veeam_o365licenses', service_name = 'VEEAM O365 License %s', - discovery_function = discovery_veeam_o365licenses, - check_function = check_veeam_o365licenses, + discovery_function=discovery_veeam_o365licenses, + check_function=check_veeam_o365licenses, check_ruleset_name='veeam_o365licenses', check_default_parameters={}, ) diff --git a/bakery/veeam_o365.py b/bakery/veeam_o365.py index fd9ebee..948f57e 100644 --- a/bakery/veeam_o365.py +++ b/bakery/veeam_o365.py @@ -24,7 +24,8 @@ def get_veeam_o365_files(conf: Any) -> FileGenerator: - yield Plugin(base_os=OS.WINDOWS, source=Path('veeam_o365_status.ps1')) + if conf.get('agent', 'do_not_deploy') == 'deploy': + yield Plugin(base_os=OS.WINDOWS, source=Path('veeam_o365_status.ps1')) register.bakery_plugin( diff --git a/graphing/veeam_o365.py b/graphing/veeam_o365.py new file mode 100644 index 0000000..7dbf947 --- /dev/null +++ b/graphing/veeam_o365.py @@ -0,0 +1,136 @@ +#!/usr/bin/python +# -*- encoding: utf-8; py-indent-offset: 4 -*- +# +# Copyright (C) 2020-2024 Marius Rieder +# +# This program is free software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 2 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +from cmk.graphing.v1 import ( + graphs as g, + metrics as m, + perfometers as p, + translations as t, +) + +translation_veeam_o365jobs = t.Translation( + name='veeam_o365jobs', + check_commands=[t.PassiveCheck('veeam_o365jobs')], + translations={ + 'transferred': t.RenameTo('veeam_o365jobs_transferred'), + 'duration': t.RenameTo('veeam_o365jobs_duration'), + 'items': t.RenameTo('veeam_o365jobs_items'), + } +) + +translation_veeam_o365licenses = t.Translation( + name='veeam_o365licenses', + check_commands=[t.PassiveCheck('veeam_o365licenses')], + translations={ + 'licenses': t.RenameTo('veeam_o365licenses_licenses'), + } +) + +metric_veeam_o365jobs_transferred = m.Metric( + name='veeam_o365jobs_transferred', + title=m.Title('Data Transferred'), + unit=m.Unit(m.IECNotation("bits")), + color=m.Color.GREEN, +) + +metric_veeam_o365jobs_duration = m.Metric( + name='veeam_o365jobs_duration', + title=m.Title('Job Duration'), + unit=m.Unit(m.TimeNotation()), + color=m.Color.GREEN, +) + +metric_veeam_o365jobs_transferred = m.Metric( + name='veeam_o365jobs_items', + title=m.Title('Items Transferred'), + unit=m.Unit(m.DecimalNotation(""), m.StrictPrecision(0)), + color=m.Color.GREEN, +) + +metric_veeam_o365licenses_licenses = m.Metric( + name='veeam_o365licenses_licenses', + title=m.Title('Used licenses'), + unit=m.Unit(m.DecimalNotation(""), m.StrictPrecision(0)), + color=m.Color.GREEN, +) + +graph_veeam_o365jobs_transferred = g.Graph( + name='veeam_o365jobs_transferred', + title=g.Title('Veeam for Office 365 Job'), + minimal_range=g.MinimalRange(0, m.MaximumOf('veeam_o365jobs_transferred')), + compound_lines=['veeam_o365jobs_transferred'], + simple_lines=[ + m.WarningOf('veeam_o365jobs_transferred'), + m.CriticalOf('veeam_o365jobs_transferred'), + ] +) + +graph_veeam_o365jobs_duration = g.Graph( + name='veeam_o365jobs_duration', + title=g.Title('Veeam for Office 365 Job'), + minimal_range=g.MinimalRange(0, m.MaximumOf('veeam_o365jobs_duration')), + compound_lines=['veeam_o365jobs_duration'], + simple_lines=[ + m.WarningOf('veeam_o365jobs_duration'), + m.CriticalOf('veeam_o365jobs_duration'), + ] +) + +graph_veeam_o365jobs_items = g.Graph( + name='veeam_o365jobs_items', + title=g.Title('Veeam for Office 365 Job'), + minimal_range=g.MinimalRange(0, m.MaximumOf('veeam_o365jobs_items')), + compound_lines=['veeam_o365jobs_items'], + simple_lines=[ + m.WarningOf('veeam_o365jobs_items'), + m.CriticalOf('veeam_o365jobs_items'), + ] +) + +graph_veeam_o365licenses_licenses = g.Graph( + name='veeam_o365licenses_licenses', + title=g.Title('Veeam for Office 365 licenses'), + minimal_range=g.MinimalRange(0, m.MaximumOf('veeam_o365licenses_licenses')), + compound_lines=['veeam_o365licenses_licenses'], + simple_lines=[ + m.WarningOf('veeam_o365licenses_licenses'), + m.CriticalOf('veeam_o365licenses_licenses'), + m.MaximumOf('veeam_o365licenses_licenses', m.Color.BLACK) + ] +) + +perfometer_veeam_o365jobs = p.Stacked( + name='veeam_o365jobs', + upper=p.Perfometer( + name='veeam_o365jobs_transferred', + focus_range=p.FocusRange(p.Closed(0), p.Open(m.WarningOf('veeam_o365jobs_transferred'))), + segments=['veeam_o365jobs_transferred'], + ), + lower=p.Perfometer( + name='veeam_o365jobs_duration', + focus_range=p.FocusRange(p.Closed(0), p.Open(m.WarningOf('veeam_o365jobs_duration'))), + segments=['veeam_o365jobs_duration'], + ), +) + +perfometer_veeam_o365licenses_licenses = p.Perfometer( + name='veeam_o365licenses_licenses', + focus_range=p.FocusRange(p.Closed(0), p.Open(m.MaximumOf('veeam_o365licenses_licenses'))), + segments=['veeam_o365licenses_licenses'], +) diff --git a/package b/package index 577ddce..c58612e 100644 --- a/package +++ b/package @@ -3,17 +3,16 @@ 'description': u'Agent Plugin and Checks for Veeam for Office 365', 'download_url': 'https://github.com/jiuka/checkmk_veeam_o365/releases', 'files': { - 'agent_based': ['veeam_o365jobs.py', 'veeam_o365licenses.py'], - 'agents': [ - 'windows/plugins/veeam_o365_status.ps1', - ], - 'checkman': ['veeam_o365jobs', 'veeam_o365licenses'], - 'gui': [ - 'metrics/veeam_o365jobs.py', - 'metrics/veeam_o365licenses.py', - 'wato/agent_bakery/veeam_o365.py', - 'wato/check_parameters/veeam_o365licenses.py', - 'wato/check_parameters/veeam_o365jobs.py', + 'agents': ['windows/plugins/veeam_o365_status.ps1'], + 'cmk_addons_plugins': [ + 'veeam_o365/agent_based/veeam_o365jobs.py', + 'veeam_o365/agent_based/veeam_o365licenses.py', + 'veeam_o365/checkman/veeam_o365jobs', + 'veeam_o365/checkman/veeam_o365licenses', + 'veeam_o365/graphing/veeam_o365.py', + 'veeam_o365/rulesets/check_parameters.py', + 'veeam_o365/rulesets/discovery_parameters.py', + 'veeam_o365/rulesets/agent_config.py', ], 'lib': [ 'python3/cmk/base/cee/plugins/bakery/veeam_o365.py', @@ -21,8 +20,8 @@ }, 'name': 'veeam_o365', 'title': u'Veeam for Office 365 Checks', - 'version': '2.6.1', - 'version.min_required': '2.2.0', - 'version.packaged': '2.2.0', - 'version.usable_until': '2.3.0' + 'version': '2.7.0-0', + 'version.min_required': '2.3.0p3', + 'version.packaged': '2.3.0', + 'version.usable_until': '2.4.0' } diff --git a/tests/unit/cmk/base/plugins/agent_based/test_veeam_o356jobs.py b/tests/unit/agent_based/test_veeam_o356jobs.py similarity index 98% rename from tests/unit/cmk/base/plugins/agent_based/test_veeam_o356jobs.py rename to tests/unit/agent_based/test_veeam_o356jobs.py index fc7f1d4..a4b8c2f 100644 --- a/tests/unit/cmk/base/plugins/agent_based/test_veeam_o356jobs.py +++ b/tests/unit/agent_based/test_veeam_o356jobs.py @@ -18,13 +18,13 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. import pytest # type: ignore[import] -from cmk.base.plugins.agent_based.agent_based_api.v1 import ( +from cmk.agent_based.v2 import ( Metric, Result, Service, State, ) -from cmk.base.plugins.agent_based import veeam_o365jobs +from cmk_addons.plugins.veeam_o365.agent_based import veeam_o365jobs EXAMPLE_STRING_TABLE = [ ['01234567-89ab-cdef-0123-456789abcold', 'cmk.onmicrosoft.com', 'Outlook Old Online', 'Success', '29.05.2020 16:45:46', '29.05.2020 16:47:55', '128.7511818', '191', '142'], @@ -129,7 +129,7 @@ def test_discovery_veeam_o365jobs(params, section, result): ] ), ( - 'cmk.onmicrosoft.com Outlook Online', {'jobId': '12345678-9abc-def0-1234-56789abcdef0', 'duration': (120, 300)}, + 'cmk.onmicrosoft.com Outlook Online', {'jobId': '12345678-9abc-def0-1234-56789abcdef0', 'duration': ('fixed', (120, 300))}, [ Result(state=State.CRIT, summary='Status: Failed'), Result(state=State.WARN, summary='Backup duration: 2 minutes 9 seconds (warn/crit at 2 minutes 0 seconds/5 minutes 0 seconds)'), diff --git a/tests/unit/cmk/base/plugins/agent_based/test_veeam_o356licenses.py b/tests/unit/agent_based/test_veeam_o356licenses.py similarity index 83% rename from tests/unit/cmk/base/plugins/agent_based/test_veeam_o356licenses.py rename to tests/unit/agent_based/test_veeam_o356licenses.py index 6970843..085fd35 100644 --- a/tests/unit/cmk/base/plugins/agent_based/test_veeam_o356licenses.py +++ b/tests/unit/agent_based/test_veeam_o356licenses.py @@ -18,13 +18,13 @@ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. import pytest # type: ignore[import] -from cmk.base.plugins.agent_based.agent_based_api.v1 import ( +from cmk.agent_based.v2 import ( Metric, Result, Service, State, ) -from cmk.base.plugins.agent_based import veeam_o365licenses +from cmk_addons.plugins.veeam_o365.agent_based import veeam_o365licenses @pytest.mark.parametrize('section, result', [ @@ -46,28 +46,28 @@ def test_discovery_veeam_o365licenses(section, result): [ Result(state=State.OK, summary='License is vaild till 28.06.2020 02:00:00'), Result(state=State.OK, summary='Period of validity: 30 days 0 hours'), + Result(state=State.OK, summary='used: 42'), Metric('licenses', 42.0, levels=(50000.0, 50000.0), boundaries=(0.0, 50000.0)), - Result(state=State.OK, summary='used 42 out of 50000 licenses (warn/crit at 50000/50000)'), ] ), ( - '0', {'validity': (3456000, 1728000)}, + '0', {'validity': ('fixed', (3456000, 1728000))}, [['Valid', '28.06.2020 02:00:00', '2592000', '42', '50000']], [ Result(state=State.OK, summary='License is vaild till 28.06.2020 02:00:00'), Result(state=State.WARN, summary='Period of validity: 30 days 0 hours (warn/crit below 40 days 0 hours/20 days 0 hours)'), + Result(state=State.OK, summary='used: 42'), Metric('licenses', 42.0, levels=(50000.0, 50000.0), boundaries=(0.0, 50000.0)), - Result(state=State.OK, summary='used 42 out of 50000 licenses (warn/crit at 50000/50000)'), ] ), ( - '0', {'licenses': (10, 5)}, + '0', {'licenses': ('absolute', {'warn': 10, 'crit': 5})}, [['Valid', '28.06.2020 02:00:00', '2592000', '42', '50']], [ Result(state=State.OK, summary='License is vaild till 28.06.2020 02:00:00'), Result(state=State.OK, summary='Period of validity: 30 days 0 hours'), + Result(state=State.WARN, summary='used: 42 (warn/crit at 40/45)'), Metric('licenses', 42.0, levels=(40.0, 45.0), boundaries=(0.0, 50.0)), - Result(state=State.WARN, summary='used 42 out of 50 licenses (warn/crit at 40/45)'), ] ), ( @@ -76,8 +76,8 @@ def test_discovery_veeam_o365licenses(section, result): [ Result(state=State.OK, summary='License is vaild till 28.06.2020 02:00:00'), Result(state=State.CRIT, summary='Expired since: 30 days 0 hours (warn/crit below 0 seconds/0 seconds)'), + Result(state=State.OK, summary='used: 42'), Metric('licenses', 42.0, levels=(50.0, 50.0), boundaries=(0.0, 50.0)), - Result(state=State.OK, summary='used 42 out of 50 licenses (warn/crit at 50/50)'), ] ), ]) From 1dc6adf7cb6c933b9fd1d28b7aa18a9d148057cc Mon Sep 17 00:00:00 2001 From: Marius Rieder Date: Wed, 5 Jun 2024 18:28:34 +0000 Subject: [PATCH 04/10] Add env --- .github/workflows/pytest.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index 801bdce..b00bf54 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -13,6 +13,12 @@ jobs: container: image: checkmk/check-mk-raw:2.3.0-latest + env: + OMD_ROOT: /omd/sites/cmk + OMD_SITE: cmk + CMK_SITE_ID: cmk + WORKSPACE: ${{ github.workspace }} + steps: - name: Initialize Checkmk Site run: /docker-entrypoint.sh /bin/true From 46f3b3cc0a815fb37243abdc0118387296cea672 Mon Sep 17 00:00:00 2001 From: Marius Rieder Date: Thu, 6 Jun 2024 07:02:15 +0200 Subject: [PATCH 05/10] Update veeam_o365.py Fix graphing --- graphing/veeam_o365.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/graphing/veeam_o365.py b/graphing/veeam_o365.py index 7dbf947..1984f96 100644 --- a/graphing/veeam_o365.py +++ b/graphing/veeam_o365.py @@ -31,6 +31,7 @@ 'transferred': t.RenameTo('veeam_o365jobs_transferred'), 'duration': t.RenameTo('veeam_o365jobs_duration'), 'items': t.RenameTo('veeam_o365jobs_items'), + 'age': t.RenameTo('veeam_o365jobs_age'), } ) @@ -56,7 +57,7 @@ color=m.Color.GREEN, ) -metric_veeam_o365jobs_transferred = m.Metric( +metric_veeam_o365jobs_items = m.Metric( name='veeam_o365jobs_items', title=m.Title('Items Transferred'), unit=m.Unit(m.DecimalNotation(""), m.StrictPrecision(0)), @@ -73,7 +74,7 @@ graph_veeam_o365jobs_transferred = g.Graph( name='veeam_o365jobs_transferred', title=g.Title('Veeam for Office 365 Job'), - minimal_range=g.MinimalRange(0, m.MaximumOf('veeam_o365jobs_transferred')), + minimal_range=g.MinimalRange(0, m.MaximumOf('veeam_o365jobs_transferred', m.Color.BLACK)), compound_lines=['veeam_o365jobs_transferred'], simple_lines=[ m.WarningOf('veeam_o365jobs_transferred'), @@ -84,7 +85,7 @@ graph_veeam_o365jobs_duration = g.Graph( name='veeam_o365jobs_duration', title=g.Title('Veeam for Office 365 Job'), - minimal_range=g.MinimalRange(0, m.MaximumOf('veeam_o365jobs_duration')), + minimal_range=g.MinimalRange(0, m.MaximumOf('veeam_o365jobs_duration', m.Color.BLACK)), compound_lines=['veeam_o365jobs_duration'], simple_lines=[ m.WarningOf('veeam_o365jobs_duration'), @@ -95,7 +96,7 @@ graph_veeam_o365jobs_items = g.Graph( name='veeam_o365jobs_items', title=g.Title('Veeam for Office 365 Job'), - minimal_range=g.MinimalRange(0, m.MaximumOf('veeam_o365jobs_items')), + minimal_range=g.MinimalRange(0, m.MaximumOf('veeam_o365jobs_items', m.Color.BLACK)), compound_lines=['veeam_o365jobs_items'], simple_lines=[ m.WarningOf('veeam_o365jobs_items'), @@ -106,7 +107,7 @@ graph_veeam_o365licenses_licenses = g.Graph( name='veeam_o365licenses_licenses', title=g.Title('Veeam for Office 365 licenses'), - minimal_range=g.MinimalRange(0, m.MaximumOf('veeam_o365licenses_licenses')), + minimal_range=g.MinimalRange(0, m.MaximumOf('veeam_o365licenses_licenses', m.Color.BLACK)), compound_lines=['veeam_o365licenses_licenses'], simple_lines=[ m.WarningOf('veeam_o365licenses_licenses'), @@ -119,18 +120,18 @@ name='veeam_o365jobs', upper=p.Perfometer( name='veeam_o365jobs_transferred', - focus_range=p.FocusRange(p.Closed(0), p.Open(m.WarningOf('veeam_o365jobs_transferred'))), + focus_range=p.FocusRange(p.Closed(0), p.Open(100)), segments=['veeam_o365jobs_transferred'], ), lower=p.Perfometer( name='veeam_o365jobs_duration', - focus_range=p.FocusRange(p.Closed(0), p.Open(m.WarningOf('veeam_o365jobs_duration'))), + focus_range=p.FocusRange(p.Closed(0), p.Open(100)), segments=['veeam_o365jobs_duration'], ), ) perfometer_veeam_o365licenses_licenses = p.Perfometer( name='veeam_o365licenses_licenses', - focus_range=p.FocusRange(p.Closed(0), p.Open(m.MaximumOf('veeam_o365licenses_licenses'))), + focus_range=p.FocusRange(p.Closed(0), p.Open(m.MaximumOf('veeam_o365licenses_licenses', m.Color.BLACK))), segments=['veeam_o365licenses_licenses'], ) From 76fa61b32830f0bdcf612f91db4cf4e902d17401 Mon Sep 17 00:00:00 2001 From: Marius Rieder Date: Fri, 7 Jun 2024 11:29:45 +0000 Subject: [PATCH 06/10] Fix some bugs --- agent_based/veeam_o365jobs.py | 2 +- package | 2 +- rulesets/check_parameters.py | 17 +++++++++++++++-- rulesets/discovery_parameters.py | 26 ++++++++++++++------------ 4 files changed, 31 insertions(+), 16 deletions(-) diff --git a/agent_based/veeam_o365jobs.py b/agent_based/veeam_o365jobs.py index df808eb..89cdba2 100644 --- a/agent_based/veeam_o365jobs.py +++ b/agent_based/veeam_o365jobs.py @@ -158,7 +158,7 @@ def check_veeam_o365jobs(item, params, section): discovery_ruleset_name='veeam_o365jobs', discovery_ruleset_type=RuleSetType.MERGED, discovery_default_parameters={}, - check_function=discovery_veeam_o365jobs, + check_function=check_veeam_o365jobs, check_ruleset_name='veeam_o365jobs', check_default_parameters=VEEAM_O365JOBS_CHECK_DEFAULT_PARAMETERS, ) diff --git a/package b/package index c58612e..5ef9c34 100644 --- a/package +++ b/package @@ -20,7 +20,7 @@ }, 'name': 'veeam_o365', 'title': u'Veeam for Office 365 Checks', - 'version': '2.7.0-0', + 'version': '2.7.0-1', 'version.min_required': '2.3.0p3', 'version.packaged': '2.3.0', 'version.usable_until': '2.4.0' diff --git a/rulesets/check_parameters.py b/rulesets/check_parameters.py index 5ea5542..946ae59 100644 --- a/rulesets/check_parameters.py +++ b/rulesets/check_parameters.py @@ -70,7 +70,7 @@ def _parameter_form_veeam_o365jobs(): 'states': DictElement( parameter_form=Dictionary( title=Title('State mapping'), - help=Help('Remap the job stat to different monitoring states.'), + help_text=Help('Remap the job stat to different monitoring states.'), elements={ 'Success': DictElement( parameter_form=ServiceState( @@ -103,7 +103,20 @@ def _parameter_form_veeam_o365jobs(): } ), required=False, - ) + ), + 'success_maxage': DictElement( + parameter_form=SimpleLevels( + title=Title('Maximal time since last successfull run'), + help_text=Help('Thresholds for last successfull run.'), + level_direction=LevelDirection.UPPER, + form_spec_template=TimeSpan( + displayed_magnitudes=[TimeMagnitude.DAY, TimeMagnitude.HOUR, TimeMagnitude.MINUTE] + ), + migrate=migrate_to_float_simple_levels, + prefill_fixed_levels=InputHint(value=(86400, 172800)), + ), + required=False, + ), } ) diff --git a/rulesets/discovery_parameters.py b/rulesets/discovery_parameters.py index 90fed89..db45510 100644 --- a/rulesets/discovery_parameters.py +++ b/rulesets/discovery_parameters.py @@ -20,26 +20,29 @@ from cmk.rulesets.v1 import Help, Title from cmk.rulesets.v1.form_specs import ( DefaultValue, + DictElement, Dictionary, SingleChoice, SingleChoiceElement, ) -from cmk.rulesets.v1.rule_specs import DiscoveryParameters, Topic, HostCondition +from cmk.rulesets.v1.rule_specs import DiscoveryParameters, Topic def _parameter_form_veeam_o365jobs_discovery(): return Dictionary( elements={ - 'item_appearance': SingleChoice( - title=Title('Appearance of job'), - help_text=Help('This option lets Check_MK use either only the job name, ' - 'prepend it with the shortend org oder the full org.'), - elements=[ - SingleChoiceElement(name='name', title=Title('Use only the job name')), - SingleChoiceElement(name='short', title=Title('Use the shortend org and the name')), - SingleChoiceElement(name='full', title=Title('Use the full org and the name')), - ], - prefill=DefaultValue('name'), + 'item_appearance': DictElement( + parameter_form=SingleChoice( + title=Title('Appearance of job'), + help_text=Help('This option lets Check_MK use either only the job name, ' + 'prepend it with the shortend org oder the full org.'), + elements=[ + SingleChoiceElement(name='name', title=Title('Use only the job name')), + SingleChoiceElement(name='short', title=Title('Use the shortend org and the name')), + SingleChoiceElement(name='full', title=Title('Use the full org and the name')), + ], + prefill=DefaultValue('name'), + ) ) }, ) @@ -53,5 +56,4 @@ def _parameter_form_veeam_o365jobs_discovery(): help_text=Help('This rule can be used to control the inventory for Veeam for ' 'Office 365 Jobs. You can configure the service name to include' 'the Organisation.'), - condition=HostCondition(), ) From 97726d47e8dd6255f29554fe791bd7dc6ec08c8a Mon Sep 17 00:00:00 2001 From: Marius Rieder Date: Mon, 10 Jun 2024 08:22:34 +0000 Subject: [PATCH 07/10] Fix build script --- .coveragerc | 2 ++ .devcontainer/build.sh | 2 +- .devcontainer/requirements.txt | 2 ++ .github/workflows/pytest.yml | 6 +++++- 4 files changed, 10 insertions(+), 2 deletions(-) create mode 100644 .coveragerc diff --git a/.coveragerc b/.coveragerc new file mode 100644 index 0000000..3dbfbb4 --- /dev/null +++ b/.coveragerc @@ -0,0 +1,2 @@ +[run] +omit = tests/* \ No newline at end of file diff --git a/.devcontainer/build.sh b/.devcontainer/build.sh index 6625ef5..27fe8ae 100755 --- a/.devcontainer/build.sh +++ b/.devcontainer/build.sh @@ -8,7 +8,7 @@ rm /omd/sites/cmk/var/check_mk/packages/${NAME} \ mkp -v package package -rm $NAME-$VERSION.mkp +rm $NAME-$VERSION.mkp ||: cp /omd/sites/cmk/var/check_mk/packages_local/$NAME-$VERSION.mkp . mkp inspect $NAME-$VERSION.mkp diff --git a/.devcontainer/requirements.txt b/.devcontainer/requirements.txt index c248ac1..239569d 100644 --- a/.devcontainer/requirements.txt +++ b/.devcontainer/requirements.txt @@ -1,4 +1,6 @@ flake8 pytest pytest-cov +pytest-md +pytest-emoji requests-mock \ No newline at end of file diff --git a/.github/workflows/pytest.yml b/.github/workflows/pytest.yml index b00bf54..572ff11 100644 --- a/.github/workflows/pytest.yml +++ b/.github/workflows/pytest.yml @@ -28,4 +28,8 @@ jobs: - name: Install pytest run: su -l -c "REQUESTS_CA_BUNDLE=/etc/ssl/certs/ca-certificates.crt pip3 install -r $GITHUB_WORKSPACE/.devcontainer/requirements.txt" cmk - name: Run pytest - run: su -l -c "python3 -m pytest" cmk \ No newline at end of file + run: | + REPORT="$(mktemp)" + chown -R cmk:cmk $GITHUB_WORKSPACE $REPORT + su -l -c "cd $GITHUB_WORKSPACE; python3 -m pytest -v --emoji -cov . --md $REPORT " cmk + cat $REPORT > $GITHUB_STEP_SUMMARY From 1c490e83bb59ec7832cee910a425779a1f3d1985 Mon Sep 17 00:00:00 2001 From: Marius Rieder Date: Mon, 10 Jun 2024 10:05:15 +0000 Subject: [PATCH 08/10] Prepare new version for Checkmk 2.3 --- package | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package b/package index 5ef9c34..f9faecb 100644 --- a/package +++ b/package @@ -20,7 +20,7 @@ }, 'name': 'veeam_o365', 'title': u'Veeam for Office 365 Checks', - 'version': '2.7.0-1', + 'version': '2.7.0', 'version.min_required': '2.3.0p3', 'version.packaged': '2.3.0', 'version.usable_until': '2.4.0' From d6f53b6172622b2ecdd984558283de9689d4c17d Mon Sep 17 00:00:00 2001 From: Marius Rieder Date: Mon, 10 Jun 2024 15:19:31 +0000 Subject: [PATCH 09/10] Update readme and add funding --- .github/FUNDING.yml | 1 + README.md | 8 ++++++++ 2 files changed, 9 insertions(+) create mode 100644 .github/FUNDING.yml diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 0000000..a9cce21 --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +buy_me_a_coffee: jiuka \ No newline at end of file diff --git a/README.md b/README.md index 5e8fb57..aafa49a 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,14 @@ This Plugin and check can monitor the Veeam for Office 365 jobs and licenses. +| Checkmk Version | Extension Version | +|-----------------|-------------------| +| Checkmk 2.3.0 | [latest](https://github.com/jiuka/checkmk_veeam_o365/releases/latest) | +| Checkmk 2.2.0 | [2.6.1](https://github.com/jiuka/checkmk_veeam_o365/releases/tag/v2.6.1) | +| Checkmk 2.1.0 | [2.5.1](https://github.com/jiuka/checkmk_veeam_o365/releases/tag/v2.5.1) | +| Checkmk 2.0.0 | [2.5.1](https://github.com/jiuka/checkmk_veeam_o365/releases/tag/v2.5.1) | +| Checkmk 1. | [1.3](https://github.com/jiuka/checkmk_veeam_o365/releases/tag/v1.3) | + ## Screenshots ### Services ![Services](examples/veeam_o365_services.png) From b81b007eeb2bcb867a8c101af8f6709cf51928cf Mon Sep 17 00:00:00 2001 From: Marius Rieder Date: Mon, 10 Jun 2024 15:32:05 +0000 Subject: [PATCH 10/10] Fix new linter warnings --- agent_based/veeam_o365jobs.py | 7 +++++-- tests/unit/agent_based/test_veeam_o356jobs.py | 12 ++++++------ 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/agent_based/veeam_o365jobs.py b/agent_based/veeam_o365jobs.py index 89cdba2..f229f1f 100644 --- a/agent_based/veeam_o365jobs.py +++ b/agent_based/veeam_o365jobs.py @@ -21,6 +21,8 @@ # 01234567-89ab-cdef-0123-456789abcdef cmk.onmicrosoft.com Outlook Online Success 29.05.2020 16:45:46 29.05.2020 16:47:55 128.7511818 191 142 # 12345678-9abc-def0-1234-56789abcdef0 cmk.onmicrosoft.com Outlook Online2 Failed 29.05.2020 16:45:46 29.05.2020 16:47:55 128.7511818 +from dataclasses import dataclass +from typing import Optional from cmk.agent_based.v2 import ( Service, Result, @@ -29,8 +31,9 @@ render, CheckPlugin, RuleSetType, + StringTable, + AgentSection, ) -from .agent_based_api.v1.type_defs import StringTable VEEAM_O365JOBS_CHECK_DEFAULT_PARAMETERS = { 'states': { @@ -83,7 +86,7 @@ def parse_veeam_o365jobs(string_table: StringTable) -> dict[str, VeeamO365Job]: return parsed -register.agent_section( +agent_section_veeam_o365jobs = AgentSection( name='veeam_o365jobs', parse_function=parse_veeam_o365jobs, ) diff --git a/tests/unit/agent_based/test_veeam_o356jobs.py b/tests/unit/agent_based/test_veeam_o356jobs.py index a4b8c2f..d077a51 100644 --- a/tests/unit/agent_based/test_veeam_o356jobs.py +++ b/tests/unit/agent_based/test_veeam_o356jobs.py @@ -166,7 +166,7 @@ def test_discovery_veeam_o365jobs(params, section, result): ] ), ( - 'cmk.onmicrosoft.com Outlook Online3', {'jobId': '23456789-abcd-ef01-2345-6789abcdef01', 'duration': (500, 600)}, + 'cmk.onmicrosoft.com Outlook Online3', {'jobId': '23456789-abcd-ef01-2345-6789abcdef01', 'duration': ('fixed', (500, 600))}, [ Result(state=State.OK, summary='Running since: 5 minutes 14 seconds'), Result(state=State.OK, notice='Last Success: 1 day 1 hour'), @@ -174,7 +174,7 @@ def test_discovery_veeam_o365jobs(params, section, result): ] ), ( - 'cmk.onmicrosoft.com Outlook Online3', {'jobId': '23456789-abcd-ef01-2345-6789abcdef01', 'duration': (120, 600)}, + 'cmk.onmicrosoft.com Outlook Online3', {'jobId': '23456789-abcd-ef01-2345-6789abcdef01', 'duration': ('fixed', (120, 600))}, [ Result(state=State.WARN, summary='Running since: 5 minutes 14 seconds (warn/crit at 2 minutes 0 seconds/10 minutes 0 seconds)'), Result(state=State.OK, notice='Last Success: 1 day 1 hour'), @@ -182,7 +182,7 @@ def test_discovery_veeam_o365jobs(params, section, result): ] ), ( - 'cmk.onmicrosoft.com Outlook Online3', {'jobId': '23456789-abcd-ef01-2345-6789abcdef01', 'duration': (120, 300)}, + 'cmk.onmicrosoft.com Outlook Online3', {'jobId': '23456789-abcd-ef01-2345-6789abcdef01', 'duration': ('fixed', (120, 300))}, [ Result(state=State.CRIT, summary='Running since: 5 minutes 14 seconds (warn/crit at 2 minutes 0 seconds/5 minutes 0 seconds)'), Result(state=State.OK, notice='Last Success: 1 day 1 hour'), @@ -190,7 +190,7 @@ def test_discovery_veeam_o365jobs(params, section, result): ] ), ( - 'cmk.onmicrosoft.com Outlook Online', {'jobId': '01234567-89ab-cdef-0123-456789abcdef', 'success_maxage': (1800, 504000)}, + 'cmk.onmicrosoft.com Outlook Online', {'jobId': '01234567-89ab-cdef-0123-456789abcdef', 'success_maxage': ('fixed', (1800, 504000))}, [ Result(state=State.OK, summary='Status: Success'), Result(state=State.OK, summary='Transferred Items: 191.00'), @@ -204,7 +204,7 @@ def test_discovery_veeam_o365jobs(params, section, result): ] ), ( - 'cmk.onmicrosoft.com Outlook Online', {'jobId': '01234567-89ab-cdef-0123-456789abcdef', 'success_maxage': (1800, 3600)}, + 'cmk.onmicrosoft.com Outlook Online', {'jobId': '01234567-89ab-cdef-0123-456789abcdef', 'success_maxage': ('fixed', (1800, 3600))}, [ Result(state=State.OK, summary='Status: Success'), Result(state=State.OK, summary='Transferred Items: 191.00'), @@ -218,7 +218,7 @@ def test_discovery_veeam_o365jobs(params, section, result): ] ), ( - 'cmk.onmicrosoft.com Outlook Online3', {'jobId': '23456789-abcd-ef01-2345-6789abcdef01', 'success_maxage': (86400, 504000)}, + 'cmk.onmicrosoft.com Outlook Online3', {'jobId': '23456789-abcd-ef01-2345-6789abcdef01', 'success_maxage': ('fixed', (86400, 504000))}, [ Result(state=State.OK, summary='Running since: 5 minutes 14 seconds'), Result(state=State.WARN, summary='Last Success: 1 day 1 hour (warn/crit at 1 day 0 hours/5 days 20 hours)'),