diff --git a/.github/actions/deb-delivery-legacy/action.yml b/.github/actions/deb-delivery-legacy/action.yml index 3bdb630f4..8a89c964a 100644 --- a/.github/actions/deb-delivery-legacy/action.yml +++ b/.github/actions/deb-delivery-legacy/action.yml @@ -24,7 +24,7 @@ runs: using: "composite" steps: - name: Use cache DEB files - uses: actions/cache/restore@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + uses: actions/cache/restore@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./*.deb key: ${{ inputs.cache_key }} diff --git a/.github/actions/deb-delivery/action.yml b/.github/actions/deb-delivery/action.yml index 5af1b4eeb..846772d5e 100644 --- a/.github/actions/deb-delivery/action.yml +++ b/.github/actions/deb-delivery/action.yml @@ -21,30 +21,40 @@ runs: using: "composite" steps: - name: Remove previously delivered DEBs + if: ${{ ! (inputs.distrib == 'jammy' && inputs.stability == 'stable') }} run: rm -f ./*.deb shell: bash - name: Use cache DEB files - uses: actions/cache/restore@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + if: ${{ ! (inputs.distrib == 'jammy' && inputs.stability == 'stable') }} + uses: actions/cache/restore@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./*.deb key: ${{ inputs.cache_key }} fail-on-cache-miss: true - - uses: jfrog/setup-jfrog-cli@901bb9632db90821c2d3f076012bdeaf66598555 # v3.4.1 + - if: ${{ ! (inputs.distrib == 'jammy' && inputs.stability == 'stable') }} + uses: jfrog/setup-jfrog-cli@901bb9632db90821c2d3f076012bdeaf66598555 # v3.4.1 env: JF_URL: https://centreon.jfrog.io JF_ACCESS_TOKEN: ${{ inputs.artifactory_token }} - name: Publish DEBs to artifactory + if: ${{ ! (inputs.distrib == 'jammy' && inputs.stability == 'stable') }} run: | FILES="*.deb" + if [[ "${{ inputs.distrib }}" == "jammy" ]]; then + REPO_PREFIX="ubuntu" + else + REPO_PREFIX="apt" + fi + for FILE in $FILES; do echo "[DEBUG] - File: $FILE" ARCH=$(echo $FILE | cut -d '_' -f3 | cut -d '.' -f1) - jf rt upload "$FILE" "apt-plugins-${{ inputs.stability }}/pool/${{ inputs.module_name }}/" --deb "${{ inputs.distrib }}/main/$ARCH" + jf rt upload "$FILE" "${REPO_PREFIX}-plugins-${{ inputs.stability }}/pool/${{ inputs.module_name }}/" --deb "${{ inputs.distrib }}/main/$ARCH" done shell: bash diff --git a/.github/actions/package-nfpm/action.yml b/.github/actions/package-nfpm/action.yml index 5aa9d0a69..85f508669 100644 --- a/.github/actions/package-nfpm/action.yml +++ b/.github/actions/package-nfpm/action.yml @@ -10,6 +10,9 @@ inputs: distrib: description: The package distrib required: true + version: + description: The package version ([major_version].[minor_version]) + required: false major_version: description: The major version required: false @@ -18,7 +21,7 @@ inputs: required: false release: description: The package release number - required: false + required: true arch: description: The package architecture required: false @@ -37,6 +40,9 @@ inputs: rpm_gpg_signing_passphrase: description: The rpm gpg signing passphrase required: true + stability: + description: "Branch stability (stable, testing, unstable, canary)" + required: true runs: using: composite @@ -59,8 +65,15 @@ runs: RPM_GPG_SIGNING_KEY_ID: ${{ inputs.rpm_gpg_signing_key_id }} RPM_GPG_SIGNING_PASSPHRASE: ${{ inputs.rpm_gpg_signing_passphrase }} run: | - export MAJOR_VERSION="${{ inputs.major_version }}" - export VERSION="${{ inputs.major_version }}.${{ inputs.minor_version }}" + if [ -z ${{ inputs.version }} ]; then + export VERSION="${{ inputs.major_version }}.${{ inputs.minor_version }}" + export MAJOR_VERSION="${{ inputs.major_version }}" + export MINOR_VERSION="${{ inputs.minor_version }}" + elif [ -z ${{ inputs.major_version }} ]; then + export VERSION="${{ inputs.version }}" + export MAJOR_VERSION=$( echo $VERSION | cut -d "-" -f1 ) + export MINOR_VERSION=$( echo $VERSION | cut -d "-" -f2 ) + fi export RELEASE="${{ inputs.release }}" export ARCH="${{ inputs.arch }}" @@ -70,23 +83,28 @@ runs: export APACHE_GROUP="apache" else export DIST="" + if [ "${{ inputs.stability }}" == "unstable" ] || [ "${{ inputs.stability }}" == "canary" ]; then + export RELEASE="$RELEASE~${{ inputs.distrib }}" + elif [ "${{ inputs.stability }}" == "testing" ]; then + export RELEASE="1~${{ inputs.distrib }}" + fi export APACHE_USER="www-data" export APACHE_GROUP="www-data" fi - MAJOR_LEFT=$( echo $MAJOR_VERSION | cut -d "." -f1 ) - MAJOR_RIGHT=$( echo $MAJOR_VERSION | cut -d "-" -f1 | cut -d "." -f2 ) - BUMP_MAJOR_RIGHT=$(( MAJOR_RIGHT_PART + 1 )) - if [ "$MAJOR_RIGHT" = "04" ]; then - BUMP_MAJOR_LEFT="$MAJOR_LEFT" - BUMP_MAJOR_RIGHT="10" - else - BUMP_MAJOR_LEFT=$(( $MAJOR_LEFT + 1 )) - BUMP_MAJOR_RIGHT="04" + if [ -z "$MAJOR_VERSION" ]; then + MAJOR_LEFT=$( echo $VERSION | cut -d "." -f1 ) + MAJOR_RIGHT=$( echo $VERSION | cut -d "-" -f1 | cut -d "." -f2 ) + if [ "$MAJOR_RIGHT" == "04" ]; then + BUMP_MAJOR_LEFT="$MAJOR_LEFT" + BUMP_MAJOR_RIGHT="10" + else + BUMP_MAJOR_LEFT=$(( $MAJOR_LEFT + 1 )) + BUMP_MAJOR_RIGHT="04" + fi + export NEXT_MAJOR_VERSION="$BUMP_MAJOR_LEFT.$BUMP_MAJOR_RIGHT" fi - export NEXT_MAJOR_VERSION="$BUMP_MAJOR_LEFT.$BUMP_MAJOR_RIGHT" - export RPM_SIGNING_KEY_FILE="$(pwd)/key.gpg" export RPM_SIGNING_KEY_ID="$RPM_GPG_SIGNING_KEY_ID" export NFPM_RPM_PASSPHRASE="$RPM_GPG_SIGNING_PASSPHRASE" @@ -104,12 +122,18 @@ runs: done shell: bash - - name: Cache packages + - if: ${{ inputs.distrib == 'el7' }} uses: actions/cache/save@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 with: path: ./*.${{ inputs.package_extension }} key: ${{ inputs.cache_key }} + - if: ${{ inputs.distrib != 'el7' }} + uses: actions/cache/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + with: + path: ./*.${{ inputs.package_extension }} + key: ${{ inputs.cache_key }} + # Update if condition to true to get packages as artifacts - if: ${{ false }} name: Upload package artifacts diff --git a/.github/actions/package/action.yml b/.github/actions/package/action.yml deleted file mode 100644 index 114178f3d..000000000 --- a/.github/actions/package/action.yml +++ /dev/null @@ -1,85 +0,0 @@ -name: package -description: Package module using nfpm -inputs: - nfpm_file_pattern: - description: The pattern of the nfpm configuration file(s) - required: true - package_extension: - description: The package extension (deb or rpm) - required: true - distrib: - description: The package distrib - required: true - version: - description: The package version - required: false - release: - description: The package release number - required: false - commit_hash: - description: The commit hash - required: true - cache_key: - description: The package files cache key - required: true - rpm_gpg_key: - description: The rpm gpg key - required: true - rpm_gpg_signing_key_id: - description: The rpm gpg signing key identifier - required: true - rpm_gpg_signing_passphrase: - description: The rpm gpg signing passphrase - required: true - -runs: - using: composite - - steps: - - name: Import gpg key - env: - RPM_GPG_SIGNING_KEY: ${{ inputs.rpm_gpg_key }} - run: echo -n "$RPM_GPG_SIGNING_KEY" > key.gpg - shell: bash - - - name: Build ${{ inputs.package_extension }} files - env: - RPM_GPG_SIGNING_KEY_ID: ${{ inputs.rpm_gpg_signing_key_id }} - RPM_GPG_SIGNING_PASSPHRASE: ${{ inputs.rpm_gpg_signing_passphrase }} - run: | - export VERSION="${{ inputs.version }}" - export RELEASE="${{ inputs.release }}" - - if [ "${{ inputs.package_extension }}" = "rpm" ]; then - export DIST=".${{ inputs.distrib }}" - else - export DIST="" - fi - - export RPM_SIGNING_KEY_FILE="$(pwd)/key.gpg" - export RPM_SIGNING_KEY_ID="$RPM_GPG_SIGNING_KEY_ID" - export NFPM_RPM_PASSPHRASE="$RPM_GPG_SIGNING_PASSPHRASE" - - for FILE in ${{ inputs.nfpm_file_pattern }}; do - DIRNAME=$(dirname $FILE) - BASENAME=$(basename $FILE) - cd $DIRNAME - sed -i "s/@COMMIT_HASH@/${{ inputs.commit_hash }}/g" $BASENAME - nfpm package --config $BASENAME --packager ${{ inputs.package_extension }} - cd - - mv $DIRNAME/*.${{ inputs.package_extension }} ./ - done - shell: bash - - - name: Upload package artifacts - uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0 - with: - name: packages-${{ inputs.distrib }} - path: ./*.${{ inputs.package_extension }} - retention-days: 1 - - - name: Cache packages - uses: actions/cache/save@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 - with: - path: ./*.${{ inputs.package_extension }} - key: ${{ inputs.cache_key }} diff --git a/.github/actions/promote-to-stable/action.yml b/.github/actions/promote-to-stable/action.yml index 1a26c7a7d..91f445adb 100644 --- a/.github/actions/promote-to-stable/action.yml +++ b/.github/actions/promote-to-stable/action.yml @@ -60,7 +60,7 @@ runs: shell: bash - name: Promote DEB package to stable - if: ${{ startsWith(inputs.distrib, 'bullseye') }} + if: ${{ startsWith(inputs.distrib, 'bullseye') || startsWith(inputs.distrib, 'bookworm' }} run: | echo "[DEBUG] - Distrib: ${{ inputs.distrib }}" diff --git a/.github/actions/rpm-delivery-legacy/action.yml b/.github/actions/rpm-delivery-legacy/action.yml index f5ab84809..042a38b39 100644 --- a/.github/actions/rpm-delivery-legacy/action.yml +++ b/.github/actions/rpm-delivery-legacy/action.yml @@ -24,7 +24,7 @@ runs: using: "composite" steps: - name: Use cache RPM files - uses: actions/cache/restore@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + uses: actions/cache/restore@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./*.rpm key: ${{ inputs.cache_key }} diff --git a/.github/actions/rpm-delivery/action.yml b/.github/actions/rpm-delivery/action.yml index 45eabad40..b0ec29c49 100644 --- a/.github/actions/rpm-delivery/action.yml +++ b/.github/actions/rpm-delivery/action.yml @@ -25,7 +25,7 @@ runs: shell: bash - name: Use cache RPM files - uses: actions/cache/restore@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + uses: actions/cache/restore@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./*.rpm key: ${{ inputs.cache_key }} diff --git a/.github/docker/Dockerfile.packaging-plugins-bookworm b/.github/docker/Dockerfile.packaging-plugins-bookworm new file mode 100644 index 000000000..caf7d402a --- /dev/null +++ b/.github/docker/Dockerfile.packaging-plugins-bookworm @@ -0,0 +1,53 @@ +ARG REGISTRY_URL + +FROM ${REGISTRY_URL}/debian:bookworm + +ENV DEBIAN_FRONTEND noninteractive + +# fix locale +RUN bash -e <); +set_spell_cmd('hunspell -l'); +all_pod_files_spelling_ok($ARGV[0]); +close(FILE); \ No newline at end of file diff --git a/.github/scripts/stopwords.t b/.github/scripts/stopwords.t new file mode 100644 index 000000000..10acbc477 --- /dev/null +++ b/.github/scripts/stopwords.t @@ -0,0 +1,5 @@ +--force-counters32 +OID +oneaccess-sys-mib +SNMP +SSH diff --git a/.github/workflows/connector-vmware.yml b/.github/workflows/connector-vmware.yml index 0be147a0c..1fcfb7743 100644 --- a/.github/workflows/connector-vmware.yml +++ b/.github/workflows/connector-vmware.yml @@ -40,6 +40,12 @@ jobs: - package_extension: deb image: packaging-plugins-bullseye distrib: bullseye + - package_extension: deb + image: packaging-plugins-bookworm + distrib: bookworm + - package_extension: deb + image: packaging-plugins-jammy + distrib: jammy container: image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }} @@ -54,7 +60,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Package - uses: ./.github/actions/package + uses: ./.github/actions/package-nfpm with: nfpm_file_pattern: "connectors/vmware/packaging/centreon-plugin-virtualization-vmware-daemon.yaml" distrib: ${{ matrix.distrib }} @@ -66,6 +72,7 @@ jobs: rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} + stability: ${{ needs.get-environment.outputs.stability }} deliver-rpm: needs: @@ -100,7 +107,7 @@ jobs: strategy: matrix: - distrib: [bullseye] + distrib: [bullseye, bookworm, jammy] steps: - name: Checkout sources diff --git a/.github/workflows/docker-builder-packaging-plugins.yml b/.github/workflows/docker-builder-packaging-plugins.yml index dd95281c6..f55989d4b 100644 --- a/.github/workflows/docker-builder-packaging-plugins.yml +++ b/.github/workflows/docker-builder-packaging-plugins.yml @@ -37,6 +37,12 @@ jobs: - runner: ["self-hosted", "collect-arm64"] dockerfile: packaging-plugins-bullseye image: packaging-plugins-bullseye-arm64 + - runner: ubuntu-22.04 + dockerfile: packaging-plugins-bookworm + image: packaging-plugins-bookworm + - runner: ubuntu-22.04 + dockerfile: packaging-plugins-jammy + image: packaging-plugins-jammy runs-on: ${{ matrix.runner }} @@ -45,22 +51,22 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Login to Registry - uses: docker/login-action@465a07811f14bebb1938fbed4728c6a1ff8901fc # v2.2.0 + 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@465a07811f14bebb1938fbed4728c6a1ff8901fc # v2.2.0 + 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@885d1462b80bc1c1c7f0b00334ad271f09369c55 # v2.10.0 + - uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 - - uses: docker/build-push-action@1104d471370f9806843c095c1db02b5a90c5f8b6 # v3.3.1 + - uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0 with: file: .github/docker/Dockerfile.${{ matrix.dockerfile }} context: . diff --git a/.github/workflows/nrpe.yml b/.github/workflows/nrpe.yml index b76e986cc..c51017cdd 100644 --- a/.github/workflows/nrpe.yml +++ b/.github/workflows/nrpe.yml @@ -38,6 +38,12 @@ jobs: - package_extension: deb image: packaging-plugins-bullseye distrib: bullseye + - package_extension: deb + image: packaging-plugins-bookworm + distrib: bookworm + - package_extension: deb + image: packaging-plugins-jammy + distrib: jammy container: image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }} @@ -94,7 +100,7 @@ jobs: shell: bash - name: Package - uses: ./.github/actions/package + uses: ./.github/actions/package-nfpm with: nfpm_file_pattern: "nrpe/packaging/*.yaml" distrib: ${{ matrix.distrib }} @@ -106,6 +112,7 @@ jobs: rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} + stability: ${{ needs.get-environment.outputs.stability }} deliver-rpm: needs: [get-environment, package] @@ -136,7 +143,7 @@ jobs: strategy: matrix: - distrib: [bullseye] + distrib: [bullseye, bookworm, jammy] steps: - name: Checkout sources diff --git a/.github/workflows/perl-cpan-libraries.yml b/.github/workflows/perl-cpan-libraries.yml index 9a5df2dd3..19f4f2640 100644 --- a/.github/workflows/perl-cpan-libraries.yml +++ b/.github/workflows/perl-cpan-libraries.yml @@ -22,7 +22,7 @@ jobs: get-environment: uses: ./.github/workflows/get-environment.yml - package: + package-rpm: needs: [get-environment] if: ${{ needs.get-environment.outputs.stability != 'stable' }} @@ -30,7 +30,7 @@ jobs: strategy: fail-fast: false matrix: - distrib: [el8, el9, bullseye] + distrib: [el8, el9] name: [ "Authen::SASL::SASLprep", @@ -98,9 +98,8 @@ jobs: "ZMQ::LibZMQ4" ] include: - - build_distribs: "el8,el9,bullseye" + - build_distribs: "el8,el9" - rpm_dependencies: "" - - deb_dependencies: "" - rpm_provides: "" - version: "" - use_dh_make_perl: "true" @@ -111,30 +110,20 @@ jobs: - distrib: el9 package_extension: rpm image: packaging-plugins-alma9 - - distrib: bullseye - package_extension: deb - image: packaging-plugins-bullseye - name: "BSON" - build_distribs: "el8,el9" rpm_provides: "perl(BSON::Bytes) perl(BSON::Code) perl(BSON::DBRef) perl(BSON::OID) perl(BSON::Raw) perl(BSON::Regex) perl(BSON::Time) perl(BSON::Timestamp) perl(BSON::Types) perl(BSON)" - name: "BSON::XS" - build_distribs: "el8,el9" - name: "Convert::Binary::C" - build_distribs: "el8,el9" - name: "DateTime::Format::Duration::ISO8601" rpm_provides: "perl(DateTime-Format-Duration-ISO8601)" - name: "DBD::Sybase" - build_distribs: "el8,el9" - name: "Device::Modbus::RTU::Client" version: "0.022" - name: "Device::Modbus::TCP::Client" version: "0.026" - name: "EV" - build_distribs: "el8,el9" - name: "FFI::CheckLib" - build_distribs: "el8,el9" - name: "FFI::Platypus" - build_distribs: "el8,el9" rpm_provides: "perl(FFI::Platypus::Buffer) perl(FFI::Platypus::Memory)" - name: "Net::DHCP" rpm_provides: "perl(Net::DHCP::Constants) perl(Net::DHCP::Packet)" @@ -142,18 +131,15 @@ jobs: version: "0.53" - name: "UUID" use_dh_make_perl: "false" - build_distribs: "el8,el9" version: "0.31" - name: "ZMQ::Constants" - build_distribs: "el9,bullseye" + build_distribs: "el9" - name: "ZMQ::FFI" - build_distribs: "el8,el9" rpm_dependencies: "zeromq" - name: "ZMQ::LibZMQ4" use_dh_make_perl: "false" version: "0.01" rpm_dependencies: "zeromq" - deb_dependencies: "libzmq5" name: package ${{ matrix.distrib }} ${{ matrix.name }} container: image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }}:latest @@ -164,7 +150,7 @@ jobs: steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - if: ${{ contains(matrix.build_distribs, matrix.distrib) && matrix.package_extension == 'rpm' }} + - if: ${{ contains(matrix.build_distribs, matrix.distrib) }} run: | yum install -y yum-utils epel-release git yum config-manager --set-enabled crb || true # alma 9 @@ -172,7 +158,7 @@ jobs: yum install -y cpanminus rpm-build libcurl-devel libssh-devel expat-devel gcc ruby libuuid-devel zeromq-devel libxml2-devel libffi-devel perl-DBI perl-Net-Pcap freetds freetds-devel shell: bash - - if: ${{ contains(matrix.build_distribs, matrix.distrib) && matrix.package_extension == 'rpm' && matrix.spec_file == '' }} + - if: ${{ contains(matrix.build_distribs, matrix.distrib) && matrix.spec_file == '' }} run: | if [ -z "${{ matrix.version }}" ]; then PACKAGE_VERSION="" @@ -205,7 +191,7 @@ jobs: fpm -s cpan -t ${{ matrix.package_extension }} --rpm-dist ${{ matrix.distrib }} --verbose --cpan-verbose --no-cpan-test$PACKAGE_DEPENDENCIES$PACKAGE_PROVIDES$PACKAGE_VERSION ${{ matrix.name }} shell: bash - - if: ${{ contains(matrix.build_distribs, matrix.distrib) && matrix.package_extension == 'rpm' && matrix.spec_file != '' }} + - if: ${{ contains(matrix.build_distribs, matrix.distrib) && matrix.spec_file != '' }} run: | mkdir -p ~/rpmbuild/{BUILD,BUILDROOT,RPMS,SOURCES,SPECS,SRPMS} @@ -214,7 +200,111 @@ jobs: cp -r ~/rpmbuild/RPMS/noarch/*.rpm . shell: bash - - if: ${{ contains(matrix.build_distribs, matrix.distrib) && matrix.package_extension == 'deb' && matrix.use_dh_make_perl == 'false' }} + - uses: actions/upload-artifact@a8a3f3ad30e3422c9c7b888a15615d19a852ae32 # v3.1.3 + with: + name: packages-${{ matrix.package_extension }}-${{ matrix.distrib }} + path: ./*.${{ matrix.package_extension }} + retention-days: 1 + + package-deb: + needs: [get-environment] + if: ${{ needs.get-environment.outputs.stability != 'stable' }} + + runs-on: ubuntu-22.04 + strategy: + fail-fast: false + matrix: + distrib: [bullseye, bookworm, jammy] + name: + [ + "Authen::SASL::SASLprep", + "Authen::SCRAM::Client", + "boolean", + "Carp::Assert", + "Clone", + "Clone::Choose", + "common::sense", + "Convert::EBCDIC", + "Crypt::Blowfish_PP", + "DateTime::Format::Duration::ISO8601", + "Device::Modbus", + "Digest::MD5::File", + "Digest::SHA1", + "Email::Send::SMTP::Gmail", + "FFI::CheckLib", + "File::SearchPath", + "Hash::Merge", + "Hash::Ordered", + "HTTP::Daemon", + "HTTP::Daemon::SSL", + "HTTP::ProxyPAC", + "JMX::Jmx4Perl", + "JSON::Parse", + "JSON::WebToken", + "LV", + "MIME::Types", + "MongoDB", + "Net::FTPSSL", + "Net::HTTPTunnel", + "Net::NTP", + "Net::SMTPS", + "Net::SMTP_auth", + "Net::Subnet", + "Net::TFTP", + "PBKDF2::Tiny", + "Schedule::Cron", + "Statistics::Descriptive", + "Statistics::Regression", + "Sys::SigAction", + "Term::Clui", + "Term::ShellUI", + "Unicode::Stringprep", + "URI::Encode", + "URI::Template", + "URL::Encode", + "UUID::URandom", + "WWW::Selenium", + "XML::Filter::BufferText", + "XML::LibXML::Simple", + "XML::SAX::Writer", + "ZMQ::Constants", + "ZMQ::LibZMQ4" + ] + include: + - build_distribs: "bullseye,bookworm,jammy" + - deb_dependencies: "" + - rpm_provides: "" + - version: "" + - use_dh_make_perl: "true" + - spec_file: "" + - distrib: bullseye + package_extension: deb + image: packaging-plugins-bullseye + - distrib: bookworm + package_extension: deb + image: packaging-plugins-bookworm + - distrib: jammy + package_extension: deb + image: packaging-plugins-jammy + - name: "DateTime::Format::Duration::ISO8601" + - name: "Statistics::Regression" + version: "0.53" + - name: "ZMQ::Constants" + - name: "ZMQ::LibZMQ4" + use_dh_make_perl: "false" + version: "0.01" + deb_dependencies: "libzmq5" + name: package ${{ matrix.distrib }} ${{ matrix.name }} + container: + image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }}:latest + credentials: + username: ${{ secrets.DOCKER_REGISTRY_ID }} + password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} + + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - if: ${{ contains(matrix.build_distribs, matrix.distrib) && matrix.use_dh_make_perl == 'false' }} run: | apt update apt install -y cpanminus ruby libcurl4-openssl-dev libssh-dev uuid-dev libczmq-dev @@ -241,7 +331,7 @@ jobs: fpm -s cpan -t ${{ matrix.package_extension }} --deb-dist ${{ matrix.distrib }} --verbose --cpan-verbose --no-cpan-test -n $PACKAGE_NAME$PACKAGE_DEPENDENCIES$PACKAGE_VERSION ${{ matrix.name }} shell: bash - - if: ${{ contains(matrix.build_distribs, matrix.distrib) && matrix.package_extension == 'deb' && matrix.use_dh_make_perl == 'true' }} + - if: ${{ contains(matrix.build_distribs, matrix.distrib) && matrix.use_dh_make_perl == 'true' }} run: | apt update apt install -y cpanminus libcurl4-openssl-dev dh-make-perl libssh-dev uuid-dev libczmq-dev libmodule-install-perl @@ -262,7 +352,7 @@ jobs: retention-days: 1 sign-rpm: - needs: [package] + needs: [package-rpm] runs-on: ubuntu-22.04 strategy: @@ -293,24 +383,27 @@ jobs: - run: rpmsign --addsign ./*.rpm shell: bash - - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + - uses: actions/cache/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./*.rpm key: ${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} download-and-cache-deb: - needs: [package] + needs: [package-deb] runs-on: ubuntu-22.04 + strategy: + matrix: + distrib: [bullseye, bookworm, jammy] steps: - uses: actions/download-artifact@6b208ae046db98c579e8a3aa621ab581ff575935 # v4.1.1 with: - name: packages-deb-bullseye + name: packages-deb-${{ matrix.distrib }} path: ./ - - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + - uses: actions/cache/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./*.deb - key: ${{ github.sha }}-${{ github.run_id }}-deb-bullseye + key: ${{ github.sha }}-${{ github.run_id }}-deb-${{ matrix.distrib }} deliver-rpm: needs: [get-environment, sign-rpm] @@ -341,7 +434,7 @@ jobs: strategy: matrix: - distrib: [bullseye] + distrib: [bullseye, bookworm, jammy] steps: - name: Checkout sources @@ -362,7 +455,7 @@ jobs: runs-on: [self-hosted, common] strategy: matrix: - distrib: [el8, el9, bullseye] + distrib: [el8, el9, bullseye, bookworm] steps: - name: Checkout sources diff --git a/.github/workflows/perl-crypt-argon2.yml b/.github/workflows/perl-crypt-argon2.yml index bce1d7415..ae7c02b5e 100644 --- a/.github/workflows/perl-crypt-argon2.yml +++ b/.github/workflows/perl-crypt-argon2.yml @@ -46,6 +46,16 @@ jobs: package_extension: deb runner: ubuntu-22.04 arch: amd64 + - image: packaging-plugins-bookworm + distrib: bookworm + package_extension: deb + runner: ubuntu-22.04 + arch: amd64 + - image: packaging-plugins-jammy + distrib: jammy + package_extension: deb + runner: ubuntu-22.04 + arch: amd64 - image: packaging-plugins-bullseye-arm64 distrib: bullseye package_extension: deb @@ -68,7 +78,7 @@ jobs: - name: Install locally Crypt::Argon2 run: | - if [ "${{ matrix.distrib }}" = "bullseye" ]; then + if [[ "${{ matrix.package_extension }}" == "deb" ]]; then apt-get update apt-get install -y cpanminus gcc else @@ -80,7 +90,7 @@ jobs: - name: Set package name and paths according to distrib run: | - if [ "${{ matrix.distrib }}" = "bullseye" ]; then + if [[ "${{ matrix.package_extension }}" == "deb" ]]; then NAME="libcrypt-argon2-perl" if [ "${{ matrix.arch }}" = "amd64" ]; then PERL_VENDORARCH="/usr/lib/x86_64-linux-gnu/perl5/5.32" @@ -109,11 +119,13 @@ jobs: distrib: ${{ matrix.distrib }} package_extension: ${{ matrix.package_extension }} arch: ${{ matrix.arch }} + release: 3 commit_hash: ${{ github.sha }} - cache_key: cache-${{ github.sha }}-${{ matrix.package_extension}}-perl-crypt-argon2-${{ matrix.distrib }}-${{ matrix.arch }}-${{ github.head_ref || github.ref_name }} + cache_key: cache-${{ github.sha }}-${{ matrix.package_extension }}-perl-crypt-argon2-${{ matrix.distrib }}-${{ matrix.arch }}-${{ github.head_ref || github.ref_name }} rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} + stability: ${{ needs.get-environment.outputs.stability }} # set condition to true if artifacts are needed - if: ${{ false }} @@ -158,6 +170,10 @@ jobs: include: - distrib: bullseye arch: amd64 + - distrib: bookworm + arch: amd64 + - distrib: jammy + arch: amd64 - distrib: bullseye arch: arm64 @@ -189,6 +205,8 @@ jobs: arch: amd64 - distrib: bullseye arch: amd64 + - distrib: bookworm + arch: amd64 - distrib: bullseye arch: arm64 diff --git a/.github/workflows/perl-filesys-smbclient.yml b/.github/workflows/perl-filesys-smbclient.yml index 9d92daf0c..d18acd2cf 100644 --- a/.github/workflows/perl-filesys-smbclient.yml +++ b/.github/workflows/perl-filesys-smbclient.yml @@ -61,7 +61,7 @@ jobs: cp -r ~/rpmbuild/RPMS/x86_64/*.rpm . shell: bash - - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + - uses: actions/cache/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./*.rpm key: unsigned-${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} @@ -92,7 +92,7 @@ jobs: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + - uses: actions/cache/restore@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./*.rpm key: unsigned-${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} @@ -103,7 +103,7 @@ jobs: - run: rpmsign --addsign ./*.rpm shell: bash - - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + - uses: actions/cache/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./*.rpm key: ${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} @@ -138,7 +138,7 @@ jobs: DEB_BUILD_OPTIONS="nocheck nodocs notest noautodbgsym" dh-make-perl make --verbose --build --version 4.0-${{ matrix.distrib }} perl-filesys-smbclient/ shell: bash - - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + - uses: actions/cache/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./*.deb key: ${{ github.sha }}-${{ github.run_id }}-deb-${{ matrix.distrib }} diff --git a/.github/workflows/perl-json-path.yml b/.github/workflows/perl-json-path.yml index bb5adc4a7..0bb26794d 100644 --- a/.github/workflows/perl-json-path.yml +++ b/.github/workflows/perl-json-path.yml @@ -38,6 +38,12 @@ jobs: - image: packaging-plugins-bullseye distrib: bullseye package_extension: deb + - image: packaging-plugins-bookworm + distrib: bookworm + package_extension: deb + - image: packaging-plugins-jammy + distrib: jammy + package_extension: deb runs-on: ubuntu-22.04 @@ -55,7 +61,7 @@ jobs: - name: Install locally JSON::Path run: | - if [ "${{ matrix.distrib }}" = "bullseye" ]; then + if [[ "${{ matrix.package_extension }}" == "deb" ]]; then apt-get update apt-get install -y cpanminus gcc else @@ -72,7 +78,7 @@ jobs: - name: Set package name and paths according to distrib run: | VERSION="1.0.3" - if [ "${{ matrix.distrib }}" = "bullseye" ]; then + if [[ "${{ matrix.package_extension }}" == "deb" ]]; then NAME="libjson-path-perl" PERL_VENDORLIB="/usr/share/perl5" else @@ -98,12 +104,14 @@ jobs: nfpm_file_pattern: "dependencies/perl-json-path/perl-json-path.yaml" distrib: ${{ matrix.distrib }} package_extension: ${{ matrix.package_extension }} + release: 3 arch: all commit_hash: ${{ github.sha }} - cache_key: cache-${{ github.sha }}-${{ matrix.package_extension}}-perl-json-path-${{ matrix.distrib }}-${{ github.head_ref || github.ref_name }} + cache_key: cache-${{ github.sha }}-${{ matrix.package_extension }}-perl-json-path-${{ matrix.distrib }}-${{ github.head_ref || github.ref_name }} rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} + stability: ${{ needs.get-environment.outputs.stability }} # set condition to true if artifacts are needed - if: ${{ false }} @@ -145,8 +153,7 @@ jobs: strategy: matrix: - distrib: [bullseye] - + distrib: [bullseye, bookworm] name: Deliver ${{ matrix.distrib }} @@ -169,7 +176,7 @@ jobs: runs-on: [self-hosted, common] strategy: matrix: - distrib: [bullseye] + distrib: [bullseye, bookworm] steps: - name: Checkout sources diff --git a/.github/workflows/perl-keepass-reader.yml b/.github/workflows/perl-keepass-reader.yml index 1274b533d..8e2bcc56e 100644 --- a/.github/workflows/perl-keepass-reader.yml +++ b/.github/workflows/perl-keepass-reader.yml @@ -57,7 +57,7 @@ jobs: cp -r ~/rpmbuild/RPMS/noarch/*.rpm . shell: bash - - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + - uses: actions/cache/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./*.rpm key: unsigned-${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} @@ -88,7 +88,7 @@ jobs: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + - uses: actions/cache/restore@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./*.rpm key: unsigned-${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} @@ -99,7 +99,7 @@ jobs: - run: rpmsign --addsign ./*.rpm shell: bash - - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + - uses: actions/cache/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./*.rpm key: ${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} @@ -120,6 +120,10 @@ jobs: include: - image: bullseye distrib: bullseye + - image: bookworm + distrib: bookworm + - image: jammy + distrib: jammy name: package ${{ matrix.distrib }} container: image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/packaging-plugins-${{ matrix.image }}:latest @@ -140,7 +144,7 @@ jobs: DEB_BUILD_OPTIONS="nocheck nodocs notest noautodbgsym" dh-make-perl make -p libkeepass-reader-perl --verbose --build --version 0.2-${{ matrix.distrib }} perl-keepass-reader/ shell: bash - - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + - uses: actions/cache/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./*.deb key: ${{ github.sha }}-${{ github.run_id }}-deb-${{ matrix.distrib }} @@ -180,7 +184,7 @@ jobs: strategy: matrix: - distrib: [bullseye] + distrib: [bullseye, bookworm, jammy] steps: - name: Checkout sources @@ -201,7 +205,7 @@ jobs: runs-on: [self-hosted, common] strategy: matrix: - distrib: [el8, el9, bullseye] + distrib: [el8, el9, bullseye, bookworm] steps: - name: Checkout sources diff --git a/.github/workflows/perl-libssh-session.yml b/.github/workflows/perl-libssh-session.yml index 44b2051ed..63cc505ef 100644 --- a/.github/workflows/perl-libssh-session.yml +++ b/.github/workflows/perl-libssh-session.yml @@ -44,6 +44,16 @@ jobs: package_extension: deb runner: ubuntu-22.04 arch: amd64 + - image: packaging-plugins-bookworm + distrib: bookworm + package_extension: deb + runner: ubuntu-22.04 + arch: amd64 + - image: packaging-plugins-jammy + distrib: jammy + package_extension: deb + runner: ubuntu-22.04 + arch: amd64 - image: packaging-plugins-bullseye-arm64 distrib: bullseye package_extension: deb @@ -66,7 +76,7 @@ jobs: - name: Install locally Libssh::Session run: | - if [ "${{ matrix.distrib }}" = "bullseye" ]; then + if [[ "${{ matrix.package_extension }}" == "deb" ]]; then apt-get update apt-get install -y cpanminus gcc libssh-dev else @@ -78,7 +88,7 @@ jobs: - name: Set package name and paths according to distrib run: | - if [ "${{ matrix.distrib }}" = "bullseye" ]; then + if [[ "${{ matrix.package_extension }}" == "deb" ]]; then NAME="libssh-session-perl" if [ "${{ matrix.arch }}" = "amd64" ]; then PERL_VENDORARCH="/usr/lib/x86_64-linux-gnu/perl5/5.32" @@ -107,11 +117,13 @@ jobs: distrib: ${{ matrix.distrib }} package_extension: ${{ matrix.package_extension }} arch: ${{ matrix.arch }} + release: 4 commit_hash: ${{ github.sha }} - cache_key: cache-${{ github.sha }}-${{ matrix.package_extension}}-perl-libssh-session-${{ matrix.distrib }}-${{ matrix.arch }}-${{ github.head_ref || github.ref_name }} + cache_key: cache-${{ github.sha }}-${{ matrix.package_extension }}-perl-libssh-session-${{ matrix.distrib }}-${{ matrix.arch }}-${{ github.head_ref || github.ref_name }} rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} + stability: ${{ needs.get-environment.outputs.stability }} # set condition to true if artifacts are needed - if: ${{ false }} @@ -158,6 +170,10 @@ jobs: arch: amd64 - distrib: bullseye arch: arm64 + - distrib: bookworm + arch: amd64 + - distrib: jammy + arch: amd64 name: Deliver ${{ matrix.distrib }} ${{ matrix.arch }} @@ -187,6 +203,8 @@ jobs: arch: amd64 - distrib: bullseye arch: amd64 + - distrib: bookworm + arch: amd64 - distrib: bullseye arch: arm64 diff --git a/.github/workflows/perl-net-curl.yml b/.github/workflows/perl-net-curl.yml index e19efeb9f..3bf2fc9d7 100644 --- a/.github/workflows/perl-net-curl.yml +++ b/.github/workflows/perl-net-curl.yml @@ -44,6 +44,16 @@ jobs: package_extension: deb runner: ubuntu-22.04 arch: amd64 + - image: packaging-plugins-bookworm + distrib: bookworm + package_extension: deb + runner: ubuntu-22.04 + arch: amd64 + - image: packaging-plugins-jammy + distrib: jammy + package_extension: deb + runner: ubuntu-22.04 + arch: amd64 - image: packaging-plugins-bullseye-arm64 distrib: bullseye package_extension: deb @@ -66,7 +76,7 @@ jobs: - name: Install locally Net::Curl run: | - if [ "${{ matrix.distrib }}" = "bullseye" ]; then + if [[ "${{ matrix.package_extension }}" == "deb" ]]; then apt-get update apt-get install -y libcurl4-openssl-dev cpanminus gcc else @@ -78,7 +88,7 @@ jobs: - name: Set package name and paths according to distrib run: | - if [ "${{ matrix.distrib }}" = "bullseye" ]; then + if [[ "${{ matrix.package_extension }}" == "deb" ]]; then NAME="libnet-curl-perl" if [ "${{ matrix.arch }}" = "amd64" ]; then PERL_VENDORARCH="/usr/lib/x86_64-linux-gnu/perl5/5.32" @@ -108,10 +118,12 @@ jobs: package_extension: ${{ matrix.package_extension }} arch: ${{ matrix.arch }} commit_hash: ${{ github.sha }} - cache_key: cache-${{ github.sha }}-${{ matrix.package_extension}}-perl-net-curl-${{ matrix.distrib }}-${{ matrix.arch }}-${{ github.head_ref || github.ref_name }} + release: 3 + cache_key: cache-${{ github.sha }}-${{ matrix.package_extension }}-perl-net-curl-${{ matrix.distrib }}-${{ matrix.arch }}-${{ github.head_ref || github.ref_name }} rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} + stability: ${{ needs.get-environment.outputs.stability }} # set condition to true if artifacts are needed - if: ${{ false }} @@ -119,7 +131,7 @@ jobs: uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0 with: name: packages-${{ matrix.distrib }}-${{ matrix.arch }} - path: ./*.${{ matrix.package_extension}} + path: ./*.${{ matrix.package_extension }} retention-days: 1 deliver-rpm: @@ -156,6 +168,10 @@ jobs: include: - distrib: bullseye arch: amd64 + - distrib: bookworm + arch: amd64 + - distrib: jammy + arch: amd64 - distrib: bullseye arch: arm64 @@ -187,6 +203,8 @@ jobs: arch: amd64 - distrib: bullseye arch: amd64 + - distrib: bookworm + arch: amd64 - distrib: bullseye arch: arm64 diff --git a/.github/workflows/perl-openwsman.yml b/.github/workflows/perl-openwsman.yml index 3e74e157a..c64601535 100644 --- a/.github/workflows/perl-openwsman.yml +++ b/.github/workflows/perl-openwsman.yml @@ -45,6 +45,18 @@ jobs: runner: ubuntu-22.04 arch: amd64 version: 2.7.2 + - image: packaging-plugins-bookworm + distrib: bookworm + package_extension: deb + runner: ubuntu-22.04 + arch: amd64 + version: 2.7.2 + - image: packaging-plugins-jammy + distrib: jammy + package_extension: deb + runner: ubuntu-22.04 + arch: amd64 + version: 2.7.2 - image: packaging-plugins-bullseye-arm64 distrib: bullseye package_extension: deb @@ -68,7 +80,7 @@ jobs: - name: Install locally sblim-sfcc run: | - if [ "${{ matrix.distrib }}" = "bullseye" ]; then + if [[ "${{ matrix.package_extension }}" == "deb" ]]; then apt-get update apt-get install -y libcurl4-openssl-dev cd /tmp @@ -91,7 +103,7 @@ jobs: - name: Build openwsman run: | - if [ "${{ matrix.distrib }}" = "bullseye" ]; then + if [[ "${{ matrix.package_extension }}" == "deb" ]]; then apt-get install -y cmake libssl-dev libpam-dev swig libxml2-dev else dnf install -y wget cmake gcc-c++ libcurl-devel pam-devel swig libxml2-devel openssl-devel @@ -104,10 +116,11 @@ jobs: cd build cmake .. -DBUILD_PYTHON=No -DBUILD_PYTHON3=No -DBUILD_JAVA=No -DBUILD_RUBY=No -DBUILD_PERL=Yes make + shell: bash - name: Set package name and paths according to distrib run: | - if [ "${{ matrix.distrib }}" = "bullseye" ]; then + if [[ "${{ matrix.package_extension }}" == "deb" ]]; then NAME_PERL="libopenwsman-perl" USRLIB="/usr/lib/" if [ "${{ matrix.arch }}" = "amd64" ]; then @@ -138,18 +151,20 @@ jobs: shell: bash - name: Package sblim-sfcc - if: ${{ matrix.distrib == 'bullseye' }} + if: ${{ matrix.package_extension == 'deb' }} uses: ./.github/actions/package-nfpm with: nfpm_file_pattern: "dependencies/perl-openwsman/sblim-sfcc.yaml" distrib: ${{ matrix.distrib }} package_extension: ${{ matrix.package_extension }} arch: ${{ matrix.arch }} + release: 2 commit_hash: ${{ github.sha }} - cache_key: cache-${{ github.sha }}-${{ matrix.package_extension}}-sblim-sfcc-${{ matrix.distrib }}-${{ matrix.arch }}-${{ github.head_ref || github.ref_name }} + cache_key: cache-${{ github.sha }}-${{ matrix.package_extension }}-sblim-sfcc-${{ matrix.distrib }}-${{ matrix.arch }}-${{ github.head_ref || github.ref_name }} rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} + stability: ${{ needs.get-environment.outputs.stability }} - name: Package libwsman uses: ./.github/actions/package-nfpm @@ -158,11 +173,13 @@ jobs: distrib: ${{ matrix.distrib }} package_extension: ${{ matrix.package_extension }} arch: ${{ matrix.arch }} + release: 4 commit_hash: ${{ github.sha }} - cache_key: cache-${{ github.sha }}-${{ matrix.package_extension}}-libwsman-${{ matrix.distrib }}-${{ matrix.arch }}-${{ github.head_ref || github.ref_name }} + cache_key: cache-${{ github.sha }}-${{ matrix.package_extension }}-libwsman-${{ matrix.distrib }}-${{ matrix.arch }}-${{ github.head_ref || github.ref_name }} rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} + stability: ${{ needs.get-environment.outputs.stability }} - name: Package perl-openwsman uses: ./.github/actions/package-nfpm @@ -171,11 +188,13 @@ jobs: distrib: ${{ matrix.distrib }} package_extension: ${{ matrix.package_extension }} arch: ${{ matrix.arch }} + release: 4 commit_hash: ${{ github.sha }} - cache_key: cache-${{ github.sha }}-${{ matrix.package_extension}}-perl-openwsman-${{ matrix.distrib }}-${{ matrix.arch }}-${{ github.head_ref || github.ref_name }} + cache_key: cache-${{ github.sha }}-${{ matrix.package_extension }}-perl-openwsman-${{ matrix.distrib }}-${{ matrix.arch }}-${{ github.head_ref || github.ref_name }} rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} + stability: ${{ needs.get-environment.outputs.stability }} # set condition to true if artifacts are needed - if: ${{ false }} @@ -229,6 +248,10 @@ jobs: include: - distrib: bullseye arch: amd64 + - distrib: bookworm + arch: amd64 + - distrib: jammy + arch: amd64 - distrib: bullseye arch: arm64 @@ -278,6 +301,8 @@ jobs: arch: amd64 - distrib: bullseye arch: amd64 + - distrib: bookworm + arch: amd64 - distrib: bullseye arch: arm64 @@ -286,7 +311,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Promote sblim-sfcc ${{ matrix.distrib }} ${{ matrix.arch }} to stable - if: ${{ matrix.distrib == 'bullseye' }} + if: ${{ contains(fromJSON('["bullseye", "bookworm", "jammy"]'), matrix.distrib) }} uses: ./.github/actions/promote-to-stable with: artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} diff --git a/.github/workflows/perl-vmware-vsphere.yml b/.github/workflows/perl-vmware-vsphere.yml index b1847e802..2d16d5ebc 100644 --- a/.github/workflows/perl-vmware-vsphere.yml +++ b/.github/workflows/perl-vmware-vsphere.yml @@ -39,7 +39,7 @@ jobs: shell: bash - name: Cache vsphere cli sources - uses: actions/cache/save@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + uses: actions/cache/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: vmware-vsphere-cli-distrib key: ${{ github.sha }}-${{ github.run_id }}-sources-perl-vmware-vsphere @@ -47,6 +47,7 @@ jobs: package: needs: - get-sources + - get-environment runs-on: ubuntu-22.04 strategy: matrix: @@ -60,6 +61,12 @@ jobs: - package_extension: deb image: packaging-plugins-bullseye distrib: bullseye + - package_extension: deb + image: packaging-plugins-bookworm + distrib: bookworm + - package_extension: deb + image: packaging-plugins-jammy + distrib: jammy container: image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }} @@ -74,23 +81,25 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Import source files - uses: actions/cache/restore@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + uses: actions/cache/restore@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: vmware-vsphere-cli-distrib key: ${{ github.sha }}-${{ github.run_id }}-sources-perl-vmware-vsphere fail-on-cache-miss: true - name: Package - uses: ./.github/actions/package + uses: ./.github/actions/package-nfpm with: nfpm_file_pattern: "dependencies/perl-vmware-vsphere/packaging/perl-vmware-vsphere.yaml" distrib: ${{ matrix.distrib }} package_extension: ${{ matrix.package_extension }} commit_hash: ${{ github.sha }} + release: ${{ needs.get-environment.outputs.release }} cache_key: ${{ github.sha }}-${{ github.run_id }}-${{ matrix.package_extension }}-${{ matrix.distrib }} rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} + stability: ${{ needs.get-environment.outputs.stability }} deliver-rpm: needs: @@ -125,7 +134,7 @@ jobs: strategy: matrix: - distrib: [bullseye] + distrib: [bullseye, bookworm, jammy] steps: - name: Checkout sources diff --git a/.github/workflows/plink.yml b/.github/workflows/plink.yml index 36f3f4548..e5b55e53e 100644 --- a/.github/workflows/plink.yml +++ b/.github/workflows/plink.yml @@ -55,7 +55,7 @@ jobs: cp -r ~/rpmbuild/RPMS/x86_64/*.rpm . shell: bash - - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + - uses: actions/cache/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./*.rpm key: unsigned-${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} @@ -86,7 +86,7 @@ jobs: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + - uses: actions/cache/restore@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./*.rpm key: unsigned-${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} @@ -97,7 +97,7 @@ jobs: - run: rpmsign --addsign ./*.rpm shell: bash - - uses: actions/cache@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + - uses: actions/cache/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./*.rpm key: ${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} diff --git a/.github/workflows/plugin-delivery.yml b/.github/workflows/plugin-delivery.yml index e528995fd..6966f69b8 100644 --- a/.github/workflows/plugin-delivery.yml +++ b/.github/workflows/plugin-delivery.yml @@ -30,7 +30,7 @@ jobs: - name: Checkout sources uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: actions/cache/restore@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + - uses: actions/cache/restore@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./build/ key: fatpacked-plugins-${{ github.sha }}-${{ github.run_id }} @@ -96,7 +96,7 @@ jobs: strategy: fail-fast: false matrix: - distrib: [bullseye] + distrib: [bullseye, bookworm, jammy] steps: - name: Checkout sources diff --git a/.github/workflows/plugins-selinux.yml b/.github/workflows/plugins-selinux.yml index 4a771a394..0236b5aa0 100644 --- a/.github/workflows/plugins-selinux.yml +++ b/.github/workflows/plugins-selinux.yml @@ -55,7 +55,7 @@ jobs: shell: bash - name: Package - uses: ./.github/actions/package + uses: ./.github/actions/package-nfpm with: nfpm_file_pattern: "selinux/packaging/centreon-plugins-selinux.yaml" distrib: ${{ matrix.distrib }} @@ -67,6 +67,7 @@ jobs: rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} + stability: ${{ needs.get-environment.outputs.stability }} deliver-rpm: needs: [get-environment, package] diff --git a/.github/workflows/plugins.yml b/.github/workflows/plugins.yml index 74d80778f..d2287bdf0 100644 --- a/.github/workflows/plugins.yml +++ b/.github/workflows/plugins.yml @@ -33,7 +33,7 @@ jobs: with: fetch-depth: 0 - - uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236 # v4.7.1 + - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0 with: python-version: '3.9' @@ -93,7 +93,7 @@ jobs: fetch-depth: 1 - name: Prepare FatPacker - uses: shogo82148/actions-setup-perl@v1 + uses: shogo82148/actions-setup-perl@ea0507898383e7dbce382138da0c21af1849eb9e # v1.27.0 with: perl-version: '5.34' install-modules-with: cpm @@ -104,7 +104,7 @@ jobs: COMMIT=$(git log -1 HEAD --pretty=format:%h) perl .github/scripts/plugins-source.container.pl "${{ needs.get-plugins.outputs.plugins }}" "${{ needs.get-environment.outputs.version }} ($COMMIT)" - - uses: actions/cache/save@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + - uses: actions/cache/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./build/ key: fatpacked-plugins-${{ github.sha }}-${{ github.run_id }} @@ -129,6 +129,12 @@ jobs: - package_extension: deb image: packaging-plugins-bullseye distrib: bullseye + - package_extension: deb + image: packaging-plugins-bookworm + distrib: bookworm + - package_extension: deb + image: packaging-plugins-jammy + distrib: jammy container: image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }} @@ -141,13 +147,22 @@ jobs: steps: - name: Checkout sources if: ${{ matrix.distrib == 'el7' }} - uses: actions/checkout@v3 # el7 is not compatible with checkout v4 which uses node20 + # el7 is not compatible with checkout v4 which uses node20 + uses: actions/checkout@f43a0e5ff2bd294095638e18286ca9a3d1956744 # v3.6.0 - name: Checkout sources if: ${{ matrix.distrib != 'el7' }} uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: actions/cache/restore@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + - if: ${{ matrix.distrib == 'el7' }} + uses: actions/cache/restore@704facf57e6136b1bc63b828d79edcd491f0ee84 # v3.3.2 + with: + path: ./build/ + key: fatpacked-plugins-${{ github.sha }}-${{ github.run_id }} + fail-on-cache-miss: true + + - if: ${{ matrix.distrib != 'el7' }} + uses: actions/cache/restore@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 with: path: ./build/ key: fatpacked-plugins-${{ github.sha }}-${{ github.run_id }} @@ -213,7 +228,7 @@ jobs: done shell: bash - - uses: ./.github/actions/package + - uses: ./.github/actions/package-nfpm with: nfpm_file_pattern: ".github/packaging/*.yaml" distrib: ${{ matrix.distrib }} @@ -225,6 +240,7 @@ jobs: rpm_gpg_key: ${{ secrets.RPM_GPG_SIGNING_KEY }} rpm_gpg_signing_key_id: ${{ secrets.RPM_GPG_SIGNING_KEY_ID }} rpm_gpg_signing_passphrase: ${{ secrets.RPM_GPG_SIGNING_PASSPHRASE }} + stability: ${{ needs.get-environment.outputs.stability }} deliver: needs: [get-environment, package] diff --git a/.github/workflows/spellchecker.yml b/.github/workflows/spellchecker.yml new file mode 100644 index 000000000..cc82951bf --- /dev/null +++ b/.github/workflows/spellchecker.yml @@ -0,0 +1,54 @@ +name: spell-checker + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +on: + workflow_dispatch: + pull_request: + paths: + - '.github/workflows/spellchecker.yml' + - 'src/**' + - '.github/scripts/pod_spell_check.t' + +jobs: + pod-spell-check: + if: ${{ !contains(github.event.pull_request.labels.*.name, 'do-not-spell-check') }} + runs-on: ubuntu-22.04 + + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - uses: dorny/paths-filter@4512585405083f25c027a35db413c2b3b9006d50 # v2.11.1 + id: filter + with: + base: ${{ github.ref }} + list-files: shell + filters: | + plugins: + - added|modified: src/** + + - name: Install CPAN Libraries + uses: shogo82148/actions-setup-perl@ea0507898383e7dbce382138da0c21af1849eb9e # v1.27.0 + with: + perl-version: '5.34' + install-modules-with: cpm + install-modules: Test::More Test::Spelling + + - name: Install librairies + continue-on-error: true + run: | + sudo apt-get update + sudo apt-get install -y hunspell + shell: bash + + - name: Run spell check + id: run_check + run: | + set +e + for f in ${{ steps.filter.outputs.plugins_files }}; do + echo "perl .github/scripts/pod_spell_check.t $f" + output=$(perl .github/scripts/pod_spell_check.t $f) + done + shell: bash diff --git a/.github/workflows/tests-functional.yml b/.github/workflows/tests-functional.yml index ae06e4ba3..9b5235dd5 100644 --- a/.github/workflows/tests-functional.yml +++ b/.github/workflows/tests-functional.yml @@ -28,7 +28,7 @@ jobs: sudo apt-get install -qqy snmpsim - name: Install Node.js - uses: actions/setup-node@1a4442cacd436585916779262731d5b162bc6ec7 # v3.8.2 + uses: actions/setup-node@b39b52d1213e96004bfcb1c61a8a6fa8ab84f3e8 # v4.0.1 with: node-version: 16 @@ -36,7 +36,7 @@ jobs: run: npm install -g -D @mockoon/cli@3.1.0 - name: Install perl dependencies - uses: shogo82148/actions-setup-perl@v1 + uses: shogo82148/actions-setup-perl@ea0507898383e7dbce382138da0c21af1849eb9e # v1.27.0 with: perl-version: '5.34' install-modules-with: cpm @@ -55,7 +55,7 @@ jobs: JSON::XS - name: Install Python - uses: actions/setup-python@65d7f2d534ac1bc67fcd62888c5f4f3d2cb2b236 # v4.7.1 + uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0 with: python-version: '3.11' diff --git a/dependencies/perl-crypt-argon2/perl-crypt-argon2.yaml b/dependencies/perl-crypt-argon2/perl-crypt-argon2.yaml index 57945b531..943d069dd 100644 --- a/dependencies/perl-crypt-argon2/perl-crypt-argon2.yaml +++ b/dependencies/perl-crypt-argon2/perl-crypt-argon2.yaml @@ -3,7 +3,7 @@ arch: "${ARCH}" platform: "linux" version_schema: "none" version: "0.019" -release: "2${DIST}" +release: "${RELEASE}${DIST}" section: "default" priority: "optional" maintainer: "Centreon " diff --git a/dependencies/perl-json-path/perl-json-path.yaml b/dependencies/perl-json-path/perl-json-path.yaml index d44ed290a..8d968c366 100644 --- a/dependencies/perl-json-path/perl-json-path.yaml +++ b/dependencies/perl-json-path/perl-json-path.yaml @@ -3,7 +3,7 @@ arch: "${ARCH}" platform: "linux" version_schema: "none" version: "@VERSION@" -release: "2${DIST}" +release: "${RELEASE}${DIST}" section: "default" priority: "optional" maintainer: "Centreon " diff --git a/dependencies/perl-libssh-session/perl-libssh-session.yaml b/dependencies/perl-libssh-session/perl-libssh-session.yaml index b63ba2796..a1f9c7116 100644 --- a/dependencies/perl-libssh-session/perl-libssh-session.yaml +++ b/dependencies/perl-libssh-session/perl-libssh-session.yaml @@ -3,7 +3,7 @@ arch: "${ARCH}" platform: "linux" version_schema: "none" version: "0.8" -release: "3${DIST}" +release: "${RELEASE}${DIST}" section: "default" priority: "optional" maintainer: "Centreon " diff --git a/dependencies/perl-net-curl/perl-net-curl.yaml b/dependencies/perl-net-curl/perl-net-curl.yaml index 7648ba9e2..61cdfccf6 100644 --- a/dependencies/perl-net-curl/perl-net-curl.yaml +++ b/dependencies/perl-net-curl/perl-net-curl.yaml @@ -3,7 +3,7 @@ arch: "${ARCH}" platform: "linux" version_schema: "none" version: "0.54" -release: "2${DIST}" +release: "${RELEASE}${DIST}" section: "default" priority: "optional" maintainer: "Centreon " diff --git a/dependencies/perl-openwsman/libwsman.yaml b/dependencies/perl-openwsman/libwsman.yaml index 4af6428b4..637fe8395 100644 --- a/dependencies/perl-openwsman/libwsman.yaml +++ b/dependencies/perl-openwsman/libwsman.yaml @@ -3,7 +3,7 @@ arch: "${ARCH}" platform: "linux" version_schema: "none" version: "@VERSION@" -release: "1${DIST}" +release: "${RELEASE}${DIST}" section: "default" priority: "optional" maintainer: "Centreon " diff --git a/dependencies/perl-openwsman/perl-openwsman.yaml b/dependencies/perl-openwsman/perl-openwsman.yaml index 08572463a..b30faae46 100644 --- a/dependencies/perl-openwsman/perl-openwsman.yaml +++ b/dependencies/perl-openwsman/perl-openwsman.yaml @@ -3,7 +3,7 @@ arch: "${ARCH}" platform: "linux" version_schema: "none" version: "@VERSION@" -release: "3${DIST}" +release: "${RELEASE}${DIST}" section: "default" priority: "optional" maintainer: "Centreon " diff --git a/dependencies/perl-openwsman/sblim-sfcc.yaml b/dependencies/perl-openwsman/sblim-sfcc.yaml index a3be033e7..fe6cf25c8 100644 --- a/dependencies/perl-openwsman/sblim-sfcc.yaml +++ b/dependencies/perl-openwsman/sblim-sfcc.yaml @@ -3,7 +3,7 @@ arch: "${ARCH}" platform: "linux" version_schema: "none" version: "2.7.2" -release: "1${DIST}" +release: "${RELEASE}${DIST}" section: "default" priority: "optional" maintainer: "Centreon " diff --git a/doc/en/developer/guide.md b/doc/en/developer/guide.md index 9328a795f..8fbcb08e7 100644 --- a/doc/en/developer/guide.md +++ b/doc/en/developer/guide.md @@ -1,2211 +1,10 @@ -# Description - -This document introduces the best practices in the development of "centreon-plugins". - -As all plugins are written in Perl, “there is more than one way to do it”. -But to avoid reinventing the wheel, you should first take a look at the “example” directory, you will get an overview of how to build your own plugin and associated modes. - -There are 3 chapters: - -* [Quick Start](#quick-start) : Howto create file structure. -* [Libraries Reference](#libraries-reference) : API description. -* [Code Style Guidelines](#code-style-guidelines) : Follow it. -* [Model Classes Usage](#model-classes-usage) : description of classes you should use for your plugin. - -The lastest version is available on following git repository: https://github.com/centreon/centreon-plugins.git - -# TOC -- [Description](#description) -- [TOC](#toc) - - [Quick Start](#quick-start) - - [Directory creation](#directory-creation) - - [Plugin creation](#plugin-creation) - - [Mode creation](#mode-creation) - - [Commit and push](#commit-and-push) - - [Libraries reference](#libraries-reference) - - [Output](#output) - - [output_add](#output_add) - - [perfdata_add](#perfdata_add) - - [Perfdata](#perfdata) - - [get_perfdata_for_output](#get_perfdata_for_output) - - [threshold_validate](#threshold_validate) - - [threshold_check](#threshold_check) - - [change_bytes](#change_bytes) - - [Snmp](#snmp) - - [get_leef](#get_leef) - - [load](#load) - - [get_table](#get_table) - - [get_multiple_table](#get_multiple_table) - - [get_hostname](#get_hostname) - - [get_port](#get_port) - - [oid_lex_sort](#oid_lex_sort) - - [Misc](#misc) - - [trim](#trim) - - [change_seconds](#change_seconds) - - [backtick](#backtick) - - [execute](#execute) - - [windows_execute](#windows_execute) - - [Statefile](#statefile) - - [read](#read) - - [get](#get) - - [write](#write) - - [HTTP](#http) - - [connect](#connect) - - [DBI](#dbi) - - [connect](#connect-1) - - [query](#query) - - [fetchrow_array](#fetchrow_array) - - [fetchall_arrayref](#fetchall_arrayref) - - [fetchrow_hashref](#fetchrow_hashref) - - [Complete examples](#complete-examples) - - [Simple SNMP request](#simple-snmp-request) - - [Plugin file](#plugin-file) - - [Mode file](#mode-file) - - [Command line](#command-line) - - [Code Style Guidelines](#code-style-guidelines) - - [Indentation](#indentation) - - [Comments](#comments) - - [Subroutine & Variable Names](#subroutine--variable-names) - - [Curly Brackets, Parenthesis](#curly-brackets-parenthesis) - - [If/Else Statements](#ifelse-statements) - - [Model Classes Usage](#model-classes-usage) - - [Class counter](#class-counter) - - [When to use it ?](#when-to-use-it-) - - [Class methods](#class-methods) - - [Examples](#examples) - - [Example 1](#example-1) - - [Example 2](#example-2) - - [Example 3](#example-3) - - [Class hardware](#class-hardware) - -## Quick Start - ---- - -### Directory creation - ---- - -First of all, you need to create a directory on the git to store the new plugin. - -Root directories are organized by section: - -* Application : apps -* Database : database -* Hardware : hardware -* network equipment : network -* Operating System : os -* Storage equipment : storage - -According to the monitored object, it exists an organization which can use: - -* Type -* Constructor -* Model -* Monitoring Protocol - -For example, if you want to add a plugin to monitor Linux by SNMP, you need to create this directory: - -```shell - - $ mkdir -p os/linux/snmp - -``` - -You also need to create a "mode" directory for futures modes: - -```shell - - $ mkdir os/linux/snmp/mode - -``` - -### Plugin creation - -Once the directory is created, create the plugin file inside it: - -```shell - - $ touch plugin.pm - -``` - -Then, edit plugin.pm to add **license terms** by copying it from an other plugin. Don't forget to put your name at the end of it: - -```perl - - # ... - # Authors : <> - -``` - -Next, describe your **package** name : it matches your plugin directory. - -```perl - - package path::to::plugin; - -``` - -Declare used libraries (**strict** and **warnings** are mandatory). Centreon libraries are described later: - -```perl - - use strict; - use warnings; - use base qw(**centreon_library**); - -``` - -The plugin need a **new** constructor to instantiate the object: - -```perl - - sub new { - my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); - bless $self, $class; - - ... - - return $self; - } - -``` - -Plugin version must be declared in the **new** constructor: - -```perl - - $self->{version} = '0.1'; - -``` - -Several modes can be declared in the **new** constructor: - -```perl - - $self->{modes} = { - 'mode1' => '::mode::mode1', - 'mode2' => '::mode::mode2', - ... - }; - -``` - -Then, declare the module: - -```perl - - 1; - -``` - -A description of the plugin is needed to generate the documentation: - -```perl - - __END__ - - =head1 PLUGIN DESCRIPTION - - . - - =cut - -``` - -> **TIP**: You can copy-paste an other plugin.pm and adapt some lines (package, arguments...). - -> **TIP**: The plugin has ".pm" extension because it's a Perl module. So don't forget to add **1;** at the end of the file. - -## Mode creation - ---- - -Once **plugin.pm** is created and modes are declared in it, create modes in the **mode** directory: - -```shell - - cd mode - touch mode1.pm - -``` - -Then, edit mode1.pm to add **license terms** by copying it from an other mode. Don't forget to put your name at the end of it: - -```perl - - # ... - # Authors : <> - -``` - -Next, describe your **package** name: it matches your mode directory. - -```perl - - package path::to::plugin::mode::mode1; - -``` - -Declare used libraries (always the same): - -```perl - - use strict; - use warnings; - use base qw(centreon::plugins::mode); - -``` - -The mode needs a **new** constructor to instantiate the object: - -```perl - - sub new { - my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); - bless $self, $class; - - ... - - return $self; - } - -``` - -Mode version must be declared in the **new** constructor: - -```perl - - $self->{version} = '1.0'; - -``` - -Several options can be declared in the **new** constructor: - -```perl - - $options{options}->add_options(arguments => { - "option1:s" => { name => 'option1' }, - "option2:s" => { name => 'option2', default => 'value1' }, - "option3" => { name => 'option3' }, - }); - -``` - -Here is the description of arguments used in this example: - -* option1 : String value -* option2 : String value with default value "value1" -* option3 : Boolean value - -> **TIP** : You can have more informations about options format here: http://perldoc.perl.org/Getopt/Long.html - -The mode need a **check_options** method to validate options: - -```perl - - sub check_options { - my ($self, %options) = @_; - $self->SUPER::init(%options); - ... - } - -``` - -For example, Warning and Critical thresholds must be validate in **check_options** method: - -```perl - - if (($self->{perfdata}->threshold_validate(label => 'warning', value => $self->{option_results}->{warning})) == 0) { - $self->{output}->add_option_msg(short_msg => "Wrong warning threshold '" . $self->{option_results}->{warning} . "'."); - $self->{output}->option_exit(); - } - if (($self->{perfdata}->threshold_validate(label => 'critical', value => $self->{option_results}->{critical})) == 0) { - $self->{output}->add_option_msg(short_msg => "Wrong critical threshold '" . $self->{option_results}->{critical} . "'."); - $self->{output}->option_exit(); - } - -``` - -In this example, help is printed if thresholds do not have a correct format. - -Then comes the **run** method, where you perform measurement, check thresholds, display output and format performance datas. - -This is an example to check a SNMP value: - -```perl - - sub run { - my ($self, %options) = @_; - $self->{snmp} = $options{snmp}; - $self->{hostname} = $self->{snmp}->get_hostname(); - - my $result = $self->{snmp}->get_leef(oids => [$self->{option_results}->{oid}], nothing_quit => 1); - my $value = $result->{$self->{option_results}->{oid}}; - - my $exit = $self->{perfdata}->threshold_check(value => $value, - threshold => [ { label => 'critical', 'exit_litteral' => 'critical' }, { label => 'warning', exit_litteral => 'warning' } ]); - $self->{output}->output_add(severity => $exit, - short_msg => sprintf("SNMP Value is %s.", $value)); - - $self->{output}->perfdata_add(label => 'value', unit => undef, - value => $value, - warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning'), - critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical'), - min => undef, max => undef); - - $self->{output}->display(); - $self->{output}->exit(); - } - -``` - -In this example, we check a SNMP OID that we compare to warning and critical thresholds. -There are the methods which we use: - -* get_leef : get a SNMP value from an OID -* threshold_check : compare SNMP value to warning and critical thresholds -* output_add : add output -* perfdata_add : add perfdata to output -* display : display output -* exit : exit - -Then, declare the module: - -```perl - - 1; - -``` - -A description of the mode and its arguments is needed to generate the documentation: - -```perl - - __END__ - - =head1 PLUGIN DESCRIPTION - - . - - =cut - -``` - -## Commit and push - ---- - -Before committing the plugin, you need to create an **enhancement ticket** on the centreon-plugins forge : http://forge.centreon.com/projects/centreon-plugins - -Once plugin and modes are developed, you can commit (commit messages in english) and push your work: - -```shell - - git add path/to/plugin - git commit -m "Add new plugin for XXXX refs #" - git push - -``` - -## Libraries reference - ---- - -This chapter describes Centreon libraries which you can use in your development. - -### Output - ---- - -This library allows you to build output of your plugin. - -#### output_add - - -**Description** - -Add string to output (print it with **display** method). -If status is different than 'ok', output associated with 'ok' status is not printed. - -**Parameters** - -Parameter | Type | Default | Description -----------|--------|---------|-------------------------------------------- -severity | String | OK | Status of the output. -separator | String | \- | Separator between status and output string. -short_msg | String | | Short output (first line). -long_msg | String | | Long output (used with --verbose option). - -**Example** - -This is an example of how to manage output: - -```perl - - $self->{output}->output_add(severity => 'OK', - short_msg => 'All is ok'); - $self->{output}->output_add(severity => 'Critical', - short_msg => 'There is a critical problem'); - $self->{output}->output_add(long_msg => 'Port 1 is disconnected'); - - $self->{output}->display(); - -``` - -Output displays : - -``` - - CRITICAL - There is a critical problem - Port 1 is disconnected - -``` -#### perfdata_add - -**Description** - -Add performance data to output (print it with **display** method). -Performance data are displayed after '|'. - -**Parameters** - -Parameter | Type | Default | Description -----------|--------|---------|--------------------------------------- -label | String | | Label of the performance data. -value | Int | | Value of the performance data. -unit | String | | Unit of the performance data. -warning | String | | Warning threshold. -critical | String | | Critical threshold. -min | Int | | Minimum value of the performance data. -max | Int | | Maximum value of the performance data. - -**Example** - -This is an example of how to add performance data: - -```perl - - $self->{output}->output_add(severity => 'OK', - short_msg => 'Memory is ok'); - $self->{output}->perfdata_add(label => 'memory_used', - value => 30000000, - unit => 'B', - warning => '80000000', - critical => '90000000', - min => 0, - max => 100000000); - - $self->{output}->display(); - -``` - -Output displays : - -``` - - OK - Memory is ok | 'memory_used'=30000000B;80000000;90000000;0;100000000 - -``` - -### Perfdata - ---- - -This library allows you to manage performance data. - -#### get_perfdata_for_output - -**Description** - -Manage thresholds of performance data for output. - -**Parameters** - -Parameter | Type | Default | Description -----------|--------------|---------|---------------------------------------------------------- -**label** | String | | Threshold label. -total | Int | | Percent threshold to transform in global. -cast_int | Int (0 or 1) | | Cast absolute to int. -op | String | | Operator to apply to start/end value (uses with 'value'). -value | Int | | Value to apply with 'op' option. - -**Example** - -This is an example of how to manage performance data for output: - -```perl - - my $format_warning_perfdata = $self->{perfdata}->get_perfdata_for_output(label => 'warning', total => 1000000000, cast_int => 1); - my $format_critical_perfdata = $self->{perfdata}->get_perfdata_for_output(label => 'critical', total => 1000000000, cast_int => 1); - - $self->{output}->perfdata_add(label => 'memory_used', - value => 30000000, - unit => 'B', - warning => $format_warning_perfdata, - critical => $format_critical_perfdata, - min => 0, - max => 1000000000); - -``` - -> **TIP** : In this example, instead of print warning and critical thresholds in 'percent', the function calculates and prints these in 'bytes'. - -#### threshold_validate - -**Description** - -Validate and affect threshold to a label. - -**Parameters** - -Parameter | Type | Default | Description -----------|--------|---------|----------------- -label | String | | Threshold label. -value | String | | Threshold value. - -**Example** - -This example checks if warning threshold is correct: - -```perl - - if (($self->{perfdata}->threshold_validate(label => 'warning', value => $self->{option_results}->{warning})) == 0) { - $self->{output}->add_option_msg(short_msg => "Wrong warning threshold '" . $self->{option_results}->{warning} . "'."); - $self->{output}->option_exit(); - } - -``` - -> **TIP** : You can see the correct threshold format here: https://nagios-plugins.org/doc/guidelines.html#THRESHOLDFORMAT - -#### threshold_check - -**Description** - -Check performance data value with threshold to determine status. - -**Parameters** - -Parameter | Type | Default | Description -----------|--------------|---------|------------------------------------------------------- -value | Int | | Performance data value to compare. -threshold | String array | | Threshold label to compare and exit status if reached. - -**Example** - -This example checks if performance data reached thresholds: - -```perl - - $self->{perfdata}->threshold_validate(label => 'warning', value => 80); - $self->{perfdata}->threshold_validate(label => 'critical', value => 90); - my $prct_used = 85; - - my $exit = $self->{perfdata}->threshold_check(value => $prct_used, threshold => [ { label => 'critical', 'exit_litteral' => 'critical' }, { label => 'warning', exit_litteral => 'warning' } ]); - - $self->{output}->output_add(severity => $exit, - short_msg => sprint("Used memory is %i%%", $prct_used)); - $self->{output}->display(); - -``` - -Output displays : - -``` - - WARNING - Used memory is 85% | - -``` - -#### change_bytes - -**Description** - -Convert bytes to human readable unit. -Return value and unit. - -**Parameters** - -Parameter | Type | Default | Description -----------|------|---------|----------------------------------- -value | Int | | Performance data value to convert. -network | | 1024 | Unit to divide (1000 if defined). - -**Example** - -This example change bytes to human readable unit: - -```perl - - my ($value, $unit) = $self->{perfdata}->change_bytes(value => 100000); - - print $value.' '.$unit."\n"; - -``` - -Output displays : - -``` - - 100 KB - -``` - -### Snmp - ---- - -This library allows you to use SNMP protocol in your plugin. -To use it, add the following line at the beginning of your **plugin.pm**: - -```perl - - use base qw(centreon::plugins::script_snmp); - -``` - -#### get_leef - -**Description** - -Return hash table table of SNMP values for multiple OIDs (do not work with SNMP table). - -**Parameters** - -Parameter | Type | Default | Description --------------|--------------|---------|------------------------------------------------------ -**oids** | String array | | Array of OIDs to check (Can be set by 'load' method). -dont_quit | Int (0 or 1) | 0 | Don't quit even if an snmp error occured. -nothing_quit | Int (0 or 1) | 0 | Quit if no value is returned. - -**Example** - -This is an example of how to get 2 SNMP values: - -```perl - - my $oid_hrSystemUptime = '.1.3.6.1.2.1.25.1.1.0'; - my $oid_sysUpTime = '.1.3.6.1.2.1.1.3.0'; - - my $result = $self->{snmp}->get_leef(oids => [ $oid_hrSystemUptime, $oid_sysUpTime ], nothing_quit => 1); - - print $result->{$oid_hrSystemUptime}."\n"; - print $result->{$oid_sysUpTime}."\n"; - -``` -#### load - -**Description** - -Load a range of OIDs to use with **get_leef** method. - -**Parameters** - -Parameter | Type | Default | Description -----------------|--------------|---------|--------------------------------------------------------------- -**oids** | String array | | Array of OIDs to check. -instances | Int array | | Array of OID instances to check. -instance_regexp | String | | Regular expression to get instances from **instances** option. -begin | Int | | Instance to begin -end | Int | | Instance to end - -**Example** - -This is an example of how to get 4 instances of a SNMP table by using **load** method: - -```perl - - my $oid_dskPath = '.1.3.6.1.4.1.2021.9.1.2'; - - $self->{snmp}->load(oids => [$oid_dskPercentNode], instances => [1,2,3,4]); - - my $result = $self->{snmp}->get_leef(nothing_quit => 1); - - use Data::Dumper; - print Dumper($result); - -``` - -This is an example of how to get multiple instances dynamically (memory modules of Dell hardware) by using **load** method: - -```perl - - my $oid_memoryDeviceStatus = '.1.3.6.1.4.1.674.10892.1.1100.50.1.5'; - my $oid_memoryDeviceLocationName = '.1.3.6.1.4.1.674.10892.1.1100.50.1.8'; - my $oid_memoryDeviceSize = '.1.3.6.1.4.1.674.10892.1.1100.50.1.14'; - my $oid_memoryDeviceFailureModes = '.1.3.6.1.4.1.674.10892.1.1100.50.1.20'; - - my $result = $self->{snmp}->get_table(oid => $oid_memoryDeviceStatus); - $self->{snmp}->load(oids => [$oid_memoryDeviceLocationName, $oid_memoryDeviceSize, $oid_memoryDeviceFailureModes], - instances => [keys %$result], - instance_regexp => '(\d+\.\d+)$'); - - my $result2 = $self->{snmp}->get_leef(); - - use Data::Dumper; - print Dumper($result2); - -``` -#### get_table - -**Description** - -Return hash table of SNMP values for SNMP table. - -**Parameters** - -Parameter | Type | Default | Description --------------|--------------|---------|-------------------------------------------------------- -**oid** | String | | OID of the snmp table to check. -start | Int | | First OID to check. -end | Int | | Last OID to check. -dont_quit | Int (0 or 1) | 0 | Don't quit even if an SNMP error occured. -nothing_quit | Int (0 or 1) | 0 | Quit if no value is returned. -return_type | Int (0 or 1) | 0 | Return a hash table with one level instead of multiple. - -**Example** - -This is an example of how to get a SNMP table: - -```perl - - my $oid_rcDeviceError = '.1.3.6.1.4.1.15004.4.2.1'; - my $oid_rcDeviceErrWatchdogReset = '.1.3.6.1.4.1.15004.4.2.1.2.0'; - - my $results = $self->{snmp}->get_table(oid => $oid_rcDeviceError, start => $oid_rcDeviceErrWatchdogReset); - - use Data::Dumper; - print Dumper($results); - -``` - -#### get_multiple_table - -**Description** - - -Return hash table of SNMP values for multiple SNMP tables. - -**Parameters** - -Parameter | Type | Default | Description --------------|--------------|---------|----------------------------------------------------------- -**oids** | Hash table | | Hash table of OIDs to check (Can be set by 'load' method). - | | | Keys can be: "oid", "start", "end". -dont_quit | Int (0 or 1) | 0 | Don't quit even if an SNMP error occured. -nothing_quit | Int (0 or 1) | 0 | Quit if no value is returned. -return_type | Int (0 or 1) | 0 | Return a hash table with one level instead of multiple. - -**Example** - -This is an example of how to get 2 SNMP tables: - -```perl - - my $oid_sysDescr = ".1.3.6.1.2.1.1.1"; - my $aix_swap_pool = ".1.3.6.1.4.1.2.6.191.2.4.2.1"; - - my $results = $self->{snmp}->get_multiple_table(oids => [ - { oid => $aix_swap_pool, start => 1 }, - { oid => $oid_sysDescr }, - ]); - - use Data::Dumper; - print Dumper($results); - -``` - -#### get_hostname - -**Description** - -Get hostname parameter (useful to get hostname in mode). - -**Parameters** - -None. - -**Example** - -This is an example of how to get hostname parameter: - -```perl - - my $hostname = $self->{snmp}->get_hostname(); - -``` - -#### get_port - -**Description** - -Get port parameter (useful to get port in mode). - -**Parameters** - -None. - -**Example** - -This is an example of how to get port parameter: - -```perl - - my $port = $self->{snmp}->get_port(); - -``` - -#### oid_lex_sort - -**Description** - -Return sorted OIDs. - -**Parameters** - -Parameter | Type | Default | Description -----------|--------------|---------|----------------------- -**-** | String array | | Array of OIDs to sort. - -**Example** - -This example prints sorted OIDs: - -```perl - - foreach my $oid ($self->{snmp}->oid_lex_sort(keys %{$self->{results}->{$my_oid}})) { - print $oid; - } - -``` - -### Misc - ---- - -This library provides a set of miscellaneous methods. -To use it, you can directly use the path of the method: - -```perl - - centreon::plugins::misc::; - -``` - -#### trim - -**Description** - -Strip whitespace from the beginning and end of a string. - -**Parameters** - -Parameter | Type | Default | Description -----------|--------|---------|----------------- -**-** | String | | String to strip. - -**Example** - -This is an example of how to use **trim** method: - -```perl - - my $word = ' Hello world ! '; - my $trim_word = centreon::plugins::misc::trim($word); - - print $word."\n"; - print $trim_word."\n"; - -``` - -Output displays : -``` - - Hello world ! - -``` - -#### change_seconds - -**Description** - -Convert seconds to human readable text. - -**Parameters** - -Parameter | Type | Default | Description -----------|------|---------|------------------------------ -**-** | Int | | Number of seconds to convert. - -**Example** - -This is an example of how to use **change_seconds** method: - -```perl - - my $seconds = 3750; - my $human_readable_time = centreon::plugins::misc::change_seconds($seconds); - - print 'Human readable time : '.$human_readable_time."\n"; - -``` - -Output displays : -``` - - Human readable time : 1h 2m 30s - -``` - -#### backtick - -**Description** - -Execute system command. - -**Parameters** - -Parameter | Type | Default | Description -----------------|--------------|---------|---------------------------------------- -**command** | String | | Command to execute. -arguments | String array | | Command arguments. -timeout | Int | 30 | Command timeout. -wait_exit | Int (0 or 1) | 0 | Command process ignore SIGCHLD signals. -redirect_stderr | Int (0 or 1) | 0 | Print errors in output. - -**Example** - -This is an example of how to use **backtick** method: - -```perl - - my ($error, $stdout, $exit_code) = centreon::plugins::misc::backtick( - command => 'ls /home', - timeout => 5, - wait_exit => 1 - ); - - print $stdout."\n"; - -``` - -Output displays files in '/home' directory. - -#### execute - -**Description** - -Execute command remotely. - -**Parameters** - -Parameter | Type | Default | Description -----------------|--------|---------|---------------------------------------------------------------- -**output** | Object | | Plugin output ($self->{output}). -**options** | Object | | Plugin options ($self->{option_results}) to get remote options. -sudo | String | | Use sudo command. -**command** | String | | Command to execute. -command_path | String | | Command path. -command_options | String | | Command arguments. - -**Example** - -This is an example of how to use **execute** method. -We suppose ``--remote`` option is enabled: - -```perl - - my $stdout = centreon::plugins::misc::execute(output => $self->{output}, - options => $self->{option_results}, - sudo => 1, - command => 'ls /home', - command_path => '/bin/', - command_options => '-l'); - -``` -Output displays files in /home using ssh on a remote host. - -#### windows_execute - -**Description** - -Execute command on Windows. - -**Parameters** - -Parameter | Type | Default | Description -----------------|--------|---------|------------------------------------- -**output** | Object | | Plugin output ($self->{output}). -**command** | String | | Command to execute. -command_path | String | | Command path. -command_options | String | | Command arguments. -timeout | Int | | Command timeout. -no_quit | Int | | Don't quit even if an error occured. - -**Example** - -This is an example of how to use **windows_execute** method. - -```perl - - my $stdout = centreon::plugins::misc::windows_execute(output => $self->{output}, - timeout => 10, - command => 'ipconfig', - command_path => '', - command_options => '/all'); - -``` - -Output displays IP configuration on a Windows host. - -### Statefile - ---- - -This library provides a set of methods to use a cache file. -To use it, add the following line at the beginning of your **mode**: - -```perl - - use centreon::plugins::statefile; - -``` - -#### read - -**Description** - -Read cache file. - -**Parameters** - -Parameter | Type | Default | Description -------------------|--------|---------|----------------------------- -**statefile** | String | | Name of the cache file. -**statefile_dir** | String | | Directory of the cache file. -memcached | String | | Memcached server to use. - -**Example** - -This is an example of how to use **read** method: - -```perl - - $self->{statefile_value} = centreon::plugins::statefile->new(%options); - $self->{statefile_value}->check_options(%options); - $self->{statefile_value}->read(statefile => 'my_cache_file', - statefile_dir => '/var/lib/centreon/centplugins' - ); - - use Data::Dumper; - print Dumper($self->{statefile_value}); - -``` - -Output displays cache file and its parameters. - -#### get - -**Description** - -Get data from cache file. - -**Parameters** - -Parameter | Type | Default | Description -----------|--------|---------|----------------------------- -name | String | | Get a value from cache file. - -**Example** - -This is an example of how to use **get** method: - -```perl - - $self->{statefile_value} = centreon::plugins::statefile->new(%options); - $self->{statefile_value}->check_options(%options); - $self->{statefile_value}->read(statefile => 'my_cache_file', - statefile_dir => '/var/lib/centreon/centplugins' - ); - - my $value = $self->{statefile_value}->get(name => 'property1'); - print $value."\n"; - -``` - -Output displays value for 'property1' of the cache file. - -#### write - -**Description** - -Write data to cache file. - -**Parameters** - -Parameter | Type | Default | Description -----------|--------|---------|----------------------------- -data | String | | Data to write in cache file. - -**Example** - -This is an example of how to use **write** method: - -```perl - - $self->{statefile_value} = centreon::plugins::statefile->new(%options); - $self->{statefile_value}->check_options(%options); - $self->{statefile_value}->read(statefile => 'my_cache_file', - statefile_dir => '/var/lib/centreon/centplugins' - ); - - my $new_datas = {}; - $new_datas->{last_timestamp} = time(); - $self->{statefile_value}->write(data => $new_datas); - -``` - -Then, you can read the result in '/var/lib/centreon/centplugins/my_cache_file', timestamp is written in it. - -### HTTP - ---- - -This library provides a set of methodss to use HTTP protocol. -To use it, add the following line at the beginning of your **mode**: - -```perl - - use centreon::plugins::http; - -``` - -Some options must be set in **plugin.pm**: - - Option | Type | Description --------------|--------|-------------------------------------------------------- -**hostname** | String | IP Addr/FQDN of the webserver host. -**port** | String | HTTP port. -**proto** | String | Used protocol ('http' or 'https'). -credentials | | Use credentials. -ntlm | | Use NTLM authentication (if ``--credentials`` is used). -username | String | Username (if ``--credentials`` is used). -password | String | User password (if ``--credentials`` is used). -proxyurl | String | Proxy to use. -url_path | String | URL to connect (start to '/'). - -#### connect - -**Description** - -Test a connection to an HTTP url. -Return content of the webpage. - -**Parameters** - -This method use plugin options previously defined. - -**Example** - -This is an example of how to use **connect** method. - -We suppose these options are defined : -* --hostname = 'google.com' -* --urlpath = '/' -* --proto = 'http' -* --port = 80 - -```perl - - $self->{http} = centreon::plugins::http->new(output => $self->{output}, options => $self->{options}); - $self->{http}->set_options(%{$self->{option_results}}); - my $webcontent = $self->{http}->request(); - print $webcontent; - -``` - -Output displays content of the webpage '\http://google.com/'. - -### DBI - ---- - -This library allows you to connect to databases. -To use it, add the following line at the beginning of your **plugin.pm**: - -```perl - - use base qw(centreon::plugins::script_sql); - -``` - -#### connect - -**Description** - -Connect to databases. - -**Parameters** - -Parameter | Type | Default | Description -----------|--------------|---------|----------------------------------- -dontquit | Int (0 or 1) | 0 | Don't quit even if errors occured. - -**Example** - - -This is an example of how to use **connect** method. - -The format of the connection string can have the following forms: - -``` - DriverName:database_name - DriverName:database_name@hostname:port - DriverName:database=database_name;host=hostname;port=port -``` - -In plugin.pm: - -```perl - - $self->{sqldefault}->{dbi} = (); - $self->{sqldefault}->{dbi} = { data_source => 'mysql:host=127.0.0.1;port=3306' }; - -``` - -In your mode: - -```perl - - $self->{sql} = $options{sql}; - my ($exit, $msg_error) = $self->{sql}->connect(dontquit => 1); - -``` - -Then, you are connected to the MySQL database. - -#### query - -**Description** - -Send query to database. - -**Parameters** - -Parameter | Type | Default | Description -----------|--------|---------|------------------- -query | String | | SQL query to send. - -**Example** - -This is an example of how to use **query** method: - -```perl - - $self->{sql}->query(query => q{SHOW /*!50000 global */ STATUS LIKE 'Slow_queries'}); - my ($name, $result) = $self->{sql}->fetchrow_array(); - - print 'Name : '.$name."\n"; - print 'Value : '.$value."\n"; - -``` - -Output displays count of MySQL slow queries. - -#### fetchrow_array - -**Description** - -Return Array from sql query. - -**Parameters** - -None. - -**Example** - -This is an example of how to use **fetchrow_array** method: - -```perl - - $self->{sql}->query(query => q{SHOW /*!50000 global */ STATUS LIKE 'Uptime'}); - my ($dummy, $result) = $self->{sql}->fetchrow_array(); - - print 'Uptime : '.$result."\n"; - -``` - -Output displays MySQL uptime. - -#### fetchall_arrayref - -**Description** - -Return Array from SQL query. - -**Parameters** - -None. - -**Example** - -This is an example of how to use **fetchrow_array** method: - -```perl - - $self->{sql}->query(query => q{ - SELECT SUM(DECODE(name, 'physical reads', value, 0)), - SUM(DECODE(name, 'physical reads direct', value, 0)), - SUM(DECODE(name, 'physical reads direct (lob)', value, 0)), - SUM(DECODE(name, 'session logical reads', value, 0)) - FROM sys.v_$sysstat - }); - my $result = $self->{sql}->fetchall_arrayref(); - - my $physical_reads = @$result[0]->[0]; - my $physical_reads_direct = @$result[0]->[1]; - my $physical_reads_direct_lob = @$result[0]->[2]; - my $session_logical_reads = @$result[0]->[3]; - - print $physical_reads."\n"; - -``` - -Output displays physical reads on Oracle database. - -#### fetchrow_hashref - -**Description** - -Return Hash table from SQL query. - -**Parameters** - -None. - -**Example** - -This is an example of how to use **fetchrow_hashref** method: - -```perl - - $self->{sql}->query(query => q{ - SELECT datname FROM pg_database - }); - - while ((my $row = $self->{sql}->fetchrow_hashref())) { - print $row->{datname}."\n"; - } - -``` - -Output displays Postgres databases. - -## Complete examples - ---- - -### Simple SNMP request - ---- - -**Description** - - -This example explains how to check a single SNMP value on a PfSense firewall (memory dropped packets). -We use cache file because it's a SNMP counter. So we need to get the value between 2 checks. -We get the value and compare it to warning and critical thresholds. - -#### Plugin file - - -First, create the plugin directory and the plugin file: - -``` - - $ mkdir -p apps/pfsense/snmp - $ touch apps/pfsense/snmp/plugin.pm - -``` - -> **TIP** : PfSense is a firewall application and we check it using SNMP protocol - -Then, edit **plugin.pm** and add the following lines: - -```perl - - # - # Copyright 2018 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. - # - - # Path to the plugin - package apps::pfsense::snmp::plugin; - - # Needed libraries - use strict; - use warnings; - # Use this library to check using SNMP protocol - use base qw(centreon::plugins::script_snmp); - -``` - -> **TIP** : Don't forget to edit 'Authors' line. - -Add **new** method to instantiate the plugin: - -```perl - - sub new { - my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); - bless $self, $class; - # $options->{options} = options object - - # Plugin version - $self->{version} = '0.1'; - - # Modes association - %{$self->{modes}} = ( - # Mode name => path to the mode - 'memory-dropped-packets' => 'apps::pfsense::snmp::mode::memorydroppedpackets', - ); - - return $self; - } - -``` - -Declare this plugin as a perl module: - -```perl - - 1; - -``` - -Add a description to the plugin: - -```perl - - __END__ - - =head1 PLUGIN DESCRIPTION - - Check pfSense in SNMP. - - =cut - -``` - -> **TIP** : This description is printed with '--help' option. - - -#### Mode file - -Then, create the mode directory and the mode file: - -```shell - - $ mkdir apps/pfsense/snmp/mode - $ touch apps/pfsense/snmp/mode/memorydroppedpackets.pm - -``` - -Edit **memorydroppedpackets.pm** and add the following lines: - -```perl - - # - # Copyright 2018 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. - # - - # Path to the plugin - package apps::pfsense::snmp::mode::memorydroppedpackets; - - # Needed library for modes - use base qw(centreon::plugins::mode); - - # Needed libraries - use strict; - use warnings; - - # Custom library - use POSIX; - - # Needed library to use cache file - use centreon::plugins::statefile; - -``` - -Add **new** method to instantiate the mode: - -```perl - - sub new { - my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); - bless $self, $class; - - # Mode version - $self->{version} = '1.0'; - - # Declare options - $options{options}->add_options(arguments => - { - # option name => variable name - "warning:s" => { name => 'warning', }, - "critical:s" => { name => 'critical', }, - }); - - # Instantiate cache file - $self->{statefile_value} = centreon::plugins::statefile->new(%options); - return $self; - } - -``` - -> **TIP** : A default value can be added to options. - Example : "warning:s" => { name => 'warning', default => '80'}, - -Add **check_options** method to validate options: - -```perl - - sub check_options { - my ($self, %options) = @_; - $self->SUPER::init(%options); - - # Validate threshold options with threshold_validate method - if (($self->{perfdata}->threshold_validate(label => 'warning', value => $self->{option_results}->{warning})) == 0) { - $self->{output}->add_option_msg(short_msg => "Wrong warning threshold '" . $self->{option_results}->{warning} . "'."); - $self->{output}->option_exit(); - } - if (($self->{perfdata}->threshold_validate(label => 'critical', value => $self->{option_results}->{critical})) == 0) { - $self->{output}->add_option_msg(short_msg => "Wrong critical threshold '" . $self->{option_results}->{critical} . "'."); - $self->{output}->option_exit(); - } - - # Validate cache file options using check_options method of statefile library - $self->{statefile_value}->check_options(%options); - } - -``` - -Add **run** method to execute mode: - -```perl - - sub run { - my ($self, %options) = @_; - # $options{snmp} = snmp object - - # Get SNMP options - $self->{snmp} = $options{snmp}; - $self->{hostname} = $self->{snmp}->get_hostname(); - $self->{snmp_port} = $self->{snmp}->get_port(); - - # SNMP oid to request - my $oid_pfsenseMemDropPackets = '.1.3.6.1.4.1.12325.1.200.1.2.6.0'; - my ($result, $value); - - # Get SNMP value for oid previsouly defined - $result = $self->{snmp}->get_leef(oids => [ $oid_pfsenseMemDropPackets ], nothing_quit => 1); - # $result is a hash table where keys are oids - $value = $result->{$oid_pfsenseMemDropPackets}; - - # Read the cache file - $self->{statefile_value}->read(statefile => 'pfsense_' . $self->{hostname} . '_' . $self->{snmp_port} . '_' . $self->{mode}); - # Get cache file values - my $old_timestamp = $self->{statefile_value}->get(name => 'last_timestamp'); - my $old_memDropPackets = $self->{statefile_value}->get(name => 'memDropPackets'); - - # Create a hash table with new values that will be write to cache file - my $new_datas = {}; - $new_datas->{last_timestamp} = time(); - $new_datas->{memDropPackets} = $value; - - # Write new values to cache file - $self->{statefile_value}->write(data => $new_datas); - - # If cache file didn't have any values, create it and wait another check to calculate value - if (!defined($old_timestamp) || !defined($old_memDropPackets)) { - $self->{output}->output_add(severity => 'OK', - short_msg => "Buffer creation..."); - $self->{output}->display(); - $self->{output}->exit(); - } - - # Fix when PfSense reboot (snmp counters initialize to 0) - $old_memDropPackets = 0 if ($old_memDropPackets > $new_datas->{memDropPackets}); - - # Calculate time between 2 checks - my $delta_time = $new_datas->{last_timestamp} - $old_timestamp; - $delta_time = 1 if ($delta_time == 0); - - # Calculate value per second - my $memDropPacketsPerSec = ($new_datas->{memDropPackets} - $old_memDropPackets) / $delta_time; - - # Calculate exit code by comparing value to thresholds - # Exit code can be : 'OK', 'WARNING', 'CRITICAL', 'UNKNOWN' - my $exit_code = $self->{perfdata}->threshold_check(value => $memDropPacketsPerSec, - threshold => [ { label => 'critical', 'exit_litteral' => 'critical' }, { label => 'warning', exit_litteral => 'warning' } ]); - - # Add a performance data - $self->{output}->perfdata_add(label => 'dropped_packets_Per_Sec', - value => sprintf("%.2f", $memDropPacketsPerSec), - warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning'), - critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical'), - min => 0); - - # Add output - $self->{output}->output_add(severity => $exit_code, - short_msg => sprintf("Dropped packets due to memory limitations : %.2f /s", - $memDropPacketsPerSec)); - - # Display output - $self->{output}->display(); - $self->{output}->exit(); - } - -``` - -Declare this plugin as a perl module: - -```perl - - 1; - -``` - -Add a description of the mode options: - -```perl - - __END__ - - =head1 MODE - - Check number of packets per second dropped due to memory limitations. - - =over 8 - - =item B<--warning> - - Warning threshold for dropped packets in packets per second. - - =item B<--critical> - - Critical threshold for dropped packets in packets per second. - - =back - - =cut - -``` - -#### Command line - -This is an example of command line: - -``` - - $ perl centreon_plugins.pl --plugin apps::pfsense::snmp::plugin --mode memory-dropped-packets --hostname 192.168.0.1 --snmp-community 'public' --snmp-version '2c' --warning '1' --critical '2' - -``` - -Output may display: - -``` - - OK: Dropped packets due to memory limitations : 0.00 /s | dropped_packets_Per_Sec=0.00;0;;1;2 - -``` - -## Code Style Guidelines - ---- - -**Introduction** - -Perl code from Pull-request must conform to the following style guidelines. If you find any code which doesn't conform, please fix it. - -### Indentation - - -Space should be used to indent all code blocks. Tabs should never be used to indent code blocks. Mixing tabs and spaces results in misaligned code blocks for other developers who prefer different indentation settings. -Please use 4 for indentation space width. - -```perl - - if ($1 > 1) { - ....return 1; - } else { - if ($i == -1) { - ....return 0; - } - return -1 - } - -``` - -### Comments - -There should always be at least 1 space between the # character and the beginning of the comment. This makes it a little easier to read multi-line comments: - -```perl - - # Good comment - #Wrong comment - -``` - -### Subroutine & Variable Names - -Whenever possible, use underscore to seperator words and don't use uppercase characters: - -```perl - - sub get_logs {} - my $start_time; - -``` - -Keys of hash table should be used alphanumeric and underscore characters only (and no quote!): - -```perl - - $dogs->{meapolitan_mastiff} = 10; - -``` - -### Curly Brackets, Parenthesis - -There should be a space between every control/loop keyword and the opening parenthesis: - -```perl - - if ($i == 1) { - ... - } - while ($i == 2) { - ... - } - -``` - -### If/Else Statements - -'else', 'elsif' should be on the same line after the previous closing curly brace: - -```perl - - if ($i == 1) { - ... - } else { - ... - } - -``` - -You can use single line if conditional: - -```perl - - next if ($i == 1); - -``` - -## Model Classes Usage - ---- -**Introduction** - -With the experience of plugin development, we have created two classes: - -* centreon::plugins::templates::counter -* centreon::plugins::templates::hardware - -It was developed to have a more consistent code and less redundant code. According to context, you should use one of two classes for modes. -Following classes can be used for whatever plugin type (SNMP, Custom, DBI,...). - -### Class counter - -#### When to use it ? - -If you have some counters (CPU Usage, Memory, Session...), you should use that class. -If you have only one global counter to check, it's maybe not useful to use it (but only for these case). - -#### Class methods - -List of methods: - -* **new**: class constructor. Overload if you need to add some specific options or to use a statefile. -* **check_options**: overload if you need to check your specific options. -* **manage_selection**: overload if *mandatory*. Method to get informations for the equipment. -* **set_counters**: overload if **mandatory**. Method to configure counters. - -## Examples - ---- - -### Example 1 - - -We want to develop the following SNMP plugin: - -* measure the current sessions and current SSL sessions usages. - -```perl - - package my::module::name; - - use base qw(centreon::plugins::templates::counter); - - use strict; - use warnings; - - sub set_counters { - my ($self, %options) = @_; - - $self->{maps_counters_type} = [ - { name => 'global', type => 0, message_separator => ' - ' }, - ]; - $self->{maps_counters}->{global} = [ - { label => 'sessions', set => { - key_values => [ { name => 'sessions' } ], - output_template => 'Current sessions : %s', - perfdatas => [ - { label => 'sessions', template => '%s', min => 0 }, - ], - } - }, - { label => 'sessions-ssl', set => { - key_values => [ { name => 'sessions_ssl' } ], - output_template => 'Current ssl sessions : %s', - perfdatas => [ - { label => 'sessions_ssl', template => '%s', min => 0 }, - ], - } - }, - ]; - } - - sub manage_selection { - my ($self, %options) = @_; - - # OIDs are fake. Only for the example. - my ($oid_sessions, $oid_sessions_ssl) = ('.1.2.3.4.0', '.1.2.3.5.0'); - - my $result = $options{snmp}->get_leef( - oids => [ $oid_sessions, $oid_sessions_ssl ], - nothing_quit => 1 - ); - $self->{global} = { - sessions => $result->{$oid_sessions}, - sessions_ssl => $result->{$oid_sessions_ssl} - }; - } - -``` - -Output may display: - -``` - - OK: Current sessions : 24 - Current ssl sessions : 150 | sessions=24;;;0; sessions_ssl=150;;;0; - -``` - -As you can see, we create two arrays of hash tables in **set_counters** method. We use arrays to order the output. - -* **maps_counters_type**: global configuration. Attributes list: - - * *name*: the name is really important. It will be used in hash **map_counters** and also in **manage_selection** as you can see. - * *type*: 0 or 1. With 0 value, the output will be written in the short output. With the value 1, it depends if we have one or multiple instances. - * *message_multiple*: only useful with *type* 1 value. The message will be displayed in short ouput if we have multiple instances selected. - * *message_separator*: the string displayed between counters (Default: ', '). - * *cb_prefix_output*, *cb_suffix_output*: name of a method (in a string) to callback. Methods will return a string to be displayed before or after **all** counters. - * *cb_init*: name of a method (in a string) to callback. Method will return 0 or 1. With 1 value, counters are not checked. - -* **maps_counters**: complex structure to configure counters. Attributes list: - - * *label*: name used for threshold options. - * *threshold*: if we set the value to 0. There is no threshold check options (can be used if you want to set and check option yourself). - * *set*: hash table: - - * *keys_values*: array of hashes. Set values used for the counter. Order is important (by default, the first value is used to check). - - * *name*: attribute name. Need to match with attributes in **manage_selection** method! - * *diff*: if we set the value to 1, we'll have the difference between two checks (need a statefile!). - * *per_second*: if we set the value to 1, the *diff* values will be calculated per seconds (need a statefile!). No need to add diff attribute. - - * *output_template*: string to display. '%s' will be replaced by the first value of *keys_values*. - * *output_use*: which value to be used in *output_template* (If not set, we use the first value of *keys_values*). - * *output_change_bytes*: if we set the value to 1 or 2, we can use a second '%s' in *output_template* to display the unit. 1 = divide by 1024 (Bytes), 2 = divide by 1000 (bits). - * *perfdata*: array of hashes. To configure perfdatas - - * *label*: name displayed. - * *value*: value to used. It's the name from *keys_values*. - * *template*: value format (could be for example: '%.3f'). - * *unit*: unit displayed. - * *min*, *max*: min and max displayed. You can use a value from *keys_values*. - * *label_extra_instance*: if we set the value to 1, perhaps we'll have a suffix concat with *label*. - * *instance_use*: which value from *keys_values* to be used. To be used if *label_extra_instance* is 1. - -### Example 2 - -We want to add the current number of sessions by virtual servers. - -```perl - - package my::module::name; - - use base qw(centreon::plugins::templates::counter); - - use strict; - use warnings; - - sub set_counters { - my ($self, %options) = @_; - - $self->{maps_counters_type} = [ - { name => 'global', type => 0, cb_prefix_output => 'prefix_global_output' }, - { name => 'vs', type => 1, cb_prefix_output => 'prefix_vs_output', message_multiple => 'All Virtual servers are ok' } - ]; - $self->{maps_counters}->{global} = [ - { label => 'total-sessions', set => { - key_values => [ { name => 'sessions' } ], - output_template => 'current sessions : %s', - perfdatas => [ - { label => 'total_sessions', template => '%s', min => 0 }, - ], - } - }, - { label => 'total-sessions-ssl', set => { - key_values => [ { name => 'sessions_ssl' } ], - output_template => 'current ssl sessions : %s', - perfdatas => [ - { label => 'total_sessions_ssl', template => '%s', min => 0 }, - ], - } - }, - ]; - - $self->{maps_counters}->{vs} = [ - { label => 'sessions', set => { - key_values => [ { name => 'sessions' }, { name => 'display' } ], - output_template => 'current sessions : %s', - perfdatas => [ - { label => 'sessions', template => '%s', - min => 0, label_extra_instance => 1, instance_use => 'display' }, - ], - } - }, - { label => 'sessions-ssl', set => { - key_values => [ { name => 'sessions_ssl' }, { name => 'display' } ], - output_template => 'current ssl sessions : %s', - perfdatas => [ - { label => 'sessions_ssl', template => '%s', - min => 0, label_extra_instance => 1, instance_use => 'display' }, - ], - } - }, - ]; - } - - sub prefix_vs_output { - my ($self, %options) = @_; - - return "Virtual server '" . $options{instance_value}->{display} . "' "; - } - - sub prefix_global_output { - my ($self, %options) = @_; - - return "Total "; - } - - sub manage_selection { - my ($self, %options) = @_; - - # OIDs are fake. Only for the example. - my ($oid_sessions, $oid_sessions_ssl) = ('.1.2.3.4.0', '.1.2.3.5.0'); - - my $result = $options{snmp}->get_leef(oids => [ $oid_sessions, $oid_sessions_ssl ], - nothing_quit => 1); - $self->{global} = { sessions => $result->{$oid_sessions}, - sessions_ssl => $result->{$oid_sessions_ssl} - }; - my $oid_table_vs = '.1.2.3.10'; - my $mapping = { - vsName => { oid => '.1.2.3.10.1' }, - vsSessions => { oid => '.1.2.3.10.2' }, - vsSessionsSsl => { oid => '.1.2.3.10.3' }, - }; - - $self->{vs} = {}; - $result = $options{snmp}->get_table(oid => $oid_table_vs, - nothing_quit => 1); - foreach my $oid (keys %{$result->{ $oid_table_vs }}) { - next if ($oid !~ /^$mapping->{vsName}->{oid}\.(.*)$/; - my $instance = $1; - my $data = $options{snmp}->map_instance(mapping => $mapping, results => $result->{$oid_table_vs}, instance => $instance); - - $self->{vs}->{$instance} = { display => $data->{vsName}, - sessions => $data->{vsSessions}, sessions_ssl => $data->{vsSessionsSsl}}; - } - } - -``` - -If we have at least 2 virtual servers: - -``` - - OK: Total current sessions : 24, current ssl sessions : 150 - All Virtual servers are ok | total_sessions=24;;;0; total_sessions_ssl=150;;;0; sessions_foo1=11;;;0; sessions_ssl_foo1=70;;;0; sessions_foo2=13;;;0; sessions_ssl_foo2=80;;;0; - Virtual server 'foo1' current sessions : 11, current ssl sessions : 70 - Virtual server 'foo2' current sessions : 13, current ssl sessions : 80 - -``` - -### Example 3 - -The model can also be used to check strings (not only counters). So we want to check the status of a virtualserver. - -```perl - - package my::module::name; - - use base qw(centreon::plugins::templates::counter); - - use strict; - use warnings; - - sub set_counters { - my ($self, %options) = @_; - - $self->{maps_counters_type} = [ - { name => 'vs', type => 1, cb_prefix_output => 'prefix_vs_output', message_multiple => 'All Virtual server status are ok' } - ]; - $self->{maps_counters}->{vs} = [ - { label => 'status', threshold => 0, set => { - key_values => [ { name => 'status' }, { name => 'display' } ], - closure_custom_calc => $self->can('custom_status_calc'), - closure_custom_output => $self->can('custom_status_output'), - closure_custom_perfdata => sub { return 0; }, - closure_custom_threshold_check => $self->can('custom_threshold_output') - } - } - ]; - } - - sub custom_threshold_output { - my ($self, %options) = @_; - my $status = 'ok'; - - if ($self->{result_values}->{status} =~ /problem/) { - $status = 'critical'; - } - return $status; - } - - sub custom_status_output { - my ($self, %options) = @_; - - my $msg = sprintf("status is '%s'", $self->{result_values}->{status}); - return $msg; - } - - sub custom_status_calc { - my ($self, %options) = @_; - - $self->{result_values}->{status} = $options{new_datas}->{$self->{instance} . '_status'}; - $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; - return 0; - } - - sub prefix_vs_output { - my ($self, %options) = @_; - - return "Virtual server '" . $options{instance_value}->{display} . "' "; - } - - sub check_options { - my ($self, %options) = @_; - $self->SUPER::check_options(%options); - - } - - sub manage_selection { - my ($self, %options) = @_; - - my $oid_table_vs = '.1.2.3.10'; - my $mapping = { - vsName => { oid => '.1.2.3.10.1' }, - vsStatus => { oid => '.1.2.3.10.4' }, - }; - - $self->{vs} = {}; - my $result = $options{snmp}->get_table(oid => $oid_table_vs, - nothing_quit => 1); - foreach my $oid (keys %{$result->{ $oid_table_vs }}) { - next if ($oid !~ /^$mapping->{vsName}->{oid}\.(.*)$/; - my $instance = $1; - my $data = $options{snmp}->map_instance(mapping => $mapping, results => $result->{$oid_table_vs}, instance => $instance); - - $self->{vs}->{$instance} = { display => $data->{vsName}, - status => $data->{vsStatus} }; - } - } - -``` - -The following example show 4 new attributes: - -* *closure_custom_calc*: should be used to do more complex calculation. -* *closure_custom_output*: should be used to have a more complex output (An example: want to display the total, free and used value at the same time). -* *closure_custom_perfdata*: should be used to manage yourself the perfdata. -* *closure_custom_threshold_check*: should be used to manage yourself the threshold check. - - -## Class hardware - ---- - -TODO +# Plugins / Connectors global documentation + +******* +Table of contents +1. [Basics & main guidelines](plugins_global.md) +2. [Advanced plugins development concepts](plugins_advanced.md) +3. [How to develop a plugin to monitor a REST API](tutorial-api.md) +4. [How to develop a plugin to monitor a device supporting SNMP](tutorial-snmp.md) +5. \[Coming soon\][How to develop a Service Discovery mode](tutorial-service_discovery.md) +******* \ No newline at end of file diff --git a/doc/en/developer/plugins_advanced.md b/doc/en/developer/plugins_advanced.md new file mode 100644 index 000000000..f4dda783e --- /dev/null +++ b/doc/en/developer/plugins_advanced.md @@ -0,0 +1,1277 @@ +# Plugins / Connectors advenced documentation + +## IV. List of shared libraries in centreon directory + +This chapter describes Centreon libraries which you can use in your development. + +
+ +******* +Table of contents +1. [Output](#lib_output) +2. [Perfdata](#lib_perfdata) +3. [SNMP](#lib_snmp) +4. [Misc](#lib_misc) +5. [Statefile](#lib_statefile) +6. [HTTP](#lib_http) +7. [DBI](#lib_dbi) +8. [Model Classes Usage](#model_class_usage) +******* + +
+ +### 1. Output + +This library allows you to build output of your plugin. + +#### 1.1 output_add + +**Description** + +This function adds a string to the output (it is printed when the `display()` method is called). If the status is different from 'ok', the output associated with 'ok' status is not printed. + +**Parameters** + +| Parameter | Type | Default | Description | +|-----------|--------|---------|---------------------------------------------| +| severity | String | OK | Status of the output. Accepted values: OK, WARNING, CRITICAL, UNKNOWN. | +| separator | String | \- | Separator between status and output string. | +| short_msg | String | | Short output (first line). | +| long_msg | String | | Long output (used with --verbose option). | +| debug | Int | | If set to 1, the message is displayed only when --debug option is passed | + +**Example** + +This is an example of how to manage output: + +```perl +$self->{output}->output_add(severity => 'OK', + short_msg => 'All is ok'); +$self->{output}->output_add(severity => 'Critical', + short_msg => 'There is a critical problem'); +$self->{output}->output_add(long_msg => 'Port 1 is disconnected'); + +$self->{output}->display(); +``` + +The displayed output is: + +``` +CRITICAL - There is a critical problem +Port 1 is disconnected +``` + +#### 1.2 perfdata_add + +**Description** + +Add performance data to output (print it with **display** method). +Performance data are displayed after '|'. + +**Parameters** + +| Parameter | Type | Default | Description | +|-----------|--------|---------|----------------------------------------| +| label | String | | [legacy] Label of the performance data. | +| nlabel | String | | Label of the performance data in a more standard and explicit fashion. | +| value | Int | | Value of the performance data. | +| unit | String | | Unit of the performance data. | +| warning | String | | Warning threshold. | +| critical | String | | Critical threshold. | +| min | Int | | Minimum value of the performance data. | +| max | Int | | Maximum value of the performance data. | + +**Example** + +This is an example of how to add performance data: + +```perl + +$self->{output}->output_add(severity => 'OK', + short_msg => 'Memory is ok'); +$self->{output}->perfdata_add(label => 'memory_used', + value => 30000000, + unit => 'B', + warning => '80000000', + critical => '90000000', + min => 0, + max => 100000000); + +$self->{output}->display(); +``` +Output displays : + +``` +OK - Memory is ok | 'memory_used'=30000000B;80000000;90000000;0;100000000 +``` + +
+ +### 2. Perfdata + +This library allows you to manage performance data. + +#### 2.1 get_perfdata_for_output + +**Description** +Manage thresholds of performance data for output. + +**Parameters** + +| Parameter | Type | Default | Description | +|-----------|--------------|---------|-----------------------------------------------------------| +| **label** | String | | Threshold label. | +| total | Int | | Percent threshold to transform in global. | +| cast_int | Int (0 or 1) | | Cast absolute to int. | +| op | String | | Operator to apply to start/end value (uses with 'value'). | +| value | Int | | Value to apply with 'op' option. | + +**Example** + +This is an example of how to manage performance data for output: + +```perl +my $format_warning_perfdata = $self->{perfdata}->get_perfdata_for_output(label => 'warning', total => 1000000000, cast_int => 1); +my $format_critical_perfdata = $self->{perfdata}->get_perfdata_for_output(label => 'critical', total => 1000000000, cast_int => 1); + +$self->{output}->perfdata_add(label => 'memory_used', + value => 30000000, + unit => 'B', + warning => $format_warning_perfdata, + critical => $format_critical_perfdata, + min => 0, + max => 1000000000); + +``` + +**tip** +In this example, instead of print warning and critical thresholds in 'percent', the function calculates and prints these in 'bytes'. + +#### 2.2 threshold_validate + +**Description** + +Validate and affect threshold to a label. + +**Parameters** + +| Parameter | Type | Default | Description | +|-----------|--------|---------|------------------| +| label | String | | Threshold label. | +| value | String | | Threshold value. | + +**Example** + +This example checks if warning threshold is correct: + +```perl + +if (($self->{perfdata}->threshold_validate(label => 'warning', value => $self->{option_results}->{warning})) == 0) { + $self->{output}->add_option_msg(short_msg => "Wrong warning threshold '" . $self->{option_results}->{warning} . "'."); + $self->{output}->option_exit(); +} +``` + +**tip** +You can see the correct threshold format here: https://nagios-plugins.org/doc/guidelines.html#THRESHOLDFORMAT + +#### 2.3 threshold_check + +**Description** + +Compare performance data value with threshold to determine status. + +**Parameters** + +| Parameter | Type | Default | Description | +|-----------|--------------|---------|--------------------------------------------------------| +| value | Int | | Performance data value to compare. | +| threshold | String array | | Threshold label to compare and exit status if reached. | + +**Example** + +This example checks if performance data reached thresholds: + +```perl +$self->{perfdata}->threshold_validate(label => 'warning', value => 80); +$self->{perfdata}->threshold_validate(label => 'critical', value => 90); +my $prct_used = 85; + +my $exit = $self->{perfdata}->threshold_check(value => $prct_used, threshold => [ { label => 'critical', 'exit_litteral' => 'critical' }, { label => 'warning', exit_litteral => 'warning' } ]); + +$self->{output}->output_add(severity => $exit, + short_msg => sprint("Used memory is %i%%", $prct_used)); +$self->{output}->display(); +``` +Output displays : + +``` + WARNING - Used memory is 85% | +``` + +#### 2.4 change_bytes + +**Description** + +Convert bytes to human readable unit. +Return value and unit. + +**Parameters** + +| Parameter | Type | Default | Description | +|-----------|------|---------|------------------------------------| +| value | Int | | Performance data value to convert. | +| network | | 1024 | Unit to divide (1000 if defined). | + +**Example** + +This example change bytes to human readable unit: + +```perl + +my ($value, $unit) = $self->{perfdata}->change_bytes(value => 100000); + +print $value.' '.$unit."\n"; +``` +Output displays : + +``` + 100 KB +``` + +
+ +### 3. SNMP + +This library allows you to use SNMP protocol in your plugin. +To use it, add the following line at the beginning of your **plugin.pm**: + +```perl +use base qw(centreon::plugins::script_snmp); +``` + +#### 3.1 get_leef + +**Description** + +Return hash table of SNMP values for multiple OIDs (do not work with SNMP table). + +**Parameters** + +**Example** + +This is an example of how to get 2 SNMP values: + +```perl + +my $oid_hrSystemUptime = '.1.3.6.1.2.1.25.1.1.0'; +my $oid_sysUpTime = '.1.3.6.1.2.1.1.3.0'; + +my $result = $self->{snmp}->get_leef(oids => [ $oid_hrSystemUptime, $oid_sysUpTime ], nothing_quit => 1); + +print $result->{$oid_hrSystemUptime}."\n"; +print $result->{$oid_sysUpTime}."\n"; +``` + +#### 3.2 load + +**Description** + +Load a range of OIDs to use with **get_leef** method. + +**Parameters** + +| Parameter | Type | Default | Description | +|-----------------|--------------|---------|----------------------------------------------------------------| +| **oids** | String array | | Array of OIDs to check. | +| instances | Int array | | Array of OID instances to check. | +| instance_regexp | String | | Regular expression to get instances from **instances** option. | +| begin | Int | | Instance to begin | +| end | Int | | Instance to end | + +**Example** + +This is an example of how to get 4 instances of a SNMP table by using **load** method: + +```perl +my $oid_dskPath = '.1.3.6.1.4.1.2021.9.1.2'; + +$self->{snmp}->load(oids => [$oid_dskPercentNode], instances => [1,2,3,4]); + +my $result = $self->{snmp}->get_leef(nothing_quit => 1); + +use Data::Dumper; +print Dumper($result); +``` +This is an example of how to get multiple instances dynamically (memory modules of Dell hardware) by using **load** method: + +```perl +my $oid_memoryDeviceStatus = '.1.3.6.1.4.1.674.10892.1.1100.50.1.5'; +my $oid_memoryDeviceLocationName = '.1.3.6.1.4.1.674.10892.1.1100.50.1.8'; +my $oid_memoryDeviceSize = '.1.3.6.1.4.1.674.10892.1.1100.50.1.14'; +my $oid_memoryDeviceFailureModes = '.1.3.6.1.4.1.674.10892.1.1100.50.1.20'; + +my $result = $self->{snmp}->get_table(oid => $oid_memoryDeviceStatus); +$self->{snmp}->load(oids => [$oid_memoryDeviceLocationName, $oid_memoryDeviceSize, $oid_memoryDeviceFailureModes], + instances => [keys %$result], + instance_regexp => '(\d+\.\d+)$'); + +my $result2 = $self->{snmp}->get_leef(); + +use Data::Dumper; +print Dumper($result2); +``` + +#### 3.3 get_table + +**Description** + +Return hash table of SNMP values for SNMP table. + +**Parameters** + +| Parameter | Type | Default | Description | +|--------------|--------------|---------|---------------------------------------------------------| +| **oid** | String | | OID of the snmp table to check. | +| start | Int | | First OID to check. | +| end | Int | | Last OID to check. | +| dont_quit | Int (0 or 1) | 0 | Don't quit even if an SNMP error occured. | +| nothing_quit | Int (0 or 1) | 0 | Quit if no value is returned. | +| return_type | Int (0 or 1) | 0 | Return a hash table with one level instead of multiple. | + +**Example** + +This is an example of how to get a SNMP table: + +```perl +my $oid_rcDeviceError = '.1.3.6.1.4.1.15004.4.2.1'; +my $oid_rcDeviceErrWatchdogReset = '.1.3.6.1.4.1.15004.4.2.1.2.0'; + +my $results = $self->{snmp}->get_table(oid => $oid_rcDeviceError, start => $oid_rcDeviceErrWatchdogReset); + +use Data::Dumper; +print Dumper($results); +``` + +#### 3.4 get_multiple_table + +**Description** + +Return hash table of SNMP values for multiple SNMP tables. + +**Parameters** + +| Parameter | Type | Default | Description | +|--------------|--------------|---------|------------------------------------------------------------| +| oids | Hash table | - | Hash table of OIDs to check (Can be set by 'load' method). | +| - | - | - | Keys can be: "oid", "start", "end". | +| dont_quit | Int (0 or 1) | 0 | Don't quit even if an SNMP error occured. | +| nothing_quit | Int (0 or 1) | 0 | Quit if no value is returned. | +| return_type | Int (0 or 1) | 0 | Return a hash table with one level instead of multiple. | + +**Example** + +This is an example of how to get 2 SNMP tables: + +```perl +my $oid_sysDescr = ".1.3.6.1.2.1.1.1"; +my $aix_swap_pool = ".1.3.6.1.4.1.2.6.191.2.4.2.1"; + +my $results = $self->{snmp}->get_multiple_table(oids => [ + { oid => $aix_swap_pool}, + { oid => $oid_sysDescr }, + ]); + +use Data::Dumper; +print Dumper($results); +``` + +#### 3.5 get_hostname + +**Description** + +Get hostname parameter (useful to get hostname in mode). + +**Parameters** + +None. + +**Example** + +This is an example of how to get hostname parameter: + +```perl +my $hostname = $self->{snmp}->get_hostname(); +``` + +#### 3.6 get_port + +**Description** + + +Get port parameter (useful to get port in mode). + +**Parameters** + +None. + +**Example** + +This is an example of how to get port parameter: + +```perl +my $port = $self->{snmp}->get_port(); +``` + +#### 3.7 oid_lex_sort + +**Description** + +Return sorted OIDs. + +**Parameters** + +| Parameter | Type | Default | Description | +|-----------|--------------|---------|------------------------| +| **-** | String array | | Array of OIDs to sort. | + +**Example** + +This example prints sorted OIDs: + +```perl +foreach my $oid ($self->{snmp}->oid_lex_sort(keys %{$self->{results}->{$my_oid}})) { + print $oid; +} +``` + +
+ +### 4. Misc + +This library provides a set of miscellaneous methods. +To use it, you can directly use the path of the method: + +```perl +centreon::plugins::misc::; +``` +-------------- +#### 4.1 trim + +**Description** + +Strip whitespace from the beginning and end of a string. + +**Parameters** + +| Parameter | Type | Default | Description | +|-----------|--------|---------|------------------| +| **-** | String | | String to strip. | + +**Example** + +This is an example of how to use **trim** method: + +```perl +my $word = ' Hello world ! '; +my $trim_word = centreon::plugins::misc::trim($word); + +print $word."\n"; +print $trim_word."\n"; +``` +Output displays : + +``` +Hello world ! +``` + +#### 4.2 change_seconds + +**Description** + +Convert seconds to human readable text. + +**Parameters** + +| Parameter | Type | Default | Description | +|-----------|------|---------|-------------------------------| +| **-** | Int | | Number of seconds to convert. | + +**Example** + +This is an example of how to use **change_seconds** method: + +```perl +my $seconds = 3750; +my $human_readable_time = centreon::plugins::misc::change_seconds($seconds); + +print 'Human readable time : '.$human_readable_time."\n"; +``` +Output displays : + +``` +Human readable time : 1h 2m 30s +``` + +#### 4.3 backtick + +**Description** + +Execute system command. + +**Parameters** + +| Parameter | Type | Default | Description | +|-----------------|--------------|---------|-----------------------------------------| +| **command** | String | | Command to execute. | +| arguments | String array | | Command arguments. | +| timeout | Int | 30 | Command timeout. | +| wait_exit | Int (0 or 1) | 0 | Command process ignore SIGCHLD signals. | +| redirect_stderr | Int (0 or 1) | 0 | Print errors in output. | + +**Example** + +This is an example of how to use **backtick** method: + +```perl +my ($error, $stdout, $exit_code) = centreon::plugins::misc::backtick( + command => 'ls /home', + timeout => 5, + wait_exit => 1 + ); + +print $stdout."\n"; +``` +Output displays files in '/home' directory. + + +#### 4.4 execute + +**Description** + +Execute command remotely. + +**Parameters** + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|-----------------------------------------------------------------| +| **output** | Object | | Plugin output ($self->{output}). | +| **options** | Object | | Plugin options ($self->{option_results}) to get remote options. | +| sudo | String | | Use sudo command. | +| **command** | String | | Command to execute. | +| command_path | String | | Command path. | +| command_options | String | | Command arguments. | + +**Example** + +This is an example of how to use **execute** method. +We suppose ``--remote`` option is enabled: + +```perl +my $stdout = centreon::plugins::misc::execute(output => $self->{output}, + options => $self->{option_results}, + sudo => 1, + command => 'ls /home', + command_path => '/bin/', + command_options => '-l'); +``` +Output displays files in /home using ssh on a remote host. + +#### 4.5 windows_execute + +**Description** + +Execute command on Windows. + +**Parameters** + +| Parameter | Type | Default | Description | +|-----------------|--------|---------|--------------------------------------| +| **output** | Object | | Plugin output ($self->{output}). | +| **command** | String | | Command to execute. | +| command_path | String | | Command path. | +| command_options | String | | Command arguments. | +| timeout | Int | | Command timeout. | +| no_quit | Int | | Don't quit even if an error occured. | + +**Example** + +This is an example of how to use **windows_execute** method. + +```perl +my $stdout = centreon::plugins::misc::windows_execute(output => $self->{output}, + timeout => 10, + command => 'ipconfig', + command_path => '', + command_options => '/all'); +``` +Output displays IP configuration on a Windows host. + +
+ +### 5.Statefile + +This library provides a set of methods to use a cache file. +To use it, add the following line at the beginning of your **mode**: + +```perl +use centreon::plugins::statefile; +``` + +#### 5.1 read + +**Description** + +Read cache file. + +**Parameters** + +| Parameter | Type | Default | Description | +|-------------------|--------|---------|------------------------------| +| **statefile** | String | | Name of the cache file. | +| **statefile_dir** | String | | Directory of the cache file. | +| memcached | String | | Memcached server to use. | + +**Example** + +This is an example of how to use **read** method: + +```perl +$self->{statefile_value} = centreon::plugins::statefile->new(%options); +$self->{statefile_value}->check_options(%options); +$self->{statefile_value}->read(statefile => 'my_cache_file', + statefile_dir => '/var/lib/centreon/centplugins' + ); + +use Data::Dumper; +print Dumper($self->{statefile_value}); +``` +Output displays cache file and its parameters. + +#### 5.2 get + +**Description** + +Get data from cache file. + +**Parameters** + +| Parameter | Type | Default | Description | +|-----------|--------|---------|------------------------------| +| name | String | | Get a value from cache file. | + +**Example** + +This is an example of how to use **get** method: + +```perl +$self->{statefile_value} = centreon::plugins::statefile->new(%options); +$self->{statefile_value}->check_options(%options); +$self->{statefile_value}->read(statefile => 'my_cache_file', + statefile_dir => '/var/lib/centreon/centplugins' + ); + +my $value = $self->{statefile_value}->get(name => 'property1'); +print $value."\n"; +``` +Output displays value for 'property1' of the cache file. + +#### 5.3 write + +**Description** + +Write data to cache file. + +**Parameters** + +| Parameter | Type | Default | Description | +|-----------|--------|---------|------------------------------| +| data | String | | Data to write in cache file. | + +**Example** + +This is an example of how to use **write** method: + +```perl +$self->{statefile_value} = centreon::plugins::statefile->new(%options); +$self->{statefile_value}->check_options(%options); +$self->{statefile_value}->read(statefile => 'my_cache_file', + statefile_dir => '/var/lib/centreon/centplugins' + ); + +my $new_datas = {}; +$new_datas->{last_timestamp} = time(); +$self->{statefile_value}->write(data => $new_datas); +``` +Then, you can read the result in '/var/lib/centreon/centplugins/my_cache_file', timestamp is written in it. + +
+ +### 6. HTTP + +This library provides a set of methodss to use HTTP protocol. +To use it, add the following line at the beginning of your **mode**: + +```perl +use centreon::plugins::http; +``` + +Some options must be set in **plugin.pm**: + +| Option | Type | Description | +|--------------|--------|---------------------------------------------------------| +| **hostname** | String | IP Addr/FQDN of the webserver host. | +| **port** | String | HTTP port. | +| **proto** | String | Used protocol ('http' or 'https'). | +| credentials | | Use credentials. | +| ntlm | | Use NTLM authentication (if ``--credentials`` is used). | +| username | String | Username (if ``--credentials`` is used). | +| password | String | User password (if ``--credentials`` is used). | +| proxyurl | String | Proxy to use. | +| url_path | String | URL to connect (start to '/'). | + +#### 6.1 connect + +**Description** + +Test a connection to an HTTP url. +Return content of the webpage. + +**Parameters** + +This method use plugin options previously defined. + +**Example** + +This is an example of how to use **connect** method. + +We suppose these options are defined : +* --hostname = 'google.com' +* --urlpath = '/' +* --proto = 'http' +* --port = 80 + +```perl +$self->{http} = centreon::plugins::http->new(output => $self->{output}, options => $self->{options}); +$self->{http}->set_options(%{$self->{option_results}}); +my $webcontent = $self->{http}->request(); +print $webcontent; +``` +Output displays content of the webpage '\http://google.com/'. + +
+ +### 7. DBI + +This library allows you to connect to databases. +To use it, add the following line at the beginning of your **plugin.pm**: + +```perl +use base qw(centreon::plugins::script_sql); +``` + +#### 7.1 connect + +**Description** + +Connect to databases. + +**Parameters** + +| Parameter | Type | Default | Description | +|-----------|--------------|---------|------------------------------------| +| dontquit | Int (0 or 1) | 0 | Don't quit even if errors occured. | + +**Example** + +This is an example of how to use **connect** method. + +The format of the connection string can have the following forms: + +``` + DriverName:database_name + DriverName:database_name@hostname:port + DriverName:database=database_name;host=hostname;port=port +``` +In plugin.pm: + +```perl +$self->{sqldefault}->{dbi} = (); +$self->{sqldefault}->{dbi} = { data_source => 'mysql:host=127.0.0.1;port=3306' }; +``` +In your mode: + +```perl +$self->{sql} = $options{sql}; +my ($exit, $msg_error) = $self->{sql}->connect(dontquit => 1); +``` +Then, you are connected to the MySQL database. + +#### 7.2 query + +**Description** + +Send query to database. + +**Parameters** + +| Parameter | Type | Default | Description | +|-----------|--------|---------|--------------------| +| query | String | | SQL query to send. | + +**Example** + +This is an example of how to use **query** method: + +```perl +$self->{sql}->query(query => q{SHOW /*!50000 global */ STATUS LIKE 'Slow_queries'}); +my ($name, $result) = $self->{sql}->fetchrow_array(); + +print 'Name : '.$name."\n"; +print 'Value : '.$value."\n"; +``` +Output displays count of MySQL slow queries. + +#### 7.3 fetchrow_array + +**Description** + +Return Array from sql query. + +**Parameters** + +None. + +**Example** + +This is an example of how to use **fetchrow_array** method: + +```perl +$self->{sql}->query(query => q{SHOW /*!50000 global */ STATUS LIKE 'Uptime'}); +my ($dummy, $result) = $self->{sql}->fetchrow_array(); + +print 'Uptime : '.$result."\n"; +``` +Output displays MySQL uptime. + +#### 7.4 fetchall_arrayref + +**Description** + +Return Array from SQL query. + +**Parameters** + +None. + +**Example** + +This is an example of how to use **fetchrow_array** method: + +```perl +$self->{sql}->query(query => q{ + SELECT SUM(DECODE(name, 'physical reads', value, 0)), + SUM(DECODE(name, 'physical reads direct', value, 0)), + SUM(DECODE(name, 'physical reads direct (lob)', value, 0)), + SUM(DECODE(name, 'session logical reads', value, 0)) + FROM sys.v_$sysstat +}); +my $result = $self->{sql}->fetchall_arrayref(); + +my $physical_reads = @$result[0]->[0]; +my $physical_reads_direct = @$result[0]->[1]; +my $physical_reads_direct_lob = @$result[0]->[2]; +my $session_logical_reads = @$result[0]->[3]; + +print $physical_reads."\n"; +``` +Output displays physical reads on Oracle database. + +#### 7.5 fetchrow_hashref + +**Description** + +Return Hash table from SQL query. + +**Parameters** + +None. + +**Example** + +This is an example of how to use **fetchrow_hashref** method: + +```perl +$self->{sql}->query(query => q{ + SELECT datname FROM pg_database +}); + +while ((my $row = $self->{sql}->fetchrow_hashref())) { + print $row->{datname}."\n"; +} +``` +Output displays Postgres databases. + +
+ +### 8. Model Classes Usage + +**Introduction** + +With the experience of plugin development, we have created two classes: + +* centreon::plugins::templates::counter +* centreon::plugins::templates::hardware + +It was developed to have a more consistent code and less redundant code. +According to context, you should use one of two classes for modes. +Following classes can be used for whatever plugin type (SNMP, Custom, DBI,...). + +**Class counter** + +*When to use it ?* + +If you have some counters (CPU Usage, Memory, Session...), you should use that +class. +If you have only one global counter to check, it's maybe not useful to use it +(but only for these case). + +*Class methods* + +List of methods: + +* **new**: class constructor. Overload if you need to add some specific options +or to use a statefile. +* **check_options**: overload if you need to check your specific options. +* **manage_selection**: overload if *mandatory*. Method to get informations for +the equipment. +* **set_counters**: overload if **mandatory**. Method to configure counters. + +**Class hardware** + + + + + + +TODO + + + + + +[Table of content (1)](#table_of_contents) + + + + +#### 8.1. Example 1 + +We want to develop the following SNMP plugin: + +* measure the current sessions and current SSL sessions usages. + +```perl + package my::module::name; + + use base qw(centreon::plugins::templates::counter); + + use strict; + use warnings; + + sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0, message_separator => ' - ' }, + ]; + $self->{maps_counters}->{global} = [ + { label => 'sessions', set => { + key_values => [ { name => 'sessions' } ], + output_template => 'Current sessions : %s', + perfdatas => [ + { label => 'sessions', template => '%s', min => 0 }, + ], + } + }, + { label => 'sessions-ssl', set => { + key_values => [ { name => 'sessions_ssl' } ], + output_template => 'Current ssl sessions : %s', + perfdatas => [ + { label => 'sessions_ssl', template => '%s', min => 0 }, + ], + } + }, + ]; + } + + sub manage_selection { + my ($self, %options) = @_; + + # OIDs are fake. Only for the example. + my ($oid_sessions, $oid_sessions_ssl) = ('.1.2.3.4.0', '.1.2.3.5.0'); + + my $result = $options{snmp}->get_leef( + oids => [ $oid_sessions, $oid_sessions_ssl ], + nothing_quit => 1 + ); + $self->{global} = { + sessions => $result->{$oid_sessions}, + sessions_ssl => $result->{$oid_sessions_ssl} + }; + } +``` +Output may display: + +``` + OK: Current sessions : 24 - Current ssl sessions : 150 | sessions=24;;;0; sessions_ssl=150;;;0; +``` +As you can see, we create two arrays of hash tables in **set_counters** method. We use arrays to order the output. + +* **maps_counters_type**: global configuration. Attributes list: + + * *name*: the name is really important. It will be used in hash **map_counters** and also in **manage_selection** as you can see. + * *type*: 0 or 1. With 0 value, the output will be written in the short output. With the value 1, it depends if we have one or multiple instances. + * *message_multiple*: only useful with *type* 1 value. The message will be displayed in short ouput if we have multiple instances selected. + * *message_separator*: the string displayed between counters (Default: ', '). + * *cb_prefix_output*, *cb_suffix_output*: name of a method (in a string) to callback. Methods will return a string to be displayed before or after **all** counters. + * *cb_init*: name of a method (in a string) to callback. Method will return 0 or 1. With 1 value, counters are not checked. + +* **maps_counters**: complex structure to configure counters. Attributes list: + + * *label*: name used for threshold options. + * *type*: depend of data dimensions + * 0 : global + * 1 : instance + * 2 : group + * 3 : multiple + * *threshold*: if we set the value to 0. There is no threshold check options (can be used if you want to set and check option yourself). + * *set*: hash table: + + * *keys_values*: array of hashes. Set values used for the counter. Order is important (by default, the first value is used to check). + + * *name*: attribute name. Need to match with attributes in **manage_selection** method! + * *diff*: if we set the value to 1, we'll have the difference between two checks (need a statefile!). + * *per_second*: if we set the value to 1, the *diff* values will be calculated per seconds (need a statefile!). No need to add diff attribute. + + * *output_template*: string to display. '%s' will be replaced by the first value of *keys_values*. + * *output_use*: which value to be used in *output_template* (If not set, we use the first value of *keys_values*). + * *output_change_bytes*: if we set the value to 1 or 2, we can use a second '%s' in *output_template* to display the unit. 1 = divide by 1024 (Bytes), 2 = divide by 1000 (bits). + * *perfdata*: array of hashes. To configure perfdatas + + * *label*: name displayed. + * *value*: value to used. It's the name from *keys_values*. + * *template*: value format (could be for example: '%.3f'). + * *unit*: unit displayed. + * *min*, *max*: min and max displayed. You can use a value from *keys_values*. + * *label_extra_instance*: if we set the value to 1, perhaps we'll have a suffix concat with *label*. + * *instance_use*: which value from *keys_values* to be used. To be used if *label_extra_instance* is 1. + +#### 8.2. Example 2 + +We want to add the current number of sessions by virtual servers. + +```perl + package my::module::name; + + use base qw(centreon::plugins::templates::counter); + + use strict; + use warnings; + + sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0, cb_prefix_output => 'prefix_global_output' }, + { name => 'vs', type => 1, cb_prefix_output => 'prefix_vs_output', message_multiple => 'All Virtual servers are ok' } + ]; + $self->{maps_counters}->{global} = [ + { label => 'total-sessions', set => { + key_values => [ { name => 'sessions' } ], + output_template => 'current sessions : %s', + perfdatas => [ + { label => 'total_sessions', template => '%s', min => 0 }, + ], + } + }, + { label => 'total-sessions-ssl', set => { + key_values => [ { name => 'sessions_ssl' } ], + output_template => 'current ssl sessions : %s', + perfdatas => [ + { label => 'total_sessions_ssl', template => '%s', min => 0 }, + ], + } + }, + ]; + + $self->{maps_counters}->{vs} = [ + { label => 'sessions', set => { + key_values => [ { name => 'sessions' }, { name => 'display' } ], + output_template => 'current sessions : %s', + perfdatas => [ + { label => 'sessions', template => '%s', + min => 0, label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + { label => 'sessions-ssl', set => { + key_values => [ { name => 'sessions_ssl' }, { name => 'display' } ], + output_template => 'current ssl sessions : %s', + perfdatas => [ + { label => 'sessions_ssl', template => '%s', + min => 0, label_extra_instance => 1, instance_use => 'display' }, + ], + } + }, + ]; + } + + sub prefix_vs_output { + my ($self, %options) = @_; + + return "Virtual server '" . $options{instance_value}->{display} . "' "; + } + + sub prefix_global_output { + my ($self, %options) = @_; + + return "Total "; + } + + sub manage_selection { + my ($self, %options) = @_; + + # OIDs are fake. Only for the example. + my ($oid_sessions, $oid_sessions_ssl) = ('.1.2.3.4.0', '.1.2.3.5.0'); + + my $result = $options{snmp}->get_leef(oids => [ $oid_sessions, $oid_sessions_ssl ], + nothing_quit => 1); + $self->{global} = { sessions => $result->{$oid_sessions}, + sessions_ssl => $result->{$oid_sessions_ssl} + }; + my $oid_table_vs = '.1.2.3.10'; + my $mapping = { + vsName => { oid => '.1.2.3.10.1' }, + vsSessions => { oid => '.1.2.3.10.2' }, + vsSessionsSsl => { oid => '.1.2.3.10.3' }, + }; + + $self->{vs} = {}; + $result = $options{snmp}->get_table(oid => $oid_table_vs, + nothing_quit => 1); + foreach my $oid (keys %{$result->{ $oid_table_vs }}) { + next if ($oid !~ /^$mapping->{vsName}->{oid}\.(.*)$/; + my $instance = $1; + my $data = $options{snmp}->map_instance(mapping => $mapping, results => $result->{$oid_table_vs}, instance => $instance); + + $self->{vs}->{$instance} = { display => $data->{vsName}, + sessions => $data->{vsSessions}, sessions_ssl => $data->{vsSessionsSsl}}; + } + } +``` +If we have at least 2 virtual servers: + +``` + OK: Total current sessions : 24, current ssl sessions : 150 - All Virtual servers are ok | total_sessions=24;;;0; total_sessions_ssl=150;;;0; sessions_foo1=11;;;0; sessions_ssl_foo1=70;;;0; sessions_foo2=13;;;0; sessions_ssl_foo2=80;;;0; + Virtual server 'foo1' current sessions : 11, current ssl sessions : 70 + Virtual server 'foo2' current sessions : 13, current ssl sessions : 80 +``` + +#### 8.3. Example 3 + +The model can also be used to check strings (not only counters). So we want to check the status of a virtualserver. + +```perl + package my::module::name; + + use base qw(centreon::plugins::templates::counter); + + use strict; + use warnings; + + sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'vs', type => 1, cb_prefix_output => 'prefix_vs_output', message_multiple => 'All Virtual server status are ok' } + ]; + $self->{maps_counters}->{vs} = [ + { label => 'status', threshold => 0, set => { + key_values => [ { name => 'status' }, { name => 'display' } ], + closure_custom_calc => $self->can('custom_status_calc'), + closure_custom_output => $self->can('custom_status_output'), + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => $self->can('custom_threshold_output') + } + } + ]; + } + + sub custom_threshold_output { + my ($self, %options) = @_; + my $status = 'ok'; + + if ($self->{result_values}->{status} =~ /problem/) { + $status = 'critical'; + } + return $status; + } + + sub custom_status_output { + my ($self, %options) = @_; + + my $msg = sprintf("status is '%s'", $self->{result_values}->{status}); + return $msg; + } + + sub custom_status_calc { + my ($self, %options) = @_; + + $self->{result_values}->{status} = $options{new_datas}->{$self->{instance} . '_status'}; + $self->{result_values}->{display} = $options{new_datas}->{$self->{instance} . '_display'}; + return 0; + } + + sub prefix_vs_output { + my ($self, %options) = @_; + + return "Virtual server '" . $options{instance_value}->{display} . "' "; + } + + sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + } + + sub manage_selection { + my ($self, %options) = @_; + + my $oid_table_vs = '.1.2.3.10'; + my $mapping = { + vsName => { oid => '.1.2.3.10.1' }, + vsStatus => { oid => '.1.2.3.10.4' }, + }; + + $self->{vs} = {}; + my $result = $options{snmp}->get_table(oid => $oid_table_vs, + nothing_quit => 1); + foreach my $oid (keys %{$result->{ $oid_table_vs }}) { + next if ($oid !~ /^$mapping->{vsName}->{oid}\.(.*)$/; + my $instance = $1; + my $data = $options{snmp}->map_instance(mapping => $mapping, results => $result->{$oid_table_vs}, instance => $instance); + + $self->{vs}->{$instance} = { display => $data->{vsName}, + status => $data->{vsStatus} }; + } + } +``` +The following example show 4 new attributes: + +* *closure_custom_calc*: should be used to do more complex calculation. +* *closure_custom_output*: should be used to have a more complex output (An example: want to display the total, free and used value at the same time). +* *closure_custom_perfdata*: should be used to manage yourself the perfdata. +* *closure_custom_threshold_check*: should be used to manage yourself the threshold check. + +[Table of content (1)](#table_of_contents) \ No newline at end of file diff --git a/doc/en/developer/plugins_global.md b/doc/en/developer/plugins_global.md new file mode 100644 index 000000000..384cbb453 --- /dev/null +++ b/doc/en/developer/plugins_global.md @@ -0,0 +1,1075 @@ +# Plugins / Connectors global documentation + +
+ +******* +Table of contents +1. [Overview](#overview) +2. [Understand the data](#understand_data) +3. [Directories layout](#architecture_layout) +4. [Set up your environment](#set_up) +5. [Code Style Guidelines](#code-style-guidelines) +6. [plugin.pm](#create_plugin) +7. [mode.pm](#create_mode) +8. [Tutorials](#tutorials) +9. [Commit and Fatpack generation](#fatpack) +10. [Plugin outputs](#outputs) +11. [Plugins options](#options) +12. [Discovery](#discovery) +13. [Performances](#performances) +14. [Security](#security) +15. [Help and documentation](#help_doc) +******* + +
+ +## 1. Overview + +Centreon plugins are a free and open source way to monitor systems. The project +can be used with Centreon and all monitoring softwares compatible with Nagios +plugins. You can monitor many systems: + +* **application**: Apache, Asterisk, Elasticsearch, Github, Jenkins, Kafka, + Nginx, +Pfsense, Redis, Tomcat, Varnish,... +* **cloud**: AWS, Azure, Docker, Office365, Nutanix, Prometheus,... +* **database**: Firebird, Informix, MS SQL, MySQL, Oracle, Postgres, Cassandra +* **hardware**: printers (rfc3805), UPS (Powerware, Mge, Standard), Sun + Hardware, +Cisco UCS, SensorIP, HP Proliant, HP Bladechassis, Dell Openmanage, Dell CMC, +Raritan,... +* **network**: Aruba, Brocade, Bluecoat, Brocade, Checkpoint, Cisco + AP/IronPort/ASA/ +Standard, Extreme, Fortigate, H3C, Hirschmann, HP Procurve, F5 BIG-IP, Juniper, +PaloAlto, Redback, Riverbed, Ruggedcom, Stonesoft,... +* **os**: Linux (SNMP, NRPE), Freebsd (SNMP), AIX (SNMP), Solaris (SNMP)... +* **storage**: EMC Clariion, Netapp, Nimble, HP MSA p2000, Dell EqualLogic, + Qnap, +Panzura, Synology... + +This document introduces the best practices in the development of +"centreon-plugins". + +As all plugins are written in Perl, “there is more than one way to do it”. +But to avoid reinventing the wheel, you should first take a look at the +“example” directory, you will get an overview of how to build your own plugin +and associated modes. + +The lastest version is available on following git repository: +https://github.com/centreon/centreon-plugins.git + +[Table of contents](#table_of_contents) + +
+ +## 2.Understand the data + +First of any development, understanding the data is very important as it will drive the way you will design +the **mode** internals. This is the **first thing to do**, no matter what protocol you +are using. + +There are several important properties for a piece of data: + +- Type of the data to process: string, int... There is no limitation in the kind of data you can process +- Dimensions of the data, is it **global** or linked to an **instance**? +- Data layout, in other words anticipate the kind of **data structure** to manipulate. + +Coming soon : A mindmap of what type of plugins is adequate + +[Table of contents](#table_of_contents) + +
+ +## 3. Directories layout + +### 3.1 Plugins directories layout + +The project content is made of a main binary (`centreon_plugins.pl`), and a +logical directory structure allowing to separate plugins and modes files across +the domain they are referring to. + +You can display it using the command `tree -L 1`. + +```shell +. +├── apps +├── blockchain +├── centreon +├── centreon_plugins.pl +├── changelog +├── cloud +├── contrib +├── database +├── doc +├── example +├── hardware +├── Jenkinsfile +├── LICENSE.txt +├── network +├── notification +├── os +├── README.md +├── snmp_standard +├── sonar-project.properties +└── storage +``` +Root directories are organized by section: + +* Application : apps +* Database : database +* Hardware : hardware +* Network equipment : network +* Operating System : os +* Storage equipment : storage + +### 3.2 Single plugin directory layout + +According to the monitored object, it exists an organization which can use: + +* Type +* Constructor +* Model +* Monitoring Protocol + +Let's take a deeper look at the layout of the directory containing modes to +monitor Linux systems through the command-line (`tree os/linux/local/ -L 1`). + +```shell +os/linux/local/ +├── custom # Type: Directory. Contains code that can be used by several modes (e.g authentication, token management, ...). +│ └── cli.pm # Type: File. *Custom mode* defining common methods +├── mode # Type: Directory. Contains all **modes**. +[...] +│ └── cpu.pm # Type: File. **Mode** containing the code to monitor the CPU +[...] +└── plugin.pm # Type: File. **Plugin** definition. +``` +Note the os/linux/local. The project offers other ways to monitor Linux, SNMP +for example. To avoid mixing modes using different protocols in the same +directory and face some naming collisions, we split them across several +directories making it clear what protocol they rely on. + +Now, let's see how these concepts combine to build a command line: +```shell +# --plugin= --mode= +perl centreon_plugins.pl --plugin=os::linux::local::plugin --mode=cpu +``` + +### 3.3 Shared directories + +Some specific directories are not related to a domain (os, cloud...) and are +used across all plugins. + +#### 3.3.1 The centreon directory + +The centreon directory is specific, it contains: + +* **Project libraries/packages**. This is all the code that will help you to +develop faster by avoiding coding protocol-related things (SNMP, HTTPx, SSH...) +or common things like options or cache management from scratch. You can read the +perl modules if you're an experienced developer but there is very little +chance that you would have to modify anything in it. +* **Common files shared by multiple plugins**. This is to avoid duplicating +code across the directory tree and ease the maintenance of the project. + +An more detailed description of this libraries is available [here](plugins_advanced.md) + +#### 3.3.2 The snmp_standard/mode directory + +The snmp_standard/mode exists since the beginning when SNMP monitoring was much +more used than it is today. All the modes it contains use standard OIDs, which +means that many plugins are relying on these when the manufacturer supports +standard MIBs on their devices. + +[Table of contents](#table_of_contents) + +
+ +## 4.Set up your environment + +[Table of contents](#table_of_contents) + +To use the centreon-plugins framework, you'll need the following: + +- A Linux operating system, ideally Debian 11 or RHEL/RHEL-like >= 8 +- The [git](https://git-scm.com/book/en/v2/Getting-Started-Installing-Git) command line utility +- A [GitHub](https://github.com/) account. + +### Enable our standard repositories + +#### Debian + +If you have not already install lsb-release, first you need to follow this steps : + +If needed go to sudo mode +```shell +sudo -i +``` +Install lib-release +```shell +apt install lsb-release +``` +Create access to centreon repository (note you may need to change the version in example it's 22.04 but you can select one most up to date) +```shell +echo "deb https://apt.centreon.com/repository/22.04/ $(lsb_release -sc) main" | tee /etc/apt/sources.list.d/centreon.list +wget -O- https://apt-key.centreon.com | gpg --dearmor | tee /etc/apt/trusted.gpg.d/centreon.gpg > /dev/null 2>&1 +``` +Install the following dependencies: +```shell +apt-get install 'libpod-parser-perl' 'libnet-curl-perl' 'liburi-encode-perl' 'libwww-perl' \ + 'liblwp-protocol-https-perl' 'libhttp-cookies-perl' 'libio-socket-ssl-perl' 'liburi-perl' \ + 'libhttp-proxypac-perl' 'libcryptx-perl' 'libjson-xs-perl' 'libjson-path-perl' \ + 'libcrypt-argon2-perl' 'libkeepass-reader-perl' +``` +#### RHEL 8 and alike +Create access to centreon repository (note you may need to change the version in example it's 22.04 but you can select one most up to date) +```shell +dnf install -y https://yum.centreon.com/standard/22.04/el8/stable/noarch/RPMS/centreon-release-22.04-3.el8.noarch.rpm +``` +Install the following dependencies: +```shell +dnf install 'perl(Digest::MD5)' 'perl(Pod::Find)' 'perl-Net-Curl' 'perl(URI::Encode)' \ + 'perl(LWP::UserAgent)' 'perl(LWP::Protocol::https)' 'perl(IO::Socket::SSL)' 'perl(URI)' \ + 'perl(HTTP::ProxyPAC)' 'perl-CryptX' 'perl(MIME::Base64)' 'perl(JSON::XS)' 'perl-JSON-Path' \ + 'perl-KeePass-Reader' 'perl(Storable)' 'perl(POSIX)' 'perl(Encode)' +``` + +#### Fork and clone the centreon-plugins repository + +Within GitHub UI, on the top left, click on the **Fork** button. + +Use the git utility to fetch your repository fork: + +```shell +git clone https://@github.com//centreon-plugins +``` + +Create a branch: + +```shell +cd centreon-plugins +git checkout -b 'my-first-plugin' +``` + +[Table of contents](#table_of_contents) + +
+ +## 5. Code Style Guidelines + +**Introduction** + +Perl code from Pull-request must conform to the following style guidelines. If you find any code which doesn't conform, please fix it. + +### 5.1 Indentation + +Space should be used to indent all code blocks. Tabs should never be used to indent code blocks. Mixing tabs and spaces results in misaligned code blocks for other developers who prefer different indentation settings. +Please use 4 for indentation space width. + +```perl + if ($1 > 1) { + ....return 1; + } else { + if ($i == -1) { + ....return 0; + } + return -1 + } +``` + +### 5.2 Comments + +There should always be at least 1 space between the # character and the beginning of the comment. This makes it a little easier to read multi-line comments: + +```perl + # Good comment + #Wrong comment +``` + +### 5.3 Subroutine & Variable Names + +Whenever possible, use underscore to seperate words and don't use uppercase characters: + +```perl + sub get_logs {} + my $start_time; +``` +Keys of hash table should use alphanumeric and underscore characters only (and no quote!): + +```perl + $dogs->{meapolitan_mastiff} = 10; +``` + +### 5.4 Curly Brackets, Parenthesis + +There should be a space between every control/loop keyword and the opening parenthesis: + +```perl + if ($i == 1) { + ... + } + while ($i == 2) { + ... + } +``` + +### 5.5 If/Else Statements + +'else', 'elsif' should be on the same line after the previous closing curly brace: + +```perl + if ($i == 1) { + ... + } else { + ... + } +``` +You can use single line if conditional: + +```perl + next if ($i == 1); +``` + +[Table of contents](#table_of_contents) + +
+ +## 6.plugin.pm + +The `plugin.pm` is the first thing to create, it contains: + +- A set of instructions to load required libraries and compilation options +- A list of all **mode(s)** and path(s) to their associated files/perl packages +- A description that will display when you list all plugins or display this plugin's help. + +In this file you can always find : +* **license / copyright** + +First this file contains the Copyright section. At the end of it, you can add +your author informations like this : +``` +# ... +# Authors : <> +``` + +* **package name** + +Path to your package. '::' instead of '/', and no .pm +at the end. + +```perl +package path::to::plugin; +``` + +* **libraries** + +Strict and warnings are mandatory + +```perl +use strict; +use warnings; +``` + +One of the centreon libraries : + +```perl +use base qw(**centreon_library**); +``` +There are five kinds of centreon libraries access here : +* centreon::plugins::script_simple : Previously the general use case if no custom is needed, more explainations [here](tutorial-api.md) in this section. +* centreon::plugins::script_custom : Need custom directory - More explainations [here](tutorial-api.md) in this section. +* centreon::plugins::script_snmp : If SNMP protocol is needed for this plugin +* centreon::plugins::script_sql : If DB acess is needed for this plugin +* centreon::plugins::script_wsman : Concern Windows specific protocols + + +* **new constructor** + +The plugin need a new constructor to instantiate the object: +```perl +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + # Plugin version declaration is in the new constructor: + $self->{version} = '0.1'; + + # Several modes can be declared in the new constructor: + %{$self->{modes}} = ( + 'mode1' => '::mode::mode1', + 'mode2' => '::mode::mode2', + ... + ); + + return $self; +} +``` + +* **documentation section** + +A description of the plugin is needed to generate the documentation: + +```perl +__END__ + +=head1 PLUGIN DESCRIPTION + +. + +=cut +``` +> **TIP** : You can copy-paste an other plugin.pm and adapt some lines (package, arguments...). + The plugin has ".pm" extension because it's a Perl module. So don't forget to add 1; at the end of the file. + +[Table of contents](#table_of_contents) + +
+ +## 7.mode.pm + +Mode.pm as plugin.pm has also : +* license / copyright +* package name +* libraries +* new constructor + +But mode.pm also usually contains: +* options in the new constructor +* check_options method +* manage_selection method (called run in old contain) + +```perl + + # ... + # Authors : <> + + package path::to::plugin::mode::mode1; + + use strict; + use warnings; + use base qw(centreon::plugins::mode); + + sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + ... + + return $self; + } +``` +Mode version must be declared in the **new** constructor: + +```perl + + $self->{version} = '1.0'; + +``` +Several options can be declared in the **new** constructor: + +```perl + + $options{options}->add_options(arguments => { + "option1:s" => { name => 'option1' }, + "option2:s" => { name => 'option2', default => 'value1' }, + "option3" => { name => 'option3' }, + }); + +``` +Here is the description of arguments used in this example: + +* option1 : String value +* option2 : String value with default value "value1" +* option3 : Boolean value + +> **TIP 1** : Options are boolean as default and string if set ":s", no other type are allowed in this argument descriptions. +The actual type of the argument, if it is other than a string, can be checked and interpreted in ```check_option()``` function defined below. + +> **TIP 2** : You can have more informations about options format here: http://perldoc.perl.org/Getopt/Long.html + +The mode can have a **check_options** method to validate options: + +```perl + + sub check_options { + my ($self, %options) = @_; + $self->SUPER::init(%options); + ... + } + +``` +For example, Warning and Critical thresholds can be validated in +**check_options** method: + +```perl + + if (($self->{perfdata}->threshold_validate(label => 'warning', value => $self->{option_results}->{warning})) == 0) { + $self->{output}->add_option_msg(short_msg => "Wrong warning threshold '" . $self->{option_results}->{warning} . "'."); + $self->{output}->option_exit(); + } + if (($self->{perfdata}->threshold_validate(label => 'critical', value => $self->{option_results}->{critical})) == 0) { + $self->{output}->add_option_msg(short_msg => "Wrong critical threshold '" . $self->{option_results}->{critical} . "'."); + $self->{output}->option_exit(); + } + +``` +In this example, help is printed if thresholds do not have a correct format. + +Previously went the *run* method, where were performed measurement, check +thresholds, display output and format performance datas. + +Since this method had been split in at least two methods : +* **set_counters** : describe data structure and their properties + (like thresholds and how they will be displayed to the users). This + method is split in two functions + +```perl + + sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'radios', type => 1, cb_prefix_output => 'prefix_radio_output', message_multiple => 'All raadio interfaces are ok' } + ]; + +``` + +* **manage_selection** : method use as main sub in the mode +* Various output custom methods. + +Examples are available in the Tutorial section. + +Then, declare the module: + +```perl + + 1; + +``` +A description of the mode and its arguments is needed to generate the documentation: + +```perl + + __END__ + + =head1 PLUGIN DESCRIPTION + + . + + =cut + +``` + +[Table of contents](#table_of_contents) + +
+ +## 8. Tutorials + +To help users to understand the most popular plugins you can find several tutorials to help you to develop your first plugin. + +* [API plugin tutorial](tutorial-api.md) +* [SNMP plugin tutorial](tutorial-snmp.md) +* [Service discovery tutorial](tutorial-service_discovery.md) + +[Table of contents](#table_of_contents) + +
+ +## 9. Commit and Fatpack generation + +### 9.1. Commit and push + +When you have finished your plugin development, before committing a plugin, you need to create an **enhancement ticket** on the +centreon-plugins forge : http://forge.centreon.com/projects/centreon-plugins + +Once plugin and modes are developed, you can commit (commit messages in english) +and push your work: + +```shell + git add path/to/plugin + git commit -m "Add new plugin for XXXX refs #" + git push +``` + +### 9.2 FatPack generation + +Centreon plugin-pack use plugins through FatPack format. +To convert your plugin into Fatpack format follow this steps : + +Install libapp-fatpacker-perl +```shell +sudo apt install libapp-fatpacker-perl +``` + +Create a shell script ```plugin_generator.sh``` + +```shell +#!/bin/bash + +BuildDir=/home//fatpack_generator #Directory path where build the fatpack +GitPluginBranch=my-first-plugin #Branch you have create in "Set up your environment" section +PluginPath=cloud/docker/local #Path from src to your plugin directory +PluginPathMode=cloud/docker/local/mode #Path from src to your plugin mode directory +ScriptName=centreon_docker_ssh #Set the name of your Fatpack.pl / This name is the one used in plugin-pack + +if [ ! -d "$BuildDir" ]; then + echo 'Create BuildDir' + mkdir $BuildDir +fi +cd $BuildDir + +if [ -d "centreon-plugins" ]; then + echo 'Update centreon-plugins' + cd centreon-plugins + git checkout develop -f + git fetch + git checkout $GitPluginBranch -f + git pull + cd .. +else + echo 'Clone centreon-plugins' + git clone --branch $GitPluginBranch https://github.com/centreon/centreon-plugins.git +fi + +if [ -d "plugin" ]; then + echo 'Remove plugin' + rm -R plugin +fi +echo 'Create plugin/lib' +mkdir -p plugin/lib +cd $BuildDir/centreon-plugins/src +echo $PWD +echo 'Find pm' +find . -name "*.pm" -exec sed -i ' /__END__/d' {} \; + +echo 'Copy common plugins files' +cp -R --parent centreon/plugins/{http,misc,mode,options,output,perfdata,script,statefile,values}.pm centreon/plugins/backend/ centreon/plugins/templates/ centreon/plugins/alternative/ ../../plugin/lib/ +echo 'Copy centreon_plugins.pl' +cp centreon_plugins.pl ../../plugin +echo 'Prepare fatpacker' +cp -R --parent $PluginPathMode ../../plugin/lib/ +sed -i 's/alternative_fatpacker = 0/alternative_fatpacker = 1/' ../../plugin/lib/centreon/plugins/script.pm + +echo 'Copy plugin files' +cp -R --parent centreon/plugins/{script_snmp,snmp}.pm $PluginPath snmp_standard/mode/{cpu,cpudetailed,diskio,diskusage,inodes,interfaces,loadaverage,listdiskspath,listinterfaces,liststorages,memory,processcount,storage,swap,ntp,tcpcon,uptime}.pm snmp_standard/mode/resources/ ../../plugin/lib/ + +cd ../../plugin +echo 'Generate fatpack' +fatpack file centreon_plugins.pl > $ScriptName.pl +``` + +Execute plugin_generator.sh +```shell +sudo ./plugin_generator.sh +``` + +You can find your FatPack plugin in the folder plugin in ```BuildDir/plugin``` + +[Table of contents](#table_of_contents) + +
+ +## 10. Plugin outputs + +### 10.1 Formatting + +The output of a monitoring probe must always be: + +```bash +STATUS: Information text | metric1=[UOM];;;; metric2=value[OEM];;;; \n +Line 1 containing additional details \n +Line 2 containing additional details \n +Line 3 containing additional details \n +``` + +Let’s identify and name its three main parts: + +* Short output: everything before the pipe (`|`) +* Performance data and Metrics: everything after the pipe (`|`) +* Extended output: Everything after the first carriage return (`\n`), splitting each detail line is the best practice. + +### 10.2 Short output + +This part is the one users will more likely see in their monitoring tool or obtain as part of a push/alert message. The information should be straightforward and help identify what is going on quickly. + +A plugin must always propose at least such output: + +```bash +STATUS: Information text +``` + +`STATUS`must stick with return codes: + +* 0: OK +* 1: WARNING +* 2: CRITICAL +* 3: UNKNOWN + +`Information text` should display only relevant information. That implies: + +* showing only the bits of information that led to the NOT-OK state when an alarm is active +* keeping it short. When checking a large number of a single component (e.g. all partitions on a filer), try to construct a global message, then switch to the format above when an alarm arises. + +#### Centreon Plugin example + +The output when checking several storage partitions on a server, when everything is OK: + +`OK: All storages are ok |` + +The output of the same plugin, when one of the storage partition space usages triggers a WARNING threshold: + +`WARNING: Storage '/var/lib' Usage Total: 9.30 GB Used: 956.44 MB (10.04%) Free: 8.37 GB (89.96%) |` + +### 10.3 Performance data and metrics + +This part is not mandatory. However, if you want to benefit from Centreon or Nagios©-like tools with built-in metrology features, you will need to adopt this format: + +`metric1=[UOM];;;;` + +After the equals sign, split each piece of information about the metric using a semi-colon. + +* `metric1=`: The metric’s name is everything before the equals (=) sign. The more detailed it is, the easier it will be to understand a graph or to extend the usability of the metric in a third-party analytics/observability platform. De facto, a metric name must not contain an equals sign. Try to make it self-explanatory even without the Host/Service context. +* ``: The measurement result, must be a number (int, float) +* `[UOM]`: Optional Unit Of Measurement. You can also include the unit in the metric’s name as we do in the Centreon metric naming philosophy. It is one of the following: + * none (no unit specified), when dealing with a number of things (e.g. users, licences, viruses…) + * 's' when dealing with seconds. ‘us’ and ‘ms’ are also valid for microseconds or milliseconds (e.g. response or connection time) + * '%' when dealing with percentage (e.g. memory, CPU, storage space…) + * 'B' (Bytes), when dealing with storage, memory… The Byte must be the default as it ensures compatibility with all Centreon extensions + * When dealing with a network metric or any throughput, ‘b' (Bits). When computing a rate per second, you can use ‘b/s’ +* ``: Optional. Fill it with the user’s value as a WARNING threshold for the metric. +* ``: Optional. Fill it with the user-supplied value as a CRITICAL threshold for the metric. +* ``: Optional. Fill it with the lowest value the metric can take. +* ``: Optional. Fill it with the highest value the metric can take. + +Frequently, you have to manage the case where you have to display the same metric for several instances of things. The best practice is to choose a character to separate the metric name from its instance with a given character. At Centreon, we use the `#` sign, and we strongly recommend you do the same (it is recognised and processed by Centreon-Broker). + +Less frequently, you may want to add even more context; that’s why we created a sub-instance concept following the same principles. Append it to the instance of your metric and use a splitting character to clarify that it is another dimension and not confuse it with the primary instance. We use the `~` sign; once again, we strongly advise you to stick with it whenever it is possible. + +#### Centreon Plugin Performance Data / Metrics examples + +A **system boot partition** + +`'/boot#storage.space.usage.bytes'=255832064B;;0:99579084;0;995790848` + +`/boot` is the instance + +`storage.space.usage.bytes` is the metric name (note the .bytes at the end specifying the unit) + +`B` is the legacy metric’s unit for Bytes. + +Pay attention to the critical threshold (0:99579084), always use the same unit. + +A **network interface** + +`'eth0#interface.traffic.in.bitspersecond'=0.00b/s;;;0;` + +`eth0` is the instance + +`interface.traffic.in.bitspersecond` is the metric name (note the `.persecond` at the end specifying the unit) + +`b/s` is the legacy metric’s unit for bits per second + +A **cloud metric** + +`'azure-central~/var/lib/mysql#azure.insights.logicaldisk.free.percentage'=94.82%;;;0;100` + +`azure-central` is the instance + +`/var/lib/mysql` is the sub-instance + +`azure.insights.logicaldisk.free.percentage` is the metric name (note the `free` instead of `usage`, and `.percentage` at the end to specify the unit) + +`%` is the legacy metric’s unit + +### 10.4 Extended output + +The extended output's primary purpose is to display each bit of collected information separately on a single line. It will only print if the user adds a `--verbose` flag to its command. + +Overall, you should use it to: + +* add extra context (numbered instance, serial number) about a checked component +* print items the check excludes because plugin options have filtered them out +* organize how the information is displayed using groups that follow the logic of the check. + +#### Centreon Plugin example + +Here is an example of a Cisco device environment check: + +```bash +: | +Environment type: other +Checking fans + fan 'Switch X - FAN - T1 1, Normal' status is normal [instance: 1014]. + fan 'Switch X - FAN - T1 2, Normal' status is normal [instance: 1015]. + fan 'Switch X - FAN 1' status is up [instance: 1014] + fan 'Switch X - FAN 2' status is up [instance: 1015] +Checking power supplies + power supply 'Switch X - Power Supply B, Normal' status is normal [instance: 1013] [source: ac] + Power supply 'Switch X - Power Supply B' status is on [instance: 1013] +Checking temperatures + temperature 'Switch X - Inlet Temp Sensor, GREEN ' status is normal [instance: 1010] [value: 23 C] + temperature 'Switch X - Outlet Temp Sensor, GREEN ' status is normal [instance: 1011] [value: 30 C] + temperature 'Switch X - HotSpot Temp Sensor, GREEN ' status is normal [instance: 1012] [value: 41 C] +Checking voltages +Checking modules + module 'C9200L-48P-4G' status is ok [instance: 1000] +Checking physicals +Checking sensors + sensor 'Switch X - Temp Inlet Sensor 0' status is 'ok' [instance: 1010] [value: 23 celsius] + sensor 'Switch X - Temp Outlet Sensor 1' status is 'ok' [instance: 1011] [value: 30 celsius] + sensor 'Switch X - Temp Hotspot Sensor 2' status is 'ok' [instance: 1012] [value: 41 celsius] + sensor 'GigabitEthernet1/1/1 Module Temperature Sensor' status is 'ok' [instance: 1115] [value: 29.2 celsius] + sensor 'GigabitEthernet1/1/1 Supply Voltage Sensor' status is 'ok' [instance: 1116] [value: 3.3 voltsDC] + sensor 'GigabitEthernet1/1/1 Bias Current Sensor' status is 'ok' [instance: 1117] [value: 0.0202 amperes] + sensor 'GigabitEthernet1/1/1 Transmit Power Sensor' status is 'ok' [instance: 1118] [value: -4.5 dBm] + sensor 'GigabitEthernet1/1/1 Receive Power Sensor' status is 'ok' [instance: 1119] [value: -1.2 dBm] +``` + +[Table of contents](#table_of_contents) + +
+ +## 11. Plugins Options + +Option management is a central piece of a successful plugin. You should: + +* Carefully name your options to make them **self-explanatory** +* For a given option, there are two possible behaviours (but only one can apply to a given option): flag (boolean) to enable an option and value, where an additional argument must be provided to set the option's value. +* Always **check** the values supplied by the user and print a **clear message** when they do not fit with plugin requirements +* Set the option to a default value when relevant + +[Table of contents](#table_of_contents) + +
+ +## 12. Discovery + +This section describes how you should format your data to comply with the requirements of Centreon Discovery UI modules. + +In a nutshell: + +* [host discovery](/docs/monitoring/discovery/hosts-discovery) allows you to return a JSON list the autodiscovery module will understand so the user can choose to automatically or manually add to its monitoring configuration. Optionally, it can use one of the discovered items properties to make some decisions (filter in or out, create or assign a specific host group, etc.) +* [service discovery](/docs/monitoring/discovery/services-discovery) allows you to return XML data to help users configure unitary checks and link them to a given host (e.g. each VPN definition in AWS VPN, each network interface on a router...). + +There's no choice here; you should stick with the guidelines described here after if you want your code to be fully compliant with our modules. + +### 12.1 Hosts + +The discovery plugin can be a specific script or a particular execution mode enabled with an option. In centreon-plugins, we do it through dedicated `discovery*.pm` modes. + +This execution mode is limited to a query toward a cloud provider, an application, or whatever contains a list of assets. The expected output must hold some keys: + +* `end_time`: the unix timestamp when the execution stops +* `start_time`: the unix timestamp when the execution starts +* `duration`: the duration in seconds (`end_time - start_time`) +* `discovered_items`: the number of discovered items +* `results`: an array of hashes, each hash being a collection of key/values describing the discovered assets. + +```json title='Sample host discovery output' +{ + "end_time" : 1649431535, + "start_time" : 1649431534, + "duration" : 1, + "discovered_items" : 2, + "results" : [ + { + "public_dns_name" : "ec2-name.eu-west-1.compute.amazonaws.com", + "name" : "prod-ec2", + "key_name" : "prd-aws-ec2", + "tags" : [ + { + "value" : "Licences Management", + "key" : "Desc" + }, + { + "value" : "CI", + "key" : "Billing" + } + ], + "state" : "running", + "private_dns_name" : "ip-W-X-Y-Z.eu-west-1.compute.internal", + "vpc_id" : "vpc-xxxveafea", + "type" : "ec2", + "id" : "i-3feafea", + "private_ip" : "W.X.Y.Z", + "instance_type" : "t2.medium" + }, + { + "public_dns_name" : "other-ec2-name.eu-west-1.compute.amazonaws.com", + "name" : "prod-other-ec2", + "key_name" : "prd-aws-ec2", + "tags" : [ + { + "value" : "Licences Management", + "key" : "Desc" + }, + { + "value" : "CI", + "key" : "Billing" + } + ], + "state" : "running", + "private_dns_name" : "ip-A-B-C-D.eu-west-1.compute.internal", + "vpc_id" : "vpc-xxxveafea", + "type" : "ec2", + "id" : "i-3gfbgfb", + "private_ip" : "A.B.C.D", + "instance_type" : "t2.medium" + } + ] +} +``` + +You can use more advanced structures for values in the result sets, it can be: + +* an array of hashes: + +```json title='Nmap discovery - Tags' +"services" : [ + { + "name" : "ssh", + "port" : "22/tcp" + }, + { + "port" : "80/tcp", + "name" : "http" + } +] +``` + +* a flat array: + +```json title='VMWare discovery - IP vMotion' +"ip_vmotion" : [ + "10.10.5.21", + "10.30.5.21" +], +``` + +Using these structures is convenient when you need to group object properties behind a single key. + +On the users' side, it allows using these values to filter in or out some of the results or make a better choice +about the host template for a given discovered host. + +### 12.2 Services + +Service discovery relies on XML to return information that will be parsed and used by the UI module to +create new services efficiently. + +As for hosts, it can be an option at runtime, or an execution mode. In centreon-plugins, we choose to have dedicated +`list.pm` modes. + +All `list.pm` modes contain two options that will return properties and results that will be used in the +discovery rules definitions. + +The first service discovery option is `--disco-format`, it enables the plugin to return the supported keys in the rule: + +```bash title='Linux Network int --disco-format output' +-bash-4.2$ /usr/lib/centreon/plugins/centreon_linux_snmp.pl --plugin=os::linux::snmp::plugin --mode=list-interfaces --hostname=127.0.0.1 --disco-format + + + name + total + status + interfaceid + type + +``` + +The output above shows that the discovery of network interfaces on Linux will return those properties: + +- `name`: the name of the interface +- `total`: the maximum bandwidth supported +- `status`: the configuration status of the interface (convenient to exclude administratively down interfaces) +- `interfaceid`: the id +- `type`: interface type (like ethernet, fiber, loopback, etc.) + +Executing exactly the same command, substituting `--disco-format` with `--disco-show` will output the discovered interfaces: + +```bash title='Linux Network int --disco-show output' +/usr/lib/centreon/plugins/centreon_linux_snmp.pl --plugin=os::linux::snmp::plugin --mode=list-interfaces --hostname=127.0.0.1 --disco-show + + + +``` + +The result contains one line per interface and each line contains each set of properties as a `key="value"` pair. Note that even if +no data is obtained for a given key, it still has to be displayed (e.g `total=""`). + +[Table of contents](#table_of_contents) + +
+ +## 13. Performances + +A monitoring plugin has to do one thing and do it right - it's important to code your plugin with the idea to make +it as efficient as possible. Keep in mind that your Plugin might run every minute, against a large +number of devices, so a minor optimization can result in important benefits at scale. + +Also think about the 'thing' you're monitoring, it's important to always try to reduce the overhead of a check +from the monitored object point of view. + +### 13.1 Execution time + +The most basic way to bench a plugin performance is its execution time. Use the +`time` command utility to run your check and measure over several runs how it behaves. + +### 13.2 Cache + +In some cases, it can be interesting to cache some information. + +Caching in a local file might save some calls against an API, for example do not authenticate at every check. +When possible, use the token obtained at the first check and stored in the cache file to only call the +authentication endpoint when it's absolutely necessary. + +More generally, when an identifier, name or anything that would never change across different executions requires a +request against the third-party system, cache it to optimize single-check processing time. + +### 13.3 Algorithm + +Optimizing the number of requests against a third-party system can also lie in the check algorithm. Prefer scraping +the maximum of data in one check and then filter the results programmatically instead of issuing multiple very specific +requests that would result in longer execution time and greater load on the target system. + +### 13.4 Timeout + +A Plugin must always include a timeout to avoid never ending checks that might overload your monitoring +system when something is broken and that, for any reason, the plugin cannot obtain the information. + +[Table of contents](#table_of_contents) + +
+ +## 14. Security + +### 14.1 System commands + +If the plugin requires to execute a command at the operating system level, and users can modify the command name or +its parameters, make sure that nobody can leverage your plugin's capabilities to break the underlying +system or access sensitive information. + +#### 14.2 Dependencies + +There is no need to re-invent the wheel: standard centreon-plugins dependencies provide you with the most common +external libraries that might be required to write a new plugin. + +Don't overuse large libraries that might end being unsupported or where some governance modification might lead to +security problems. + +[Table of contents](#table_of_contents) + +
+ +## 15. Help and documentation + +For each plugin, the minimum documentation is the help, you have to explain to users what the plugin +is doing and how they can use the built-in options to achieve their own alerting scenario. + +You can look at how we handle help at mode level with the centreon-plugins framework [here](develop-with-centreon-plugins.md). + +[Table of contents](#table_of_contents) diff --git a/doc/en/developer/tutorial-api.md b/doc/en/developer/tutorial-api.md new file mode 100644 index 000000000..ebb618ee7 --- /dev/null +++ b/doc/en/developer/tutorial-api.md @@ -0,0 +1,1101 @@ +# API plugin tutorial + +All files showed in this section can be found on the centreon-plugins GitHub in +the [tutorial](https://github.com/centreon/centreon-plugins/tree/develop/src/contrib/tutorial) **contrib** +section. + +> You have to move the contents of `contrib/tutorial/apps/` to `apps/` if you want to run it for testing purposes. +> +> `cp -R src/contrib/tutorial/apps/* src/apps/` + +**Context: simple JSON health API** + +In this tutorial, we will create a very simple probe checking an application's health +displayed in JSON through a simple API. + +You can mockup an API with the free [mocky](https://designer.mocky.io/) tool. +We created one for this tutorial, test it with `curl https://run.mocky.io/v3/da8d5aa7-abb4-4a5f-a31c-6700dd34a656` + +It returns the following output: + +```json title="my-awesome-app health JSON" +{ + "health": "yellow", + "db_queries":{ + "select": 1230, + "update": 640, + "delete": 44 + }, + "connections":[ + { + "component": "my-awesome-frontend", + "value": 122 + }, + { + "component": "my-awesome-db", + "value": 92 + } + ], + "errors":[ + { + "component": "my-awesome-frontend", + "value": 32 + }, + { + "component": "my-awesome-db", + "value": 27 + } + ] +} +``` + +## 1. Understand the data + +Understanding the data is very important as it will drive the way you will design +the **mode** internals. This is the **first thing to do**, no matter what protocol you +are using. + +There are several important properties for a piece of data: + +- Type of the data to process: string, int... There is no limitation in the kind of data you can process +- Dimensions of the data, is it **global** or linked to an **instance**? +- Data layout, in other words anticipate the kind of **data structure** to manipulate. + +In our example, the most common things are present. We can summarize it like that: + +- the `health` node is **global** data and is a string. Structure is a simple *key/value* pair +- the `db_queries` node is a collection of **global** integer values about the database. Structure is a hash containing multiple key/value pairs +- the `connections` node contains integer values (`122`, `92`) referring to specific **instances** (`my-awesome-frontend`, `my-awesome-db`). The structure is an array of hashes +- `errors` is the same as `connections` except the data itself tracks errors instead of connections. + +Understanding this will be important to code it correctly. + +## 2. Create directories for a new plugin + +Create directories and files required for your **plugin** and **modes**. + +Go to your centreon-plugins local git and create the appropriate directories and files: + +```shell +# path to the main directory and the subdirectory containing modes +mkdir -p src/apps/myawesomeapp/api/mode/ +# path to the main plugin file +touch src/apps/myawesomeapp/api/plugin.pm +# path to the specific mode(s) file(s) => for example appsmetrics.pm +touch src/apps/myawesomeapp/api/mode/appsmetrics.pm +``` + +## 3. Create the plugin file : plugin.pm + +Here is the commented version of the plugin.pm file: + +```perl title="my-awesome-app plugin.pm file" +[.. license and copyright things ..] + +# Name of your perl package +package apps::myawesomeapp::api::plugin; + +# Always use strict and warnings, will guarantee that your code is clean and help debugging it +use strict; +use warnings; +# Load the base for your plugin, here we don't do SNMP, SQL or have a custom directory, so we use the _simple base +use base qw(centreon::plugins::script_simple); + +# Global sub to create and return the perl object. Don't bother understand what each instruction is doing. +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + # A version, we don't really use it but could help if your want to version your code + $self->{version} = '0.1'; + # Important part! + # On the left, the name of the mode as users will use it in their command line + # On the right, the path to the file (note that .pm is not present at the end) + $self->{modes} = { + 'app-metrics' => 'apps::myawesomeapp::api::mode::appmetrics' + }; + + return $self; +} + +# Declare this file as a perl module/package +1; + +# Beginning of the documenation/help. `__END__` Specify to the interpreter that instructions below don't need to be compiled +# =head1 [..] Specify the section level and the label when using the plugin with --help +# Check my-awesome [..] Quick overview of wath the plugin is doing +# =cut Close the head1 section + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check my-awesome-app health and metrics through its custom API + +=cut +``` + +Your first dummy plugin is working, congrats! + +Run this command: + +`perl centreon_plugins.pl --plugin=apps::myawesomeapp::api::plugin --list-mode` + +It already outputs a lot of things. Ellipsized lines are basically all standard capabilities +inherited from the **script_custom** base. + +You probably already recognized things you've previsously defined in your **plugin.pm** module. + +```perl + +Plugin Description: + Check my-awesome-app health and metrics through its custom API + +Global Options: + --mode Choose a mode. +[..] + --version + Display plugin version. +[..] + +Modes Available: + app-metrics +``` + +## 4. Create the mode file : appmetrics.pm + +The `appmetrics.pm` file will contain your code, in other words, all the instructions to: + +- Declare options for the mode +- Connect to **run.mocky.io** over HTTPS +- Get the JSON from the **/v3/da8d5aa7-abb4-4a5f-a31c-6700dd34a656** endpoint +- Extract information and format it to be compliant with Centreon. + +Let's build it iteratively. + +> Important note: function (sub) names must not be modified. For example, you cannot +> choose to rename `check_options` to `option_check`. + +### 4.1 Common declarations and subs + +```perl +# Path to your package. '::' instead of '/', and no .pm at the end. +package apps::myawesomeapp::api::mode::appmetrics; + +# Don't forget these ;) +use strict; +use warnings; +# We want to connect to an HTTP server, let's use the common module +use centreon::plugins::http; +# Use the counter module. It will save you a lot of work and will manage a lot of things for you. +# Consider this as mandatory when writing a new mode. +use base qw(centreon::plugins::templates::counter); +# Import some functions that will make your life easier +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); +# We will have to process some JSON, no need to reinvent the wheel, load the lib you installed in a previous section +use JSON::XS; +``` + +Add a `new` function (sub) to initialize the mode: + +```perl +sub new { + my ($class, %options) = @_; + # All options/properties of this mode, always add the force_new_perfdata => 1 to enable new metric/performance data naming. + # It also where you can specify that the plugin uses a cache file for example + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + # This is where you can specify options/arguments your plugin supports. + # All options here stick to what the centreon::plugins::http module needs to establish a connection + # You don't have to specify all options from the http module, only the one that the user may want to tweak for its needs + $options{options}->add_options(arguments => { + # On the left it's the option name that will be used in the command line. The ':s' at the end is to + # define that this options takes a value. + # On the right, it's the code name for this option, optionally you can define a default value so the user + # doesn't have to set it + 'hostname:s' => { name => 'hostname' }, + 'proto:s' => { name => 'proto', default => 'https' }, + 'port:s' => { name => 'port', default => 443 }, + 'timeout:s' => { name => 'timeout' }, + # These options are here to defined conditions about which status the plugin will return regarding HTTP response code + 'unknown-status:s' => { name => 'unknown_status', default => '%{http_code} < 200 or %{http_code} >= 300' }, + 'warning-status:s' => { name => 'warning_status' }, + 'critical-status:s' => { name => 'critical_status', default => '' } + }); + + # This is to create a local copy of a centreon::plugins::http that we will manipulate + # %options basically overwrite default http value with key/value pairs from options above to instantiate the http module + # Ref https://github.com/centreon/centreon-plugins/blob/520a1f8c10cd434c6dedd1e342285eecff8b9d1b/centreon/plugins/http.pm#L59 + $self->{http} = centreon::plugins::http->new(%options); + return $self; +} +``` + +Add a `check_options` function. This sub will execute right after `new` and allow you to check that the user passed + mandatory parameter(s) and in some case check that the format is correct. + +```perl +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + # Check if the user provided a value for --hostname option. If not, display a message and exit + if (!defined($self->{option_results}->{hostname}) || $self->{option_results}->{hostname} eq '') { + $self->{output}->add_option_msg(short_msg => 'Please set hostname option'); + $self->{output}->option_exit(); + } + # Set parameters for http module, note that the $self->{option_results} is a hash containing + # all your options key/value pairs. + $self->{http}->set_options(%{$self->{option_results}}); +} + +1; +``` + +Nice work, you now have a mode that can be executed without errors! + +Run this command `perl centreon_plugins.pl --plugin=apps::myawesomeapp::api::plugin --mode=app-metrics`, which +outputs this message: + +`UNKNOWN: Please set hostname option` + +Now let's do some monitoring thanks to centreon-plugins. + +### 4.2 Declare your counters + +This part essentially maps the data you want to get from the API with the internal +counter mode structure. + +Remember how we categorized the data in the previous section understand-the-data. + +The `$self->{maps_counters_type}` data structure describes these data while the `$self->{maps_counters}->{global}` one defines +their properties like thresholds and how they will be displayed to the users. + +```perl +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + # health and queries are global metric, they don't refer to a specific instance. + # In other words, you cannot get several values for health or queries + # That's why the type is 0. + { name => 'health', type => 0, cb_prefix_output => 'prefix_health_output' }, + { name => 'queries', type => 0, cb_prefix_output => 'prefix_queries_output' }, + # app_metrics groups connections and errors and each will receive value for both instances (my-awesome-frontend and my-awesome-db) + # the type => 1 explicits that + # as above, you can define a callback (cb) function to manage the output prefix. This function is called + # each time a value is passed to the counter and can be shared across multiple counters. + { name => 'app_metrics', type => 1, cb_prefix_output => 'prefix_app_output' } + ]; + + $self->{maps_counters}->{health} = [ + # This counter is specific because it deals with a string value + { + label => 'health', + # All properties below (before et) are related to the catalog_status_ng catalog function imported at the top of our mode + type => 2, + # These properties allow you to define default thresholds for each status but not mandatory. + warning_default => '%{health} =~ /yellow/', + critical_default => '%{health} =~ /red/', + # To simplify, manage things related to how get value in the counter, what to display and specific threshold + # check because of the type of the data (string) + set => { + key_values => [ { name => 'health' } ], + output_template => 'status: %s', + # Force ignoring perfdata as the collected data is a string + closure_custom_perfdata => sub { return 0; }, + closure_custom_threshold_check => \&catalog_status_threshold_ng + } + } + ]; + $self->{maps_counters}->{queries} = [ + # The label defines options name, a --warning-select and --critical-select will be added to the mode + # The nlabel is the name of your performance data / metric that will show up in your graph + { + label => 'select', + nlabel => 'myawesomeapp.db.queries.select.count', + set => { + # Key value name is the name we will use to pass the data to this counter. You can have several ones. + key_values => [ { name => 'select' } ], + # Output template describe how the value will display + output_template => 'select: %s', + # Perfdata array allow you to define relevant metrics properties (min, max) and its sprintf template format + perfdatas => [ + { template => '%d', min => 0 } + ] + } + }, + { label => 'update', nlabel => 'myawesomeapp.db.queries.update.count', set => { + key_values => [ { name => 'update' } ], + output_template => 'update: %s', + perfdatas => [ + { template => '%d', min => 0 } + ] + } + }, + { label => 'delete', nlabel => 'myawesomeapp.db.queries.delete.count', set => { + key_values => [ { name => 'delete' } ], + output_template => 'delete: %s', + perfdatas => [ + { template => '%d', min => 0 } + ] + } + } + ]; + $self->{maps_counters}->{app_metrics} = [ + # The app_metrics has two different labels, connection and errors. + { label => 'connections', nlabel => 'myawesomeapp.connections.count', set => { + # pay attention the extra display key_value. It will receive the instance value. (my-awesome-db, my-awesome-frontend). + # the display key_value isn't mandatory but we show it here for education purpose + key_values => [ { name => 'connections' }, { name => 'display' } ], + output_template => 'connections: %s', + perfdatas => [ + # we add the label_extra_instance option to have one perfdata per instance + { template => '%d', min => 0, label_extra_instance => 1 } + ] + } + }, + { label => 'errors', nlabel => 'myawesomeapp.errors.count', set => { + key_values => [ { name => 'errors' }, { name => 'display' } ], + output_template => 'errors: %s', + perfdatas => [ + { template => '%d', min => 0, label_extra_instance => 1 } + ] + } + } + ]; +} + +# This should always be present at the end of the script. +1; +``` + +> Remember to always move the final `1;` instruction at the end of the script when you add new lines during this tutorial. + +The mode compiles. Run the command +supplying a value to the `--hostname` option to see what it displays: + +```shell +perl centreon_plugins.pl --plugin=apps::myawesomeapp::api::plugin --mode=app-metrics --hostname=fakehost +OK: status : skipped (no value(s)) - select : skipped (no value(s)), update : skipped (no value(s)), delete : skipped (no value(s)) +``` + +You can see some of your counters with the `skipped (no value(s))`, it's normal, this is because we +just created the counters definition and structure but didn't push any values into it. + +### 4.3 Create prefix callback functions + +These functions are not mandatory but help to make the output more readable for a human. We will create +it now but as you have noticed the mode compiles so you can choose to keep those for the polishing moment. + +During counters definitions, we associated a callback function to each of them: + +- `cb_prefix_output => 'prefix_health_output'` +- `cb_prefix_output => 'prefix_queries_output'` +- `cb_prefix_output => 'prefix_app_output'` + +Define those functions by adding it to our `appmetrics.pm` file. They are self-explanatory. + +```perl +sub prefix_health_output { + my ($self, %options) = @_; + + return 'My-awesome-app:'; +} + +sub prefix_queries_output { + my ($self, %options) = @_; + + return 'Queries:'; +} + +sub prefix_app_output { + my ($self, %options) = @_; + + # This notation allows you to return the value of the instance (the display key_value) + # to bring some context to the output. + return "'" . $options{instance_value}->{display} . "' "; +} + +1; +``` + +Execute your command and check that the output matches the one below: + +```shell +perl centreon_plugins.pl --plugin=apps::myawesomeapp::api::plugin --mode=app-metrics --hostname=fakehost +OK: My-awesome-app: status : skipped (no value(s)) - Queries: select : skipped (no value(s)), update : skipped (no value(s)), delete : skipped (no value(s)) +``` + +The output is easier to read and separators are visible between global counters. + +### 4.4 Get raw data from API and understand the data structure + +It's the moment to write the main sub (`manage_selection`) - the most complex, but also the one that +will transform your mode to something useful and alive. + +Think about the logic, what we have to do is: + +- Connect to **run.mocky.io** over HTTPS +- Query a specific path corresponding to our API +- Store and process the result +- Spread this result across counters definitions + +Start by writing the code to connect to **run.mocky.io**. It is where the centreon-plugins +framework delivers its power. + +> All print instructions are available as commented code in the GitHub tutorial resources. + +Write the request and add a print to display the received data: + +```perl +sub manage_selection { + my ($self, %options) = @_; + # We have already loaded all things required for the http module + # Use the request method from the module to run the GET request against the path + my ($content) = $self->{http}->request(url_path => '/v3/da8d5aa7-abb4-4a5f-a31c-6700dd34a656'); + print $content . "\n"; +} + +1; +``` + +Run this command `perl centreon_plugins.pl --plugin=apps::myawesomeapp::api::plugin --mode=app-metrics --hostname=run.mocky.io`. + +The output should be: + +```perl title="Basic raw content print" +{ + "health": "yellow", + "db_queries":{ + "select": 1230, + "update": 640, + "delete": 44 + }, + "connections":[ + { + "component": "my-awesome-frontend", + "value": 122 + }, + { + "component": "my-awesome-db", + "value": 92 + } + ], + "errors":[ + { + "component": "my-awesome-frontend", + "value": 32 + }, + { + "component": "my-awesome-db", + "value": 27 + } + ] +} +OK: My-awesome-app: status : skipped (no value(s)) - Queries: select : skipped (no value(s)), update : skipped (no value(s)), delete : skipped (no value(s)) +``` + +Add an `eval` structure to transform `$content` into a data structure that can be easily manipulated with perl. Let's +introduce the standard `Data::Dumper` library that can help understanding your data structures. + +We load the Data::Dumper library and use one of its methods to print the JSON. A second line is here to print +a simple message and get you familiar with how to access data within perl data structures. + +```perl +sub manage_selection { + my ($self, %options) = @_; + # We have already loaded all things required for the http module + # Use the request method from the imported module to run the GET request against the URL path of our API + my ($content) = $self->{http}->request(url_path => '/v3/da8d5aa7-abb4-4a5f-a31c-6700dd34a656'); + + # Declare a scalar deserialize the JSON content string into a perl data structure + my $decoded_content; + eval { + $decoded_content = JSON::XS->new->decode($content); + }; + # Catch the error that may arise in case the data received is not JSON + if ($@) { + $self->{output}->add_option_msg(short_msg => "Cannot encode JSON result"); + $self->{output}->option_exit(); + } + use Data::Dumper; + print Dumper($decoded_content); + print "My App health is '" . $decoded_content->{health} . "'\n"; +} + +1; +``` + +Run the command `perl centreon_plugins.pl --plugin=apps::myawesomeapp::api::plugin --mode=app-metrics --hostname=run.mocky.io` +again and see how it changed. + +You now have your JSON deserialized into a perl `$VAR1` which represents your `$decoded_content` structure. + +You can also note the result of the latest print and how we accessed the `yellow` value. + +```shell tile="Perl data structure from JSON" +$VAR1 = { + 'connections' => [ + { + 'component' => 'my-awesome-frontend', + 'value' => 122 + }, + { + 'value' => 92, + 'component' => 'my-awesome-db' + } + ], + 'health' => 'yellow', + 'errors' => [ + { + 'value' => 32, + 'component' => 'my-awesome-frontend' + }, + { + 'value' => 27, + 'component' => 'my-awesome-db' + } + ], + 'db_queries' => { + 'select' => 1230, + 'update' => 640, + 'delete' => 44 + } + }; +My App health is 'yellow' +``` + +### 4.5 Push data to global counters (type => 0) + +Now that we know our data structure and how to access the values, we have to assign this +value to the counters we initially defined. Pay attention to the comments above +the `$self->{health}` and `$self->{db_queries}` assignations. + +```perl title="Global counters (type => 0)" +sub manage_selection { + my ($self, %options) = @_; + # We have already loaded all things required for the http module + # Use the request method from the imported module to run the GET request against the URL path of our API + my ($content) = $self->{http}->request(url_path => '/v3/da8d5aa7-abb4-4a5f-a31c-6700dd34a656'); + # Uncomment the line below when you reached this part of the tutorial. + # print $content; + + # Declare a scalar deserialize the JSON content string into a perl data structure + my $decoded_content; + eval { + $decoded_content = JSON::XS->new->decode($content); + }; + # Catch the error that may arise in case the data received is not JSON + if ($@) { + $self->{output}->add_option_msg(short_msg => "Cannot encode JSON result"); + $self->{output}->option_exit(); + } + # Uncomment the lines below when you reached this part of the tutorial. + # use Data::Dumper; + # print Dumper($decoded_content); + # print "My App health is '" . $decoded_content->{health} . "'\n"; + + # Here is where the counter magic happens. + + # $self->{health} is your counter definition (see $self->{maps_counters}->{}) + # Here, we map the obtained string $decoded_content->{health} with the health key_value in the counter. + $self->{health} = { + health => $decoded_content->{health} + }; + + # $self->{queries} is your counter definition (see $self->{maps_counters}->{}) + # Here, we map the obtained values from the db_queries nodes with the key_value defined in the counter. + $self->{queries} = { + select => $decoded_content->{db_queries}->{select}, + update => $decoded_content->{db_queries}->{update}, + delete => $decoded_content->{db_queries}->{delete} + }; + +} + +1; +``` + +Let's run our command again: no more `skipped (no value(s))` message. You even get a +WARNING state because of the `yellow` app state. + +```shell +perl centreon_plugins.pl --plugin=apps::myawesomeapp::api::plugin --mode=app-metrics --hostname=run.mocky.io +WARNING: My-awesome-app status: yellow | 'myawesomeapp.db.queries.select.count'=1230;;;0; 'myawesomeapp.db.queries.update.count'=640;;;0; 'myawesomeapp.db.queries.delete.count'=44;;;0; +``` + +Performance data confirm that values for database queries are correctly set as well. + +This is how the counters mode template work (`use base qw(centreon::plugins::templates::counter);`), the only thing you have +to do is getting the data from the thing you have to monitor and push it to a counter definition. + +Behind the scenes, it manages a lot of things for you: + +- Options: `--warning-health --warning-select --warning-update --warning-delete and --critical-` have automatically been defined +- Performance data: thanks to `nlabel` and values from `perfdatas:[]` array in your counters +- Display: It writes the status and substitutes values with the one assigned to the counter + +Now, you probably understand better why the preparation work about understanding collected data and the counter definition part is essential: simply because it's the bigger part of the job. + +### 4.6 Push data to counters having an instance (type => 1) + +Now let's deal with counters with instances. That means that the same counters will +receive multiple data, each of these data refering to a specific dimension. + +They require to be manipulated in a slightly different way as we will have to specify the +name we want to associate with the data. + +First, we have to loop over both `connections` and `errors` arrays to access the app name and +measured value and then spread it within counters. + +```perl title="Counters with instances (type 1)" +sub manage_selection { + my ($self, %options) = @_; + # We have already loaded all things required for the http module + # Use the request method from the imported module to run the GET request against the URL path of our API + my ($content) = $self->{http}->request(url_path => '/v3/da8d5aa7-abb4-4a5f-a31c-6700dd34a656'); + # Uncomment the line below when you reached this part of the tutorial. + # print $content; + + # Declare a scalar deserialize the JSON content string into a perl data structure + my $decoded_content; + eval { + $decoded_content = JSON::XS->new->decode($content); + }; + # Catch the error that may arise in case the data received is not JSON + if ($@) { + $self->{output}->add_option_msg(short_msg => "Cannot encode JSON result"); + $self->{output}->option_exit(); + } + # Uncomment the lines below when you reached this part of the tutorial. + # use Data::Dumper; + # print Dumper($decoded_content); + # print "My App health is '" . $decoded_content->{health} . "'\n"; + + # Here is where the counter magic happens. + + # $self->{health} is your counter definition (see $self->{maps_counters}->{}) + # Here, we map the obtained string $decoded_content->{health} with the health key_value in the counter. + $self->{health} = { + health => $decoded_content->{health} + }; + + # $self->{queries} is your counter definition (see $self->{maps_counters}->{}) + # Here, we map the obtained values from the db_queries nodes with the key_value defined in the counter. + $self->{queries} = { + select => $decoded_content->{db_queries}->{select}, + update => $decoded_content->{db_queries}->{update}, + delete => $decoded_content->{db_queries}->{delete} + }; + + # Initialize an empty app_metrics counter. + $self->{app_metrics} = {}; + # Loop in the connections array of hashes + foreach my $entry (@{ $decoded_content->{connections} }) { + # Same logic than type => 0 counters but an extra key $entry->{component} to associate the value + # with a specific instance + $self->{app_metrics}->{ $entry->{component} }->{display} = $entry->{component}; + $self->{app_metrics}->{ $entry->{component} }->{connections} = $entry->{value}; + }; + + # Exactly the same thing with errors + foreach my $entry (@{ $decoded_content->{errors} }) { + # Don't need to redefine the display key, just assign a value to the error key_value while + # keeping the $entry->{component} key to associate the value with the good instance + $self->{app_metrics}->{ $entry->{component} }->{errors} = $entry->{value}; + }; + +} + +1; +``` + +Your `app-metrics` mode is (almost) complete. Once again, the counters template managed a lot +behind the scenes. + +Execute this command to see how it evolved since the last execution. We modify the command with some +additional parameters: + +- `--warning-health='%{health} eq "care"'` to avoid getting a WARNING, put any value that will not match yellow. Providing it +as a parameter will automatically override the hardcoded default code value +- `--verbose` will display the long output and the details for each `type => 1` counters + +```shell +perl centreon_plugins.pl --plugin=apps::myawesomeapp::api::plugin --mode=app-metrics --hostname=run.mocky.io --warning-health='%{health} eq "care"' --verbose +``` + +Here is the expected output: + +```shell +OK: My-awesome-app status: yellow - Queries: select: 1230, update: 640, delete: 44 | 'myawesomeapp.db.queries.select.count'=1230;;;0; 'myawesomeapp.db.queries.update.count'=640;;;0; 'myawesomeapp.db.queries.delete.count'=44;;;0; 'my-awesome-db#myawesomeapp.connections.count'=92;;;0; 'my-awesome-db#myawesomeapp.errors.count'=27;;;0; 'my-awesome-frontend#myawesomeapp.connections.count'=122;;;0; 'my-awesome-frontend#myawesomeapp.errors.count'=32;;;0; +'my-awesome-db' connections: 92, errors: 27 +'my-awesome-frontend' connections: 122, errors: 32 +``` + +You now get metrics displayed for both components `'my-awesome-db'` and `'my-awesome-frontend'` and also performance data +for your graphs. Note how the counter template automatically added the instance dimension on the left of the `nlabel` defined +for each counters: **my-awesome-frontend#** myawesomeapp.errors.count'=32;;;0; + +### 4.7 Help section and assistant to build your centreon objects + +Last but not least, you need to write a help section to explain users what your mode is +doing and what options they can use. + +The centreon-plugins framework has a built-in assistant to help you with the list of counters +and options. + +Run this command to obtain a summary that will simplify the work of creating Centreon commands and write +the mode's help: + +```shell +perl centreon_plugins.pl --plugin=apps::myawesomeapp::api::plugin --mode=app-metrics --hostname='anyvalue' --list-counters --verbose +``` + +Get information from its output (shown below) to start building your mode's help: + +```shell +counter list: select update delete health connections errors +configuration: --warning-select='$_SERVICEWARNINGSELECT$' --critical-select='$_SERVICECRITICALSELECT$' --warning-update='$_SERVICEWARNINGUPDATE$' --critical-update='$_SERVICECRITICALUPDATE$' --warning-delete='$_SERVICEWARNINGDELETE$' --critical-delete='$_SERVICECRITICALDELETE$' --warning-health='$_SERVICEWARNINGHEALTH$' --critical-health='$_SERVICECRITICALHEALTH$' --warning-connections='$_SERVICEWARNINGCONNECTIONS$' --critical-connections='$_SERVICECRITICALCONNECTIONS$' --warning-errors='$_SERVICEWARNINGERRORS$' --critical-errors='$_SERVICECRITICALERRORS$' +``` + +Here is how you can write the help, note that this time you will add the content after the `1;` and add the same +`__END__` instruction like you did in the `plugin.pm` file. + + +```perl title="Help section" +__END__ + +=head1 MODE + +Check my-awesome-app metrics exposed through its API + +=over 8 + +=item B<--warning/critical-health> + +Warning and critical threshold for application health string. + +Defaults values are: --warning-health='%{health} eq "yellow"' --critical-health='%{health} eq "red"' + +=item B<--warning/critical-select> + +Warning and critical threshold for select queries + +=item B<--warning/critical-update> + +Warning and critical threshold for update queries + +=item B<--warning/critical-delete> + +Warning and critical threshold for delete queries + +=item B<--warning/critical-connections> + +Warning and critical threshold for connections + +=item B<--warning/critical-errors> + +Warning and critical threshold for errors + +=back +``` + +You're done! You can enjoy a complete plugin and mode and the help now displays in a specific +mode section: + + +```shell +perl centreon_plugins.pl --plugin=apps::myawesomeapp::api::plugin --mode=app-metrics --help +[.. + All global options from the centreon-plugins framework that your plugin benefits from +..] +Mode: + Check my-awesome-app metrics exposed through its API + + --warning/critical-health + Warning and critical threshold for application health string. + + Defaults are: --warning-health='%{health} eq "yellow"' & + --critical-health='%{health} eq "red"' + + --warning/critical-select + Warning and critical threshold for select queries + + --warning/critical-update + Warning and critical threshold for update queries + + --warning/critical-delete + Warning and critical threshold for delete queries + + --warning/critical-connections + Warning and critical threshold for connections + + --warning/critical-errors + Warning and critical threshold for errors +``` + +## 5. Convert in custom mode + +Custom mode is a well established type of plugin. Then it can be useful to understand the way to build and use it. +Custom is a mode made for when you may have different way to collect plugin input. More broadly, plugins using custom mode afford flexibility if later you have to add a new way to give input in a plugin. This is the main reason why most of latest plugins are in custom mode baseline. + +Most of the time the way to collect input use api and this is the most common custom mode you will find in plugins. +There are also cli file for command line or tcp, etc. + +In our example case of tutoral it's an api case. + +### 5.1 Create custom file + +First we need to create the custom file : api.pm + +```shell +mkdir -p src/apps/myawesomeapp/api/custom/ +touch src/apps/myawesomeapp/api/custom/api.pm +``` +### 5.2 Changes in plugin.pm + +First we need to change plugins script libraririe : +```perl +centreon::plugins::script_simple +``` +replace by +```perl +centreon::plugins::script_custom +``` +Then in new constructor a new line calling for the custom is needed +```perl +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + 'app-metrics' => 'apps::myawesomeapp::api::mode::appmetrics' + }; + + $self->{custom_modes}->{api} = 'apps::myawesomeapp::api::custom::api'; + return $self; +} +``` +### 5.3 Changes in mode.pm + +Custom mode allows to change the way to obtain input, thus all that concern input and the way to process it is push to the custom file. The mode file will contain all needed functions for processing input to give the output needed. + +First the new constructor will change : +```perl +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; +} +``` + +The check_options function is push into the custom file because it was usefull for the input formating + +The manage_selection function is updated to remove all that concern the input management. + +```perl +sub manage_selection { + my ($self, %options) = @_; + + #This line replace the input section previously available here + my $results = $options{custom}->request_api(); + + # $self->{health} is your counter definition (see $self->{maps_counters}->{}) + # Here, we map the obtained string $decoded_content->{health} with the health key_value in the counter. + $self->{health} = { + health => $results->{health} + }; + + # $self->{queries} is your counter definition (see $self->{maps_counters}->{}) + # Here, we map the obtained values from the db_queries nodes with the key_value defined in the counter. + $self->{queries} = { + select => $results->{db_queries}->{select}, + update => $results->{db_queries}->{update}, + delete => $results->{db_queries}->{delete} + }; + + # Initialize an empty app_metrics counter. + $self->{app_metrics} = {}; + # Loop in the connections array of hashes + foreach my $entry (@{ $results->{connections} }) { + # Same logic than type => 0 counters but an extra key $entry->{component} to associate the value + # with a specific instance + $self->{app_metrics}->{ $entry->{component} }->{display} = $entry->{component}; + $self->{app_metrics}->{ $entry->{component} }->{connections} = $entry->{value} + }; + + # Exactly the same thing with errors + foreach my $entry (@{ $results->{errors} }) { + # Don't need to redefine the display key, just assign a value to the error key_value while + # keeping the $entry->{component} key to associate the value with the good instance + $self->{app_metrics}->{ $entry->{component} }->{errors} = $entry->{value}; + }; +} +``` + +### 5.4 New file : api.pm + +As explained in the previous section, the custom file will contain all needed functions about input and the way to process it. + +This new file needs to contains the packages and libraries declarations : + +```perl +package apps::myawesomeapp::api::custom::api; + +use strict; +use warnings; + +use centreon::plugins::http; +use centreon::plugins::templates::catalog_functions qw(catalog_status_threshold_ng); +use JSON::XS; +``` + +It also contains the following functions : +* new constructor : construct the object in the same way than in mode file previously +* set_options +* set_defaults +* check_options +* settings +* request_api + +#### new constructor + +```perl +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 avaliable + 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' }, + 'proto:s' => { name => 'proto', default => 'https' }, + 'port:s' => { name => 'port', default => 443 }, + 'timeout:s' => { name => 'timeout' }, + 'unknown-status:s' => { name => 'unknown_status', default => '%{http_code} < 200 or %{http_code} >= 300' }, + 'warning-status:s' => { name => 'warning_status' }, + 'critical-status:s' => { name => 'critical_status', default => '' } + }); + } + # Adding Help structure to the object + $options{options}->add_help(package => __PACKAGE__, sections => 'REST API OPTIONS', once => 1); + # Adding output structure to the object + $self->{output} = $options{output}; + # Command line legacy from appsmetrics.pm in single mode + $self->{http} = centreon::plugins::http->new(%options); + + return $self; +} +``` + +#### set_options + +This function overwrite the set_options function in http module + +```perl +sub set_options { + my ($self, %options) = @_; + + $self->{option_results} = $options{option_results}; +} +``` + +#### set_defaults + +This function is empty. + +```perl +sub set_defaults {} +``` + +#### check_options + +```perl +sub check_options { + my ($self, %options) = @_; + + # Check if options are propely define + $self->{hostname} = (defined($self->{option_results}->{hostname})) ? $self->{option_results}->{hostname} : ''; + $self->{proto} = (defined($self->{option_results}->{proto})) ? $self->{option_results}->{proto} : 'https'; + $self->{port} = (defined($self->{option_results}->{port})) ? $self->{option_results}->{port} : 443; + $self->{timeout} = (defined($self->{option_results}->{timeout})) ? $self->{option_results}->{timeout} : 10; + $self->{unknown_status} = (defined($self->{option_results}->{unknown_status})) ? $self->{option_results}->{unknown_status} : ''; + $self->{warning_status} = (defined($self->{option_results}->{warning_status})) ? $self->{option_results}->{warning_status} : ''; + $self->{critical_status} = (defined($self->{option_results}->{critical_status})) ? $self->{option_results}->{critical_status} : ''; + + # Check if the user provided a value for --hostname option. If not, display a message and exit + if (!defined($self->{hostname}) || $self->{hostname} eq '') { + $self->{output}->add_option_msg(short_msg => 'Please set hostname option'); + $self->{output}->option_exit(); + } + + return 0; +} +``` + +#### settings + +This function allows to initialize api object options structure and feed it calling set_options + +```perl +sub settings { + my ($self, %options) = @_; + + # Initialize options structure + $self->{option_results}->{hostname} = $self->{hostname}; + $self->{option_results}->{proto} = $self->{proto}; + $self->{option_results}->{port} = $self->{port}; + $self->{option_results}->{timeout} = $self->{timeout}; + $self->{option_results}->{unknown_status} = $self->{unknown_status}; + $self->{option_results}->{warning_status} = $self->{warning_status}; + $self->{option_results}->{critical_status} = $self->{critical_status}; + + # Feed options structure using set_options + $self->{http}->set_options(%{$self->{option_results}}); +} +``` + +#### request_api + +```perl +sub request_api { + my ($self, %options) = @_; + + # Define APi options needed for request + $self->settings(); + + my ($content) = $self->{http}->request(url_path => '/v3/da8d5aa7-abb4-4a5f-a31c-6700dd34a656'); + + if (!defined($content) || $content eq '') { + $self->{output}->add_option_msg(short_msg => "API returns empty content [code: '" . $self->{http}->get_code() . "'] [message: '" . $self->{http}->get_message() . "']"); + $self->{output}->option_exit(); + } + + my $decoded; + eval { + $decoded = JSON::XS->new->decode($content); + }; + if ($@) { + $self->{output}->add_option_msg(short_msg => "Cannot encode JSON result"); + $self->{output}->option_exit(); + } + + return $decoded; +} +``` \ No newline at end of file diff --git a/doc/en/developer/tutorial-service_discovery.md b/doc/en/developer/tutorial-service_discovery.md new file mode 100644 index 000000000..fe4d5d354 --- /dev/null +++ b/doc/en/developer/tutorial-service_discovery.md @@ -0,0 +1 @@ +Coming soon \ No newline at end of file diff --git a/doc/en/developer/tutorial-snmp.md b/doc/en/developer/tutorial-snmp.md new file mode 100644 index 000000000..44dee7190 --- /dev/null +++ b/doc/en/developer/tutorial-snmp.md @@ -0,0 +1,422 @@ +# SNMP plugin tutorial + +All files showed in this section can be found on the centreon-plugins GitHub in +the [tutorial](https://github.com/centreon/centreon-plugins/tree/develop/src/contrib/tutorial) **contrib** +section. + +> You have to move the contents of `contrib/tutorial/apps/` to `apps/` if you want to run it for testing purposes. +> +> `cp -R src/contrib/tutorial/network/* src/network/` + +You also need to be able to use linux standard snmpwalk in your development environment. +If you can't, you can use [this snmpwalk](https://github.com/centreon/centreon-plugins/blob/develop/tests/resources/snmp/os_linux_snmp_plugin.snmpwalk) coupled with snmpsim (in Docker for example) + +**Description** + +This example explains how to check a single SNMP oid value to check system CPUs. + +## 1. Understand the data + +Understanding the data is very important as it will drive the way you will design +the **mode** internals. This is the **first thing to do**, no matter what protocol you +are using. + +There are several important properties for a piece of data: + +- Type of the data to process: string, int... There is no limitation in the kind of data you can process +- Dimensions of the data, is it **global** or linked to an **instance**? +- Data layout, in other words anticipate the kind of **data structure** to manipulate. + +Here we use a very simple example with only one oid value : `hrProcessorLoad` = `.1.3.6.1.2.1.25.3.3.1.2` +If you use [this snmpwalk](https://github.com/centreon/centreon-plugins/blob/develop/tests/resources/snmp/os_linux_snmp_plugin.snmpwalk) you have this values : +``` +.1.3.6.1.2.1.25.3.3.1.2.768 = INTEGER: 6 +.1.3.6.1.2.1.25.3.3.1.2.769 = INTEGER: 16 +``` +- the `cpu` node contains integer values (`6`, `16`) referring to specific **instances** (`768`, `769`). The structure is an array of hashes + +## 2. Create directories for a new plugin + +Create directories and files required for your **plugin** and **modes**. + +Go to your centreon-plugins local git and create the appropriate directories and files: + +```shell +# path to the main directory and the subdirectory containing modes +mkdir -p src/network/mysnmpplugin/snmp/mode +# path to the main plugin file +touch network/mysnmpplugin/snmp/plugin.pm +# path to the specific mode(s) file(s) => for example appsmetrics.pm +touch network/mysnmpplugin/snmp/mode/cpu.pm +``` + +## 3. Create the plugin file : plugin.pm + +Edit **plugin.pm** and add the following lines: + +```perl + # + # Copyright 2023 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. + # + + # Path to the plugin + package network::mysnmpplugin::snmp::plugin; + + # Needed libraries + use strict; + use warnings; + # Use this library to check using SNMP protocol + use base qw(centreon::plugins::script_snmp); +``` +> **TIP** : Don't forget to edit 'Authors' line. + +Add ```new``` method to instantiate the plugin: + +```perl + sub new { + my ( $class, %options ) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + # $options->{options} = options object + + # Modes association + $self->{modes} = { + # Mode name => path to the mode + 'cpu' => 'network::mysnmpplugin::snmp::mode::cpu' + }; + + return $self; + } +``` +Declare this plugin as a perl module: + +```perl + 1; +``` +Add a description to the plugin: + +```perl + __END__ + + =head1 PLUGIN DESCRIPTION + + Check my-plugin-snmp CPU through SNMP. + + =cut +``` +> **TIP** : This description is printed with '--help' option. + +To test if this plugin file works you can run this command: + +`perl centreon_plugins.pl --plugin=apps::mysnmpplugin:::snmp::plugin --list-mode` + +It already outputs a lot of things. Ellipsized lines are basically all standard capabilities +inherited from the **script_custom** base. + +```perl +Plugin Description: + Check CPU through SNMP. + +Global Options: + --mode Choose a mode. +[...] + --version + Display plugin version. +[...] + +Modes Available: + cpu + +``` + +## 4. Create the mode file : cpu.pm + +### 4.1 Common declarations and new constructor + +Edit **cpu.pm** and add the following lines: + +```perl +# +# Copyright 2023 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. +# + +# Path to the plugin +package network::mysnmpplugin::snmp::mode::cpu; + +# Consider this as mandatory when writing a new mode. +use base qw(centreon::plugins::templates::counter); + +# Needed libraries +use strict; +use warnings; + +``` + +Add a `new` function (sub) to initialize the mode: + +```perl +sub new { + my ($class, %options) = @_; + # All options/properties of this mode, always add the force_new_perfdata => 1 to enable new metric/performance data naming. + # It also where you can specify that the plugin uses a cache file for example + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + # Declare options + $options{options}->add_options(arguments => { + # One the left it's the option name that will be used in the command line. The ':s' at the end is to + # define that this options takes a value. + # On the right, it's the code name for this option, optionnaly you can define a default value so the user + # doesn't have to set it. + # option name => variable name + 'filter-id:s' => { name => 'filter_id' } + }); + + return $self; +} +``` + +### 4.2 Declare your counters + +This part essentially maps the data you want to get from the SNMP with the internal +counter mode structure. + +Remember how we categorized the data in the previous section understand-the-data. + +The `$self->{maps_counters_type}` data structure describes these data while the `$self->{maps_counters}->{global}` one defines +their properties like thresholds and how they will be displayed to the users. + +```perl +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + # cpu will receive value for both instances (768 and 769) : the type => 1 explicits that + # You can define a callback (cb) function to manage the output prefix. This function is called + # each time a value is passed to the counter and can be shared across multiple counters. + { name => 'cpu', type => 1, cb_prefix_output => 'prefix_cpu_output', message_multiple => 'All CPUs are ok' } + ]; + + $self->{maps_counters}->{cpu} = [ + { label => 'cpu-usage-prct', nlabel => 'cpu.usage.percentage', set => { + key_values => [ { name => 'cpu_usage' }, { name => 'name' } ], + output_template => '%.2f %%', + perfdatas => [ + # we add the label_extra_instance option to have one perfdata per instance + { label => 'cpu', template => '%.2f', min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'name' } + ] + } + } + ]; +} +``` + +### 4.3 Create prefix callback functions + +These functions are not mandatory but help to make the output more readable for a human. We will create +it now but as you have noticed the mode compiles so you can choose to keep those for the polishing moment. + +During counters definitions, we associated a callback function like this : +- `cb_prefix_output => 'prefix_cpu_output'` + +Define those function by adding it to our `cpu.pm` file. It is self-explanatory. + +```perl +sub prefix_cpu_output { + my ($self, %options) = @_; + + return "CPU '" . $options{instance_value}->{name} . "' usage: "; +} +``` + +### 4.4 Get raw data from SNMP and understand the data structure + +It's the moment to write the main sub (`manage_selection`) - the most complex, but also the one that +will transform your mode to something useful and alive. + +Think about the logic, what we have to do is: + +- Query a specific path corresponding to a SNMP oid +- Store and process the result +- Spread this result across counters definitions + +```perl +sub manage_selection { + my ($self, %options) = @_; + ################################################### + ##### Load SNMP informations to a result hash ##### + ################################################### + + # Select relevant oids for CPU monitoring + my $mapping = { + # hashKey => { oid => 'oid_number_path'} + hrProcessorID => { oid => '.1.3.6.1.2.1.25.3.3.1.1' }, + hrProcessorLoad => { oid => '.1.3.6.1.2.1.25.3.3.1.2' } + # + }; + + # Point at the begining of the SNMP table + # Oid to point the table ahead all the oids given in mapping + my $oid_hrProcessorTable = '.1.3.6.1.2.1.25.3.3.1'; + + # Use SNMP Centreon plugins tools to push SNMP result in hash to handle with. + my $cpu_result = $options{snmp}->get_table( + oid => $oid_hrProcessorTable, + nothing_quit => 1 + ); + + ################################################### + ##### SNMP Result table to browse ##### + ################################################### + foreach my $oid (keys %{$cpu_result}) { + next if ($oid !~ /^$mapping->{hrProcessorID}->{oid}\.(.*)$/); + + # Catch table instance if exist : + # Instance is a number availible for a same oid refering to different target + my $instance = $1; + # Uncomment the lines below to see what instance looks like : + + # use Data::Dumper; + # print Dumper($oid); + # print Dumper($instance); + + # Data Dumper returns : with oid = hrProcessorID.instance + # $VAR1 = '.1.3.6.1.2.1.25.3.3.1.1.769'; + # $VAR1 = '769'; + # $VAR1 = '.1.3.6.1.2.1.25.3.3.1.1.768'; + # $VAR1 = '768'; + + my $result = $options{snmp}->map_instance(mapping => $mapping, results => $cpu_result, instance => $instance); + + # Here is the way to handle with basic name/id filter. + # This filter is compare with hrProcessorID and in case of no match the oid is skipped + if (defined($self->{option_results}->{filter_id}) && $self->{option_results}->{filter_id} ne '' && + $result->{hrProcessorID} !~ /$self->{option_results}->{filter_id}/) { + $self->{output}->output_add(long_msg => "skipping '" . $result->{hrProcessorID} . "': no matching filter.", debug => 1); + next; + } + + # If the oid is not skipped above, here is convert the target values in result hash. + # Here is where the counter magic happens. + # $self->{cpu} is your counter definition (see $self->{maps_counters}->{}) + # Here, we map the obtained string $result->{hrProcessorLoad} with the cpu_usage key_value in the counter. + $self->{cpu}->{$instance} = { + name => $result->{hrProcessorID}, + cpu_usage => $result->{hrProcessorLoad} + }; + } + + # IMPORTANT ! + # If you use a way to filter the values set in result hash, + # check if at the end of parsing the result table isn't empty. + # If it's the case, add a message for user to explain the filter doesn't match. + if (scalar(keys %{$self->{cpu}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No processor ID matching with filter found."); + $self->{output}->option_exit(); + } +} +``` + +Declare this plugin as a perl module: + +```perl + 1; +``` + +Execute this command (`--verbose` will display the long output and the details for each `type => 1` counters). +This command is based on use Docker SNMPSIM to simulate snmpwalk behavior (hostname, snmp-community and snmp-port). + +```shell +perl centreon_plugins.pl --plugin=network::mysnmpplugin::snmp::plugin --mode=cpu --hostname=localhost --snmp-community=local/os_linux_snmp_plugin --snmp-port=2024 --verbose +``` + +Here is the expected output: + +```shell +OK: All CPUs are ok | '.0.0#cpu.usage.percentage'=6.00%;;;0;100 '.0.0#cpu.usage.percentage'=16.00%;;;0;100 +CPU '.0.0' usage: 6.00 % +CPU '.0.0' usage: 16.00 % +``` + +### 4.5 Help section and assistant to build your centreon objects + +Last but not least, you need to write a help section to explain users what your mode is +doing and what options they can use. + +The centreon-plugins framework has a built-in assistant to help you with the list of counters +and options. + +Run this command to obtain a summary that will simplify the work of creating Centreon commands and write +the mode's help: + +```shell +perl centreon_plugins.pl --plugin=network::mysnmpplugin::snmp::plugin --mode=cpu --hostname='anyvalue' --list-counters --verbose +``` + +Get information from its output (shown below) to start building your mode's help: + +```shell +counter list: cpu-usage-prct +configuration: --warning-cpu-usage-prct='$_SERVICEWARNINGCPUUSAGEPRCT$' --critical-cpu-usage-prct='$_SERVICECRITICALCPUUSAGEPRCT$' +``` + +Here is how you can write the help, note that this time you will add the content after the `1;` and add the same +`__END__` instruction like you did in the `plugin.pm` file. + +```perl +__END__ + +=head1 MODE + +Check system CPUs. + +=over 8 + +=item B<--filter-id> + +Filter on one ID name. + +=item B<--warning> + +Warning threshold for CPU. + +=item B<--critical> + +Critical threshold for CPU. + +=back + +=cut +``` \ No newline at end of file diff --git a/packaging/centreon-plugin-Hardware-Storage-Synology-Snmp/pkg.json b/packaging/centreon-plugin-Hardware-Storage-Synology-Snmp/pkg.json index aad8cdc6a..aa44258ec 100644 --- a/packaging/centreon-plugin-Hardware-Storage-Synology-Snmp/pkg.json +++ b/packaging/centreon-plugin-Hardware-Storage-Synology-Snmp/pkg.json @@ -10,6 +10,7 @@ "snmp_standard/mode/memory.pm", "snmp_standard/mode/loadaverage.pm", "snmp_standard/mode/storage.pm", + "snmp_standard/mode/uptime.pm", "storage/synology/snmp/" ] -} \ No newline at end of file +} diff --git a/packaging/centreon-plugin-Notification-Email/deb.json b/packaging/centreon-plugin-Notification-Email/deb.json index 15206f567..679eedd74 100644 --- a/packaging/centreon-plugin-Notification-Email/deb.json +++ b/packaging/centreon-plugin-Notification-Email/deb.json @@ -1,6 +1,7 @@ { "dependencies": [ "libemail-sender-perl", - "libemail-mime-perl" + "libemail-mime-perl", + "libhtml-template-perl" ] } diff --git a/packaging/centreon-plugin-Notification-Email/rpm.json b/packaging/centreon-plugin-Notification-Email/rpm.json index 2e53d426a..5ada9436b 100644 --- a/packaging/centreon-plugin-Notification-Email/rpm.json +++ b/packaging/centreon-plugin-Notification-Email/rpm.json @@ -2,6 +2,7 @@ "dependencies": [ "perl(Email::MIME)", "perl(Email::Simple)", - "perl(Email::Sender)" + "perl(Email::Sender)", + "perl(HTML::Template)" ] } diff --git a/packaging/centreon-plugin-Virtualization-Vmware2-Connector-Plugin/deb.json b/packaging/centreon-plugin-Virtualization-Vmware2-Connector-Plugin/deb.json index 624779bd6..735060990 100644 --- a/packaging/centreon-plugin-Virtualization-Vmware2-Connector-Plugin/deb.json +++ b/packaging/centreon-plugin-Virtualization-Vmware2-Connector-Plugin/deb.json @@ -1,7 +1,7 @@ { "dependencies": [ "libjson-perl", - "zmq-libzmq4-perl", + "libzmq-libzmq4-perl", "libuuid-perl" ] } \ No newline at end of file diff --git a/src/apps/backup/rubrik/restapi/custom/api.pm b/src/apps/backup/rubrik/restapi/custom/api.pm index fcb608b25..11059959a 100644 --- a/src/apps/backup/rubrik/restapi/custom/api.pm +++ b/src/apps/backup/rubrik/restapi/custom/api.pm @@ -404,7 +404,7 @@ sub get_cache_file_response { sub cache_jobs_monitoring { my ($self, %options) = @_; - my $datas = $self->get_jobs_monitoring(disable_cache => 1, limit => $options{limit}); + my $datas = $self->get_jobs_monitoring(disable_cache => 1, get_param => $options{get_param}); $self->write_cache_file( statefile => 'jobs_monitoring', response => $datas @@ -422,7 +422,7 @@ sub get_jobs_monitoring { return $self->request_api( endpoint => '/api/v1/job_monitoring', label => 'jobMonitoringInfoList', - get_param => ['limit=' . $options{limit}] + get_param => $options{get_param} ); } diff --git a/src/apps/backup/rubrik/restapi/mode/cache.pm b/src/apps/backup/rubrik/restapi/mode/cache.pm index 99568473f..b0277cf8a 100644 --- a/src/apps/backup/rubrik/restapi/mode/cache.pm +++ b/src/apps/backup/rubrik/restapi/mode/cache.pm @@ -31,7 +31,8 @@ sub new { bless $self, $class; $options{options}->add_options(arguments => { - 'limit:s' => { name => 'limit' } + 'filter-job-type:s' => { name => 'filter_job_type' }, + 'limit:s' => { name => 'limit' } }); return $self; @@ -49,7 +50,12 @@ sub check_options { sub manage_selection { my ($self, %options) = @_; - $options{custom}->cache_jobs_monitoring(limit => $self->{option_results}->{limit}); + my $get_param = [ 'limit=' . $self->{option_results}->{limit} ]; + if (defined($self->{option_results}->{filter_job_type}) && $self->{option_results}->{filter_job_type} ne '') { + push @{$get_param}, 'job_type=' . $self->{option_results}->{filter_job_type}; + } + + $options{custom}->cache_jobs_monitoring(get_param => $get_param); $self->{output}->output_add( severity => 'OK', @@ -67,6 +73,10 @@ Create cache files (job mode could use it with --cache-use option). =over 8 +=item B<--filter-job-type> + +Filter jobs by job type. + =item B<--limit> Define the number of entries to retrieve for the pagination (default: 500). diff --git a/src/apps/backup/rubrik/restapi/mode/jobs.pm b/src/apps/backup/rubrik/restapi/mode/jobs.pm index 380adbda6..24ea815ec 100644 --- a/src/apps/backup/rubrik/restapi/mode/jobs.pm +++ b/src/apps/backup/rubrik/restapi/mode/jobs.pm @@ -92,9 +92,11 @@ sub job_long_output { my ($self, %options) = @_; return sprintf( - "checking job '%s' [type: %s]", + "checking job '%s' [type: %s] [object type: %s] [location name: %s]", $options{instance_value}->{name}, - $options{instance_value}->{jobType} + $options{instance_value}->{jobType}, + $options{instance_value}->{objectType}, + $options{instance_value}->{locationName} ); } @@ -217,6 +219,7 @@ sub new { 'filter-job-name:s' => { name => 'filter_job_name' }, 'filter-job-type:s' => { name => 'filter_job_type' }, 'filter-location-name:s' => { name => 'filter_location_name' }, + 'filter-object-type:s' => { name => 'filter_object_type' }, 'unit:s' => { name => 'unit', default => 's' }, 'limit:s' => { name => 'limit' } }); @@ -244,14 +247,15 @@ sub check_options { sub manage_selection { my ($self, %options) = @_; - my $jobs_exec = $options{custom}->get_jobs_monitoring(limit => $self->{option_results}->{limit}); + my $jobs_exec = $options{custom}->get_jobs_monitoring(get_param => [ 'limit=' . $self->{option_results}->{limit} ]); $self->{cache_exec}->read(statefile => 'rubrik_' . $self->{mode} . '_' . Digest::MD5::md5_hex( $options{custom}->get_connection_info() . '_' . (defined($self->{option_results}->{filter_job_id}) ? $self->{option_results}->{filter_job_id} : '') . '_' . (defined($self->{option_results}->{filter_job_name}) ? $self->{option_results}->{filter_job_name} : '') . '_' . - (defined($self->{option_results}->{filter_job_type}) ? $self->{option_results}->{filter_job_type} : '') + (defined($self->{option_results}->{filter_job_type}) ? $self->{option_results}->{filter_job_type} : '') . '_' . + (defined($self->{option_results}->{filter_object_type}) ? $self->{option_results}->{filter_object_type} : '') ) ); my $ctime = time(); @@ -267,6 +271,8 @@ sub manage_selection { $job_exec->{objectName} !~ /$self->{option_results}->{filter_job_name}/); next if (defined($self->{option_results}->{filter_job_type}) && $self->{option_results}->{filter_job_type} ne '' && $job_exec->{jobType} !~ /$self->{option_results}->{filter_job_type}/i); + next if (defined($self->{option_results}->{filter_object_type}) && $self->{option_results}->{filter_object_type} ne '' && + $job_exec->{objectType} !~ /$self->{option_results}->{filter_object_type}/i); next if (defined($self->{option_results}->{filter_location_name}) && $self->{option_results}->{filter_location_name} ne '' && $job_exec->{locationName} !~ /$self->{option_results}->{filter_location_name}/); @@ -276,6 +282,8 @@ sub manage_selection { $self->{jobs}->{ $job_exec->{objectId} } = { name => $job_exec->{objectName}, jobType => $job_exec->{jobType}, + objectType => $job_exec->{objectType}, + locationName => $job_exec->{locationName}, timers => {}, executions => {} }; @@ -289,7 +297,8 @@ sub manage_selection { if (!defined($_->{endTime}) && $_->{jobStatus} =~ /Active/i) { $older_running_exec = $_; } - if (!defined($last_exec) && $_->{jobStatus} !~ /Scheduled/i) { + + if ($_->{jobStatus} !~ /Scheduled|Canceled|Canceling|CancelingScheduled/i) { $last_exec = $_; } @@ -382,6 +391,10 @@ Filter jobs by job name. Filter jobs by job type. +=item B<--filter-object-type> + +Filter jobs by object type. + =item B<--filter-location-name> Filter jobs by location name. diff --git a/src/apps/backup/rubrik/restapi/mode/listjobs.pm b/src/apps/backup/rubrik/restapi/mode/listjobs.pm index 8c802f344..b86460a0c 100644 --- a/src/apps/backup/rubrik/restapi/mode/listjobs.pm +++ b/src/apps/backup/rubrik/restapi/mode/listjobs.pm @@ -49,7 +49,9 @@ sub manage_selection { ); my $results = {}; foreach (@$jobs) { - $results->{ $_->{objectId} } = $_; + if (defined($_->{objectId})) { + $results->{ $_->{objectId} } = $_; + } } return $results; } @@ -63,9 +65,9 @@ sub run { long_msg => sprintf( '[jobId: %s][jobName: %s][jobType: %s][locationName: %s]', $_->{objectId}, - $_->{objectName}, - $_->{jobType}, - $_->{locationName} + defined($_->{objectName}) ? $_->{objectName} : 'none', + defined($_->{jobType}) ? $_->{jobType} : 'none', + defined($_->{locationName}) ? $_->{locationName} : 'none' ) ); } @@ -91,9 +93,9 @@ sub disco_show { foreach (values %$results) { $self->{output}->add_disco_entry( jobId => $_->{objectId}, - jobName => $_->{objectName}, - jobType => $_->{jobType}, - locationName => $_->{locationName} + jobName => defined($_->{objectName}) ? $_->{objectName} : 'none', + jobType => defined($_->{jobType}) ? $_->{jobType} : 'none', + locationName => defined($_->{locationName}) ? $_->{locationName} : 'none' ); } } diff --git a/src/apps/java/jvm/actuator/mode/cpuload.pm b/src/apps/java/jvm/actuator/mode/cpuload.pm index a6d817f76..27ff03fee 100644 --- a/src/apps/java/jvm/actuator/mode/cpuload.pm +++ b/src/apps/java/jvm/actuator/mode/cpuload.pm @@ -86,19 +86,19 @@ WARN : Probably not work for java -version < 7. =item B<--warning-system> -Warning threshold of System cpuload +Warning threshold of system CPU load. =item B<--critical-system> -Critical threshold of System cpuload +Critical threshold of system CPU load. =item B<--warning-process> -Warning threshold of Process cpuload +Warning threshold of process CPU load. =item B<--critical-process> -Critical threshold of Process cpuload +Critical threshold of process CPU load. =back diff --git a/src/apps/protocols/http/mode/collection.pm b/src/apps/protocols/http/mode/collection.pm index 3aae1dc25..1ddddb697 100644 --- a/src/apps/protocols/http/mode/collection.pm +++ b/src/apps/protocols/http/mode/collection.pm @@ -1957,7 +1957,7 @@ __END__ =head1 MODE -Collect and compute HTTP datas. +Collect and compute HTTP data. =over 8 diff --git a/src/apps/protocols/snmp/mode/cache.pm b/src/apps/protocols/snmp/mode/cache.pm index 582104f7e..cfc6e0ddf 100644 --- a/src/apps/protocols/snmp/mode/cache.pm +++ b/src/apps/protocols/snmp/mode/cache.pm @@ -94,7 +94,7 @@ __END__ =head1 MODE -Cache SNMP datas in a JSON cache file. +Cache SNMP data in a JSON cache file. =over 8 diff --git a/src/apps/protocols/snmp/mode/collection.pm b/src/apps/protocols/snmp/mode/collection.pm index 2a224d014..625bbc531 100644 --- a/src/apps/protocols/snmp/mode/collection.pm +++ b/src/apps/protocols/snmp/mode/collection.pm @@ -1646,7 +1646,7 @@ __END__ =head1 MODE -Collect and compute SNMP datas. +Collect and compute SNMP data. =over 8 diff --git a/src/apps/virtualization/ovirt/mode/cpuhost.pm b/src/apps/virtualization/ovirt/mode/cpuhost.pm index 70a12a884..5077ad417 100644 --- a/src/apps/virtualization/ovirt/mode/cpuhost.pm +++ b/src/apps/virtualization/ovirt/mode/cpuhost.pm @@ -111,7 +111,7 @@ __END__ =head1 MODE -Check host cpu utilization. +Check host CPU utilization. =over 8 diff --git a/src/apps/vmware/connector/mode/cpucluster.pm b/src/apps/vmware/connector/mode/cpucluster.pm index 33644d202..9f522d33f 100644 --- a/src/apps/vmware/connector/mode/cpucluster.pm +++ b/src/apps/vmware/connector/mode/cpucluster.pm @@ -115,7 +115,7 @@ __END__ =head1 MODE -Check cluster cpu usage. +Check cluster CPU usage. =over 8 diff --git a/src/apps/vmware/connector/mode/cpuhost.pm b/src/apps/vmware/connector/mode/cpuhost.pm index a60d4a42f..810a9315d 100644 --- a/src/apps/vmware/connector/mode/cpuhost.pm +++ b/src/apps/vmware/connector/mode/cpuhost.pm @@ -173,7 +173,7 @@ __END__ =head1 MODE -Check ESX cpu usage. +Check ESX CPU usage. =over 8 diff --git a/src/apps/vmware/connector/mode/cpuvm.pm b/src/apps/vmware/connector/mode/cpuvm.pm index ed93d99df..6ca365380 100644 --- a/src/apps/vmware/connector/mode/cpuvm.pm +++ b/src/apps/vmware/connector/mode/cpuvm.pm @@ -197,7 +197,7 @@ __END__ =head1 MODE -Check virtual machine cpu usage. +Check virtual machine CPU usage. =over 8 diff --git a/src/apps/vmware/vcsa/snmp/mode/cpu.pm b/src/apps/vmware/vcsa/snmp/mode/cpu.pm index b20c67101..893514e41 100644 --- a/src/apps/vmware/vcsa/snmp/mode/cpu.pm +++ b/src/apps/vmware/vcsa/snmp/mode/cpu.pm @@ -39,7 +39,7 @@ __END__ =head1 MODE -Check cpu. +Check CPU. =over 8 diff --git a/src/apps/vmware/vcsa/snmp/mode/interfaces.pm b/src/apps/vmware/vcsa/snmp/mode/interfaces.pm index 75c7bd2e9..193b4bbf8 100644 --- a/src/apps/vmware/vcsa/snmp/mode/interfaces.pm +++ b/src/apps/vmware/vcsa/snmp/mode/interfaces.pm @@ -177,7 +177,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/apps/vmware/vcsa/snmp/mode/storage.pm b/src/apps/vmware/vcsa/snmp/mode/storage.pm index a73748ee8..2775517fc 100644 --- a/src/apps/vmware/vcsa/snmp/mode/storage.pm +++ b/src/apps/vmware/vcsa/snmp/mode/storage.pm @@ -110,7 +110,7 @@ Example: adding --display-transform-src='dev' --display-transform-dst='run' wil =item B<--show-cache> -Display cache storage datas. +Display cache storage data. =item B<--space-reservation> diff --git a/src/centreon/common/airespace/snmp/mode/cpu.pm b/src/centreon/common/airespace/snmp/mode/cpu.pm index d631ff08e..61b5983bb 100644 --- a/src/centreon/common/airespace/snmp/mode/cpu.pm +++ b/src/centreon/common/airespace/snmp/mode/cpu.pm @@ -73,7 +73,7 @@ __END__ =head1 MODE -Check cpu usage (AIRESPACE-SWITCHING-MIB). +Check CPU usage (AIRESPACE-SWITCHING-MIB). =over 8 diff --git a/src/centreon/common/bluearc/snmp/mode/interfaces.pm b/src/centreon/common/bluearc/snmp/mode/interfaces.pm index d18f9f58f..70b499717 100644 --- a/src/centreon/common/bluearc/snmp/mode/interfaces.pm +++ b/src/centreon/common/bluearc/snmp/mode/interfaces.pm @@ -185,7 +185,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/centreon/common/cisco/ironport/snmp/mode/cpu.pm b/src/centreon/common/cisco/ironport/snmp/mode/cpu.pm index bdb5629c4..8df319dd2 100644 --- a/src/centreon/common/cisco/ironport/snmp/mode/cpu.pm +++ b/src/centreon/common/cisco/ironport/snmp/mode/cpu.pm @@ -84,7 +84,7 @@ __END__ =head1 MODE -Check cpu usage of web security and mail (ASYNCOS-MAIL-MIB, ASYNCOSWEBSECURITYAPPLIANCE-MIB). +Check CPU usage of web security and mail (ASYNCOS-MAIL-MIB, ASYNCOSWEBSECURITYAPPLIANCE-MIB). =over 8 diff --git a/src/centreon/common/cisco/smallbusiness/snmp/mode/cpu.pm b/src/centreon/common/cisco/smallbusiness/snmp/mode/cpu.pm index 937559c89..7fc89033d 100644 --- a/src/centreon/common/cisco/smallbusiness/snmp/mode/cpu.pm +++ b/src/centreon/common/cisco/smallbusiness/snmp/mode/cpu.pm @@ -126,7 +126,7 @@ __END__ =head1 MODE -Check cpu usage (CISCOSBmng.mib). +Check CPU usage (CISCOSBmng.mib). =over 8 diff --git a/src/centreon/common/cisco/standard/snmp/mode/cpu.pm b/src/centreon/common/cisco/standard/snmp/mode/cpu.pm index faf97fd78..b845d8e2d 100644 --- a/src/centreon/common/cisco/standard/snmp/mode/cpu.pm +++ b/src/centreon/common/cisco/standard/snmp/mode/cpu.pm @@ -265,13 +265,13 @@ __END__ =head1 MODE -Check cpu usage (CISCO-PROCESS-MIB and CISCO-SYSTEM-EXT-MIB). +Check CPU usage (CISCO-PROCESS-MIB and CISCO-SYSTEM-EXT-MIB). =over 8 =item B<--check-order> -Check cpu in standard cisco mib. If you have some issue (wrong cpu information in a specific mib), you can change the order +Check CPU in standard cisco mib. If you have some issue (wrong CPU information in a specific mib), you can change the order (default: 'process,old_sys,system_ext'). =item B<--warning-*> B<--critical-*> diff --git a/src/centreon/common/cisco/standard/snmp/mode/interfaces.pm b/src/centreon/common/cisco/standard/snmp/mode/interfaces.pm index aef987560..8fddf4a3f 100644 --- a/src/centreon/common/cisco/standard/snmp/mode/interfaces.pm +++ b/src/centreon/common/cisco/standard/snmp/mode/interfaces.pm @@ -456,7 +456,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/centreon/common/cisco/standard/snmp/mode/load.pm b/src/centreon/common/cisco/standard/snmp/mode/load.pm index deae192e4..9bee27b9f 100644 --- a/src/centreon/common/cisco/standard/snmp/mode/load.pm +++ b/src/centreon/common/cisco/standard/snmp/mode/load.pm @@ -128,7 +128,7 @@ __END__ =head1 MODE -Check cpu load usage. +Check CPU load. =over 8 diff --git a/src/centreon/common/dell/fastpath/snmp/mode/cpu.pm b/src/centreon/common/dell/fastpath/snmp/mode/cpu.pm index 3b0ee7439..85dc7e181 100644 --- a/src/centreon/common/dell/fastpath/snmp/mode/cpu.pm +++ b/src/centreon/common/dell/fastpath/snmp/mode/cpu.pm @@ -161,7 +161,7 @@ __END__ =head1 MODE -Check cpu usage (FASTPATH-SWITCHING-MIB). +Check CPU usage (FASTPATH-SWITCHING-MIB). =over 8 diff --git a/src/centreon/common/force10/snmp/mode/cpu.pm b/src/centreon/common/force10/snmp/mode/cpu.pm index fe2373422..e7b4d5f08 100644 --- a/src/centreon/common/force10/snmp/mode/cpu.pm +++ b/src/centreon/common/force10/snmp/mode/cpu.pm @@ -177,7 +177,7 @@ __END__ =head1 MODE -Check cpu usages. +Check CPU usage. =over 8 diff --git a/src/centreon/common/fortinet/fortigate/snmp/mode/cpu.pm b/src/centreon/common/fortinet/fortigate/snmp/mode/cpu.pm index 8798696fe..09b841c53 100644 --- a/src/centreon/common/fortinet/fortigate/snmp/mode/cpu.pm +++ b/src/centreon/common/fortinet/fortigate/snmp/mode/cpu.pm @@ -168,7 +168,7 @@ __END__ =head1 MODE -Check system cpu usage (FORTINET-FORTIGATE-MIB). +Check system CPU usage (FORTINET-FORTIGATE-MIB). =over 8 @@ -179,11 +179,11 @@ Can be: 'core', 'average', 'cluster-average'. =item B<--cluster> -Add cluster cpu informations. +Add cluster CPU informations. =item B<--filter-core> -Core cpu to monitor (can be a regexp). +Core CPU to monitor (can be a regexp). =back diff --git a/src/centreon/common/fortinet/fortigate/snmp/mode/interfaces.pm b/src/centreon/common/fortinet/fortigate/snmp/mode/interfaces.pm index 56283e18f..8cfffe38f 100644 --- a/src/centreon/common/fortinet/fortigate/snmp/mode/interfaces.pm +++ b/src/centreon/common/fortinet/fortigate/snmp/mode/interfaces.pm @@ -184,7 +184,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/centreon/common/h3c/snmp/mode/interfaces.pm b/src/centreon/common/h3c/snmp/mode/interfaces.pm index 052466958..d7263afee 100644 --- a/src/centreon/common/h3c/snmp/mode/interfaces.pm +++ b/src/centreon/common/h3c/snmp/mode/interfaces.pm @@ -307,7 +307,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/centreon/common/ibm/nos/snmp/mode/disk.pm b/src/centreon/common/ibm/nos/snmp/mode/disk.pm index 4eaba6894..b30b3f1b5 100644 --- a/src/centreon/common/ibm/nos/snmp/mode/disk.pm +++ b/src/centreon/common/ibm/nos/snmp/mode/disk.pm @@ -93,7 +93,7 @@ Time in minutes before reloading cache file (default: 180). =item B<--show-cache> -Display cache storage datas. +Display cache storage data. =item B<--filter-storage-type> diff --git a/src/centreon/common/jvm/mode/cpuload.pm b/src/centreon/common/jvm/mode/cpuload.pm index e4ad233b0..2b2308e18 100644 --- a/src/centreon/common/jvm/mode/cpuload.pm +++ b/src/centreon/common/jvm/mode/cpuload.pm @@ -94,19 +94,19 @@ perl centreon_plugins.pl --plugin=apps::tomcat::jmx::plugin --custommode=jolokia =item B<--warning-system> -Warning threshold of System cpuload +Warning threshold of system CPU load. =item B<--critical-system> -Critical threshold of System cpuload +Critical threshold of system CPU load. =item B<--warning-process> -Warning threshold of Process cpuload +Warning threshold of process CPU load. =item B<--critical-process> -Critical threshold of Process cpuload +Critical threshold of process CPU load. =back diff --git a/src/centreon/common/protocols/sql/mode/collection.pm b/src/centreon/common/protocols/sql/mode/collection.pm index b0a48e4fe..ed40f7e0a 100644 --- a/src/centreon/common/protocols/sql/mode/collection.pm +++ b/src/centreon/common/protocols/sql/mode/collection.pm @@ -1534,7 +1534,7 @@ __END__ =head1 MODE -Collect and compute SQL datas. +Collect and compute SQL data. =over 8 diff --git a/src/centreon/common/protocols/sql/mode/sqlstring.pm b/src/centreon/common/protocols/sql/mode/sqlstring.pm index 58ff4e7d4..0d874bd83 100644 --- a/src/centreon/common/protocols/sql/mode/sqlstring.pm +++ b/src/centreon/common/protocols/sql/mode/sqlstring.pm @@ -95,14 +95,13 @@ sub check_options { $self->{printf_value} = 'value_field'; if (defined($self->{option_results}->{printf_value}) && $self->{option_results}->{printf_value} ne '') { - $self->{printf_value} = $1 - if ($self->{option_results}->{printf_value} =~ /\$self->\{result_values}->\{(value_field|key_field)}/); - $self->{printf_value} = $1 - if ($self->{option_results}->{printf_value} =~ /\%\{(value_field|key_field)}/); - $self->{printf_value} = $1 - if ($self->{option_results}->{printf_value} =~ /\%\((value_field|key_field)\)/); + $self->{printf_value} = $1 + if ($self->{option_results}->{printf_value} =~ /\$self->\{result_values\}->\{(value_field|key_field)\}/); + $self->{printf_value} = $1 + if ($self->{option_results}->{printf_value} =~ /\%\{(value_field|key_field)\}/); + $self->{printf_value} = $1 + if ($self->{option_results}->{printf_value} =~ /\%\((value_field|key_field)\)/); } - } sub manage_selection { diff --git a/src/centreon/common/radlan/snmp/mode/cpu.pm b/src/centreon/common/radlan/snmp/mode/cpu.pm index 12fa0113b..5f4292699 100644 --- a/src/centreon/common/radlan/snmp/mode/cpu.pm +++ b/src/centreon/common/radlan/snmp/mode/cpu.pm @@ -106,7 +106,7 @@ __END__ =head1 MODE -Check cpu usage. +Check CPU usage. =over 8 diff --git a/src/centreon/plugins/alternative/Getopt.pm b/src/centreon/plugins/alternative/Getopt.pm index 13d38af86..b7a7a8d10 100644 --- a/src/centreon/plugins/alternative/Getopt.pm +++ b/src/centreon/plugins/alternative/Getopt.pm @@ -73,7 +73,13 @@ sub GetOptions { # find type of option if ($search_str !~ /,((?:[^,]*?\|){0,}$option(?:\|.*?){0,}(:.*?){0,1}),/) { - warn "Unknown option: $option" if ($warn_message == 1); + + # for old format plugins (with run function) that not allowed list-counters options + if($option =~ /list-counters/){ + warn "list-counters option not available yet for this mode." if ($warn_message == 1); + }else{ + warn "Unknown option: $option" if ($warn_message == 1); + } $i++; next; } diff --git a/src/centreon/plugins/output.pm b/src/centreon/plugins/output.pm index 3b4eeeeb2..e2f9e540f 100644 --- a/src/centreon/plugins/output.pm +++ b/src/centreon/plugins/output.pm @@ -176,7 +176,7 @@ sub add_option_msg { sub set_ignore_label { my ($self, %options) = @_; - $self->{option_results}->{output_ignore_label} = 1; + $self->{option_results}->{output_ignore_label} = 1; } sub set_status { @@ -208,7 +208,7 @@ sub output_add { } else { $self->{global_short_concat_outputs}->{uc($options->{severity})} = $options->{short_msg}; } - + push @{$self->{global_short_outputs}->{uc($options->{severity})}}, $options->{short_msg}; $self->set_status(exit_litteral => $options->{severity}); } @@ -231,7 +231,7 @@ sub perfdata_add { $perfdata->{$_} = $options{$_}; } - if ((defined($self->{option_results}->{use_new_perfdata}) || defined($options{force_new_perfdata})) && + if ((defined($self->{option_results}->{use_new_perfdata}) || defined($options{force_new_perfdata})) && defined($options{nlabel})) { $perfdata->{label} = $options{nlabel}; } @@ -293,7 +293,7 @@ sub output_json { outputs => [], perfdatas => [] } - }; + }; foreach my $code_litteral (keys %{$self->{global_short_outputs}}) { foreach (@{$self->{global_short_outputs}->{$code_litteral}}) { @@ -343,7 +343,7 @@ sub output_xml { my ($self, %options) = @_; my $force_ignore_perfdata = (defined($options{force_ignore_perfdata}) && $options{force_ignore_perfdata} == 1) ? 1 : 0; my $force_long_output = (defined($options{force_long_output}) && $options{force_long_output} == 1) ? 1 : 0; - my ($child_plugin_name, $child_plugin_mode, $child_plugin_exit, $child_plugin_output, $child_plugin_perfdata); + my ($child_plugin_name, $child_plugin_mode, $child_plugin_exit, $child_plugin_output, $child_plugin_perfdata); my $root = $self->{xml_output}->createElement('plugin'); $self->{xml_output}->setDocumentElement($root); @@ -411,7 +411,7 @@ sub output_xml { foreach my $perf (@{$self->{perfdatas}}) { next if ($self->filter_perfdata(perf => $perf)); $self->range_perfdata(ranges => [\$perf->{warning}, \$perf->{critical}]); - + my ($child_perfdata); $child_perfdata = $self->{xml_output}->createElement('perfdata'); $child_plugin_perfdata->addChild($child_perfdata); @@ -593,8 +593,8 @@ sub display { $self->create_xml_document(); if ($self->{is_output_xml}) { $self->output_xml( - exit_litteral => $self->get_litteral_status(), - nolabel => $nolabel, + exit_litteral => $self->get_litteral_status(), + nolabel => $nolabel, force_ignore_perfdata => $force_ignore_perfdata, force_long_output => $force_long_output ); return ; @@ -603,7 +603,7 @@ sub display { $self->create_json_document(); if ($self->{is_output_json}) { $self->output_json( - exit_litteral => $self->get_litteral_status(), + exit_litteral => $self->get_litteral_status(), nolabel => $nolabel, force_ignore_perfdata => $force_ignore_perfdata, force_long_output => $force_long_output ); @@ -615,7 +615,7 @@ sub display { } $self->output_txt( - exit_litteral => $self->get_litteral_status(), + exit_litteral => $self->get_litteral_status(), nolabel => $nolabel, force_ignore_perfdata => $force_ignore_perfdata, force_long_output => $force_long_output ); @@ -642,7 +642,7 @@ sub die_exit { $self->output_json(exit_litteral => $exit_litteral, nolabel => $nolabel, force_ignore_perfdata => 1); $self->exit(exit_litteral => $exit_litteral); } - } + } $self->output_txt(exit_litteral => $exit_litteral, nolabel => $nolabel, force_ignore_perfdata => 1); $self->exit(exit_litteral => $exit_litteral); @@ -729,13 +729,13 @@ sub get_litteral_status { sub is_status { my ($self, %options) = @_; - # $options{value} = string status + # $options{value} = string status # $options{litteral} = value is litteral - # $options{compare} = string status + # $options{compare} = string status if (defined($options{litteral})) { my $value = defined($options{value}) ? $options{value} : $self->get_litteral_status(); - + if (uc($value) eq uc($options{compare})) { return 1; } @@ -906,7 +906,7 @@ sub parameter { sub add_disco_entry { my ($self, %options) = @_; - + push @{$self->{disco_entries}}, {%options}; } @@ -950,7 +950,7 @@ sub load_eval { my ($self) = @_; my ($code) = centreon::plugins::misc::mymodule_load( - output => $self->{output}, module => 'Safe', + output => $self->{output}, module => 'Safe', no_quit => 1 ); if ($code == 0) { @@ -1140,8 +1140,8 @@ sub apply_pfdata_scale { if (defined(${$options{perf}}->{max}) && ${$options{perf}}->{max} ne '') { ($value) = centreon::plugins::misc::scale_bytesbit(value => ${$options{perf}}->{max}, - src_quantity => $src_quantity, src_unit => $src_unit, - dst_quantity => defined($dst_unit) ? $dst_quantity : $options{args}->{quantity}, + src_quantity => $src_quantity, src_unit => $src_unit, + dst_quantity => defined($dst_unit) ? $dst_quantity : $options{args}->{quantity}, dst_unit => defined($dst_unit) ? $dst_unit : $options{args}->{unit}); ${$options{perf}}->{max} = sprintf('%.2f', $value); } @@ -1153,14 +1153,14 @@ sub apply_pfdata_scale { if ($result->{start} ne '' && $result->{infinite_neg} == 0) { ($result->{start}) = centreon::plugins::misc::scale_bytesbit(value => $result->{start}, - src_quantity => $src_quantity, src_unit => $src_unit, - dst_quantity => defined($dst_unit) ? $dst_quantity : $options{args}->{quantity}, + src_quantity => $src_quantity, src_unit => $src_unit, + dst_quantity => defined($dst_unit) ? $dst_quantity : $options{args}->{quantity}, dst_unit => defined($dst_unit) ? $dst_unit : $options{args}->{unit}); } if ($result->{end} ne '' && $result->{infinite_pos} == 0) { ($result->{end}) = centreon::plugins::misc::scale_bytesbit(value => $result->{end}, - src_quantity => $src_quantity, src_unit => $src_unit, - dst_quantity => defined($dst_unit) ? $dst_quantity : $options{args}->{quantity}, + src_quantity => $src_quantity, src_unit => $src_unit, + dst_quantity => defined($dst_unit) ? $dst_quantity : $options{args}->{quantity}, dst_unit => defined($dst_unit) ? $dst_unit : $options{args}->{unit}); } @@ -1216,7 +1216,7 @@ sub apply_pfdata_percent { ${$options{perf}}->{$threshold} = centreon::plugins::misc::get_threshold_litteral(%$result); } - ${$options{perf}}->{max} = 100; + ${$options{perf}}->{max} = 100; } sub apply_pfdata_eval { @@ -1364,7 +1364,7 @@ sub parse_perfdata_extend_args { my ($self, %options) = @_; # --extend-perfdata=searchlabel,newlabel,method[,[newuom],[min],[max],[warning],[critical]] - my ($pfdata_match, $pfdata_substitute, $method, $uom_sub, $min_sub, $max_sub, $warn_sub, $crit_sub) = + my ($pfdata_match, $pfdata_substitute, $method, $uom_sub, $min_sub, $max_sub, $warn_sub, $crit_sub) = split /,/, $options{arg}; return if ((!defined($pfdata_match) || $pfdata_match eq '') && $options{type} != 3); @@ -1539,29 +1539,29 @@ remove all metrics whose value equals 0 and that don't have a maximum value. =item B<--explode-perfdata-max> Create a new metric for each metric that comes with a maximum limit. The new -metric will be named identically with a '_max' suffix). +metric will be named identically with a '_max' suffix). Example: it will split 'used_prct'=26.93%;0:80;0:90;0;100 into 'used_prct'=26.93%;0:80;0:90;0;100 'used_prct_max'=100%;;;; -=item B<--change-perfdata> B<--extend-perfdata> +=item B<--change-perfdata> B<--extend-perfdata> -Change or extend perfdata. +Change or extend perfdata. Syntax: --extend-perfdata=searchlabel,newlabel,target[,[newuom],[min],[max]] Common examples: =over 4 -Convert storage free perfdata into used: --change-perfdata=free,used,invert() +Convert storage free perfdata into used: --change-perfdata='free,used,invert()' -Convert storage free perfdata into used: --change-perfdata=used,free,invert() +Convert storage free perfdata into used: --change-perfdata='used,free,invert()' -Scale traffic values automatically: --change-perfdata=traffic,,scale(auto) +Scale traffic values automatically: --change-perfdata='traffic,,scale(auto)' -Scale traffic values in Mbps: --change-perfdata=traffic_in,,scale(Mbps),mbps +Scale traffic values in Mbps: --change-perfdata='traffic_in,,scale(Mbps),mbps' -Change traffic values in percent: --change-perfdata=traffic_in,,percent() +Change traffic values in percent: --change-perfdata='traffic_in,,percent()' =back @@ -1622,7 +1622,7 @@ and an output. =item B<--output-ignore-label> -Remove the status label ("OK:", "WARNING:", "UNKNOWN:", CRITICAL:") from the +Remove the status label ("OK:", "WARNING:", "UNKNOWN:", CRITICAL:") from the beginning of the output. Example: 'OK: Ram Total:...' will become 'Ram Total:...' diff --git a/src/centreon/plugins/templates/counter.pm b/src/centreon/plugins/templates/counter.pm index 8feead304..a0b079779 100644 --- a/src/centreon/plugins/templates/counter.pm +++ b/src/centreon/plugins/templates/counter.pm @@ -26,6 +26,7 @@ use strict; use warnings; use centreon::plugins::values; use centreon::plugins::misc; +use JSON::XS; my $sort_subs = { num => sub { $a <=> $b }, @@ -173,6 +174,7 @@ sub new { } } + return $self; } @@ -181,18 +183,52 @@ sub check_options { $self->SUPER::init(%options); if (defined($self->{option_results}->{list_counters})) { - my $list_counter = 'counter list:'; + my $list_counter = ''; my $th_counter = ''; + my $counters; foreach my $key (keys %{$self->{maps_counters}}) { foreach (@{$self->{maps_counters}->{$key}}) { + $counters->{metrics}->{$_->{label}}->{nlabel} =""; + $counters->{metrics}->{$_->{label}}->{min}=""; + $counters->{metrics}->{$_->{label}}->{max}=""; + $counters->{metrics}->{$_->{label}}->{unit}=""; + $counters->{metrics}->{$_->{label}}->{output_template}=""; + if(defined($_->{nlabel})) { + $counters->{metrics}->{$_->{label}}->{nlabel} = $_->{nlabel}; + } + if(defined($_->{set}->{perfdatas}->[0]->{min})) { + $counters->{metrics}->{$_->{label}}->{min} = $_->{set}->{perfdatas}->[0]->{min}; + } + if(defined($_->{set}->{perfdatas}->[0]->{max})) { + $counters->{metrics}->{$_->{label}}->{max} = $_->{set}->{perfdatas}->[0]->{max}; + } + if(defined($_->{set}->{perfdatas}->[0]->{unit})) { + $counters->{metrics}->{$_->{label}}->{unit} = $_->{set}->{perfdatas}->[0]->{unit}; + } + if(defined($_->{set}->{perfdatas}->[0]->{template})) { + $counters->{metrics}->{$_->{label}}->{output_template} = $_->{set}->{perfdatas}->[0]->{template}; + } my $label = $_->{label}; $label =~ s/-//g; - $list_counter .= " " . $_->{label}; - $th_counter .= " --warning-$_->{label}='\$_SERVICEWARNING" . uc($label) . "\$' --critical-$_->{label}='\$_SERVICECRITICAL" . uc($label) . "\$'"; + $list_counter .= $_->{label}." "; + $th_counter .= "--warning-$_->{label}='\$_SERVICEWARNING" . uc($label) . "\$' --critical-$_->{label}='\$_SERVICECRITICAL" . uc($label) . "\$'"; + } } - $self->{output}->output_add(short_msg => $list_counter); - $self->{output}->output_add(long_msg => 'configuration: ' . $th_counter); + $counters->{"counter list"}=$list_counter; + $counters->{"pack configuration"}=$th_counter." \$_SERVICEEXTRAOPTIONS\$"; + + my $result_data =""; + eval { + $result_data = JSON::XS->new->indent->space_after->canonical->utf8->encode($counters); + }; + if ($@) { + $self->{output}->add_option_msg(short_msg => "Cannot use \$counters as it is a malformed JSON: " . $@); + $self->{output}->option_exit(); + } + + $self->{output}->output_add(short_msg => "counter list: ".$list_counter); + $self->{output}->output_add(long_msg => $result_data); $self->{output}->display(nolabel => 1, force_ignore_perfdata => 1); $self->{output}->exit(); } diff --git a/src/cloud/prometheus/exporters/cadvisor/mode/cpu.pm b/src/cloud/prometheus/exporters/cadvisor/mode/cpu.pm index af01a29b9..207daee8f 100644 --- a/src/cloud/prometheus/exporters/cadvisor/mode/cpu.pm +++ b/src/cloud/prometheus/exporters/cadvisor/mode/cpu.pm @@ -158,7 +158,7 @@ Check containers CPU usage and throttled. =item B<--cpu-attribute> -Set the cpu attribute to match element (must be a PromQL filter, Default: 'cpu="total"') +Set the CPU attribute to match element (must be a PromQL filter, Default: 'cpu="total"') =item B<--container> diff --git a/src/cloud/prometheus/exporters/nodeexporter/mode/cpu.pm b/src/cloud/prometheus/exporters/nodeexporter/mode/cpu.pm index dac303c71..761716859 100644 --- a/src/cloud/prometheus/exporters/nodeexporter/mode/cpu.pm +++ b/src/cloud/prometheus/exporters/nodeexporter/mode/cpu.pm @@ -182,7 +182,7 @@ Filter on a specific instance (must be a PromQL filter, Default: 'instance=~".*" =item B<--cpu> -Filter on a specific cpu (must be a PromQL filter, Default: 'cpu=~".*"') +Filter on a specific CPU (must be a PromQL filter, Default: 'cpu=~".*"') =item B<--warning-*> diff --git a/src/cloud/prometheus/exporters/nodeexporter/mode/cpudetailed.pm b/src/cloud/prometheus/exporters/nodeexporter/mode/cpudetailed.pm index 42a47811c..ca7d5dc3c 100644 --- a/src/cloud/prometheus/exporters/nodeexporter/mode/cpudetailed.pm +++ b/src/cloud/prometheus/exporters/nodeexporter/mode/cpudetailed.pm @@ -312,7 +312,7 @@ Filter on a specific instance (must be a PromQL filter, Default: 'instance=~".*" =item B<--cpu> -Filter on a specific cpu (must be a PromQL filter, Default: 'cpu=~".*"') +Filter on a specific CPU (must be a PromQL filter, Default: 'cpu=~".*"') =item B<--type> diff --git a/src/contrib/collection/snmp/zxtm-pool.json b/src/contrib/collection/snmp/zxtm-pool.json new file mode 100644 index 000000000..d82b2c861 --- /dev/null +++ b/src/contrib/collection/snmp/zxtm-pool.json @@ -0,0 +1,84 @@ +{ + "constants": { + "okState": "active", + "criticalState": "disabled", + "criticalConnSecond": null, + "criticalCurrConn": null + }, + "mapping": { + "poolState": { + "1": "active", + "2": "disabled", + "3": "draining", + "4": "unused", + "5": "unknown" + } + }, + "snmp": { + "tables": [ + { + "name": "poolEntry", + "oid": ".1.3.6.1.4.1.7146.1.2.3.2.1", + "used_instance": "\\.1\\.3\\.6\\.1\\.4\\.1\\.7146\\.1\\.2\\.3\\.2\\.1\\.\\d+\\.(\\d+(\\.\\d+)+)", + "entries": [ + { + "name": "poolName", + "oid": ".1.3.6.1.4.1.7146.1.2.3.2.1.1" + }, + { + "name": "poolState", + "oid": ".1.3.6.1.4.1.7146.1.2.3.2.1.14", + "map": "poolState" + }, + { + "name": "poolTotalConn", + "oid": ".1.3.6.1.4.1.7146.1.2.3.2.1.10", + "sampling": 1 + }, + { + "name": "poolCurrentConn", + "oid": ".1.3.6.1.4.1.7146.1.2.3.2.1.48" + } + ] + } + ] + }, + "selection_loop": [ + { + "name": "Pool ZXTM", + "source": "%(snmp.tables.poolEntry)", + "expand_table": { + "poolEntry": "%(snmp.tables.poolEntry.[%(poolEntry.instance)])" + }, + "critical": "%(poolEntry.poolState) =~ /%(constants.criticalState)/ or (defined(%(constants.criticalConnSecond)) and %(poolEntry.poolTotalConnPerSeconds) >= %(constants.criticalConnSecond)) or (defined(%(constants.criticalCurrConn)) and %(poolEntry.poolCurrentConn) >= %(constants.criticalCurrConn))", + "perfdatas": [ + { + "nlabel": "connS", + "instances": ["%(poolEntry.poolName)"], + "value": "%(poolEntry.poolTotalConnPerSeconds)", + "critical": "%(constants.criticalConnSecond)", + "unit": "conn/s", + "min": 0 + }, + { + "nlabel": "conn", + "instances": ["%(poolEntry.poolName)"], + "value": "%(poolEntry.poolCurrentConn)", + "critical": "%(constants.criticalConn)", + "unit": "conn", + "min": 0 + } + ], + "formatting": { + "printf_msg": "Device '%s' state is '%s', current connetions are '%d', with conn/s '%.2f'", + "printf_var": [ + "%(poolEntry.poolName)", + "%(poolEntry.poolState)", + "%(poolEntry.poolCurrentConn)", + "%(poolEntry.poolTotalConnPerSeconds)" + ], + "display_ok": true + } + } + ] +} diff --git a/src/contrib/collection/snmp/zxtm-virtualserver.json b/src/contrib/collection/snmp/zxtm-virtualserver.json new file mode 100644 index 000000000..fdf24fec2 --- /dev/null +++ b/src/contrib/collection/snmp/zxtm-virtualserver.json @@ -0,0 +1,64 @@ +{ + "constants": { + "criticalCurrConn": null + }, + "mapping": { + }, + "snmp": { + "tables": [ + { + "name": "virtualserverEntry", + "oid": ".1.3.6.1.4.1.7146.1.2.2.2.1", + "used_instance": "\\.1\\.3\\.6\\.1\\.4\\.1\\.7146\\.1\\.2\\.2\\.2\\.1\\.\\d+\\.(\\d+(\\.\\d+)+)", + "entries": [ + { + "name": "virtualserverName", + "oid": ".1.3.6.1.4.1.7146.1.2.2.2.1.1" + }, + { + "name": "virtualserverCurrentConn", + "oid": ".1.3.6.1.4.1.7146.1.2.2.2.1.9" + }, + { + "name": "virtualServerMaxConnections", + "oid": ".1.3.6.1.4.1.7146.1.2.2.2.1.10" + }, + { + "name": "virtualserverTotalHTTPRequests", + "oid": ".1.3.6.1.4.1.7146.1.2.2.2.1.43" + } + ] + } + ] + }, + "selection_loop": [ + { + "name": "Virtual Server ZXTM", + "source": "%(snmp.tables.virtualserverEntry)", + "expand_table": { + "virtualserverEntry": "%(snmp.tables.virtualserverEntry.[%(virtualserverEntry.instance)])" + }, + "critical": "defined(%(constants.criticalCurrConn)) and %(virtualserverEntry.virtualserverCurrentConn) >= %(constants.criticalCurrConn)", + "perfdatas": [ + { + "nlabel": "conn", + "instances": ["%(virtualserverEntry.virtualserverName)"], + "value": "%(virtualserverEntry.virtualserverCurrentConn)", + "critical": "%(constants.criticalConn)", + "unit": "conn", + "min": 0 + } + ], + "formatting": { + "printf_msg": "Device '%s' current connections are '%d', max connections are '%d', total HTTP requests are '%d'", + "printf_var": [ + "%(virtualserverEntry.virtualserverName)", + "%(virtualserverEntry.virtualserverCurrentConn)", + "%(virtualserverEntry.virtualServerMaxConnections)", + "%(virtualserverEntry.virtualserverTotalHTTPRequests)" + ], + "display_ok": true + } + } + ] +} diff --git a/src/contrib/tutorial/network/mysnmpplugin/snmp/mode/cpu.pm b/src/contrib/tutorial/network/mysnmpplugin/snmp/mode/cpu.pm new file mode 100644 index 000000000..5a0e5be5b --- /dev/null +++ b/src/contrib/tutorial/network/mysnmpplugin/snmp/mode/cpu.pm @@ -0,0 +1,184 @@ +# +# Copyright 2023 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. +# + +# Path to the plugin +package network::mysnmpplugin::snmp::mode::cpu; + +# Consider this as mandatory when writing a new mode. +use base qw(centreon::plugins::templates::counter); + +# Needed libraries +use strict; +use warnings; + +sub prefix_cpu_output { + my ($self, %options) = @_; + + return "CPU '" . $options{instance_value}->{name} . "' usage: "; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + # app_metrics groups connections and errors and each will receive value for both instances (my-awesome-frontend and my-awesome-db) + + #A compléter + + # the type => 1 explicits that + # You can define a callback (cb) function to manage the output prefix. This function is called + # each time a value is passed to the counter and can be shared across multiple counters. + { name => 'cpu', type => 1, cb_prefix_output => 'prefix_cpu_output', message_multiple => 'All CPUs are ok' } + ]; + + $self->{maps_counters}->{cpu} = [ + { label => 'cpu-usage-prct', nlabel => 'cpu.usage.percentage', set => { + key_values => [ { name => 'cpu_usage' }, { name => 'name' } ], + output_template => '%.2f %%', + perfdatas => [ + # we add the label_extra_instance option to have one perfdata per instance + { label => 'cpu', template => '%.2f', min => 0, max => 100, unit => '%', label_extra_instance => 1, instance_use => 'name' } + ] + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + # All options/properties of this mode, always add the force_new_perfdata => 1 to enable new metric/performance data naming. + # It also where you can specify that the plugin uses a cache file for example + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + # Declare options + $options{options}->add_options(arguments => { + # One the left it's the option name that will be used in the command line. The ':s' at the end is to + # define that this options takes a value. + # On the right, it's the code name for this option, optionnaly you can define a default value so the user + # doesn't have to set it. + # option name => variable name + 'filter-id:s' => { name => 'filter_id' } + }); + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + ################################################### + ##### Load SNMP informations to a result hash ##### + ################################################### + + # Select relevant oids for CPU monitoring + my $mapping = { + # hashKey => { oid => 'oid_number_path'} + hrProcessorID => { oid => '.1.3.6.1.2.1.25.3.3.1.1' }, + hrProcessorLoad => { oid => '.1.3.6.1.2.1.25.3.3.1.2' } + # + }; + + # Point at the begining of the SNMP table + # Oid to point the table ahead all the oids given in mapping + my $oid_hrProcessorTable = '.1.3.6.1.2.1.25.3.3.1'; + + # Use SNMP Centreon plugins tools to push SNMP result in hash to handle with. + # $cpu_result is a hash table where keys are oids + my $cpu_result = $options{snmp}->get_table( + oid => $oid_hrProcessorTable, + nothing_quit => 1 + ); + + ################################################### + ##### SNMP Result table to browse ##### + ################################################### + foreach my $oid (keys %{$cpu_result}) { + next if ($oid !~ /^$mapping->{hrProcessorID}->{oid}\.(.*)$/); + + # Catch table instance if exist : + # Instance is a number availible for a same oid refering to different target + my $instance = $1; + # Uncomment the lines below to see what instance looks like : + + # use Data::Dumper; + # print Dumper($oid); + # print Dumper($instance); + + # Data Dumper returns : with oid = hrProcessorID.instance + # $VAR1 = '.1.3.6.1.2.1.25.3.3.1.1.769'; + # $VAR1 = '769'; + # $VAR1 = '.1.3.6.1.2.1.25.3.3.1.1.768'; + # $VAR1 = '768'; + + my $result = $options{snmp}->map_instance(mapping => $mapping, results => $cpu_result, instance => $instance); + + # Here is the way to handle with basic name/id filter. + # This filter is compare with hrProcessorID and in case of no match the oid is skipped + if (defined($self->{option_results}->{filter_id}) && $self->{option_results}->{filter_id} ne '' && + $result->{hrProcessorID} !~ /$self->{option_results}->{filter_id}/) { + $self->{output}->output_add(long_msg => "skipping '" . $result->{hrProcessorID} . "': no matching filter.", debug => 1); + next; + } + + # If the oid is not skipped above, here is convert the target values in result hash. + # Here is where the counter magic happens. + # $self->{cpu} is your counter definition (see $self->{maps_counters}->{}) + # Here, we map the obtained string $result->{hrProcessorLoad} with the cpu_usage key_value in the counter. + $self->{cpu}->{$instance} = { + name => $result->{hrProcessorID}, + cpu_usage => $result->{hrProcessorLoad} + }; + } + + # IMPORTANT ! + # If you use a way to filter the values set in result hash, + # check if at the end of parsing the result table isn't empty. + # If it's the case, add a message for user to explain the filter doesn't match. + if (scalar(keys %{$self->{cpu}}) <= 0) { + $self->{output}->add_option_msg(short_msg => "No processor ID matching with filter found."); + $self->{output}->option_exit(); + } +} + +1; + +__END__ + +=head1 MODE + +Check system CPUs. + +=over 8 + +=item B<--filter-id> + +Filter on one ID name. + +=item B<--warning> + +Warning threshold for CPU. + +=item B<--critical> + +Critical threshold for CPU. + +=back + +=cut \ No newline at end of file diff --git a/src/contrib/tutorial/network/mysnmpplugin/snmp/plugin.pm b/src/contrib/tutorial/network/mysnmpplugin/snmp/plugin.pm new file mode 100644 index 000000000..099fde6d8 --- /dev/null +++ b/src/contrib/tutorial/network/mysnmpplugin/snmp/plugin.pm @@ -0,0 +1,47 @@ +# +# Copyright 2023 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 network::mysnmpplugin::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} = { + 'cpu' => 'network::mysnmpplugin::snmp::mode::cpu' + }; + + return $self; +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check my-plugin-snmp CPU through SNMP. + +=cut \ No newline at end of file diff --git a/src/hardware/devices/camera/hikvision/snmp/mode/cpu.pm b/src/hardware/devices/camera/hikvision/snmp/mode/cpu.pm index 531270f20..117bb82bd 100644 --- a/src/hardware/devices/camera/hikvision/snmp/mode/cpu.pm +++ b/src/hardware/devices/camera/hikvision/snmp/mode/cpu.pm @@ -81,7 +81,7 @@ __END__ =head1 MODE -Check cpu usage. +Check CPU usage. =over 8 diff --git a/src/hardware/devices/camera/optelecom/snmp/mode/interfaces.pm b/src/hardware/devices/camera/optelecom/snmp/mode/interfaces.pm index c7939feca..d9db00c88 100644 --- a/src/hardware/devices/camera/optelecom/snmp/mode/interfaces.pm +++ b/src/hardware/devices/camera/optelecom/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/hardware/devices/hikvision/nvr/isapi/mode/cpu.pm b/src/hardware/devices/hikvision/nvr/isapi/mode/cpu.pm index 2bc4cbd9c..633225987 100644 --- a/src/hardware/devices/hikvision/nvr/isapi/mode/cpu.pm +++ b/src/hardware/devices/hikvision/nvr/isapi/mode/cpu.pm @@ -72,7 +72,7 @@ __END__ =head1 MODE -Check cpu. +Check CPU usage. =over 8 diff --git a/src/hardware/devices/polycom/trio/restapi/mode/device.pm b/src/hardware/devices/polycom/trio/restapi/mode/device.pm index 4cef2ae30..eb81715d2 100644 --- a/src/hardware/devices/polycom/trio/restapi/mode/device.pm +++ b/src/hardware/devices/polycom/trio/restapi/mode/device.pm @@ -142,7 +142,7 @@ __END__ =head1 MODE -Check device cpu, memory and state. +Check device CPU, memory and state. =over 8 diff --git a/src/network/3com/snmp/mode/cpu.pm b/src/network/3com/snmp/mode/cpu.pm index 8cd9b4fc8..8aeef6953 100644 --- a/src/network/3com/snmp/mode/cpu.pm +++ b/src/network/3com/snmp/mode/cpu.pm @@ -120,7 +120,7 @@ __END__ =head1 MODE -Check cpu usages. +Check CPU usages. =over 8 diff --git a/src/network/adva/fsp3000/snmp/mode/interfaces.pm b/src/network/adva/fsp3000/snmp/mode/interfaces.pm index eb88ec12f..2e51fc26f 100644 --- a/src/network/adva/fsp3000/snmp/mode/interfaces.pm +++ b/src/network/adva/fsp3000/snmp/mode/interfaces.pm @@ -383,7 +383,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/alcatel/omniswitch/snmp/mode/cpu.pm b/src/network/alcatel/omniswitch/snmp/mode/cpu.pm index 5e5c951cd..621a4db52 100644 --- a/src/network/alcatel/omniswitch/snmp/mode/cpu.pm +++ b/src/network/alcatel/omniswitch/snmp/mode/cpu.pm @@ -172,7 +172,7 @@ __END__ =head1 MODE -Check cpu usage (AlcatelIND1Health.mib). +Check CPU usage (AlcatelIND1Health.mib). =over 8 diff --git a/src/network/allied/snmp/mode/cpu.pm b/src/network/allied/snmp/mode/cpu.pm index 152e5ae9d..78b765082 100644 --- a/src/network/allied/snmp/mode/cpu.pm +++ b/src/network/allied/snmp/mode/cpu.pm @@ -95,7 +95,7 @@ __END__ =head1 MODE -Check cpu usage. +Check CPU usage. =over 8 diff --git a/src/network/aruba/aoscx/snmp/mode/cpu.pm b/src/network/aruba/aoscx/snmp/mode/cpu.pm index 8f1c6b82c..fe4b4852c 100644 --- a/src/network/aruba/aoscx/snmp/mode/cpu.pm +++ b/src/network/aruba/aoscx/snmp/mode/cpu.pm @@ -100,7 +100,7 @@ __END__ =head1 MODE -Check cpu (worked since firmware 10.10). +Check CPU (worked since firmware 10.10). =over 8 diff --git a/src/network/aruba/cppm/snmp/mode/cpu.pm b/src/network/aruba/cppm/snmp/mode/cpu.pm index f48c713b5..ff19f61e1 100644 --- a/src/network/aruba/cppm/snmp/mode/cpu.pm +++ b/src/network/aruba/cppm/snmp/mode/cpu.pm @@ -45,7 +45,7 @@ Check system CPUs. =item B<--use-ucd> -Use UCD mib for cpu average. +Use UCD mib for CPU average. =item B<--warning-average> diff --git a/src/network/aruba/cppm/snmp/mode/interfaces.pm b/src/network/aruba/cppm/snmp/mode/interfaces.pm index 10b7aeff5..5bb679fc9 100644 --- a/src/network/aruba/cppm/snmp/mode/interfaces.pm +++ b/src/network/aruba/cppm/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/atrica/snmp/mode/connections.pm b/src/network/atrica/snmp/mode/connections.pm index 8e765e5e2..e66a1855d 100644 --- a/src/network/atrica/snmp/mode/connections.pm +++ b/src/network/atrica/snmp/mode/connections.pm @@ -477,7 +477,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/barracuda/bma/snmp/mode/load.pm b/src/network/barracuda/bma/snmp/mode/load.pm index ca671ddfb..b0b8bba94 100644 --- a/src/network/barracuda/bma/snmp/mode/load.pm +++ b/src/network/barracuda/bma/snmp/mode/load.pm @@ -75,7 +75,7 @@ __END__ =head1 MODE -Check system cpu load. +Check system CPU load. =over 8 diff --git a/src/network/beeware/snmp/plugin.pm b/src/network/beeware/snmp/plugin.pm index 31b3c43e7..baed4efcc 100644 --- a/src/network/beeware/snmp/plugin.pm +++ b/src/network/beeware/snmp/plugin.pm @@ -45,6 +45,6 @@ __END__ =head1 PLUGIN DESCRIPTION Check Beeware equipments in SNMP. -Please use plugin SNMP Linux for system checks ('cpu', 'memory', 'traffic',...). +Please use the SNMP Linux plugin for system checks (CPU, memory, traffic, ...). =cut diff --git a/src/network/brocade/snmp/mode/cpu.pm b/src/network/brocade/snmp/mode/cpu.pm index 64769fb3f..96aa365ca 100644 --- a/src/network/brocade/snmp/mode/cpu.pm +++ b/src/network/brocade/snmp/mode/cpu.pm @@ -97,7 +97,7 @@ __END__ =head1 MODE -Check system cpu usage (SW.mib). +Check system CPU usage (SW.mib). =over 8 diff --git a/src/network/brocade/snmp/mode/interfaces.pm b/src/network/brocade/snmp/mode/interfaces.pm index e00450114..fa7515eaf 100644 --- a/src/network/brocade/snmp/mode/interfaces.pm +++ b/src/network/brocade/snmp/mode/interfaces.pm @@ -377,7 +377,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/cambium/cnpilot/snmp/mode/interfaces.pm b/src/network/cambium/cnpilot/snmp/mode/interfaces.pm index 0e35ba15c..4a7eb6d0f 100644 --- a/src/network/cambium/cnpilot/snmp/mode/interfaces.pm +++ b/src/network/cambium/cnpilot/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/cambium/epmp/snmp/mode/interfaces.pm b/src/network/cambium/epmp/snmp/mode/interfaces.pm index 871bdb9ef..87601d35b 100644 --- a/src/network/cambium/epmp/snmp/mode/interfaces.pm +++ b/src/network/cambium/epmp/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/chapsvision/crossing/snmp/mode/interfaces.pm b/src/network/chapsvision/crossing/snmp/mode/interfaces.pm index a711f82e4..77ef8aff5 100644 --- a/src/network/chapsvision/crossing/snmp/mode/interfaces.pm +++ b/src/network/chapsvision/crossing/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/checkpoint/snmp/mode/cpu.pm b/src/network/checkpoint/snmp/mode/cpu.pm index b0154819d..13734ae1c 100644 --- a/src/network/checkpoint/snmp/mode/cpu.pm +++ b/src/network/checkpoint/snmp/mode/cpu.pm @@ -116,7 +116,7 @@ __END__ =head1 MODE -Check cpu usage. +Check CPU usage. =over 8 diff --git a/src/network/cisco/standard/ssh/mode/cpu.pm b/src/network/cisco/standard/ssh/mode/cpu.pm index fae406582..ee5c8c6a5 100644 --- a/src/network/cisco/standard/ssh/mode/cpu.pm +++ b/src/network/cisco/standard/ssh/mode/cpu.pm @@ -98,7 +98,7 @@ __END__ =head1 MODE -Check cpu usage. +Check CPU usage. =over 8 diff --git a/src/network/cisco/wap/snmp/mode/cpu.pm b/src/network/cisco/wap/snmp/mode/cpu.pm index 262b86f78..4feefce93 100644 --- a/src/network/cisco/wap/snmp/mode/cpu.pm +++ b/src/network/cisco/wap/snmp/mode/cpu.pm @@ -74,7 +74,7 @@ __END__ =head1 MODE -Check cpu usage. +Check CPU usage. =over 8 diff --git a/src/network/citrix/appacceleration/snmp/mode/cpu.pm b/src/network/citrix/appacceleration/snmp/mode/cpu.pm index 84e2ccd1a..b58b1cdf6 100644 --- a/src/network/citrix/appacceleration/snmp/mode/cpu.pm +++ b/src/network/citrix/appacceleration/snmp/mode/cpu.pm @@ -83,7 +83,7 @@ __END__ =head1 MODE -Check cpu usage. +Check CPU usage. =over 8 diff --git a/src/network/citrix/netscaler/snmp/mode/cpu.pm b/src/network/citrix/netscaler/snmp/mode/cpu.pm index e3b8ca051..646451a86 100644 --- a/src/network/citrix/netscaler/snmp/mode/cpu.pm +++ b/src/network/citrix/netscaler/snmp/mode/cpu.pm @@ -87,7 +87,7 @@ __END__ =head1 MODE -Check cpu usage (NS-MIB-smiv2). +Check CPU usage (NS-MIB-smiv2). =over 8 diff --git a/src/network/dell/nseries/snmp/mode/interfaces.pm b/src/network/dell/nseries/snmp/mode/interfaces.pm index fa4d75a79..41a3d65c5 100644 --- a/src/network/dell/nseries/snmp/mode/interfaces.pm +++ b/src/network/dell/nseries/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/digi/sarian/snmp/mode/cpu.pm b/src/network/digi/sarian/snmp/mode/cpu.pm index 2b0a10ef4..87ccf77dc 100644 --- a/src/network/digi/sarian/snmp/mode/cpu.pm +++ b/src/network/digi/sarian/snmp/mode/cpu.pm @@ -84,7 +84,7 @@ __END__ =head1 MODE -Check cpu usage (sarian-monitor.mib). +Check CPU usage (sarian-monitor.mib). =over 8 diff --git a/src/network/dlink/dgs3100/snmp/mode/cpu.pm b/src/network/dlink/dgs3100/snmp/mode/cpu.pm index 4654608b5..224da3b76 100644 --- a/src/network/dlink/dgs3100/snmp/mode/cpu.pm +++ b/src/network/dlink/dgs3100/snmp/mode/cpu.pm @@ -131,7 +131,7 @@ __END__ =head1 MODE -Check cpu usage (env_mib.mib). +Check CPU usage (env_mib.mib). =over 8 diff --git a/src/network/dlink/standard/snmp/mode/cpu.pm b/src/network/dlink/standard/snmp/mode/cpu.pm index e344481e8..be2a64c7a 100644 --- a/src/network/dlink/standard/snmp/mode/cpu.pm +++ b/src/network/dlink/standard/snmp/mode/cpu.pm @@ -256,13 +256,13 @@ __END__ =head1 MODE -Check cpu usage. +Check CPU usage. =over 8 =item B<--check-order> -Check cpu in standard dlink mib. If you have some issue (wrong cpu information in a specific mib), you can change the order +Check CPU in standard dlink mib. If you have some issue (wrong CPU information in a specific mib), you can change the order (default: 'common,industrial,agent'). =item B<--warning-*> B<--critical-*> diff --git a/src/network/dlink/standard/snmp/mode/interfaces.pm b/src/network/dlink/standard/snmp/mode/interfaces.pm index d723c9dac..b304860c2 100644 --- a/src/network/dlink/standard/snmp/mode/interfaces.pm +++ b/src/network/dlink/standard/snmp/mode/interfaces.pm @@ -248,7 +248,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/efficientip/snmp/plugin.pm b/src/network/efficientip/snmp/plugin.pm index 43cd13260..98ff9274f 100644 --- a/src/network/efficientip/snmp/plugin.pm +++ b/src/network/efficientip/snmp/plugin.pm @@ -46,6 +46,6 @@ __END__ =head1 PLUGIN DESCRIPTION Check Efficient IP equipment in SNMP. -Please use plugin SNMP Linux for system checks ('cpu', 'memory', 'traffic',...). +Please use the SNMP Linux plugin for system checks (CPU, memory, traffic, ...). =cut diff --git a/src/network/enterasys/snmp/mode/cpu.pm b/src/network/enterasys/snmp/mode/cpu.pm index 0d9702383..48ad4d700 100644 --- a/src/network/enterasys/snmp/mode/cpu.pm +++ b/src/network/enterasys/snmp/mode/cpu.pm @@ -260,7 +260,7 @@ __END__ =head1 MODE -Check cpu usage. +Check CPU usage. =over 8 diff --git a/src/network/enterasys/snmp/mode/interfaces.pm b/src/network/enterasys/snmp/mode/interfaces.pm index 5a756d5b5..bf589c090 100644 --- a/src/network/enterasys/snmp/mode/interfaces.pm +++ b/src/network/enterasys/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/extreme/snmp/mode/interfaces.pm b/src/network/extreme/snmp/mode/interfaces.pm index c69bd6a28..ac4e328dc 100644 --- a/src/network/extreme/snmp/mode/interfaces.pm +++ b/src/network/extreme/snmp/mode/interfaces.pm @@ -201,7 +201,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/f5/bigip/snmp/plugin.pm b/src/network/f5/bigip/snmp/plugin.pm index 016d6d751..29ed15ec8 100644 --- a/src/network/f5/bigip/snmp/plugin.pm +++ b/src/network/f5/bigip/snmp/plugin.pm @@ -56,6 +56,6 @@ __END__ =head1 PLUGIN DESCRIPTION Check F-5 hardware in SNMP. -Please use plugin SNMP Linux for system checks ('cpu', 'memory', 'traffic',...). +Please use the SNMP Linux plugin for system checks (CPU, memory, traffic, ...). =cut diff --git a/src/network/fiberstore/snmp/mode/cpu.pm b/src/network/fiberstore/snmp/mode/cpu.pm index 89ef50420..69924e092 100644 --- a/src/network/fiberstore/snmp/mode/cpu.pm +++ b/src/network/fiberstore/snmp/mode/cpu.pm @@ -79,7 +79,7 @@ __END__ =head1 MODE -Check cpu. +Check CPU usage. =over 8 diff --git a/src/network/fortinet/fortiadc/snmp/mode/cpu.pm b/src/network/fortinet/fortiadc/snmp/mode/cpu.pm index a719d65f3..76cabbe3c 100644 --- a/src/network/fortinet/fortiadc/snmp/mode/cpu.pm +++ b/src/network/fortinet/fortiadc/snmp/mode/cpu.pm @@ -168,7 +168,7 @@ __END__ =head1 MODE -Check cpu usage. +Check CPU usage. =over 8 diff --git a/src/network/fortinet/fortiadc/snmp/mode/interfaces.pm b/src/network/fortinet/fortiadc/snmp/mode/interfaces.pm index f08af94ab..620e5bb11 100644 --- a/src/network/fortinet/fortiadc/snmp/mode/interfaces.pm +++ b/src/network/fortinet/fortiadc/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/fortinet/fortiauthenticator/snmp/mode/cpu.pm b/src/network/fortinet/fortiauthenticator/snmp/mode/cpu.pm index 20685b9f4..5ee64a59f 100644 --- a/src/network/fortinet/fortiauthenticator/snmp/mode/cpu.pm +++ b/src/network/fortinet/fortiauthenticator/snmp/mode/cpu.pm @@ -73,7 +73,7 @@ __END__ =head1 MODE -Check cpu usage. +Check CPU usage. =over 8 diff --git a/src/network/fortinet/fortimail/snmp/mode/cpu.pm b/src/network/fortinet/fortimail/snmp/mode/cpu.pm index 75a610ca5..4d5df9625 100644 --- a/src/network/fortinet/fortimail/snmp/mode/cpu.pm +++ b/src/network/fortinet/fortimail/snmp/mode/cpu.pm @@ -72,7 +72,7 @@ __END__ =head1 MODE -Check cpu usage. +Check CPU usage. =over 8 diff --git a/src/network/fortinet/fortimail/snmp/mode/interfaces.pm b/src/network/fortinet/fortimail/snmp/mode/interfaces.pm index aa68eaa57..e2e9d3723 100644 --- a/src/network/fortinet/fortimail/snmp/mode/interfaces.pm +++ b/src/network/fortinet/fortimail/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/fortinet/fortiswitch/snmp/mode/cpu.pm b/src/network/fortinet/fortiswitch/snmp/mode/cpu.pm index 278fed295..32d5275f2 100644 --- a/src/network/fortinet/fortiswitch/snmp/mode/cpu.pm +++ b/src/network/fortinet/fortiswitch/snmp/mode/cpu.pm @@ -72,7 +72,7 @@ __END__ =head1 MODE -Check cpu. +Check CPU usage. =over 8 diff --git a/src/network/fortinet/fortiswitch/snmp/mode/interfaces.pm b/src/network/fortinet/fortiswitch/snmp/mode/interfaces.pm index ec7894bd7..f4fbb7b66 100644 --- a/src/network/fortinet/fortiswitch/snmp/mode/interfaces.pm +++ b/src/network/fortinet/fortiswitch/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/hirschmann/standard/snmp/mode/cpu.pm b/src/network/hirschmann/standard/snmp/mode/cpu.pm index 1bb1d0156..a3c9771ce 100644 --- a/src/network/hirschmann/standard/snmp/mode/cpu.pm +++ b/src/network/hirschmann/standard/snmp/mode/cpu.pm @@ -120,7 +120,7 @@ __END__ =head1 MODE -Check cpu. +Check CPU usage. =over 8 diff --git a/src/network/hp/moonshot/snmp/mode/cpu.pm b/src/network/hp/moonshot/snmp/mode/cpu.pm index 7dea63ca7..8b434df8e 100644 --- a/src/network/hp/moonshot/snmp/mode/cpu.pm +++ b/src/network/hp/moonshot/snmp/mode/cpu.pm @@ -101,7 +101,7 @@ __END__ =head1 MODE -Check cpu. +Check CPU usage. =over 8 diff --git a/src/network/hp/moonshot/snmp/mode/interfaces.pm b/src/network/hp/moonshot/snmp/mode/interfaces.pm index 08042c644..63135884c 100644 --- a/src/network/hp/moonshot/snmp/mode/interfaces.pm +++ b/src/network/hp/moonshot/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/hp/procurve/snmp/mode/cpu.pm b/src/network/hp/procurve/snmp/mode/cpu.pm index 5c11c2f9e..99be56c87 100644 --- a/src/network/hp/procurve/snmp/mode/cpu.pm +++ b/src/network/hp/procurve/snmp/mode/cpu.pm @@ -81,7 +81,7 @@ __END__ =head1 MODE -Check cpu usage (hpSwitchStat.mib). +Check CPU usage (hpSwitchStat.mib). =over 8 diff --git a/src/network/hp/procurve/snmp/mode/interfaces.pm b/src/network/hp/procurve/snmp/mode/interfaces.pm index 22c9b62b0..5af2451d2 100644 --- a/src/network/hp/procurve/snmp/mode/interfaces.pm +++ b/src/network/hp/procurve/snmp/mode/interfaces.pm @@ -394,7 +394,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/huawei/snmp/mode/interfaces.pm b/src/network/huawei/snmp/mode/interfaces.pm index fabb78c21..067279559 100644 --- a/src/network/huawei/snmp/mode/interfaces.pm +++ b/src/network/huawei/snmp/mode/interfaces.pm @@ -303,7 +303,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/juniper/common/junos/mode/cpu.pm b/src/network/juniper/common/junos/mode/cpu.pm index 0dc5d117c..f0919b239 100644 --- a/src/network/juniper/common/junos/mode/cpu.pm +++ b/src/network/juniper/common/junos/mode/cpu.pm @@ -141,7 +141,7 @@ __END__ =head1 MODE -Check cpu usage. +Check CPU usage. =over 8 diff --git a/src/network/juniper/common/junos/mode/interfaces.pm b/src/network/juniper/common/junos/mode/interfaces.pm index 40340eb3c..a32b35d33 100644 --- a/src/network/juniper/common/junos/mode/interfaces.pm +++ b/src/network/juniper/common/junos/mode/interfaces.pm @@ -378,7 +378,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/juniper/common/screenos/snmp/mode/cpu.pm b/src/network/juniper/common/screenos/snmp/mode/cpu.pm index 545636a54..95148c0eb 100644 --- a/src/network/juniper/common/screenos/snmp/mode/cpu.pm +++ b/src/network/juniper/common/screenos/snmp/mode/cpu.pm @@ -124,7 +124,7 @@ __END__ =head1 MODE -Check Juniper cpu usage (NETSCREEN-RESOURCE-MIB). +Check Juniper CPU usage (NETSCREEN-RESOURCE-MIB). =over 8 diff --git a/src/network/lenovo/rackswitch/snmp/mode/interfaces.pm b/src/network/lenovo/rackswitch/snmp/mode/interfaces.pm index 067e299dc..4dbb4e50c 100644 --- a/src/network/lenovo/rackswitch/snmp/mode/interfaces.pm +++ b/src/network/lenovo/rackswitch/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/libraesva/snmp/mode/interfaces.pm b/src/network/libraesva/snmp/mode/interfaces.pm index 299c40997..a97bf2318 100644 --- a/src/network/libraesva/snmp/mode/interfaces.pm +++ b/src/network/libraesva/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/libraesva/snmp/mode/storage.pm b/src/network/libraesva/snmp/mode/storage.pm index ad75b21fe..5e8d4c75a 100644 --- a/src/network/libraesva/snmp/mode/storage.pm +++ b/src/network/libraesva/snmp/mode/storage.pm @@ -110,7 +110,7 @@ Example: adding --display-transform-src='dev' --display-transform-dst='run' wil =item B<--show-cache> -Display cache storage datas. +Display cache storage data. =item B<--space-reservation> diff --git a/src/network/meru/snmp/mode/cpu.pm b/src/network/meru/snmp/mode/cpu.pm index 5d4a701b4..1f252038f 100644 --- a/src/network/meru/snmp/mode/cpu.pm +++ b/src/network/meru/snmp/mode/cpu.pm @@ -72,7 +72,7 @@ __END__ =head1 MODE -Check cpu. +Check CPU usage. =over 8 diff --git a/src/network/microsens/g6/snmp/mode/interfaces.pm b/src/network/microsens/g6/snmp/mode/interfaces.pm index 6673d7f1e..8af12d3bb 100644 --- a/src/network/microsens/g6/snmp/mode/interfaces.pm +++ b/src/network/microsens/g6/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/mikrotik/snmp/mode/disk.pm b/src/network/mikrotik/snmp/mode/disk.pm index fceba7577..20a4807a5 100644 --- a/src/network/mikrotik/snmp/mode/disk.pm +++ b/src/network/mikrotik/snmp/mode/disk.pm @@ -93,7 +93,7 @@ Time in minutes before reloading cache file (default: 180). =item B<--show-cache> -Display cache storage datas. +Display cache storage data. =item B<--filter-storage-type> diff --git a/src/network/mikrotik/snmp/mode/interfaces.pm b/src/network/mikrotik/snmp/mode/interfaces.pm index 5a15a197f..e6c6b6be1 100644 --- a/src/network/mikrotik/snmp/mode/interfaces.pm +++ b/src/network/mikrotik/snmp/mode/interfaces.pm @@ -274,7 +274,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/mikrotik/snmp/mode/memory.pm b/src/network/mikrotik/snmp/mode/memory.pm index 651f325a7..f4e7d1b8c 100644 --- a/src/network/mikrotik/snmp/mode/memory.pm +++ b/src/network/mikrotik/snmp/mode/memory.pm @@ -93,7 +93,7 @@ Time in minutes before reloading cache file (default: 180). =item B<--show-cache> -Display cache storage datas. +Display cache storage data. =item B<--filter-storage-type> diff --git a/src/network/mrv/optiswitch/snmp/mode/interfaces.pm b/src/network/mrv/optiswitch/snmp/mode/interfaces.pm index 70200fb78..242c63866 100644 --- a/src/network/mrv/optiswitch/snmp/mode/interfaces.pm +++ b/src/network/mrv/optiswitch/snmp/mode/interfaces.pm @@ -537,7 +537,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/netgear/sseries/snmp/mode/cpu.pm b/src/network/netgear/sseries/snmp/mode/cpu.pm index bd57023be..4c3345aef 100644 --- a/src/network/netgear/sseries/snmp/mode/cpu.pm +++ b/src/network/netgear/sseries/snmp/mode/cpu.pm @@ -93,7 +93,7 @@ __END__ =head1 MODE -Check cpu usage. +Check CPU usage. =over 8 diff --git a/src/network/netgear/sseries/snmp/mode/interfaces.pm b/src/network/netgear/sseries/snmp/mode/interfaces.pm index 1e4310425..b38c79914 100644 --- a/src/network/netgear/sseries/snmp/mode/interfaces.pm +++ b/src/network/netgear/sseries/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/nortel/standard/snmp/mode/interfaces.pm b/src/network/nortel/standard/snmp/mode/interfaces.pm index 99e59a6e9..5325b5691 100644 --- a/src/network/nortel/standard/snmp/mode/interfaces.pm +++ b/src/network/nortel/standard/snmp/mode/interfaces.pm @@ -195,7 +195,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/oneaccess/snmp/mode/cpu.pm b/src/network/oneaccess/snmp/mode/cpu.pm index 1ba1f0f72..ce2b03f20 100644 --- a/src/network/oneaccess/snmp/mode/cpu.pm +++ b/src/network/oneaccess/snmp/mode/cpu.pm @@ -86,7 +86,7 @@ __END__ =head1 MODE -Check cpu usage (oneaccess-sys-mib). +Check CPU usage (oneaccess-sys-mib). =over 8 diff --git a/src/network/oneaccess/snmp/mode/interfaces.pm b/src/network/oneaccess/snmp/mode/interfaces.pm index 28387804c..84e020104 100644 --- a/src/network/oneaccess/snmp/mode/interfaces.pm +++ b/src/network/oneaccess/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/opengear/snmp/mode/interfaces.pm b/src/network/opengear/snmp/mode/interfaces.pm index 55a6ed72e..474c61307 100644 --- a/src/network/opengear/snmp/mode/interfaces.pm +++ b/src/network/opengear/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/paloalto/snmp/mode/memory.pm b/src/network/paloalto/snmp/mode/memory.pm index 5981a78f8..61a21917e 100644 --- a/src/network/paloalto/snmp/mode/memory.pm +++ b/src/network/paloalto/snmp/mode/memory.pm @@ -87,7 +87,7 @@ Time in minutes before reloading cache file (default: 180). =item B<--show-cache> -Display cache storage datas. +Display cache storage data. =item B<--filter-storage-type> diff --git a/src/network/peplink/balance/snmp/mode/cpu.pm b/src/network/peplink/balance/snmp/mode/cpu.pm index 422326c60..017836ddc 100644 --- a/src/network/peplink/balance/snmp/mode/cpu.pm +++ b/src/network/peplink/balance/snmp/mode/cpu.pm @@ -81,7 +81,7 @@ __END__ =head1 MODE -Check cpu usage (PEPLINK-BALANCE-MIB). +Check CPU usage (PEPLINK-BALANCE-MIB). =over 8 diff --git a/src/network/radware/alteon/snmp/mode/cpu.pm b/src/network/radware/alteon/snmp/mode/cpu.pm index ac8c14367..c71933912 100644 --- a/src/network/radware/alteon/snmp/mode/cpu.pm +++ b/src/network/radware/alteon/snmp/mode/cpu.pm @@ -213,7 +213,7 @@ __END__ =head1 MODE -Check MP cpu usage (ALTEON-CHEETAH-SWITCH-MIB). +Check MP CPU usage (ALTEON-CHEETAH-SWITCH-MIB). =over 8 diff --git a/src/network/raisecom/snmp/mode/interfaces.pm b/src/network/raisecom/snmp/mode/interfaces.pm index 7e00e13bd..2b3ffdfb5 100644 --- a/src/network/raisecom/snmp/mode/interfaces.pm +++ b/src/network/raisecom/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/redback/snmp/mode/cpu.pm b/src/network/redback/snmp/mode/cpu.pm index a555e4e84..bfd67d278 100644 --- a/src/network/redback/snmp/mode/cpu.pm +++ b/src/network/redback/snmp/mode/cpu.pm @@ -141,7 +141,7 @@ __END__ =head1 MODE -Check cpu usage (RBN-CPU-METER-MIB). +Check CPU usage (RBN-CPU-METER-MIB). =over 8 diff --git a/src/network/securactive/plugin.pm b/src/network/securactive/plugin.pm index 006044f76..02cca4f08 100644 --- a/src/network/securactive/plugin.pm +++ b/src/network/securactive/plugin.pm @@ -49,6 +49,6 @@ __END__ =head1 PLUGIN DESCRIPTION Check SecurActive in SNMP. -The system (cpu, memory, traffic,...) can be used monitor with linux snmp plugin. +The system checks (CPU, memory, traffic,...) can be monitored with the linux snmp plugin. =cut diff --git a/src/network/sonus/sbc/snmp/mode/cpu.pm b/src/network/sonus/sbc/snmp/mode/cpu.pm index 229740151..48b2a5e8e 100644 --- a/src/network/sonus/sbc/snmp/mode/cpu.pm +++ b/src/network/sonus/sbc/snmp/mode/cpu.pm @@ -47,7 +47,7 @@ of time that this processor was not idle) =item B<--use-ucd> -Use UCD mib for cpu average. +Use UCD mib for CPU average. =item B<--warning-average> diff --git a/src/network/sonus/sbc/snmp/mode/interfaces.pm b/src/network/sonus/sbc/snmp/mode/interfaces.pm index b1daaa4d1..a64c1d48e 100644 --- a/src/network/sonus/sbc/snmp/mode/interfaces.pm +++ b/src/network/sonus/sbc/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/sonus/sbc/snmp/mode/storage.pm b/src/network/sonus/sbc/snmp/mode/storage.pm index f74688034..588749fa4 100644 --- a/src/network/sonus/sbc/snmp/mode/storage.pm +++ b/src/network/sonus/sbc/snmp/mode/storage.pm @@ -110,7 +110,7 @@ Example: adding --display-transform-src='dev' --display-transform-dst='run' wil =item B<--show-cache> -Display cache storage datas. +Display cache storage data. =item B<--space-reservation> diff --git a/src/network/stormshield/api/mode/cpu.pm b/src/network/stormshield/api/mode/cpu.pm index 39e45b374..4d068aac4 100644 --- a/src/network/stormshield/api/mode/cpu.pm +++ b/src/network/stormshield/api/mode/cpu.pm @@ -106,7 +106,7 @@ __END__ =head1 MODE -Check cpu usage. +Check CPU usage. =over 8 @@ -117,7 +117,7 @@ Can be: 'core', 'average'. =item B<--filter-core> -Core cpu to monitor (can be a regexp). +Core CPU to monitor (can be a regexp). =back diff --git a/src/network/teldat/snmp/mode/cpu.pm b/src/network/teldat/snmp/mode/cpu.pm index 394dacdac..10001cfbb 100644 --- a/src/network/teldat/snmp/mode/cpu.pm +++ b/src/network/teldat/snmp/mode/cpu.pm @@ -102,7 +102,7 @@ __END__ =head1 MODE -Check cpu. +Check CPU usage. =over 8 diff --git a/src/network/teldat/snmp/mode/interfaces.pm b/src/network/teldat/snmp/mode/interfaces.pm index cfcbe6f7c..5420de371 100644 --- a/src/network/teldat/snmp/mode/interfaces.pm +++ b/src/network/teldat/snmp/mode/interfaces.pm @@ -175,7 +175,7 @@ Regexp dst to transform display value. =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/teltonika/snmp/mode/interfaces.pm b/src/network/teltonika/snmp/mode/interfaces.pm index 87df8b281..73dbd6a19 100644 --- a/src/network/teltonika/snmp/mode/interfaces.pm +++ b/src/network/teltonika/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/network/tplink/snmp/mode/cpu.pm b/src/network/tplink/snmp/mode/cpu.pm index 52b36da0e..e2a2576e0 100644 --- a/src/network/tplink/snmp/mode/cpu.pm +++ b/src/network/tplink/snmp/mode/cpu.pm @@ -167,7 +167,7 @@ __END__ =head1 MODE -Check cpu usage. +Check CPU usage. =over 8 diff --git a/src/network/vectra/restapi/mode/cpu.pm b/src/network/vectra/restapi/mode/cpu.pm index b333c468e..d0bd02262 100644 --- a/src/network/vectra/restapi/mode/cpu.pm +++ b/src/network/vectra/restapi/mode/cpu.pm @@ -68,7 +68,7 @@ __END__ =head1 MODE -Check cpu. +Check CPU usage. =over 8 diff --git a/src/network/viptela/snmp/mode/cpu.pm b/src/network/viptela/snmp/mode/cpu.pm index bbfc36187..08cbc0c02 100644 --- a/src/network/viptela/snmp/mode/cpu.pm +++ b/src/network/viptela/snmp/mode/cpu.pm @@ -72,7 +72,7 @@ __END__ =head1 MODE -Check cpu. +Check CPU usage. =over 8 diff --git a/src/network/viptela/snmp/mode/interfaces.pm b/src/network/viptela/snmp/mode/interfaces.pm index f0ff67464..e47f635f9 100644 --- a/src/network/viptela/snmp/mode/interfaces.pm +++ b/src/network/viptela/snmp/mode/interfaces.pm @@ -173,7 +173,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/notification/email/mode/alert.pm b/src/notification/email/mode/alert.pm index ec0839c5c..374104814 100644 --- a/src/notification/email/mode/alert.pm +++ b/src/notification/email/mode/alert.pm @@ -30,9 +30,12 @@ use Email::Sender::Simple qw(sendmail); use Email::Sender::Transport::SMTP; use JSON::XS; use URI::Escape; +use HTML::Template; use centreon::plugins::http; +use notification::email::templates::resources; -my %color_host = ( + +my %color = ( up => { background => '#88B922', text => '#FFFFFF' @@ -41,6 +44,22 @@ my %color_host = ( background => '#FF4A4A', text => '#FFFFFF' }, + ok => { + background => '#88B922', + text => '#FFFFFF' + }, + warning => { + background => '#FD9B27', + text => '#FFFFFF' + }, + critical => { + background => '#FF4A4A', + text => '#FFFFFF' + }, + unknown => { + background => '#E0E0E0', + text => '#FFFFFF' + }, unreachable => { background => '#E0E0E0', text => '#666666' @@ -63,41 +82,6 @@ my %color_host = ( } ); -my %color_service = ( - ok => { - background => '#88B922', - text => '#FFFFFF' - }, - warning => { - background => '#FD9B27', - text => '#FFFFFF' - }, - critical => { - background => '#FF4A4A', - text => '#FFFFFF' - }, - unknown => { - background => '#E0E0E0', - text => '#FFFFFF' - }, - acknowledgement => { - background => '#F5F1E9', - text => '#666666' - }, - downtimestart => { - background => '#F0E9F8', - text => '#666666' - }, - downtimeend => { - background => '#F0E9F8', - text => '#666666' - }, - downtimecanceled => { - background => '#F0E9F8', - text => '#666666' - } -); - sub new { my ($class, %options) = @_; my $self = $class->SUPER::new(package => __PACKAGE__, %options); @@ -123,6 +107,7 @@ sub new { 'host-duration:s' => { name => 'host_duration' }, 'service-id:s' => { name => 'service_id' }, 'service-description:s' => { name => 'service_description' }, + 'service-displayname:s' => { name => 'service_displayname' }, 'service-state:s' => { name => 'service_state' }, 'service-output:s' => { name => 'service_output' }, 'service-longoutput:s' => { name => 'service_longoutput' }, @@ -178,50 +163,53 @@ sub host_message { my $host_id = $self->{option_results}->{host_id}; + my $event_type = ''; + my $author = ''; + my $author_alt = ''; + my $comment = ''; + my $comment_alt = ''; + my $include_author = 0; + my $include_comment = 0; + + if (defined($self->{option_results}->{notif_author}) && $self->{option_results}->{notif_author} ne '') { + $author = $self->{option_results}->{notif_author}; + $include_author = 1; + if ($self->{option_results}->{type} =~ /^downtime.*$/i) { + $event_type = 'Scheduled Downtime'; + $author_alt = 'Scheduled Downtime by: ' . $self->{option_results}->{notif_author}; + } elsif($self->{option_results}->{type} =~ /^acknowledgement$/i) { + $event_type = 'Acknowledged'; + $author_alt = 'Acknowledged by: ' . $self->{option_results}->{notif_author}; + } elsif($self->{option_results}->{type} =~ /^flaping.*$/i) { + $event_type = 'Flapping'; + $author_alt = 'Flapping by: ' . $self->{option_results}->{notif_author}; + } + } + + if (defined($self->{option_results}->{notif_comment}) && $self->{option_results}->{notif_comment} ne '') { + $comment = $self->{option_results}->{notif_comment}; + $include_comment = 1; + if ($self->{option_results}->{type} =~ /^downtime.*$/i) { + $event_type = 'Scheduled Downtime'; + $comment_alt = 'Scheduled Downtime Comment: ' . $self->{option_results}->{notif_comment}; + } elsif($self->{option_results}->{type} =~ /^acknowledgement$/i) { + $event_type = 'Acknowledged'; + $comment_alt = 'Acknowledged Comment: ' . $self->{option_results}->{notif_comment}; + } elsif($self->{option_results}->{type} =~ /^flaping.*$/i) { + $event_type = 'Flapping'; + $comment_alt = 'Flapping Comment: ' . $self->{option_results}->{notif_comment}; + } + } + my $details = { id => $host_id, resourcesDetailsEndpoint => "/centreon/api/latest/monitoring/resources/hosts/$host_id", tab => "details" }; - my $author_html = ''; - my $author_alt = ''; - my $comment_html = ''; - my $comment_alt = ''; - if (defined($self->{option_results}->{notif_author}) && $self->{option_results}->{notif_author} ne '') { - if ($self->{option_results}->{type} =~ /^downtime.*$/i) { - $author_html = '

Scheduled Downtime by:

-

' . $self->{option_results}->{notif_author} . '

'; - $author_alt = 'Scheduled Downtime by: ' . $self->{option_results}->{notif_author}; - } elsif ($self->{option_results}->{type} =~ /^acknowledgement$/i) { - $author_html = '

Acknowledged Author:

-

' . $self->{option_results}->{notif_author} . '

'; - $author_alt = 'Acknowledged Author: ' . $self->{option_results}->{notif_author}; - } elsif ($self->{option_results}->{type} =~ /^flaping.*$/i) { - $author_html = '

Flapping Author:

-

' . $self->{option_results}->{notif_author} . '

'; - $author_alt = 'Flapping Author: ' . $self->{option_results}->{notif_author}; - } - } - - if (defined($self->{option_results}->{notif_comment}) && $self->{option_results}->{notif_comment} ne '') { - if ($self->{option_results}->{type} =~ /^downtime.*$/i){ - $comment_html = '

Scheduled Downtime Comment:

-

' . $self->{option_results}->{notif_comment} . '

'; - $comment_alt = 'Scheduled Downtime Comment: ' . $self->{option_results}->{notif_comment}; - } elsif ($self->{option_results}->{type} =~ /^acknowledgement$/i) { - $comment_html = '

Acknowledged Comment:

-

' . $self->{option_results}->{notif_comment} . '

'; - $comment_alt = 'Acknowledged Comment: ' . $self->{option_results}->{notif_comment}; - } elsif ($self->{option_results}->{type} =~ /^flaping.*$/i) { - $comment_html = '

Flapping Comment:

-

' . $self->{option_results}->{notif_comment} . '

'; - $comment_alt = 'Flapping Comment: ' . $self->{option_results}->{notif_comment}; - } - } - my $json_data = encode_json($details); my $encoded_data = uri_escape($json_data); + my $dynamic_href = $self->{option_results}->{centreon_url} .'/centreon/monitoring/resources?details=' . $encoded_data; $self->{payload_attachment}->{subject} = '*** ' . $self->{option_results}->{type} . ' : Host: ' . $self->{option_results}->{host_name} . ' ' . $self->{option_results}->{host_state} . ' ***'; $self->{payload_attachment}->{alt_message} = ' @@ -245,284 +233,51 @@ sub host_message { Info: ' .$self->{option_results}->{host_output}; - $self->{payload_attachment}->{html_message} = ' - - - - - ' . $self->{option_results}->{host_name} . ' - - - - - - - - - - - - -
- -
- [' .$self->{option_results}->{type} . '] Host: ' . $self->{option_results}->{host_alias} . ' (' . $self->{option_results}->{host_name} . ') is ' . $self->{option_results}->{host_state} . '. *************************************************************************************************************************************** -
- - -
- - - '; } sub service_message { @@ -531,38 +286,40 @@ sub service_message { my $host_id = $self->{option_results}->{host_id}; my $service_id = $self->{option_results}->{service_id}; - my $author_html = ''; + my $event_type = ''; + my $author = ''; my $author_alt = ''; - my $comment_html = ''; + my $comment = ''; my $comment_alt = ''; + my $include_author = 0; + my $include_comment = 0; + if (defined($self->{option_results}->{notif_author}) && $self->{option_results}->{notif_author} ne '') { + $author = $self->{option_results}->{notif_author}; + $include_author = 1; if ($self->{option_results}->{type} =~ /^downtime.*$/i) { - $author_html = '

Scheduled Downtime by:

-

' . $self->{option_results}->{notif_author} . '

'; + $event_type = 'Scheduled Downtime'; $author_alt = 'Scheduled Downtime by: ' . $self->{option_results}->{notif_author}; } elsif($self->{option_results}->{type} =~ /^acknowledgement$/i) { - $author_html = '

Acknowledged Author:

-

' . $self->{option_results}->{notif_author} . '

'; - $author_alt = 'Acknowledged Author: ' . $self->{option_results}->{notif_author}; + $event_type = 'Acknowledged'; + $author_alt = 'Acknowledged by: ' . $self->{option_results}->{notif_author}; } elsif($self->{option_results}->{type} =~ /^flaping.*$/i) { - $author_html = '

Flapping Author:

-

' . $self->{option_results}->{notif_author} . '

'; - $author_alt = 'Flapping Author: ' . $self->{option_results}->{notif_author}; + $event_type = 'Flapping'; + $author_alt = 'Flapping by: ' . $self->{option_results}->{notif_author}; } } - + if (defined($self->{option_results}->{notif_comment}) && $self->{option_results}->{notif_comment} ne '') { + $comment = $self->{option_results}->{notif_comment}; + $include_comment = 1; if ($self->{option_results}->{type} =~ /^downtime.*$/i) { - $comment_html = '

Scheduled Downtime Comment:

-

' . $self->{option_results}->{notif_comment} . '

'; + $event_type = 'Scheduled Downtime'; $comment_alt = 'Scheduled Downtime Comment: ' . $self->{option_results}->{notif_comment}; } elsif($self->{option_results}->{type} =~ /^acknowledgement$/i) { - $comment_html = '

Acknowledged Comment:

-

' . $self->{option_results}->{notif_comment} . '

'; + $event_type = 'Acknowledged'; $comment_alt = 'Acknowledged Comment: ' . $self->{option_results}->{notif_comment}; } elsif($self->{option_results}->{type} =~ /^flaping.*$/i) { - $comment_html = '

Flapping Comment:

-

' . $self->{option_results}->{notif_comment} . '

'; + $event_type = 'Flapping'; $comment_alt = 'Flapping Comment: ' . $self->{option_results}->{notif_comment}; } } @@ -578,14 +335,14 @@ sub service_message { warning_status => '', critical_status => '' ); - + if ($self->{http}->get_code() !~ /200/ || $content =~ /^OK/) { - $graph_html = '

No graph

'; + $graph_html = '

No graph found

'; } elsif ($content =~ /Access denied|Resource not found|Invalid token/) { - $graph_html = '

Cannot retrieve graph: ' . $content . '

'; + $graph_html = '

Cannot retrieve graph: ' . $content . '

'; } else { $self->{payload_attachment}->{graph_png} = $content; - $graph_html = '\n"; + $graph_html = '\"Service\n"; } } @@ -595,13 +352,12 @@ sub service_message { tab => 'details' }; + my $line_break = '
'; my $json_data = encode_json($details); my $encoded_data = uri_escape($json_data); + my $dynamic_href = $self->{option_results}->{centreon_url} .'/centreon/monitoring/resources?details=' . $encoded_data; - my $line_break = '
'; - - $self->{option_results}->{service_longoutput} =~ s/\\n/
/g; - + $self->{payload_attachment}->{subject} = '*** ' . $self->{option_results}->{type} . ' : ' . $self->{option_results}->{service_description} . ' '. $self->{option_results}->{service_state} . ' on ' . $self->{option_results}->{host_name} . ' ***'; $self->{payload_attachment}->{alt_message} = ' ***** Centreon ***** @@ -626,309 +382,315 @@ sub service_message { ' . $self->{option_results}->{service_output} . ' ' . $self->{option_results}->{service_longoutput}; - $self->{payload_attachment}->{html_message} = ' - - - - - ' . $self->{option_results}->{host_name} . ' / ' . $self->{option_results}->{service_description} .' - - - - + $self->{option_results}->{service_longoutput} =~ s/\\n/
/g; + my $output = $self->{option_results}->{service_output} . $line_break . $self->{option_results}->{service_longoutput}; - - - - - - - -
- -
[' . $self->{option_results}->{type} . '] Service: ' . $self->{option_results}->{service_description} . ' on Host: ' . $self->{option_results}->{host_name} . ' (' . $self->{option_results}->{host_alias} . ') is '. $self->{option_results}->{service_state} . '. *************************************************************************************************************************************** -
- + + my $dynamic_css = HTML::Template->new( + scalarref => \$notification::email::templates::resources::get_css + ); + $dynamic_css->param( + backgroundColor => $background_color, + textColor => $text_color, + stateColor => $color{lc($self->{option_results}->{service_state})}->{background} + ); + + + my $html_part = HTML::Template->new( + scalarref => \$notification::email::templates::resources::get_bam_template); + $html_part->param( + dynamicCss => $dynamic_css->output, + type => $self->{option_results}->{type}, + serviceDescription => $self->{option_results}->{service_displayname}, + status => $self->{option_results}->{service_state}, + duration => $self->{option_results}->{service_duration}, + date => $self->{option_results}->{date}, + dynamicHref => $dynamic_href, + eventType => $event_type, + author => $author, + comment => $comment, + output => $self->{option_results}->{service_output}, + includeAuthor => $include_author, + includeComment => $include_comment + ); + + $self->{payload_attachment}->{html_message} = $html_part->output + +} + +sub metaservice_message { + my ($self, %options) = @_; + + my $host_id = $self->{option_results}->{host_id}; + my $service_id = $self->{option_results}->{service_id}; + + my $event_type = ''; + my $author = ''; + my $author_alt = ''; + my $comment = ''; + my $comment_alt = ''; + my $include_author = 0; + my $include_comment = 0; + + if (defined($self->{option_results}->{notif_author}) && $self->{option_results}->{notif_author} ne '') { + $author = $self->{option_results}->{notif_author}; + $include_author = 1; + if ($self->{option_results}->{type} =~ /^downtime.*$/i) { + $event_type = 'Scheduled Downtime'; + $author_alt = 'Scheduled Downtime by: ' . $self->{option_results}->{notif_author}; + } elsif($self->{option_results}->{type} =~ /^acknowledgement$/i) { + $event_type = 'Acknowledged'; + $author_alt = 'Acknowledged by: ' . $self->{option_results}->{notif_author}; + } elsif($self->{option_results}->{type} =~ /^flaping.*$/i) { + $event_type = 'Flapping'; + $author_alt = 'Flapping by: ' . $self->{option_results}->{notif_author}; + } + } + + if (defined($self->{option_results}->{notif_comment}) && $self->{option_results}->{notif_comment} ne '') { + $comment = $self->{option_results}->{notif_comment}; + $include_comment = 1; + if ($self->{option_results}->{type} =~ /^downtime.*$/i) { + $event_type = 'Scheduled Downtime'; + $comment_alt = 'Scheduled Downtime Comment: ' . $self->{option_results}->{notif_comment}; + } elsif($self->{option_results}->{type} =~ /^acknowledgement$/i) { + $event_type = 'Acknowledged'; + $comment_alt = 'Acknowledged Comment: ' . $self->{option_results}->{notif_comment}; + } elsif($self->{option_results}->{type} =~ /^flaping.*$/i) { + $event_type = 'Flapping'; + $comment_alt = 'Flapping Comment: ' . $self->{option_results}->{notif_comment}; + } + } + + my $graph_html; + if ($self->{option_results}->{centreon_user} && $self->{option_results}->{centreon_user} ne '' + && $self->{option_results}->{centreon_token} && $self->{option_results}->{centreon_token} ne '') { + my $content = $self->{http}->request( + hostname => '', + full_url => $self->{option_results}->{centreon_url} . '/centreon/include/views/graphs/generateGraphs/generateImage.php?akey=' . $self->{option_results}->{centreon_token} . '&username=' . $self->{option_results}->{centreon_user} . '&chartId=' . $host_id . '_'. $service_id, + timeout => $self->{option_results}->{timeout}, + unknown_status => '', + warning_status => '', + critical_status => '' + ); + + if ($self->{http}->get_code() !~ /200/ || $content =~ /^OK/) { + $graph_html = '

No graph found

'; + } elsif ($content =~ /Access denied|Resource not found|Invalid token/) { + $graph_html = '

Cannot retrieve graph: ' . $content . '

'; + } else { + $self->{payload_attachment}->{graph_png} = $content; + $graph_html = '\"Service\n"; + } + } + + my $details = { + id => $service_id, + resourcesDetailsEndpoint => "/centreon/api/latest/monitoring/resources/hosts/$host_id/services/$service_id", + tab => 'details' + }; + + my $line_break = '
'; + my $json_data = encode_json($details); + my $encoded_data = uri_escape($json_data); + my $dynamic_href = $self->{option_results}->{centreon_url} .'/centreon/monitoring/resources?details=' . $encoded_data; + + $self->{payload_attachment}->{subject} = '*** ' . $self->{option_results}->{type} . ' Meta Service: ' . $self->{option_results}->{service_displayname} . ' ' . $self->{option_results}->{service_state} . ' ***'; + $self->{payload_attachment}->{alt_message} = ' + ***** Centreon ***** + + Notification Type: ' . $self->{option_results}->{type} . ' + Meta Service: ' . $self->{option_results}->{service_displayname} . ' + State: ' . $self->{option_results}->{service_state} . ' + Date/Time: ' . $self->{option_results}->{date}; + + if(defined($author_alt) && $author_alt ne ''){ + $self->{payload_attachment}->{alt_message} .= "\n " . $author_alt . "\n"; + } + if(defined($comment_alt) && $comment_alt ne ''){ + $self->{payload_attachment}->{alt_message} .= " " . $comment_alt . "\n"; + } + $self->{payload_attachment}->{alt_message} .= ' + + Info: + ' .$self->{option_results}->{service_output}; + + my $background_color= 'white'; + my $text_color = 'black'; + if($self->{option_results}->{type} =~ /^problem|recovery$/i) { + $background_color = $color{lc($self->{option_results}->{service_state})}->{background}; + $text_color = $color{lc($self->{option_results}->{service_state})}->{text}; + } else { + $background_color = $color{lc($self->{option_results}->{type})}->{background} ; + $text_color = $color{lc($self->{option_results}->{type})}->{text}; + } + + my $dynamic_css = HTML::Template->new( + scalarref => \$notification::email::templates::resources::get_css + ); + $dynamic_css->param( + backgroundColor => $background_color, + textColor => $text_color, + stateColor => $color{lc($self->{option_results}->{service_state})}->{background} + ); + + + my $html_part = HTML::Template->new( + scalarref => \$notification::email::templates::resources::get_metaservice_template); + $html_part->param( + dynamicCss => $dynamic_css->output, + type => $self->{option_results}->{type}, + attempts => $self->{option_results}->{service_attempts}, + maxAttempts => $self->{option_results}->{max_service_attempts}, + serviceDescription => $self->{option_results}->{service_displayname}, + status => $self->{option_results}->{service_state}, + duration => $self->{option_results}->{service_duration}, + date => $self->{option_results}->{date}, + dynamicHref => $dynamic_href, + eventType => $event_type, + author => $author, + comment => $comment, + output => $self->{option_results}->{service_output}, + graphHtml => $graph_html, + includeAuthor => $include_author, + includeComment => $include_comment + ); + + $self->{payload_attachment}->{html_message} = $html_part->output -
- - - '; } sub set_payload { my ($self, %options) = @_; - if (defined($self->{option_results}->{service_description}) && $self->{option_results}->{service_description} ne '') { + if ($self->{option_results}->{host_name} =~ /^_Module_BAM.*/) { + $self->bam_message(); + } elsif ($self->{option_results}->{host_name} =~ /^_Module_Meta/ ) { + $self->metaservice_message(); + } elsif ( defined($self->{option_results}->{service_description}) && $self->{option_results}->{service_description} ne '' ) { $self->service_message(); } else { $self->host_message(); @@ -1041,7 +803,7 @@ centreon_plugins.pl --plugin=notification::email::plugin --mode=alert --to-addre Example for Centreon configuration: -centreon_plugins.pl --plugin=notification::email::plugin --mode=alert --to-address='$CONTACTEMAIL$' --host-address='$HOSTADDRESS$' --host-name='$HOSTNAME$' --host-alias='$HOSTALIAS$' --host-state='$HOSTSTATE$' --host-output='$HOSTOUTPUT$' --host-attempts='$HOSTATTEMPT$' --max-host-attempts='$MAXHOSTATTEMPTS$' --host-duration='$HOSTDURATION$' --date='$SHORTDATETIME$' --type='$NOTIFICATIONTYPE$' --service-description='$SERVICEDESC$' --service-state='$SERVICESTATE$' --service-output='$SERVICEOUTPUT$' --service-longoutput='$LONGSERVICEOUTPUT$' --service-attempts=''$SERVICEATTEMPT$ --max-service-attempts='$MAXSERVICEATTEMPTS$' --service-duration='$SERVICEDURATION$' --host-id='$HOSTID$' --service-id='$SERVICEID$' --notif-author='$NOTIFICATIONAUTHOR$' --notif-comment='$NOTIFICATIONCOMMENT$' --smtp-nossl --centreon-url='https://your-centreon-server' --smtp-address=your-smtp-server --smtp-port=your-smtp-port --from-address='centreon-engine@centreon.com' --centreon-user='your-centreon-username' --centreon-token='your-centreon-autologin-key' --smtp-user='your-smtp-username' --smtp-password='your-smtp-password' +centreon_plugins.pl --plugin=notification::email::plugin --mode=alert --to-address='$CONTACTEMAIL$' --host-address='$HOSTADDRESS$' --host-name='$HOSTNAME$' --host-alias='$HOSTALIAS$' --host-state='$HOSTSTATE$' --host-output='$HOSTOUTPUT$' --host-attempts='$HOSTATTEMPT$' --max-host-attempts='$MAXHOSTATTEMPTS$' --host-duration='$HOSTDURATION$' --date='$SHORTDATETIME$' --type='$NOTIFICATIONTYPE$' --service-description='$SERVICEDESC$' --service-displayname='$SERVICEDISPLAYNAME$' --service-state='$SERVICESTATE$' --service-output='$SERVICEOUTPUT$' --service-longoutput='$LONGSERVICEOUTPUT$' --service-attempts='$SERVICEATTEMPT$' --max-service-attempts='$MAXSERVICEATTEMPTS$' --service-duration='$SERVICEDURATION$' --host-id='$HOSTID$' --service-id='$SERVICEID$' --notif-author='$NOTIFICATIONAUTHOR$' --notif-comment='$NOTIFICATIONCOMMENT$' --smtp-nossl --centreon-url='https://your-centreon-server' --smtp-address=your-smtp-server --smtp-port=your-smtp-port --from-address='centreon-engine@centreon.com' --centreon-user='your-centreon-username' --centreon-token='your-centreon-autologin-key' --smtp-user='your-smtp-username' --smtp-password='your-smtp-password' =over 8 @@ -1121,6 +883,10 @@ ID of the service. Description of the service. +=item B<--service-displayname> + +Display BA name. + =item B<--service-state> State of the service. diff --git a/src/notification/email/templates/bam.pm b/src/notification/email/templates/bam.pm new file mode 100644 index 000000000..cb3ad2205 --- /dev/null +++ b/src/notification/email/templates/bam.pm @@ -0,0 +1,359 @@ +package notification::email::templates::bam; + +use strict; +use warnings; + +use Exporter qw(import); + +our @EXPORT_OK = qw(get_bam_template); + +sub get_bam_template { +return q{ + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ +
+ + + + + + +
+ +
+
+
+
+ + + + + + +
+ + + + +
+
+
+
+
+
+
+ + + + + + +
+ +
+
+
+
+
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+
+

Business Activity:

+

+ + is + + + + for: + + + +

+
+
+
+
+
+
+ +
+ + + + + + +
+ +
+ +
+ + + + + + +
+ + + + +
+
+

Date:

+

+ +

+
+
+
+
+
+ + + + + + +
+ +
+
+
+
+ + + + + + +
+ + + + +
+ + + + +
+ More Information
+
+
+
+
+
+
+ + +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+
+

+ by: +

+

+ +

+
+
+
+
+
+
+
+ + +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+
+

+ Comment: +

+

+ +

+
+
+
+
+
+
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+
+

Status information:

+

+ +

+
+
+
+
+
+
+
+
+
+ + + +}; +} + +1; \ No newline at end of file diff --git a/src/notification/email/templates/host.pm b/src/notification/email/templates/host.pm new file mode 100644 index 000000000..fc8b3fba9 --- /dev/null +++ b/src/notification/email/templates/host.pm @@ -0,0 +1,415 @@ +package notification::email::templates::host; + +use strict; +use warnings; + +use Exporter qw(import); + +our @EXPORT_OK = qw(get_host_template); + +sub get_host_template { +return q{ + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ +
+ + + + + + +
+ +
+
+
+
+ + + + + + +
+ + + + +
+
+
+
+
+
+
+ + + + + + +
+ + + + +
+
+ / +
+
+
+
+
+
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+
+

Host:

+

+ + is + + + + for: + + + +

+
+
+
+
+
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+
+

Host Alias:

+

+ +

+
+
+
+
+
+
+ +
+ + + + + + +
+ +
+ +
+ + + + + + +
+ + + + +
+
+

Host Address:

+

+ +

+
+
+
+
+
+ + + + + + +
+ + + + +
+
+

Date:

+

+ +

+
+
+
+
+
+ + + + + + +
+ + + + +
+ + + + +
+ More Information
+
+
+
+
+
+
+ + +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+
+

+ by: +

+

+ +

+
+
+
+
+
+
+
+ + +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+
+

+ Comment: +

+

+ +

+
+
+
+
+
+
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+
+

Status information:

+

+ +

+
+
+
+
+
+
+
+
+
+ + + +}; +} + +1; \ No newline at end of file diff --git a/src/notification/email/templates/metaservice.pm b/src/notification/email/templates/metaservice.pm new file mode 100644 index 000000000..1c3af6efe --- /dev/null +++ b/src/notification/email/templates/metaservice.pm @@ -0,0 +1,408 @@ +package notification::email::templates::metaservice; + +use strict; +use warnings; + +use Exporter qw(import); + +our @EXPORT_OK = qw(get_metaservice_template); + +sub get_metaservice_template { +return q{ + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ +
+ + + + + + +
+ +
+
+
+
+ + + + + + +
+ + + + +
+
+
+
+
+
+
+ + + + + + +
+ + + + +
+
+ / +
+
+
+
+
+
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+
+

Meta Service:

+

+ + is + + + + for: + + + +

+
+
+
+
+
+
+ +
+ + + + + + +
+ +
+ +
+ + + + + + +
+ + + + +
+
+

Date:

+

+ +

+
+
+
+
+
+ + + + + + +
+ +
+
+
+
+ + + + + + +
+ + + + +
+ + + + +
+ More Information
+
+
+
+
+
+
+ + +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+
+

+ by: +

+

+ +

+
+
+
+
+
+
+
+ + +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+
+

+ Comment: +

+

+ +

+
+
+
+
+
+
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+
+

Status information:

+

+ +

+
+
+
+
+
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+ + + + + + +
+ +
+
+
+
+
+
+
+
+
+ + + +}; +} + +1; \ No newline at end of file diff --git a/src/notification/email/templates/resources.pm b/src/notification/email/templates/resources.pm new file mode 100644 index 000000000..f763eb5bb --- /dev/null +++ b/src/notification/email/templates/resources.pm @@ -0,0 +1,18 @@ +package notification::email::templates::resources; + +use strict; +use warnings; + +use notification::email::templates::style qw(get_css); +use notification::email::templates::host qw(get_host_template); +use notification::email::templates::service qw(get_service_template); +use notification::email::templates::bam qw(get_bam_template); +use notification::email::templates::metaservice qw(get_metaservice_template); + +our $get_service_template = get_service_template(); +our $get_host_template = get_host_template(); +our $get_bam_template = get_bam_template(); +our $get_metaservice_template = get_metaservice_template(); +our $get_css = get_css(); + +1; diff --git a/src/notification/email/templates/service.pm b/src/notification/email/templates/service.pm new file mode 100644 index 000000000..c7dc7b194 --- /dev/null +++ b/src/notification/email/templates/service.pm @@ -0,0 +1,461 @@ +package notification::email::templates::service; + +use strict; +use warnings; + +use Exporter qw(import); + +our @EXPORT_OK = qw(get_service_template); + +sub get_service_template { + return q{ + + + + + + + + + + + + + +
+ +
+ + + + + + +
+ +
+ + + + + + +
+ +
+ +
+ + + + + + +
+ +
+
+
+
+ + + + + + +
+ + + + +
+
+ +
+
+
+
+
+ + + + + + +
+ + + + +
+
+ / +
+
+
+
+
+
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+
+

Host:

+

+ +

+

Service:

+

+ + + is + + + for: + + +

+
+
+
+
+
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+
+

Host Alias:

+

+ +

+
+
+
+
+
+
+ +
+ + + + + + +
+ +
+ +
+ + + + + + +
+ + + + +
+
+

Host Address:

+

+ +

+
+
+
+
+
+ + + + + + +
+ + + + +
+
+

Date:

+

+ +

+
+
+
+
+
+ + + + + + +
+ + + + +
+ + + + +
More Information
+
+
+
+
+
+
+ + +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+
+

+ by: +

+

+ +

+
+
+
+
+
+
+
+ + +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+
+

+ Comment: +

+

+

+
+
+
+
+
+
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+
+

Status information:

+

+ +

+
+
+
+
+
+
+ +
+ + + + + + +
+ +
+ + + + + + +
+ + + + +
+ + + + + + +
+ +
+
+
+
+
+
+
+
+
+ + + +}; +} + +1; diff --git a/src/notification/email/templates/style.pm b/src/notification/email/templates/style.pm new file mode 100644 index 000000000..7e6a97a1d --- /dev/null +++ b/src/notification/email/templates/style.pm @@ -0,0 +1,204 @@ +package notification::email::templates::style; + +use strict; +use warnings; + +use Exporter qw(import); + +our @EXPORT_OK = qw(get_css); + +sub get_css { +return q{ + + + + + + + +}; +} + +1; \ No newline at end of file diff --git a/src/os/linux/local/mode/process.pm b/src/os/linux/local/mode/process.pm index 4eb3f8d8c..63c00f7cd 100644 --- a/src/os/linux/local/mode/process.pm +++ b/src/os/linux/local/mode/process.pm @@ -382,7 +382,7 @@ bash -c 'tail -n +1 /proc/{pid1,pid2,...}/{statm,stat,io}' =item B<--add-cpu> -Monitor cpu usage. +Monitor CPU usage. =item B<--add-memory> diff --git a/src/os/picos/snmp/mode/interfaces.pm b/src/os/picos/snmp/mode/interfaces.pm index 684fb1719..0030ba2ce 100644 --- a/src/os/picos/snmp/mode/interfaces.pm +++ b/src/os/picos/snmp/mode/interfaces.pm @@ -307,7 +307,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/snmp_standard/mode/cpu.pm b/src/snmp_standard/mode/cpu.pm index 18e18cfe6..8c43f2e86 100644 --- a/src/snmp_standard/mode/cpu.pm +++ b/src/snmp_standard/mode/cpu.pm @@ -138,7 +138,7 @@ of time that this processor was not idle) =item B<--use-ucd> -Use UCD mib for cpu average. +Use UCD mib for CPU average. =item B<--warning-average> diff --git a/src/snmp_standard/mode/diskusage.pm b/src/snmp_standard/mode/diskusage.pm index e5e0d1534..23f42981a 100644 --- a/src/snmp_standard/mode/diskusage.pm +++ b/src/snmp_standard/mode/diskusage.pm @@ -400,7 +400,7 @@ Example: adding --display-transform-src='dev' --display-transform-dst='run' wil =item B<--show-cache> -Display cache disk path datas. +Display cache disk path data. =item B<--space-reservation> diff --git a/src/snmp_standard/mode/interfaces.pm b/src/snmp_standard/mode/interfaces.pm index 6e3399820..c5bd5de15 100644 --- a/src/snmp_standard/mode/interfaces.pm +++ b/src/snmp_standard/mode/interfaces.pm @@ -1745,7 +1745,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/snmp_standard/mode/listprocesses.pm b/src/snmp_standard/mode/listprocesses.pm index 68ffed251..cf6a62ffe 100644 --- a/src/snmp_standard/mode/listprocesses.pm +++ b/src/snmp_standard/mode/listprocesses.pm @@ -163,7 +163,7 @@ Filter by service name (can be a regexp). =item B<--add-stats> -Add cpu and memory stats. +Add CPU and memory stats. =back diff --git a/src/snmp_standard/mode/processcount.pm b/src/snmp_standard/mode/processcount.pm index b5f322541..c19273c86 100644 --- a/src/snmp_standard/mode/processcount.pm +++ b/src/snmp_standard/mode/processcount.pm @@ -284,7 +284,7 @@ sub run { min => 0); } - # Check cpu + # Check CPU if (defined($self->{option_results}->{cpu}) && $num_processes_match > 0) { my $datas = {}; $datas->{last_timestamp} = time(); @@ -354,7 +354,7 @@ __END__ =head1 MODE Check system number of processes. -Can also check memory usage and cpu usage. +Can also check memory usage and CPU usage. =over 8 @@ -434,19 +434,19 @@ memory used by matching processes (in Bytes). =item B<--cpu> -Check cpu usage. Should be used with fix processes. +Check CPU usage. Should be used with fix processes. If processes pid changes too much, the plugin can't compute values. =item B<--warning-cpu-total> -Warning threshold of cpu usage for all processes (in percent). -CPU usage is in % of one cpu, so maximum can be 100% * number of CPU +Warning threshold of CPU usage for all processes (in percent). +CPU usage is in % of one CPU, so maximum can be 100% * number of CPU and a process can have a value greater than 100%. =item B<--critical-cpu-total> -Critical threshold of cpu usage for all processes (in percent). -CPU usage is in % of one cpu, so maximum can be 100% * number of CPU +Critical threshold of CPU usage for all processes (in percent). +CPU usage is in % of one CPU, so maximum can be 100% * number of CPU and a process can have a value greater than 100%. =item B<--top> diff --git a/src/snmp_standard/mode/storage.pm b/src/snmp_standard/mode/storage.pm index fced0e6ed..6eca26d92 100644 --- a/src/snmp_standard/mode/storage.pm +++ b/src/snmp_standard/mode/storage.pm @@ -673,7 +673,7 @@ Example: adding --display-transform-src='dev' --display-transform-dst='run' wil =item B<--show-cache> -Display cache storage datas. +Display cache storage data. =item B<--space-reservation> diff --git a/src/storage/lenovo/iomega/snmp/mode/interfaces.pm b/src/storage/lenovo/iomega/snmp/mode/interfaces.pm index a16e7b755..4df9ec0f3 100644 --- a/src/storage/lenovo/iomega/snmp/mode/interfaces.pm +++ b/src/storage/lenovo/iomega/snmp/mode/interfaces.pm @@ -174,7 +174,7 @@ Example: adding --display-transform-src='eth' --display-transform-dst='ens' wil =item B<--show-cache> -Display cache interface datas. +Display cache interface data. =back diff --git a/src/storage/panzura/snmp/mode/cpucloud.pm b/src/storage/panzura/snmp/mode/cpucloud.pm index aaba1aad6..83b1053b3 100644 --- a/src/storage/panzura/snmp/mode/cpucloud.pm +++ b/src/storage/panzura/snmp/mode/cpucloud.pm @@ -80,7 +80,7 @@ __END__ =head1 MODE -Check cpu usage of cloud controller (panzura-systemext). +Check CPU usage of cloud controller (panzura-systemext). =over 8 diff --git a/src/storage/violin/3000/snmp/plugin.pm b/src/storage/violin/3000/snmp/plugin.pm index 802c791a5..b0a282261 100644 --- a/src/storage/violin/3000/snmp/plugin.pm +++ b/src/storage/violin/3000/snmp/plugin.pm @@ -44,6 +44,6 @@ __END__ =head1 PLUGIN DESCRIPTION Check Violin 3000 series in SNMP. -Please use plugin SNMP Linux for system checks ('cpu', 'memory', 'traffic',...). +Please use the SNMP Linux plugin for system checks (CPU, memory, traffic, ...). =cut diff --git a/tests/functional/snmp/storage-synology-snmp.robot b/tests/functional/snmp/storage-synology-snmp.robot index 6e5ac80b7..c1faa5f06 100644 --- a/tests/functional/snmp/storage-synology-snmp.robot +++ b/tests/functional/snmp/storage-synology-snmp.robot @@ -34,12 +34,33 @@ ${CMD} perl ${CENTREON_PLUGINS} --plugin=storage::synology: ... &{check_components_test3} ... &{check_components_test4} +&{uptime_t1} +... description=Uptime check expected to be OK +... snmpcommunity=synology_component_disk_ok +... warning= +... critical= +... expected_output=OK: System uptime is: 46m 5s | 'uptime'=2765.00s;;;0; +&{uptime_t2} +... description=Uptime check expected to be warning +... snmpcommunity=synology_component_disk_ok +... warning=10 +... critical= +... expected_output=WARNING: System uptime is: 46m 5s | 'uptime'=2765.00s;0:10;;0; +&{uptime_t3} +... description=Uptime check expected to be critical +... snmpcommunity=synology_component_disk_ok +... warning= +... critical=10 +... expected_output=CRITICAL: System uptime is: 46m 5s | 'uptime'=2765.00s;;0:10;0; + +@{uptime_tests} +... &{uptime_t1} +... &{uptime_t2} +... &{uptime_t3} *** Test Cases *** -Synology SNMP: Checking disk components - [Documentation] Monitor the different states of disk health +Components [Tags] storage synology snmp - Log To Console Synology SNMP: Checking disk components FOR ${check_components_test} IN @{check_components_tests} ${command} Catenate ... ${CMD} @@ -48,10 +69,30 @@ Synology SNMP: Checking disk components ... --snmp-version=2 ... --snmp-port=2024 ... --snmp-community=${check_components_test.snmpcommunity} + ${output} Run ${command} - Log To Console ${check_components_test.description} Should Be Equal As Strings ... ${check_components_test.expected_output} ... ${output} - ... Wrong output for components mode: ${check_components_test}.{\n}Command output:{\n}${output} + ... ${check_components_test.description} failed. Wrong output for components mode: ${check_components_test}.{\n}Command output:{\n}${output} + END + +Uptime + [Tags] storage synology snmp + FOR ${test_item} IN @{uptime_tests} + ${command} Catenate + ... ${CMD} + ... --mode=uptime + ... --hostname=127.0.0.1 + ... --snmp-version=2 + ... --snmp-port=2024 + ... --snmp-community=${test_item.snmpcommunity} + ... --warning-uptime=${test_item.warning} + ... --critical-uptime=${test_item.critical} + + ${output} Run ${command} + Should Be Equal As Strings + ... ${test_item.expected_output} + ... ${output} + ... ${test_item.description} failed. Wrong output for components mode: ${test_item}.{\n}Command output:{\n}${output} END diff --git a/tests/resources/snmp/synology_component_disk_critical.snmpwalk b/tests/resources/snmp/synology_component_disk_critical.snmpwalk index cc7e081a5..b57c024df 100644 --- a/tests/resources/snmp/synology_component_disk_critical.snmpwalk +++ b/tests/resources/snmp/synology_component_disk_critical.snmpwalk @@ -1,3 +1,4 @@ +.1.3.6.1.2.1.25.1.1.0 = 276532 .1.3.6.1.4.1.6574.1.1.0 = INTEGER: 1 .1.3.6.1.4.1.6574.1.3.0 = INTEGER: 1 .1.3.6.1.4.1.6574.1.4.1.0 = INTEGER: 1 diff --git a/tests/resources/snmp/synology_component_disk_failing.snmpwalk b/tests/resources/snmp/synology_component_disk_failing.snmpwalk index 54df78857..7efd3f94a 100644 --- a/tests/resources/snmp/synology_component_disk_failing.snmpwalk +++ b/tests/resources/snmp/synology_component_disk_failing.snmpwalk @@ -1,3 +1,4 @@ +.1.3.6.1.2.1.25.1.1.0 = 276532 .1.3.6.1.4.1.6574.1.1.0 = INTEGER: 1 .1.3.6.1.4.1.6574.1.3.0 = INTEGER: 1 .1.3.6.1.4.1.6574.1.4.1.0 = INTEGER: 1 diff --git a/tests/resources/snmp/synology_component_disk_ok.snmpwalk b/tests/resources/snmp/synology_component_disk_ok.snmpwalk index 92a3c9ebb..f8bfcabe6 100644 --- a/tests/resources/snmp/synology_component_disk_ok.snmpwalk +++ b/tests/resources/snmp/synology_component_disk_ok.snmpwalk @@ -1,3 +1,4 @@ +.1.3.6.1.2.1.25.1.1.0 = 276532 .1.3.6.1.4.1.6574.1.1.0 = INTEGER: 1 .1.3.6.1.4.1.6574.1.3.0 = INTEGER: 1 .1.3.6.1.4.1.6574.1.4.1.0 = INTEGER: 1 diff --git a/tests/resources/snmp/synology_component_disk_warning.snmpwalk b/tests/resources/snmp/synology_component_disk_warning.snmpwalk index 4a1ccdbdf..b925f9b92 100644 --- a/tests/resources/snmp/synology_component_disk_warning.snmpwalk +++ b/tests/resources/snmp/synology_component_disk_warning.snmpwalk @@ -1,3 +1,4 @@ +.1.3.6.1.2.1.25.1.1.0 = 276532 .1.3.6.1.4.1.6574.1.1.0 = INTEGER: 1 .1.3.6.1.4.1.6574.1.3.0 = INTEGER: 1 .1.3.6.1.4.1.6574.1.4.1.0 = INTEGER: 1