Release 20240516 (#5029)

This commit is contained in:
pkippes 2024-05-16 17:16:41 +02:00 committed by GitHub
commit d27a586caa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
108 changed files with 2100 additions and 295 deletions

28
.github/actions/test-plugins/action.yml vendored Normal file
View File

@ -0,0 +1,28 @@
name: "test-plugins"
description: "Test plugin that are passed as parameters"
inputs:
cache-key:
description: "The packaged plugin's cache key"
required: true
plugin-list:
description: "List of plugins to install from the cache"
required: true
package-extension:
description: "Either 'rpm' or 'deb'. Needed to determine the package manager command (dnf or apt-get)."
required: true
runs:
using: "composite"
steps:
- name: get the cached plugin
uses: actions/cache/restore@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0
with:
path: ./*.${{ inputs.package-extension }}
key: ${{ inputs.cache-key }}
fail-on-cache-miss: true
- name: Install, test and remove plugin
shell: bash
run: |
python3 .github/scripts/test-all-plugins.py ${{ inputs.package-extension }} ${{ inputs.plugin-list }}

View File

@ -1,4 +1,4 @@
ARG REGISTRY_URL
ARG REGISTRY_URL=docker.io
FROM ${REGISTRY_URL}/almalinux:8

View File

@ -1,4 +1,4 @@
ARG REGISTRY_URL
ARG REGISTRY_URL=docker.io
FROM ${REGISTRY_URL}/almalinux:9

View File

@ -1,4 +1,4 @@
ARG REGISTRY_URL
ARG REGISTRY_URL=docker.io
FROM ${REGISTRY_URL}/debian:bookworm

View File

@ -1,4 +1,4 @@
ARG REGISTRY_URL
ARG REGISTRY_URL=docker.io
FROM ${REGISTRY_URL}/debian:bullseye

View File

@ -1,4 +1,4 @@
ARG REGISTRY_URL
ARG REGISTRY_URL=docker.io
FROM ${REGISTRY_URL}/centos:7

View File

@ -1,4 +1,4 @@
ARG REGISTRY_URL
ARG REGISTRY_URL=docker.io
FROM ${REGISTRY_URL}/ubuntu:jammy

View File

@ -0,0 +1,68 @@
ARG REGISTRY_URL=docker.io
FROM ${REGISTRY_URL}/almalinux:8
RUN bash -e <<EOF
dnf install -y 'dnf-command(config-manager)' epel-release zstd jq
dnf config-manager --set-enabled powertools
dnf clean all
# Install Robotframework
dnf install -y python3.11 python3.11-pip
pip3.11 install robotframework robotframework-examples
# Install snmpsim
pip3.11 install snmpsim-lextudio
# Install node
curl -fsSL https://rpm.nodesource.com/setup_21.x | bash -
yum install -y nodejs
# Install mockoon
npm install -g -D @mockoon/cli
# Add Centreon plugins repositories
echo -e '[centreon-plugins-stable]\n\
name=centreon plugins stable x86_64\n\
baseurl=https://packages.centreon.com/rpm-plugins/el8/stable/x86_64\n\
enabled=1\n\
gpgcheck=1\n\
gpgkey=https://yum-gpg.centreon.com/RPM-GPG-KEY-CES\n\
[centreon-plugins-stable-noarch]\n\
name=centreon plugins stable noarch\n\
baseurl=https://packages.centreon.com/rpm-plugins/el8/stable/noarch\n\
enabled=1\n\
gpgcheck=1\n\
gpgkey=https://yum-gpg.centreon.com/RPM-GPG-KEY-CES\n\
[centreon-plugins-testing]\n\
name=centreon plugins testing x86_64\n\
baseurl=https://packages.centreon.com/rpm-plugins/el8/testing/x86_64\n\
enabled=1\n\
gpgcheck=1\n\
gpgkey=https://yum-gpg.centreon.com/RPM-GPG-KEY-CES\n\
[centreon-plugins-testing-noarch]\n\
name=centreon plugins testing noarch\n\
baseurl=https://packages.centreon.com/rpm-plugins/el8/testing/noarch\n\
enabled=1\n\
gpgcheck=1\n\
gpgkey=https://yum-gpg.centreon.com/RPM-GPG-KEY-CES\n\
[centreon-plugins-unstable]\n\
name=centreon plugins unstable x86_64\n\
baseurl=https://packages.centreon.com/rpm-plugins/el8/unstable/x86_64\n\
enabled=1\n\
gpgcheck=1\n\
gpgkey=https://yum-gpg.centreon.com/RPM-GPG-KEY-CES\n\
[centreon-plugins-unstable-noarch]\n\
name=centreon plugins unstable noarch\n\
baseurl=https://packages.centreon.com/rpm-plugins/el8/unstable/noarch\n\
enabled=1\n\
gpgcheck=1\n\
gpgkey=https://yum-gpg.centreon.com/RPM-GPG-KEY-CES\n'\
>> /etc/yum.repos.d/centreon-plugins.repo
mkdir -p /var/lib/centreon/centplugins/
chmod 777 /var/lib/centreon/centplugins/
dnf clean all
EOF

View File

@ -0,0 +1,67 @@
ARG REGISTRY_URL=docker.io
FROM ${REGISTRY_URL}/almalinux:9
RUN bash -e <<EOF
dnf install -y 'dnf-command(config-manager)' epel-release zstd jq
dnf config-manager --set-enabled crb
dnf clean all
# Install Robotframework
dnf install -y python3.11 python3.11-pip
pip3.11 install robotframework robotframework-examples
# Install snmpsim
pip3.11 install snmpsim-lextudio
# Install node
curl -fsSL https://rpm.nodesource.com/setup_21.x | bash -
yum install -y nodejs
# Install mockoon
npm install -g -D @mockoon/cli
# Add Centreon plugins repositories
echo -e '[centreon-plugins-stable]\n\
name=centreon plugins stable x86_64\n\
baseurl=https://packages.centreon.com/rpm-plugins/el9/stable/x86_64\n\
enabled=1\n\
gpgcheck=1\n\
gpgkey=https://yum-gpg.centreon.com/RPM-GPG-KEY-CES\n\
[centreon-plugins-stable-noarch]\n\
name=centreon plugins stable noarch\n\
baseurl=https://packages.centreon.com/rpm-plugins/el9/stable/noarch\n\
enabled=1\n\
gpgcheck=1\n\
gpgkey=https://yum-gpg.centreon.com/RPM-GPG-KEY-CES\n\
[centreon-plugins-testing]\n\
name=centreon plugins testing x86_64\n\
baseurl=https://packages.centreon.com/rpm-plugins/el9/testing/x86_64\n\
enabled=1\n\
gpgcheck=1\n\
gpgkey=https://yum-gpg.centreon.com/RPM-GPG-KEY-CES\n\
[centreon-plugins-testing-noarch]\n\
name=centreon plugins testing noarch\n\
baseurl=https://packages.centreon.com/rpm-plugins/el9/testing/noarch\n\
enabled=1\n\
gpgcheck=1\n\
gpgkey=https://yum-gpg.centreon.com/RPM-GPG-KEY-CES\n\
[centreon-plugins-unstable]\n\
name=centreon plugins unstable x86_64\n\
baseurl=https://packages.centreon.com/rpm-plugins/el9/unstable/x86_64\n\
enabled=1\n\
gpgcheck=1\n\
gpgkey=https://yum-gpg.centreon.com/RPM-GPG-KEY-CES\n\
[centreon-plugins-unstable-noarch]\n\
name=centreon plugins unstable noarch\n\
baseurl=https://packages.centreon.com/rpm-plugins/el9/unstable/noarch\n\
enabled=1\n\
gpgcheck=1\n\
gpgkey=https://yum-gpg.centreon.com/RPM-GPG-KEY-CES\n'\
>> /etc/yum.repos.d/centreon-plugins.repo
mkdir -p /var/lib/centreon/centplugins/
chmod 777 /var/lib/centreon/centplugins/
dnf clean all
EOF

View File

@ -0,0 +1,48 @@
ARG REGISTRY_URL=docker.io
FROM ${REGISTRY_URL}/debian:bookworm
ENV DEBIAN_FRONTEND noninteractive
# fix locale
RUN bash -e <<EOF
apt-get update
apt-get install -y locales libcurl4-openssl-dev curl wget zstd jq
rm -rf /var/lib/apt/lists/*
localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8
apt-get clean
EOF
ENV LANG en_US.utf8
RUN bash -e <<EOF
apt-get update
# Install Robotframework
apt-get install -y python3-dev python3-pip
rm -rf /usr/lib/python3.11/EXTERNALLY-MANAGED
pip3 install robotframework robotframework-examples
# Install snmpsim
pip3 install snmpsim-lextudio
# Install nodejs
curl -fsSL https://deb.nodesource.com/setup_21.x | bash - &&\
apt-get install -y nodejs
# Install mockoon (needs nodejs)
npm install -g -D @mockoon/cli
# Add Centreon plugins repositories
echo "deb https://packages.centreon.com/apt-plugins-stable/ bookworm main" | tee /etc/apt/sources.list.d/centreon-plugins.list
echo "deb https://packages.centreon.com/apt-plugins-testing/ bookworm main" | tee -a /etc/apt/sources.list.d/centreon-plugins.list
echo "deb https://packages.centreon.com/apt-plugins-unstable/ bookworm main" | tee -a /etc/apt/sources.list.d/centreon-plugins.list
wget -O- https://apt-key.centreon.com | gpg --dearmor | tee /etc/apt/trusted.gpg.d/centreon.gpg > /dev/null 2>&1
apt-get update
mkdir -p /var/lib/centreon/centplugins/
chmod 777 /var/lib/centreon/centplugins/
apt-get clean
EOF

View File

@ -0,0 +1,47 @@
ARG REGISTRY_URL=docker.io
FROM ${REGISTRY_URL}/debian:bullseye
ENV DEBIAN_FRONTEND noninteractive
# fix locale
RUN bash -e <<EOF
apt-get update
apt-get install -y locales libcurl4-openssl-dev curl wget zstd jq
rm -rf /var/lib/apt/lists/*
localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8
apt-get clean
EOF
ENV LANG en_US.utf8
RUN bash -e <<EOF
apt-get update
# Install Robotframework
apt-get install -y python3 python3-dev python3-pip
pip3 install robotframework robotframework-examples
# Install snmpsim
pip3 install snmpsim-lextudio
# Install nodejs
curl -fsSL https://deb.nodesource.com/setup_21.x | bash - &&\
apt-get install -y nodejs
# Install mockoon (needs nodejs)
npm install -g -D @mockoon/cli
# Add Centreon plugins repositories
echo "deb https://packages.centreon.com/apt-plugins-stable/ bullseye main" | tee /etc/apt/sources.list.d/centreon-plugins.list
echo "deb https://packages.centreon.com/apt-plugins-testing/ bullseye main" | tee -a /etc/apt/sources.list.d/centreon-plugins.list
echo "deb https://packages.centreon.com/apt-plugins-unstable/ bullseye main" | tee -a /etc/apt/sources.list.d/centreon-plugins.list
wget -O- https://apt-key.centreon.com | gpg --dearmor | tee /etc/apt/trusted.gpg.d/centreon.gpg > /dev/null 2>&1
apt-get update
mkdir -p /var/lib/centreon/centplugins/
chmod 777 /var/lib/centreon/centplugins/
apt-get clean
EOF

View File

@ -0,0 +1,45 @@
ARG REGISTRY_URL=docker.io
FROM ${REGISTRY_URL}/ubuntu:jammy
ENV DEBIAN_FRONTEND noninteractive
# fix locale
RUN bash -e <<EOF
apt-get update
apt-get install -y locales libcurl4-openssl-dev curl wget zstd jq
rm -rf /var/lib/apt/lists/*
localedef -i en_US -c -f UTF-8 -A /usr/share/locale/locale.alias en_US.UTF-8
apt-get clean
EOF
ENV LANG en_US.utf8
RUN bash -e <<EOF
apt-get update
# Install Robotframework
apt-get install -y python3 python3-dev python3-pip
pip3 install robotframework robotframework-examples
# Install snmpsim
pip3 install snmpsim-lextudio
# Install nodejs
curl -fsSL https://deb.nodesource.com/setup_21.x | bash - &&\
apt-get install -y nodejs
# Install mockoon (needs nodejs)
npm install -g -D @mockoon/cli
# Add Centreon plugins repositories
echo "deb https://packages.centreon.com/ubuntu-plugins-testing/ jammy main" | tee -a /etc/apt/sources.list.d/centreon-plugins.list
echo "deb https://packages.centreon.com/ubuntu-plugins-unstable/ jammy main" | tee -a /etc/apt/sources.list.d/centreon-plugins.list
wget -O- https://apt-key.centreon.com | gpg --dearmor | tee /etc/apt/trusted.gpg.d/centreon.gpg > /dev/null 2>&1
apt-get update
mkdir -p /var/lib/centreon/centplugins/
chmod 777 /var/lib/centreon/centplugins/
apt-get clean
EOF

View File

@ -43,7 +43,7 @@ for filepath in os.popen('find packaging -type f -name pkg.json').read().split('
packaging_path = re.search('.*\/(centreon-plugin-.*)\/pkg.json', filepath).group(1)
if not packaging_path == packaging["pkg_name"]:
packaging_path = packaging_path + "=>" + packaging["pkg_name"]
packaging_path = packaging["pkg_name"]
directory_path = re.search('^(.+)\/pkg.json', filepath).group(1)

133
.github/scripts/test-all-plugins.py vendored Normal file
View File

@ -0,0 +1,133 @@
#!/usr/bin/env python3
import subprocess
import sys
import os
import json
def get_tests_folders(plugin_name):
folder_list = []
pkg_file = open("./packaging/" + plugin_name + "/pkg.json")
packaging = json.load(pkg_file)
for file in packaging["files"]: # loop on "files" array in pkg.json file.
if file.endswith("/") and os.path.exists("tests/robot/" + file): # if this is a directory and there is test for it.
folder_list.append("tests/robot/" + file)
return folder_list
def get_plugin_full_path(plugin_name):
pkg_file = open("./packaging/" + plugin_name + "/pkg.json")
packaging = json.load(pkg_file)
return "/usr/lib/centreon/plugins/" + packaging["plugin_name"]
def test_plugin(plugin_name):
folders_list = get_tests_folders(plugin_name)
print(f"{plugin_name} folders_list : {folders_list}")
if len(folders_list) == 0:
return 0 # no tests present at the moment, but we still have tested the plugin can be installed.
robot_results = subprocess.run("robot -v ''CENTREON_PLUGINS:" + get_plugin_full_path(plugin_name) + " " + " ".join(folders_list),
shell=True, check=False)
return robot_results.returncode
def try_command(cmd, error):
return_obj = subprocess.run(cmd, shell=True, check=False)
print(return_obj)
if return_obj.returncode != 0:
print(error)
sys.exit(1)
def launch_snmp_sim():
subprocess.run("useradd snmp", shell=True, check=False)
# we don't want to quit if this fail because it often means the user already exist.
# this folder seem needed to launch snmp plugins. I didn't reproduce in my env, but without it,
# the first snmp plugin launched by robot prepend the message "Created directory: /var/lib/snmp/cert_indexes".
try_command(cmd="mkdir -p /var/lib/snmp/cert_indexes/", error="can't create /var/lib/snmp/cert_indexes/ dir")
try_command(cmd="chown snmp:snmp -R /var/lib/snmp/cert_indexes/", error="can't set cert_indexes folder permissions")
snmpsim_cmd = "snmpsim-command-responder --logging-method=null --agent-udpv4-endpoint=127.0.0.1:2024 --process-user=snmp --process-group=snmp --data-dir='./tests/robot' &"
try_command(cmd=snmpsim_cmd, error="can't launch snmp sim daemon.")
def install_plugin(plugin, archi):
with open('/var/log/robot-plugins-installation-tests.log', "a") as outfile:
if archi == "deb":
outfile.write("apt install -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' -y ./" + plugin.lower() + "*.deb\n")
output_status = (subprocess.run(
"apt install -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' -y ./" + plugin.lower() + "*.deb",
shell=True, check=False, stderr=subprocess.STDOUT, stdout=outfile)).returncode
elif archi == "rpm":
outfile.write("dnf install -y ./" + plugin + "*.rpm\n")
output_status = (subprocess.run("dnf install -y ./" + plugin + "*.rpm", shell=True, check=False,
stderr=subprocess.STDOUT, stdout=outfile)).returncode
else:
print(f"Unknown architecture, expected deb or rpm, got {archi}. Exiting.")
exit(1)
return output_status
def remove_plugin(plugin, archi):
with open('/var/log/robot-plugins-installation-tests.log', "a") as outfile:
if archi == "deb":
outfile.write("apt -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' autoremove -y " + plugin.lower() + "\n")
output_status = (subprocess.run(
"apt -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' autoremove -y " + plugin.lower(),
shell=True, check=False, stderr=subprocess.STDOUT, stdout=outfile)).returncode
# -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' is an option to force apt to keep the package in
# /var/cache/apt/archives, so it do not re download them for every installation.
# 'autoremove', contrary to 'remove' all dependancy while removing the original package.
elif archi == "rpm":
outfile.write("dnf remove -y " + plugin + "\n")
output_status = (subprocess.run("dnf remove -y " + plugin, shell=True, check=False,
stderr=subprocess.STDOUT, stdout=outfile)).returncode
else:
print(f"Unknown architecture, expected deb or rpm, got {archi}. Exiting.")
exit(1)
return output_status
if __name__ == '__main__':
print("starting program")
if len(sys.argv) < 2:
print("please provide architecture (deb or rpm) and list of plugin to test as arguments (one plugin name per "
"argument, separated by space)")
sys.exit(1)
launch_snmp_sim()
archi = sys.argv.pop(1) # expected either deb or rpm.
script_name = sys.argv.pop(0)
error_install = 0
error_tests = 0
error_purge = 0
nb_plugins = 0
list_plugin_error = []
for plugin in sys.argv:
print("plugin : ", plugin)
nb_plugins += 1
tmp = install_plugin(plugin, archi)
if tmp > 0:
list_plugin_error.append(plugin)
error_install += tmp
tmp = test_plugin(plugin)
if tmp > 0:
list_plugin_error.append(plugin)
error_tests += tmp
tmp = remove_plugin(plugin, archi)
if tmp > 0:
list_plugin_error.append(plugin)
error_purge += tmp
print(f"{nb_plugins} plugins tested.\n there was {error_install} installation error, {error_tests} test "
f"errors, and {error_purge} removal error list of error : {list_plugin_error}",)
if error_install != 0 or error_tests != 0 or error_purge != 0:
exit(1)
exit(0)
# the snmpsim daemon is still runing when we exit, as this script is mainly run in a docker on CI, it will be
# cleared up eventually.
# to clear it up manually, use ps -ax | grep snmpsim-command-respond | cut -dp -f1 | sudo xargs kill

View File

@ -11,11 +11,11 @@ on:
- develop
paths:
- ".github/workflows/docker-builder-packaging-plugins.yml"
- ".github/docker/*"
- ".github/docker/packaging/*"
pull_request:
paths:
- ".github/workflows/docker-builder-packaging-plugins.yml"
- ".github/docker/*"
- ".github/docker/packaging/*"
jobs:
create-and-push-docker:
@ -68,7 +68,7 @@ jobs:
- uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0
with:
file: .github/docker/Dockerfile.${{ matrix.dockerfile }}
file: .github/docker/packaging/Dockerfile.${{ matrix.dockerfile }}
context: .
build-args: "REGISTRY_URL=${{ vars.DOCKER_PROXY_REGISTRY_URL }}"
pull: true

View File

@ -0,0 +1,73 @@
name: docker-builder-testing-plugins
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
on:
workflow_dispatch:
push:
branches:
- develop
paths:
- ".github/workflows/docker-builder-testing-plugins.yml"
- ".github/docker/testing/*"
pull_request:
paths:
- ".github/workflows/docker-builder-testing-plugins.yml"
- ".github/docker/testing/*"
jobs:
create-and-push-docker:
strategy:
matrix:
include:
- runner: ubuntu-22.04
dockerfile: alma8
image: alma8
- runner: ubuntu-22.04
dockerfile: alma9
image: alma9
- runner: ubuntu-22.04
dockerfile: bullseye
image: bullseye
- runner: ["self-hosted", "collect-arm64"]
dockerfile: bullseye
image: bullseye-arm64
- runner: ubuntu-22.04
dockerfile: bookworm
image: bookworm
- runner: ubuntu-22.04
dockerfile: jammy
image: jammy
runs-on: ${{ matrix.runner }}
steps:
- name: Checkout sources
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Login to Registry
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
with:
registry: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}
username: ${{ secrets.DOCKER_REGISTRY_ID }}
password: ${{ secrets.DOCKER_REGISTRY_PASSWD }}
- name: Login to proxy registry
uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0
with:
registry: ${{ vars.DOCKER_PROXY_REGISTRY_URL }}
username: ${{ secrets.DOCKER_REGISTRY_ID }}
password: ${{ secrets.DOCKER_REGISTRY_PASSWD }}
- uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0
- uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0
with:
file: .github/docker/testing/Dockerfile.testing-plugins-${{ matrix.dockerfile }}
context: .
build-args: "REGISTRY_URL=${{ vars.DOCKER_PROXY_REGISTRY_URL }}"
pull: true
push: true
tags: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/testing-plugins-${{ matrix.image }}:latest

View File

@ -53,6 +53,7 @@ jobs:
"Digest::MD5::File",
"Digest::SHA1",
"Email::Send::SMTP::Gmail",
"Exporter::Shiny",
"EV",
"FFI::CheckLib",
"FFI::Platypus",
@ -121,6 +122,8 @@ jobs:
version: "0.022"
- name: "Device::Modbus::TCP::Client"
version: "0.026"
- name: "Exporter::Shiny"
build_distribs: el8
- name: "EV"
- name: "FFI::CheckLib"
- name: "FFI::Platypus"
@ -140,6 +143,7 @@ jobs:
use_dh_make_perl: "false"
version: "0.01"
rpm_dependencies: "zeromq"
name: package ${{ matrix.distrib }} ${{ matrix.name }}
container:
image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }}:latest
@ -160,7 +164,7 @@ jobs:
dnf module reset -y ruby
dnf module enable -y ruby:3.1
dnf install -y ruby
dnf install -y ruby ruby-devel
shell: bash
- if: ${{ contains(matrix.build_distribs, matrix.distrib) && matrix.spec_file == '' }}

View File

@ -69,11 +69,8 @@ jobs:
dnf install -y cpanminus gcc
fi
if [ "${{ matrix.distrib }}" = "el8" ]; then
cpanm -v -l /tmp JSON::Path@0.5
else
cpanm -v -l /tmp JSON::Path@1.0.4
fi
cpanm -v -l /tmp JSON::Path@1.0.4
shell: bash
- name: Set package name and paths according to distrib
@ -90,7 +87,6 @@ jobs:
else
NAME="perl-JSON-Path"
if [ "${{ matrix.distrib }}" = "el8" ]; then
VERSION="0.5" # https://github.com/centreon/centreon-plugins/issues/4540
PERL_VENDORLIB="/usr/local/share/perl5"
else
PERL_VENDORLIB="/usr/local/share/perl5/$PERL_VERSION"

View File

@ -76,10 +76,10 @@ jobs:
PLUGINS="$(python3 .github/scripts/process-plugins.py '${{ steps.filter.outputs.common == 'true' }}')"
echo "plugins=$(echo $PLUGINS)" >> $GITHUB_OUTPUT
if [ "$PLUGINS" == '' ]; then
echo "::notice::There are no modifications to the plugins packages"
fi
shell: bash
fatpacker:
@ -243,8 +243,55 @@ jobs:
rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }}
stability: ${{ needs.get-environment.outputs.stability }}
test-plugins:
needs: [get-environment, get-plugins, package]
strategy:
fail-fast: false
matrix:
distrib: [el8, el9, jammy, bullseye, bookworm]
include:
- package_extension: rpm
image: testing-plugins-alma8
distrib: el8
- package_extension: rpm
image: testing-plugins-alma9
distrib: el9
- package_extension: deb
image: testing-plugins-bullseye
distrib: bullseye
- package_extension: deb
image: testing-plugins-bookworm
distrib: bookworm
- package_extension: deb
image: testing-plugins-jammy
distrib: jammy
runs-on: ubuntu-22.04
container:
image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }}
credentials:
username: ${{ secrets.DOCKER_REGISTRY_ID }}
password: ${{ secrets.DOCKER_REGISTRY_PASSWD }}
steps:
- name: Checkout sources
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- uses: ./.github/actions/test-plugins
with:
cache-key: ${{ github.sha }}-${{ github.run_id }}-${{ matrix.package_extension }}-${{ matrix.distrib }}
package-extension: ${{ matrix.package_extension }}
plugin-list: ${{ needs.get-plugins.outputs.plugins }}
- name: Upload apt/dnf logs as artifacts if tests failed
if: failure()
uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1
with:
name: plugin-installation-${{ matrix.distrib }}
path: /var/log/robot-plugins-installation-tests.log
retention-days: 1
deliver:
needs: [get-environment, package]
needs: [get-environment, package, test-plugins]
if: ${{ contains(fromJson('["stable", "testing", "unstable"]'), needs.get-environment.outputs.stability) }}
uses: ./.github/workflows/plugin-delivery.yml
with:

View File

@ -1,76 +0,0 @@
name: functional-tests
concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
on:
workflow_dispatch:
pull_request:
paths:
- '.github/workflows/tests-functional.yml'
- 'src/**'
- 'tests/functional/**'
- 'tests/resources/mockoon/**'
- 'tests/resources/snmp/**'
jobs:
functional-tests-with-robot:
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- name: Install libs
run: |
sudo apt update
sudo apt-get install -y libcurl4-openssl-dev
sudo apt-get install -qqy snmpsim
- name: Install Node.js
uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4.0.2
with:
node-version: 21
- name: Install Mockoon CLI
run: npm install -g -D @mockoon/cli@7.0.0
- name: Install perl dependencies
uses: shogo82148/actions-setup-perl@28eae78d12c2bba1163aec45d123f6d9228bc307 # v1.29.0
with:
perl-version: '5.34'
install-modules-with: cpm
install-modules: |
Alien::SNMP
DateTime
Net::Curl::Easy
Paws
Net::SNMP
URI::Encode
XML::LibXML
DBI
DBD::mysql
POSIX
Time::HiRes
JSON::XS
- name: Install Python
uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0
with:
python-version: '3.11'
- name: Install Robot Framework
run: |
pip3.11 install robotframework
pip3.11 install RobotFramework-Examples
shell: bash
- name: Run Robot Framework tests
run: |
sudo mkdir -p /var/lib/centreon/centplugins/
sudo chmod 777 /var/lib/centreon/centplugins/
sudo useradd snmp
sudo mkdir -p /usr/snmpsim/data
sudo cp -r tests/robot/* /usr/snmpsim/data/
snmpsimd --logging-method=null --agent-udpv4-endpoint=127.0.0.1:2024 --process-user=snmp --process-group=snmp &
robot tests/robot

View File

@ -0,0 +1,5 @@
{
"dependencies": [
"libdatetime-perl"
]
}

View File

@ -0,0 +1,9 @@
{
"pkg_name": "centreon-plugin-Applications-Monitoring-Quanta-Restapi",
"pkg_summary": "Centreon Plugin to check Quanta.io application probes results.",
"plugin_name": "centreon_monitoring_quanta_restapi.pl",
"files": [
"centreon/plugins/script_custom.pm",
"apps/monitoring/quanta/restapi"
]
}

View File

@ -0,0 +1,5 @@
{
"dependencies": [
"perl(DateTime)"
]
}

View File

@ -0,0 +1,5 @@
{
"dependencies": [
"libsocket-perl"
]
}

View File

@ -0,0 +1,9 @@
{
"pkg_name": "centreon-plugin-Applications-RRDCached",
"pkg_summary": "Centreon Plugin to check RRDCached related informations",
"plugin_name": "centreon_rrdcached.pl",
"files": [
"centreon/plugins/script_custom.pm",
"apps/rrdcached/"
]
}

View File

@ -0,0 +1,5 @@
{
"dependencies": [
"perl(IO::Socket)"
]
}

View File

@ -0,0 +1,14 @@
{
"pkg_name": "centreon-plugin-Hardware-Devices-Camera-Avigilon-Snmp",
"pkg_summary": "Centreon Plugin to monitor Avigilon camera using SNMP",
"plugin_name": "centreon_camera_avigilon_snmp.pl",
"files": [
"centreon/plugins/script_snmp.pm",
"centreon/plugins/snmp.pm",
"snmp_standard/mode/interfaces.pm",
"snmp_standard/mode/listinterfaces.pm",
"snmp_standard/mode/resources/",
"snmp_standard/mode/uptime.pm",
"hardware/devices/camera/avigilon/snmp/"
]
}

View File

@ -0,0 +1,5 @@
{
"dependencies": [
"libsnmp-perl"
]
}

View File

@ -0,0 +1,5 @@
{
"dependencies": [
"perl(SNMP)"
]
}

View File

@ -0,0 +1,4 @@
{
"dependencies": [
]
}

View File

@ -0,0 +1,9 @@
{
"pkg_name": "centreon-plugin-Virtualization-Ovirt-Api",
"pkg_summary": "Centreon Plugin to monitor oVirt using API",
"plugin_name": "centreon_ovirt_api.pl",
"files": [
"centreon/plugins/script_custom.pm",
"apps/virtualization/ovirt/"
]
}

View File

@ -0,0 +1,4 @@
{
"dependencies": [
]
}

View File

@ -131,11 +131,11 @@ Check web scenario availability metrics.
=item B<--scenario-id>
Set ID of the scenario.
Set ID of the scenario (mandatory option).
=item B<--timeframe>
Set timeframe in seconds (default: 14400).
Set timeframe in seconds (default: 900).
=item B<--warning-*> B<--critical-*>

View File

@ -106,27 +106,28 @@ sub countFiles {
# Cannot list we skip
next;
}
# this loop is recursive, when we find a directory we add it to the list used by the for loop.
# max_depth is used to limit the depth we search.
# same behaviour as ftp and sftp protocol.
foreach my $file (@$files) {
next if ($file->[0] != SMBC_FILE && $file->[0] != SMBC_DIR);
next if ($file->[0] != SMBC_FILE && $file->[0] != SMBC_DIR);
next if ($file->[1] eq '.' || $file->[1] eq '..');
my $name = $dir . '/' . $file->[1];
if (defined($self->{option_results}->{filter_file}) && $self->{option_results}->{filter_file} ne '' &&
$name !~ /$self->{option_results}->{filter_file}/) {
$self->{output}->output_add(long_msg => sprintf("skipping '%s'", $name), debug => 1);
next;
}
if ($file->[0] == SMBC_DIR) {
if (defined($self->{option_results}->{max_depth}) && $level + 1 <= $self->{option_results}->{max_depth}) {
push @$list, { name => $name, level => $level + 1 };
}
} else {
$self->{output}->output_add(long_msg => sprintf("Match '%s'", $name));
$self->{global}->{detected}++;
next;
} elsif (!centreon::plugins::misc::is_empty($self->{option_results}->{filter_file})
# if this is a file check the filter_file regex
&& $name !~ /$self->{option_results}->{filter_file}/) {
$self->{output}->output_add(long_msg => sprintf("skipping '%s'", $name), debug => 1);
next;
}
$self->{output}->output_add(long_msg => sprintf("Match '%s'", $name));
$self->{global}->{detected}++;
}
}
}

View File

@ -89,7 +89,7 @@ sub run {
my $exit_code = $self->{perfdata}->threshold_check(value => $count,
threshold => [ { label => 'critical', exit_litteral => 'critical' }, { label => 'warning', exit_litteral => 'warning' } ]);
$self->{output}->output_add(severity => $exit_code,
short_msg => sprintf("Number of files : %s", $count));
$self->{output}->perfdata_add(label => 'files',
@ -105,7 +105,7 @@ sub countFiles {
my ($self) = @_;
my @listings;
my $count = 0;
if (!defined($self->{option_results}->{directory}) || scalar(@{$self->{option_results}->{directory}}) == 0) {
push @listings, [ { name => '.', level => 0 } ];
} else {
@ -121,36 +121,39 @@ sub countFiles {
my $hash = pop @$list;
my $dir = $hash->{name};
my $level = $hash->{level};
if (!(@files = apps::protocols::ftp::lib::ftp::execute($self, command => $map_commands{ls}->{$self->{ssl_or_not}}->{name}, command_args => [$dir]))) {
# Cannot list we skip
next;
}
# this loop is recursive, when we find a directory we add it to the list used by the for loop.
# max_depth is used to limit the depth we search.
# same behaviour as cifs(samba) and sftp protocol.
foreach my $line (@files) {
# IIS: 05-13-15 10:59AM 1184403 test.jpg
next if ($line !~ /(\S+)\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+\S+\s+(.*)/ &&
$line !~ /^\s*\S+\s*\S+\s*(\S+)\s+(.*)/);
$line !~ /^\s*\S+\s*\S+\s*(\S+)\s+(.*)/);
my ($rights, $filename) = ($1, $2);
my $bname = basename($filename);
next if ($bname eq '.' || $bname eq '..');
my $name = $dir . '/' . $bname;
if (defined($self->{option_results}->{filter_file}) && $self->{option_results}->{filter_file} ne '' &&
$name !~ /$self->{option_results}->{filter_file}/) {
if ($rights =~ /^(d|<DIR>)/i) {
# in the case of a directory and the max level is not reached yet, we add it to the recursive browsing
if (defined($self->{option_results}->{max_depth})
&& $level + 1 <= $self->{option_results}->{max_depth}) {
push @$list, { name => $name, level => $level + 1 };
}
next;
} elsif (!centreon::plugins::misc::is_empty($self->{option_results}->{filter_file})
&& $name !~ /$self->{option_results}->{filter_file}/) {
$self->{output}->output_add(long_msg => sprintf("Skipping '%s'", $name));
# in the case of a file that does not match the filter, we skip
next;
}
if ($rights =~ /^(d|<DIR>)/i) {
if (defined($self->{option_results}->{max_depth}) && $level + 1 <= $self->{option_results}->{max_depth}) {
push @$list, { name => $name, level => $level + 1};
}
} else {
$self->{output}->output_add(long_msg => sprintf("Match '%s'", $name));
$count++;
}
}
$self->{output}->output_add(long_msg => sprintf("Match '%s'", $name));
$count++;
}
}
}
return $count;

View File

@ -26,7 +26,7 @@ use base qw(centreon::plugins::script_simple);
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
$self->{modes} = {

View File

@ -34,12 +34,12 @@ sub set_counters {
$self->{maps_counters}->{global} = [
{ label => 'files-detected', nlabel => 'files.detected.count', set => {
key_values => [ { name => 'detected' } ],
output_template => 'number of files: %s',
perfdatas => [
{ template => '%s', min => 0 }
]
}
key_values => [ { name => 'detected' } ],
output_template => 'number of files: %s',
perfdatas => [
{ template => '%s', min => 0 }
]
}
}
];
}
@ -93,7 +93,7 @@ sub manage_selection {
sub countFiles {
my ($self, %options) = @_;
my @listings;
foreach my $dir (@{$self->{option_results}->{directory}}) {
push @listings, [ { name => $dir, level => 0 } ];
}
@ -111,26 +111,27 @@ sub countFiles {
# Cannot list we skip
next;
}
# this loop is recursive, when we find a directory we add it to the list used by the for loop.
# max_depth is used to limit the depth we search.
# same behaviour as cifs(samba) and ftp protocol.
foreach my $file (@{$rv->{files}}) {
next if ($file->{name} eq '.' || $file->{name} eq '..');
my $name = $dir . '/' . $file->{name};
if (defined($self->{option_results}->{filter_file}) && $self->{option_results}->{filter_file} ne '' &&
$name !~ /$self->{option_results}->{filter_file}/) {
$self->{output}->output_add(long_msg => sprintf("skipping '%s'", $name), debug => 1);
next;
}
if ($file->{type} == 2) {
# case of a directory
if (defined($self->{option_results}->{max_depth}) && $level + 1 <= $self->{option_results}->{max_depth}) {
push @$list, { name => $name, level => $level + 1 };
}
} else {
$self->{output}->output_add(long_msg => sprintf("Match '%s'", $name));
$self->{global}->{detected}++;
next;
} elsif (!centreon::plugins::misc::is_empty($self->{option_results}->{filter_file})
&& $name !~ /$self->{option_results}->{filter_file}/) {
$self->{output}->output_add(long_msg => sprintf("skipping '%s'", $name), debug => 1);
next;
}
}
$self->{output}->output_add(long_msg => sprintf("Match '%s'", $name));
$self->{global}->{detected}++;
}
}
}
}

View File

@ -0,0 +1,118 @@
# Copyright 2024 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# 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.
#
package apps::rrdcached::custom::tcp;
use strict;
use warnings;
use IO::Socket;
sub new {
my ($class, %options) = @_;
my $self = {};
bless $self, $class;
# Check if an output option is available
if (!defined($options{output})) {
print "Class Custom: Need to specify 'output' argument.\n";
exit 3;
}
# Check if options are available
if (!defined($options{options})) {
$options{output}->add_option_msg(short_msg => "Class Custom: Need to specify 'options' argument.");
$options{output}->option_exit();
}
if (!defined($options{noptions})) {
# Adding options legacy from appsmetrics.pm in single mode
$options{options}->add_options(arguments => {
'hostname:s' => { name => 'hostname', default => '127.0.0.1' },
'port:s' => { name => 'port', default => 42217 },
'timeout:s' => { name => 'timeout', default => 5 }
});
}
# Adding Help structure to the object
$options{options}->add_help(package => __PACKAGE__, sections => 'RRDCACHED TCP OPTIONS', once => 1);
# Adding output structure to the object
$self->{output} = $options{output};
return $self;
}
sub set_options {
my ($self, %options) = @_;
$self->{option_results} = $options{option_results};
}
sub set_defaults {}
sub check_options {
my ($self, %options) = @_;
return 0;
}
sub connect {
my ($self, %options) = @_;
my $socket = IO::Socket::INET->new(
PeerHost => $self->{option_results}->{hostname},
PeerPort => $self->{option_results}->{port},
Timeout => $self->{option_results}->{timeout},
Proto => 'tcp',
);
return $socket;
}
1;
__END__
=head1 NAME
TCP socket custom mode.
=head1 SYNOPSIS
RRDcached access via TCP socket.
=head1 RRDCACHED TCP OPTIONS
=over 8
=item B<--hostname>
Hostname to connect to.
=item B<--port>
TCP port (default: 42217)
=item B<--timeout>
Connection timeout.
=back
=head1 DESCRIPTION
B<custom>.
=cut

View File

@ -0,0 +1,111 @@
# Copyright 2024 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# 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.
#
package apps::rrdcached::custom::unix;
use strict;
use warnings;
use IO::Socket;
sub new {
my ($class, %options) = @_;
my $self = {};
bless $self, $class;
# Check if an output option is available
if (!defined($options{output})) {
print "Class Custom: Need to specify 'output' argument.\n";
exit 3;
}
# Check if options are available
if (!defined($options{options})) {
$options{output}->add_option_msg(short_msg => "Class Custom: Need to specify 'options' argument.");
$options{output}->option_exit();
}
if (!defined($options{noptions})) {
$options{options}->add_options(arguments => {
'socket-path:s' => { name => 'socket_path', default => '/var/rrdtool/rrdcached/rrdcached.sock' },
'timeout:s' => { name => 'timeout', default => 5 }
});
}
# Adding the custom mode's help to the object
$options{options}->add_help(package => __PACKAGE__, sections => 'RRDCACHED UNIX SOCKET OPTIONS', once => 1);
# Adding output structure to the object
$self->{output} = $options{output};
return $self;
}
sub set_options {
my ($self, %options) = @_;
$self->{option_results} = $options{option_results};
}
sub set_defaults {}
sub check_options {
my ($self, %options) = @_;
return 0;
}
sub connect {
my ($self, %options) = @_;
my $socket = IO::Socket::UNIX->new(
Type => SOCK_STREAM(),
Peer => $self->{option_results}->{socket_path},
Timeout => $self->{option_results}->{timeout},
);
return $socket;
}
1;
__END__
=head1 NAME
UNIX socket custom mode.
=head1 SYNOPSIS
RRDcached access via UNIX socket.
=head1 RRDCACHED UNIX SOCKET OPTIONS
=over 8
=item B<--socket-path>
Path to the UNIX socket (default is /var/rrdtool/rrdcached/rrdcached.sock).
=item B<--timeout>
Connection timeout.
=back
=head1 DESCRIPTION
B<custom>.
=cut

View File

@ -0,0 +1,118 @@
#
# Copyright 2024 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# 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.
#
package apps::rrdcached::mode::ping;
use strict;
use warnings;
use IO::Socket;
use base qw(centreon::plugins::templates::counter);
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
bless $self, $class;
$options{options}->add_options(arguments => {});
return $self;
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{
name => 'global',
type => 0
}
];
$self->{maps_counters}->{global} = [
{
label => 'response',
type => 2,
critical_default => '%{response} !~ /PONG/',
set => {
key_values => [ { name => 'response' } ],
output_template => 'response: %s',
closure_custom_threshold_check => \&catalog_status_threshold_ng
}
}
];
}
sub manage_selection {
my ($self, %options) = @_;
my $ping_answered = 'no response';
# open the socket of either type TCP/UNIX
my $socket = $options{custom}->connect();
# exit if we cannot connect/open it
if (!defined($socket) or !$socket->connected()) {
$self->{output}->output_add(severity => 'CRITICAL', short_msg => "Can't connect to socket, is rrdcached running ? is your socket path/address:port correct ?");
$self->{output}->display();
$self->{output}->exit();
}
# send the PING command and receive the response
$socket->send("PING\n");
SOCKETREAD:
while (my $data = <$socket>) {
chomp $data;
# store the response
$ping_answered = $data;
$self->{output}->output_add(long_msg => sprintf("Received response - %s", $data));
# only one line is expected so we can quit immediately
$socket->send("QUIT\n");
close($socket);
# exit the while loop
last SOCKETREAD;
}
$self->{global} = {
response => $ping_answered
};
}
1;
__END__
=head1 MODE
Check if the RRDcached daemon is answering to the basic PING command.
=item B<--warning-response>
Define the conditions to match for the status to be WARNING. You can use the variable '%{response}'.
=item B<--critical-response>
Define the conditions to match for the status to be CRITICAL. You can use the variable '%{response}'.
Default: '%{response} !~ /PONG/'.
=over 8
=back

View File

@ -20,131 +20,130 @@
package apps::rrdcached::mode::stats;
use base qw(centreon::plugins::mode);
use strict;
use warnings;
use IO::Socket;
use base qw(centreon::plugins::templates::counter);
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
bless $self, $class;
$options{options}->add_options(arguments =>
{
"host:s" => { name => 'host', default => '127.0.0.1' },
"port:s" => { name => 'port', default => '42217' },
"unix-socket-path:s" => { name => 'unix_socket_path', default => '/var/rrdtool/rrdcached/rrdcached.sock' },
"warning-update:s" => { name => 'warning_update', default => '3000' },
"critical-update:s" => { name => 'critical_update', default => '5000' },
"warning-queue:s" => { name => 'warning_queue', default => '70' },
"critical-queue:s" => { name => 'critical_queue', default => '100' },
"socket-type:s" => { name => 'socket_type', default => 'unix' },
});
$options{options}->add_options(arguments => {});
return $self;
}
sub check_options {
sub set_counters {
my ($self, %options) = @_;
$self->SUPER::init(%options);
if (($self->{perfdata}->threshold_validate(label => 'warning-update', value => $self->{option_results}->{warning_update})) == 0) {
$self->{output}->add_option_msg(short_msg => "Wrong warning-update threshold '" . $self->{warning} . "'.");
$self->{output}->option_exit();
}
if (($self->{perfdata}->threshold_validate(label => 'critical-update', value => $self->{option_results}->{critical_update})) == 0) {
$self->{output}->add_option_msg(short_msg => "Wrong critical threshold '" . $self->{critical} . "'.");
$self->{output}->option_exit();
}
if (($self->{perfdata}->threshold_validate(label => 'warning-queue', value => $self->{option_results}->{warning_queue})) == 0) {
$self->{output}->add_option_msg(short_msg => "Wrong warning-queue threshold '" . $self->{warning} . "'.");
$self->{output}->option_exit();
}
if (($self->{perfdata}->threshold_validate(label => 'critical-queue', value => $self->{option_results}->{critical_queue})) == 0) {
$self->{output}->add_option_msg(short_msg => "Wrong critical-queue threshold '" . $self->{critical} . "'.");
$self->{output}->option_exit();
}
$self->{maps_counters_type} = [
{
name => 'global',
type => 0
}
];
$self->{maps_counters}->{global} = [
{
label => 'queue-length',
nlabel => 'rrdcached.queue-length',
set => {
key_values => [ { name => 'queue_length' } ],
output_template => 'queue length: %s',
perfdatas => [
{
template => '%d',
min => 0
}
]
}
},
{
label => 'waiting-updates',
nlabel => 'rrdcached.waiting-updates',
set => {
key_values => [ { name => 'waiting_updates' } ],
output_template => 'waiting updates: %s',
perfdatas => [
{
template => '%d',
min => 0
}
]
}
}
];
}
sub run {
sub manage_selection {
my ($self, %options) = @_;
my $data;
my @stat;
my @tab;
my $queueLenght;
my $socket;
if ($self->{option_results}->{socket_type} eq 'tcp') {
$socket = IO::Socket::INET->new(
PeerHost => $self->{option_results}->{host},
PeerPort => $self->{option_results}->{port},
Proto => 'tcp',
);
} else {
my $SOCK_PATH = $self->{option_results}->{unix_socket_path};
$socket = IO::Socket::UNIX->new(
Type => SOCK_STREAM(),
Peer => $SOCK_PATH,
);
my %raw_data;
# open the socket of either type TCP/UNIX
my $socket = $options{custom}->connect();
# exit if we cannot connect/open it
if (!defined($socket) or !$socket->connected()) {
$self->{output}->output_add(severity => 'CRITICAL', short_msg => "Can't connect to socket, is RRDcached running
? Is your socket path or address:port correct ?");
$self->{output}->display();
$self->{output}->exit();
}
if (!defined($socket)) {
$self->{output}->output_add(severity => 'CRITICAL',
short_msg => "Can't connect to socket, is rrdcached running ? is your socket path/address:port correct ?");
$self->{output}->display();
$self->{output}->exit();
} else {
$socket->send("STATS\n");
while ($data = <$socket>) {
if ($data =~ /(\d+) Statistics follow/) {
my $stats_number = $1;
if ($stats_number < 9) {
$self->{output}->output_add(severity => 'UNKNOWN',
short_msg => "Stats available are incomplete, check rrdcached daemon (try again if few moments)");
$self->{output}->display();
$self->{output}->exit();
}
}
next if $data !~ m/(^UpdatesR|Data|Queue)/;
push @tab,$data;
$socket->send("QUIT\n");
}
close($socket);
foreach my $line (@tab) {
my ($key, $value) = split (/:\s*/, $line,2);
push @stat, $value;
$self->{output}->output_add(long_msg => sprintf("%s = %i", $key, $value));
# send the STATS command and receive the response
$socket->send("STATS\n");
SOCKETREAD:
while ($data = <$socket>) {
chomp $data;
# there should be at least 9 statistics in the response
if ($data =~ /(\d+) Statistics follow/) {
my $stats_number = $1;
if ($stats_number < 9) {
$self->{output}->output_add(
severity => 'UNKNOWN',
short_msg => "The returned statistics are incomplete. Try again later or check that the service is up.");
$self->{output}->display();
$self->{output}->exit();
}
next SOCKETREAD;
}
chomp($stat[0]);
my $updatesNotWritten = $stat[1] - $stat[2];
my $exit1 = $self->{perfdata}->threshold_check(value => $updatesNotWritten, threshold => [ { label => 'critical-update', 'exit_litteral' => 'critical' }, { label => 'warning-update', exit_litteral => 'warning' } ]);
my $exit2 = $self->{perfdata}->threshold_check(value => $stat[0], threshold => [ { label => 'critical-queue', 'exit_litteral' => 'critical' }, { label => 'warning-queue', exit_litteral => 'warning' } ]);
my $exit = $self->{output}->get_most_critical(status => [ $exit1, $exit2 ]);
# parse the stats as "Key: value" lines
if (my ($key, $value) = $data =~ m/^([^:]+):\s*([\d]+)$/) {
$raw_data{$key} = $value;
$self->{output}->output_add(long_msg => "Received data - $key: $value");
} else {
$self->{output}->output_add(long_msg => "Skipping data - $data");
next SOCKETREAD;
}
# once all the expected data has been received, we can quit the command and close the socket
if (defined($raw_data{QueueLength}) and defined($raw_data{UpdatesReceived}) and defined($raw_data{DataSetsWritten})) {
$socket->send("QUIT\n");
close($socket);
last SOCKETREAD;
}
}
$self->{output}->output_add(severity => $exit,
short_msg => sprintf("RRDCached has %i updates waiting and %i node(s) in queue", $updatesNotWritten, $stat[0]));
$self->{output}->perfdata_add(label => 'QueueLenght', unit => 'nodes',
value => $stat[0],
warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning'),
critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical'),
min => 0);
$self->{output}->perfdata_add(label => 'UpdatesWaiting', unit => 'updates',
value => $updatesNotWritten,
warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning'),
critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical'),
min => 0);
# just in case...
if (!defined($raw_data{QueueLength}) or !defined($raw_data{UpdatesReceived}) or !defined($raw_data{DataSetsWritten})) {
# all the data have not been gathered despite the socket's answer is finished
close($socket) if $socket->connected();
# exit with unknown status
$self->{output}->output_add(severity => 'UNKNOWN', short_msg => "The returned statistics are incomplete. Try again later.");
$self->{output}->display();
$self->{output}->exit();
}
}
# at this point, we should have the needed data, let's store it to our counter
$self->{global} = {
queue_length => $raw_data{QueueLength},
waiting_updates => $raw_data{UpdatesReceived} - $raw_data{DataSetsWritten}
};
}
1;
@ -153,46 +152,25 @@ __END__
=head1 MODE
Check Updates cache of rrdcached daemon (compute delta between UpdatesReceived and DataSetsWritten from the rrdcached socket STATS command)
Check if the cache of RRDcached daemon's queue is too long or if it has too many updates waiting (difference between
UpdatesReceived and DataSetsWritten from the rrdcached socket STATS command).
=over 8
=item B<--tcp>
=item B<--warning-rrdcached-waiting-updates>
Specify this option if TCP socket is used
Warning threshold for cached RRD updates (one update can include several values).
=item B<--host>
=item B<--critical-rrdcached-waiting-updates>
Host where the socket is (should be set if --tcp is used) (default: 127.0.0.1)
Critical threshold for cached RRD updates (one update can include several values).
=item B<--port>
=item B<--warning-rrdcached-queue-length>
Port where the socket is listening (default: 42217)
Warning threshold for the number of nodes currently enqueued in the update queue.
=item B<--unix>
=item B<--critical-rrdcached-queue-length>
Specify this option if UNIX socket is used
=item B<--socket-path>
Path to the socket (should be set if --unix is used) (default is /var/rrdtool/rrdcached/rrdcached.sock)
=item B<--warning-update>
Warning number of cached RRD updates (One update can include several values)
=item B<--critical-update>
Critical number of cached RRD updates (One update can include several values)
=item B<--warning-queue>
Warning number of nodes in rrdcached queue
=item B<--critical-queue>
Critical number of nodes in rrdcached queue
Critical threshold for the number of nodes currently enqueued in the update queue.
=back
=cut

View File

@ -22,7 +22,7 @@ package apps::rrdcached::plugin;
use strict;
use warnings;
use base qw(centreon::plugins::script_simple);
use base qw(centreon::plugins::script_custom);
sub new {
my ($class, %options) = @_;
@ -30,9 +30,13 @@ sub new {
bless $self, $class;
$self->{version} = '0.1';
%{$self->{modes}} = (
$self->{modes} = {
'stats' => 'apps::rrdcached::mode::stats',
);
'ping' => 'apps::rrdcached::mode::ping'
};
$self->{custom_modes}->{tcp} = 'apps::rrdcached::custom::tcp';
$self->{custom_modes}->{unix} = 'apps::rrdcached::custom::unix';
return $self;
}
@ -43,6 +47,6 @@ __END__
=head1 PLUGIN DESCRIPTION
Check RRDCached related informations
Check RRDCached status and statistics.
=cut

View File

@ -193,7 +193,7 @@ Warning threshold where '*' can be:
'matched-events', 'deadlettered-events', 'unmatched-events',
'dropped-events'.
=item B<--critical-vault-capacity-percentage>
=item B<--critical-*>
Critical threshold where '*' can be:
'matched-events', 'deadlettered-events', 'unmatched-events',

View File

@ -0,0 +1,180 @@
#
# Copyright 2024 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# 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.
#
package hardware::devices::camera::avigilon::snmp::mode::interfaces;
use base qw(snmp_standard::mode::interfaces);
use strict;
use warnings;
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
bless $self, $class;
return $self;
}
1;
__END__
=head1 MODE
Check interfaces.
=over 8
=item B<--add-global>
Check global port statistics (by default if no --add-* option is set).
=item B<--add-status>
Check interface status.
=item B<--add-duplex-status>
Check duplex status (with --warning-status and --critical-status).
=item B<--add-traffic>
Check interface traffic.
=item B<--add-errors>
Check interface errors.
=item B<--add-cast>
Check interface cast.
=item B<--add-speed>
Check interface speed.
=item B<--add-volume>
Check interface data volume between two checks (not supposed to be graphed, useful for BI reporting).
=item B<--check-metrics>
If the expression is true, metrics are checked (default: '%{opstatus} eq "up"').
=item B<--warning-status>
Define the conditions to match for the status to be WARNING.
You can use the following variables: %{admstatus}, %{opstatus}, %{duplexstatus}, %{display}
=item B<--critical-status>
Define the conditions to match for the status to be CRITICAL (default: '%{admstatus} eq "up" and %{opstatus} ne "up"').
You can use the following variables: %{admstatus}, %{opstatus}, %{duplexstatus}, %{display}
=item B<--warning-*> B<--critical-*>
Thresholds.
Can be: 'total-port', 'total-admin-up', 'total-admin-down', 'total-oper-up', 'total-oper-down',
'in-traffic', 'out-traffic', 'in-error', 'in-discard', 'out-error', 'out-discard',
'in-ucast', 'in-bcast', 'in-mcast', 'out-ucast', 'out-bcast', 'out-mcast',
'speed' (b/s).
=item B<--units-traffic>
Units of thresholds for the traffic (default: 'percent_delta') ('percent_delta', 'bps', 'counter').
=item B<--units-errors>
Units of thresholds for errors/discards (default: 'percent_delta') ('percent_delta', 'percent', 'delta', 'deltaps', 'counter').
=item B<--units-cast>
Units of thresholds for communication types (default: 'percent_delta') ('percent_delta', 'percent', 'delta', 'deltaps', 'counter').
=item B<--nagvis-perfdata>
Display traffic perfdata to be compatible with NagVis widget.
=item B<--interface>
Set the interface (number expected) example: 1,2,... (empty means 'check all interfaces').
=item B<--name>
Allows you to define the interface (in option --interface) by name instead of OID index. The name matching mode supports regular expressions.
=item B<--speed>
Set interface speed for incoming/outgoing traffic (in Mb).
=item B<--speed-in>
Set interface speed for incoming traffic (in Mb).
=item B<--speed-out>
Set interface speed for outgoing traffic (in Mb).
=item B<--map-speed-dsl>
Get interface speed configuration for interface type 'ADSL' and 'VDSL2'.
Syntax: --map-speed-dsl=interface-src-name,interface-dsl-name
E.g: --map-speed-dsl=Et0.835,Et0-vdsl2
=item B<--force-counters64>
Force to use 64 bits counters only. Can be used to improve performance.
=item B<--force-counters32>
Force to use 32 bits counters (even in SNMP version 2c and version 3). Should be used when 64 bits counters are buggy.
=item B<--reload-cache-time>
Time in minutes before reloading cache file (default: 180).
=item B<--oid-filter>
Define the OID to be used to filter interfaces (default: ifName) (values: ifDesc, ifAlias, ifName, IpAddr).
=item B<--oid-display>
Define the OID that will be used to name the interfaces (default: ifName) (values: ifDesc, ifAlias, ifName, IpAddr).
=item B<--oid-extra-display>
Add an OID to display.
=item B<--display-transform-src> B<--display-transform-dst>
Modify the interface name displayed by using a regular expression.
Example: adding --display-transform-src='eth' --display-transform-dst='ens' will replace all occurrences of 'eth' with 'ens'
=item B<--show-cache>
Display cache interface data.
=back
=cut

View File

@ -0,0 +1,105 @@
#
# Copyright 2024 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# 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.
#
package hardware::devices::camera::avigilon::snmp::mode::memory;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
sub custom_memory_output {
my ($self, %options) = @_;
my ($total_value, $total_unit) = $self->{perfdata}->change_bytes(value => $self->{result_values}->{total});
return sprintf(
'total system memory available: %s',
$total_value . " " . $total_unit
);
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'memory', type => 0 }
];
$self->{maps_counters}->{memory} = [
{ label => 'available', nlabel => 'memory.available', set => {
key_values => [{ name => 'total' }],
closure_custom_output => $self->can('custom_memory_output'),
perfdatas => [
{ value => 'total', template => '%d', min => 0,
unit => 'B', cast_int => 1, label_extra_instance => 1, instance_use => 'name' }
],
}
}
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
bless $self, $class;
$options{options}->add_options(arguments => {
});
return $self;
}
sub manage_selection {
my ($self, %options) = @_;
my $oid_total = '.1.3.6.1.4.1.46202.1.1.1.6.0'; #memAvailable
my $snmp_result = $options{snmp}->get_leef(
oids => [$oid_total],
nothing_quit => 1
);
$self->{memory} = {
total => $snmp_result->{$oid_total}
};
}
1;
__END__
=head1 MODE
Check system memory available.
=over 8
=item B<--warning-available*>
Warning threshold for total memory available (B).
=item B<--critical-available*>
Critical threshold for total memory available (B).
=back
=cut

View File

@ -0,0 +1,128 @@
#
# Copyright 2024 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# 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.
#
package hardware::devices::camera::avigilon::snmp::mode::storage;
use base qw(centreon::plugins::templates::counter);
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
use centreon::plugins::misc qw(is_empty);
use strict;
use warnings;
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'storage', type => 0 }
];
$self->{maps_counters}->{storage} = [
{ label => 'status',
type => 2,
unknown_default => '%{storage_state} =~ /Unknown/i',
warning_default => '%{storage_state} =~ /insufficientMediaCapacity/i || %{storage_state} =~ /insufficientMediaSpeed/i',
critical_default => '%{storage_state} =~ /mediaNotPresent/i || %{storage_state} =~ /error/i',
set => {
key_values => [{ name => 'storage_state' }],
output_template => 'state of the SD card: %s',
closure_custom_perfdata => sub { return 0; },
closure_custom_threshold_check => \&catalog_status_threshold_ng
}
}
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
bless $self, $class;
$options{options}->add_options(arguments => {
});
return $self;
}
sub manage_selection {
my ($self, %options) = @_;
my $storage_state_mapping = {
1 => 'mediaNotPresent',
2 => 'mediaDetected',
3 => 'existingDataOnMediaDetected',
4 => 'mediaFormatting',
5 => 'scanningForRecordings',
6 => 'readOnly',
7 => 'readyToRecord',
8 => 'recording',
9 => 'errorFormatting',
10 => 'errorWriting',
11 => 'insufficientMediaCapacity',
12 => 'insufficientMediaSpeed',
13 => 'error'
};
my $oid_storage_state = '.1.3.6.1.4.1.46202.1.1.1.5.0'; #storageState
my $snmp_result = $options{snmp}->get_leef(
oids => [$oid_storage_state],
nothing_quit => 1
);
if(centreon::plugins::misc::is_empty($storage_state_mapping->{$snmp_result->{$oid_storage_state}})==0){
$self->{storage} = {
storage_state => $storage_state_mapping->{$snmp_result->{$oid_storage_state}}
};
# If state is not in the mapping, return unkown
}else{
$self->{storage} = {
storage_state => "Unknown"
};
}
}
1;
__END__
=head1 MODE
Check storage state of the SD card.
=over 8
=item B<--unknown-status>
Define the conditions to match to return a unknown status (default: "%{storage_state} =~ /Unknown/i").
The condition can be written using the following macros: %{storage_state}.
=item B<--warning-status>
Define the conditions to match to return a warning status (default: "%{storage_state} =~ /insufficientMediaCapacity/i || %{storage_state} =~ /insufficientMediaSpeed/i").
The condition can be written using the following macros: %{storage_state}.
=item B<--critical-status>
Define the conditions to match to return a critical status (default: "%{storage_state} =~ /mediaNotPresent/i || %{storage_state} =~ /error/i").
The condition can be written using the following macros: %{storage_state}.
=back
=cut

View File

@ -0,0 +1,144 @@
#
# Copyright 2024 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# 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.
#
package hardware::devices::camera::avigilon::snmp::mode::temperature;
use base qw(centreon::plugins::templates::counter);
use strict;
use warnings;
use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng);
sub custom_status_output {
my ($self, %options) = @_;
return sprintf(
"sensor %s [type:%s] status: %s",
$self->{result_values}->{id},
$self->{result_values}->{type},
$self->{result_values}->{status}
);
}
sub set_counters {
my ($self, %options) = @_;
$self->{maps_counters_type} = [
{ name => 'sensors', type => 0 }
];
$self->{maps_counters}->{sensors} = [
{ label => 'temperature',
nlabel => 'sensor.temperature.celsius',
set => {
key_values => [{ name => 'temperature' }],
output_template => 'temperature: %.2f C',
perfdatas => [
{ template => '%s', min => 0, unit => 'C', label_extra_instance => 1, instance_use => 'id' }
]
}
},
{ label => 'status',
type => 2,
critical_default => '%{status} ne "ok"',
set => {
key_values => [{ name => 'status' }, { name => 'id' }, { name => 'type' }],
closure_custom_output => $self->can('custom_status_output'),
closure_custom_perfdata => sub { return 0; },
closure_custom_threshold_check => \&catalog_status_threshold_ng
}
}
];
}
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1);
bless $self, $class;
$options{options}->add_options(arguments => {
'filter-sensor-id:s' => { name => 'filter_id' }
});
return $self;
}
my $state_mapping = {
1 => 'ok',
2 => 'failure',
3 => 'outOfBoundary'
};
my $type_mapping = {
1 => 'mainSensor',
};
sub manage_selection {
my ($self, %options) = @_;
my $oid_type = '.1.3.6.1.4.1.46202.1.1.1.1.1.1'; # tempSensorType: The type of a temperature sensor, i.e. where it is mounted
my $oid_id = '.1.3.6.1.4.1.46202.1.1.1.1.1.2'; # tempSensorId: The unique identifier for a temperature sensor.
my $oid_status = '.1.3.6.1.4.1.46202.1.1.1.1.1.3'; # tempSensorStatus: The status of a temperature sensor.
my $oid_temperature = '.1.3.6.1.4.1.46202.1.1.1.1.1.4'; # tempSensorValue: The temperature as measured in degrees Celsius.
my $snmp_result = $options{snmp}->get_leef(
oids => [$oid_type, $oid_id, $oid_status, $oid_temperature],
nothing_quit => 1
);
$self->{sensors} = {
id => $snmp_result->{$oid_id},
type => $type_mapping->{$snmp_result->{$oid_type}},
status => $state_mapping->{$snmp_result->{$oid_status}},
temperature => $snmp_result->{$oid_temperature}
};
}
1;
__END__
=head1 MODE
Check temperature sensor state and value.
=over 8
=item B<--warning-status>
Define the conditions to match to return a warning status.
The condition can be written using the following macros: %{status}.
=item B<--critical-status>
Define the conditions to match to return a critical status (default: '%{status} ne "ok"').
The condition can be written using the following macros: %{status}.
=item B<--warning-temperature*>
Warning threshold for temperature (Celsius).
=item B<--critical-temperature*>
Critical threshold for temperature (Celsius).
=back
=cut

View File

@ -0,0 +1,52 @@
#
# Copyright 2024 Centreon (http://www.centreon.com/)
#
# Centreon is a full-fledged industry-strength solution that meets
# the needs in IT infrastructure and application monitoring for
# service performance.
#
# 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.
#
package hardware::devices::camera::avigilon::snmp::plugin;
use strict;
use warnings;
use base qw(centreon::plugins::script_snmp);
sub new {
my ($class, %options) = @_;
my $self = $class->SUPER::new(package => __PACKAGE__, %options);
bless $self, $class;
%{$self->{modes}} = (
'interfaces' => 'hardware::devices::camera::avigilon::snmp::mode::interfaces',
'list-interfaces' => 'snmp_standard::mode::listinterfaces',
'memory' => 'hardware::devices::camera::avigilon::snmp::mode::memory',
'storage' => 'hardware::devices::camera::avigilon::snmp::mode::storage',
'temperature' => 'hardware::devices::camera::avigilon::snmp::mode::temperature',
'uptime' => 'snmp_standard::mode::uptime',
);
return $self;
}
1;
__END__
=head1 PLUGIN DESCRIPTION
Check Avigilon camera in SNMP.
=cut

View File

@ -23,23 +23,34 @@ package network::citrix::netscaler::snmp::mode::components::psu;
use strict;
use warnings;
my %map_psu_status = (
0 => 'not supported',
1 => 'not present',
2 => 'failed',
3 => 'normal',
);
my $mapping = {
sysHealthCounterName => { oid => '.1.3.6.1.4.1.5951.4.1.1.41.7.1.1' },
sysHealthCounterValue => { oid => '.1.3.6.1.4.1.5951.4.1.1.41.7.1.2', map => \%map_psu_status },
};
my $oid_nsSysHealthEntry = '.1.3.6.1.4.1.5951.4.1.1.41.7.1';
sub load {}
sub check {
my ($self) = @_;
my %map_psu_status;
if (!$self->{option_results}->{alternative_status_mapping}) {
%map_psu_status = (
0 => 'not supported',
1 => 'not present',
2 => 'failed',
3 => 'normal',
);
} else {
%map_psu_status = (
0 => 'normal',
1 => 'not present',
2 => 'failed',
3 => 'not supported',
);
}
my $mapping = {
sysHealthCounterName => { oid => '.1.3.6.1.4.1.5951.4.1.1.41.7.1.1' },
sysHealthCounterValue => { oid => '.1.3.6.1.4.1.5951.4.1.1.41.7.1.2', map => \%map_psu_status },
};
$self->{output}->output_add(long_msg => "Checking power supplies");
$self->{components}->{psu} = {name => 'psus', total => 0, skip => 0};

Some files were not shown because too many files have changed in this diff Show More