diff --git a/.github/actions/test-plugins/action.yml b/.github/actions/test-plugins/action.yml index 84aab55c9..b3cbd5381 100644 --- a/.github/actions/test-plugins/action.yml +++ b/.github/actions/test-plugins/action.yml @@ -24,5 +24,4 @@ runs: - name: Install, test and remove plugin shell: bash - run: | - python3 .github/scripts/test-all-plugins.py ${{ inputs.package-extension }} ${{ inputs.plugin-list }} + run: python3 .github/scripts/test-all-plugins.py ${{ inputs.package-extension }} ${{ inputs.plugin-list }} diff --git a/.github/packaging/centreon-plugin.yaml.template b/.github/packaging/centreon-plugin.yaml.template index 5d3afb958..976a58368 100644 --- a/.github/packaging/centreon-plugin.yaml.template +++ b/.github/packaging/centreon-plugin.yaml.template @@ -47,6 +47,7 @@ overrides: perl(Storable), perl(POSIX), perl(Encode), + perl(XML::LibXML), @RPM_DEPENDENCIES@ ] conflicts: @@ -72,6 +73,7 @@ overrides: libcrypt-argon2-perl, libkeepass-reader-perl, libdatetime-perl, + libxml-libxml-perl, @DEB_DEPENDENCIES@ ] conflicts: diff --git a/.github/scripts/test-all-plugins.py b/.github/scripts/test-all-plugins.py index 176e7eaba..646aa5620 100644 --- a/.github/scripts/test-all-plugins.py +++ b/.github/scripts/test-all-plugins.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +import glob import subprocess import sys import os @@ -26,7 +27,7 @@ def test_plugin(plugin_name): print(f"{plugin_name} folders_list : {folders_list}") if len(folders_list) == 0: return 0 # no tests present at the moment, but we still have tested the plugin can be installed. - robot_results = subprocess.run("robot -v ''CENTREON_PLUGINS:" + get_plugin_full_path(plugin_name) + " " + " ".join(folders_list), + robot_results = subprocess.run("robot --exclude notauto -v ''CENTREON_PLUGINS:" + get_plugin_full_path(plugin_name) + " " + " ".join(folders_list), shell=True, check=False) return robot_results.returncode @@ -51,13 +52,26 @@ def launch_snmp_sim(): snmpsim_cmd = "snmpsim-command-responder --logging-method=null --agent-udpv4-endpoint=127.0.0.1:2024 --process-user=snmp --process-group=snmp --data-dir='./tests/robot' &" try_command(cmd=snmpsim_cmd, error="can't launch snmp sim daemon.") +def refresh_packet_manager(archi): + with open('/var/log/robot-plugins-installation-tests.log', "a") as outfile: + if archi == "deb": + outfile.write("apt-get update\n") + output_status = (subprocess.run( + "apt-get update", + shell=True, check=False, stderr=subprocess.STDOUT, stdout=outfile)).returncode + elif archi == "rpm": + return 0 + else: + print(f"Unknown architecture, expected deb or rpm, got {archi}. Exiting.") + exit(1) + return output_status def install_plugin(plugin, archi): with open('/var/log/robot-plugins-installation-tests.log', "a") as outfile: if archi == "deb": - outfile.write("apt install -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' -y ./" + plugin.lower() + "*.deb\n") + outfile.write("apt-get install -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' -y ./" + plugin.lower() + "*.deb\n") output_status = (subprocess.run( - "apt install -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' -y ./" + plugin.lower() + "*.deb", + "apt-get install -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' -y ./" + plugin.lower() + "*.deb", shell=True, check=False, stderr=subprocess.STDOUT, stdout=outfile)).returncode elif archi == "rpm": outfile.write("dnf install -y ./" + plugin + "*.rpm\n") @@ -72,9 +86,9 @@ def install_plugin(plugin, archi): def remove_plugin(plugin, archi): with open('/var/log/robot-plugins-installation-tests.log', "a") as outfile: if archi == "deb": - outfile.write("apt -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' autoremove -y " + plugin.lower() + "\n") + outfile.write("apt-get -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' autoremove -y " + plugin.lower() + "\n") output_status = (subprocess.run( - "apt -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' autoremove -y " + plugin.lower(), + "apt-get -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' autoremove -y " + plugin.lower(), shell=True, check=False, stderr=subprocess.STDOUT, stdout=outfile)).returncode # -o 'Binary::apt::APT::Keep-Downloaded-Packages=1;' is an option to force apt to keep the package in # /var/cache/apt/archives, so it do not re download them for every installation. @@ -87,6 +101,13 @@ def remove_plugin(plugin, archi): else: print(f"Unknown architecture, expected deb or rpm, got {archi}. Exiting.") exit(1) + # Remove cache files + tmp_files = glob.glob('/tmp/cache/*') + for file in tmp_files: + try: + os.remove(file) + except Exception as e: + print(f"Erreur while removing file {file} : {str(e)}") return output_status @@ -101,13 +122,25 @@ if __name__ == '__main__': archi = sys.argv.pop(1) # expected either deb or rpm. script_name = sys.argv.pop(0) + # Create a directory for cache files + os.mkdir("/tmp/cache") + error_install = 0 error_tests = 0 error_purge = 0 nb_plugins = 0 list_plugin_error = [] + + # call apt update (or maybe dnf clean all if needed) + refresh_packet_manager(archi) + for plugin in sys.argv: print("plugin : ", plugin) + folders_list = get_tests_folders(plugin) + if len(folders_list) == 0: + print(f"we don't test {plugin} as it don't have any robots tests.") + continue + nb_plugins += 1 tmp = install_plugin(plugin, archi) if tmp > 0: diff --git a/.github/workflows/docker-builder-packaging-plugins.yml b/.github/workflows/docker-builder-packaging-plugins.yml index 99cdb0da5..948c98360 100644 --- a/.github/workflows/docker-builder-packaging-plugins.yml +++ b/.github/workflows/docker-builder-packaging-plugins.yml @@ -51,22 +51,22 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Login to Registry - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 with: registry: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }} username: ${{ secrets.DOCKER_REGISTRY_ID }} password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - name: Login to proxy registry - uses: docker/login-action@343f7c4344506bcbf9b4de18042ae17996df046d # v3.0.0 + uses: docker/login-action@e92390c5fb421da1463c202d546fed0ec5c39f20 # v3.1.0 with: registry: ${{ vars.DOCKER_PROXY_REGISTRY_URL }} username: ${{ secrets.DOCKER_REGISTRY_ID }} password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - - uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 + - uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0 - - uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0 + - uses: docker/build-push-action@2cdde995de11925a030ce8070c3d77a52ffcf1c0 # v5.3.0 with: file: .github/docker/packaging/Dockerfile.${{ matrix.dockerfile }} context: . diff --git a/.github/workflows/docker-builder-testing-plugins.yml b/.github/workflows/docker-builder-testing-plugins.yml index 9ffc0aaf8..b3aa9f149 100644 --- a/.github/workflows/docker-builder-testing-plugins.yml +++ b/.github/workflows/docker-builder-testing-plugins.yml @@ -61,7 +61,7 @@ jobs: username: ${{ secrets.DOCKER_REGISTRY_ID }} password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - - uses: docker/setup-buildx-action@f95db51fddba0c2d1ec667646a06c2ce06100226 # v3.0.0 + - uses: docker/setup-buildx-action@d70bba72b1f3fd22344832f00baa16ece964efeb # v3.3.0 - uses: docker/build-push-action@4a13e500e55cf31b7a5d59a38ab2040ab0f42f56 # v5.1.0 with: diff --git a/.github/workflows/perl-cpan-libraries.yml b/.github/workflows/perl-cpan-libraries.yml index 94ea3fa2c..7521bffe2 100644 --- a/.github/workflows/perl-cpan-libraries.yml +++ b/.github/workflows/perl-cpan-libraries.yml @@ -68,15 +68,18 @@ jobs: "JSON::WebToken", "LV", "MIME::Types", + "Mojo::IOLoop::Signal", "MongoDB", "Net::DHCP", "Net::FTPSSL", "Net::HTTPTunnel", + "Net::MQTT::Simple", "Net::NTP", "Net::SMTPS", "Net::SMTP_auth", "Net::Subnet", "Net::TFTP", + "Paws", "PBKDF2::Tiny", "Schedule::Cron", "Statistics::Descriptive", @@ -103,7 +106,6 @@ jobs: - rpm_dependencies: "" - rpm_provides: "" - version: "" - - use_dh_make_perl: "true" - spec_file: "" - distrib: el8 package_extension: rpm @@ -113,19 +115,15 @@ jobs: image: packaging-plugins-alma9 - name: "BSON" 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" - - name: "Convert::Binary::C" - name: "DateTime::Format::Duration::ISO8601" rpm_provides: "perl(DateTime-Format-Duration-ISO8601)" - - name: "DBD::Sybase" - name: "Device::Modbus::RTU::Client" version: "0.022" - name: "Device::Modbus::TCP::Client" version: "0.026" - name: "Exporter::Shiny" build_distribs: el8 - - name: "EV" - - name: "FFI::CheckLib" + rpm_provides: "perl(Exporter::Shiny) perl(Exporter::Tiny)" - name: "FFI::Platypus" rpm_provides: "perl(FFI::Platypus::Buffer) perl(FFI::Platypus::Memory)" - name: "Net::DHCP" @@ -133,14 +131,12 @@ jobs: - name: "Statistics::Regression" version: "0.53" - name: "UUID" - use_dh_make_perl: "false" version: "0.31" - name: "ZMQ::Constants" build_distribs: "el9" - name: "ZMQ::FFI" rpm_dependencies: "zeromq" - name: "ZMQ::LibZMQ4" - use_dh_make_perl: "false" version: "0.01" rpm_dependencies: "zeromq" @@ -160,7 +156,7 @@ jobs: yum install -y yum-utils epel-release git yum config-manager --set-enabled crb || true # alma 9 yum config-manager --set-enabled powertools || true # alma 8 - yum install -y cpanminus rpm-build libcurl-devel libssh-devel expat-devel gcc libuuid-devel zeromq-devel libxml2-devel libffi-devel perl-DBI perl-Net-Pcap freetds freetds-devel + yum install -y cpanminus rpm-build libcurl-devel libssh-devel expat-devel gcc libuuid-devel zeromq-devel libxml2-devel libffi-devel perl-DBI perl-Net-Pcap freetds freetds-devel perl-Module-Build-Tiny dnf module reset -y ruby dnf module enable -y ruby:3.1 @@ -226,15 +222,92 @@ jobs: path: ./*.${{ matrix.package_extension }} retention-days: 1 + merge-package-rpm-artifacts: + needs: [package-rpm] + runs-on: ubuntu-22.04 + strategy: + matrix: + distrib: [el8, el9] + + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Merging Artifacts + uses: ./.github/actions/merge-artifacts + with: + target_name: packages-rpm-${{ matrix.distrib }} + source_paths: packages-rpm-${{ matrix.distrib }}/*.rpm + source_name_pattern: packages-rpm-${{ matrix.distrib }}- + github_token: ${{ secrets.GITHUB_TOKEN }} + + sign-rpm: + needs: [merge-package-rpm-artifacts] + + runs-on: ubuntu-22.04 + strategy: + matrix: + distrib: [el8, el9] + name: sign rpm ${{ matrix.distrib }} + container: + image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/rpm-signing:ubuntu + options: -t + credentials: + username: ${{ secrets.DOCKER_REGISTRY_ID }} + password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} + + steps: + - run: apt-get install -y zstd + shell: bash + + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 + with: + name: packages-rpm-${{ matrix.distrib }} + path: ./ + + - run: echo "HOME=/root" >> $GITHUB_ENV + shell: bash + + - run: rpmsign --addsign ./*.rpm + shell: bash + + - uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 + with: + path: ./*.rpm + key: ${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} + + deliver-rpm: + needs: [get-environment, sign-rpm] + if: ${{ contains(fromJson('["testing", "unstable"]'), needs.get-environment.outputs.stability) }} + runs-on: [self-hosted, common] + + strategy: + matrix: + distrib: [el8, el9] + + steps: + - name: Checkout sources + uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 + + - name: Delivery + uses: ./.github/actions/rpm-delivery + with: + module_name: perl-cpan-libraries + distrib: ${{ matrix.distrib }} + artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} + cache_key: ${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} + stability: ${{ needs.get-environment.outputs.stability }} + package-deb: needs: [get-environment] if: ${{ needs.get-environment.outputs.stability != 'stable' }} - runs-on: ubuntu-22.04 + runs-on: ${{ matrix.runner_name }} strategy: fail-fast: false matrix: - distrib: [bullseye, bookworm, jammy] + image: [packaging-plugins-bullseye, packaging-plugins-bookworm, packaging-plugins-jammy, packaging-plugins-bullseye-arm64] name: [ "Authen::SCRAM::Client", @@ -247,15 +320,20 @@ jobs: "Hash::Ordered", "HTTP::ProxyPAC", "JMX::Jmx4Perl", + "Mojo::IOLoop::Signal", "Net::FTPSSL", "Net::HTTPTunnel", + "Net::MQTT::Simple", "Net::SMTP_auth", + "Paws", "Statistics::Regression", "WWW::Selenium", "ZMQ::Constants", "ZMQ::LibZMQ4" ] include: + - runner_name: ubuntu-22.04 + - arch: amd64 - build_distribs: "bullseye,bookworm,jammy" - deb_dependencies: "" - rpm_provides: "" @@ -271,6 +349,13 @@ jobs: - distrib: jammy package_extension: deb image: packaging-plugins-jammy + - distrib: bullseye + package_extension: deb + image: packaging-plugins-bullseye-arm64 + arch: arm64 + runner_name: ["self-hosted", "collect-arm64"] + - name: "Paws" + use_dh_make_perl: "false" - name: "Statistics::Regression" build_distribs: "bullseye" version: "0.53" @@ -278,7 +363,7 @@ jobs: use_dh_make_perl: "false" version: "0.01" deb_dependencies: "libzmq5" - name: package ${{ matrix.distrib }} ${{ matrix.name }} + name: package ${{ matrix.distrib }} ${{ matrix.arch }} ${{ matrix.name }} container: image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/${{ matrix.image }}:latest credentials: @@ -330,12 +415,13 @@ jobs: cpanm Module::Install gem install fpm - fpm -s cpan -t ${{ matrix.package_extension }} --deb-dist ${{ matrix.distrib }} --iteration ${{ matrix.distrib }} --verbose --cpan-verbose --no-cpan-test -n $PACKAGE_NAME$PACKAGE_DEPENDENCIES -v ${{ steps.package-version.outputs.package_version }} ${{ matrix.name }} + fpm -a native -s cpan -t ${{ matrix.package_extension }} --deb-dist ${{ matrix.distrib }} --iteration ${{ matrix.distrib }} --verbose --cpan-verbose --no-cpan-test -n $PACKAGE_NAME$PACKAGE_DEPENDENCIES -v ${{ steps.package-version.outputs.package_version }} ${{ matrix.name }} shell: bash - if: ${{ contains(matrix.build_distribs, matrix.distrib) && matrix.use_dh_make_perl == 'true' }} run: | - apt-get install -y libcurl4-openssl-dev dh-make-perl libssh-dev uuid-dev libczmq-dev libmodule-install-perl + apt-get install -y libcurl4-openssl-dev dh-make-perl libssh-dev uuid-dev libczmq-dev libmodule-install-perl libmodule-build-tiny-perl + # module-build-tiny is required for Mojo::IOLoop::Signal build. DEB_BUILD_OPTIONS="nocheck nodocs notest" dh-make-perl make --dist ${{ matrix.distrib }} --build --version ${{ steps.package-version.outputs.package_version }}-${{ matrix.distrib }} --cpan ${{ matrix.name }} shell: bash @@ -353,27 +439,10 @@ jobs: - if: ${{ contains(matrix.build_distribs, matrix.distrib) }} uses: actions/upload-artifact@5d5d22a31266ced268874388b861e4b58bb5c2f3 # v4.3.1 with: - name: packages-${{ matrix.package_extension }}-${{ matrix.distrib }}-${{ steps.package-name.outputs.name_with_dash}} + name: packages-${{ matrix.package_extension }}-${{ matrix.distrib }}-${{ matrix.arch }}-${{ steps.package-name.outputs.name_with_dash}} path: ./*.${{ matrix.package_extension }} retention-days: 1 - merge-package-rpm-artifacts: - needs: [package-rpm] - runs-on: ubuntu-22.04 - strategy: - matrix: - distrib: [el8, el9] - - steps: - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Merging Artifacts - uses: ./.github/actions/merge-artifacts - with: - target_name: packages-rpm-${{ matrix.distrib }} - source_paths: packages-rpm-${{ matrix.distrib }}/*.rpm - source_name_pattern: packages-rpm-${{ matrix.distrib }}- - github_token: ${{ secrets.GITHUB_TOKEN }} merge-package-deb-artifacts: needs: [package-deb] @@ -393,43 +462,6 @@ jobs: source_name_pattern: packages-deb-${{ matrix.distrib }}- github_token: ${{ secrets.GITHUB_TOKEN }} - sign-rpm: - needs: [merge-package-rpm-artifacts] - - runs-on: ubuntu-22.04 - strategy: - matrix: - distrib: [el8, el9] - name: sign rpm ${{ matrix.distrib }} - container: - image: ${{ vars.DOCKER_INTERNAL_REGISTRY_URL }}/rpm-signing:ubuntu - options: -t - credentials: - username: ${{ secrets.DOCKER_REGISTRY_ID }} - password: ${{ secrets.DOCKER_REGISTRY_PASSWD }} - - steps: - - run: apt-get install -y zstd - shell: bash - - - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - uses: actions/download-artifact@87c55149d96e628cc2ef7e6fc2aab372015aec85 # v4.1.3 - with: - name: packages-rpm-${{ matrix.distrib }} - path: ./ - - - run: echo "HOME=/root" >> $GITHUB_ENV - shell: bash - - - run: rpmsign --addsign ./*.rpm - shell: bash - - - 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: [merge-package-deb-artifacts] runs-on: ubuntu-22.04 @@ -437,38 +469,16 @@ jobs: matrix: distrib: [bullseye, bookworm, jammy] steps: - - uses: actions/download-artifact@87c55149d96e628cc2ef7e6fc2aab372015aec85 # v4.1.3 + - uses: actions/download-artifact@65a9edc5881444af0b9093a5e628f2fe47ea3b2e # v4.1.7 with: name: packages-deb-${{ matrix.distrib }} path: ./ - - uses: actions/cache/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + - uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: ./*.deb key: ${{ github.sha }}-${{ github.run_id }}-deb-${{ matrix.distrib }} - deliver-rpm: - needs: [get-environment, sign-rpm] - if: ${{ contains(fromJson('["testing", "unstable"]'), needs.get-environment.outputs.stability) }} - runs-on: [self-hosted, common] - - strategy: - matrix: - distrib: [el8, el9] - - steps: - - name: Checkout sources - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - - name: Delivery - uses: ./.github/actions/rpm-delivery - with: - module_name: perl-cpan-libraries - distrib: ${{ matrix.distrib }} - artifactory_token: ${{ secrets.ARTIFACTORY_ACCESS_TOKEN }} - cache_key: ${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} - stability: ${{ needs.get-environment.outputs.stability }} - deliver-deb: needs: [get-environment, download-and-cache-deb] if: ${{ contains(fromJson('["testing", "unstable"]'), needs.get-environment.outputs.stability) }} diff --git a/.github/workflows/perl-filesys-smbclient.yml b/.github/workflows/perl-filesys-smbclient.yml index 197541af0..62875563f 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/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + - uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 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/restore@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + - uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 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/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + - uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: ./*.rpm key: ${{ github.sha }}-${{ github.run_id }}-rpm-${{ matrix.distrib }} @@ -142,7 +142,7 @@ jobs: DEB_BUILD_OPTIONS="nocheck nodocs notest noautodbgsym" dh-make-perl make --dist ${{ matrix.distrib }} --verbose --build --version 4.0-${{ matrix.distrib }} perl-filesys-smbclient/ shell: bash - - uses: actions/cache/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + - uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 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 d128646f9..2c7c4a888 100644 --- a/.github/workflows/perl-json-path.yml +++ b/.github/workflows/perl-json-path.yml @@ -9,6 +9,7 @@ on: pull_request: paths: - "dependencies/perl-json-path/**" + - ".github/workflows/perl-json-path.yml" push: branches: - develop @@ -17,6 +18,7 @@ on: - "[2-9][0-9].[0-9][0-9].x" paths: - "dependencies/perl-json-path/**" + - ".github/workflows/perl-json-path.yml" jobs: get-environment: diff --git a/.github/workflows/perl-vmware-vsphere.yml b/.github/workflows/perl-vmware-vsphere.yml index 7c284e42e..65af62e75 100644 --- a/.github/workflows/perl-vmware-vsphere.yml +++ b/.github/workflows/perl-vmware-vsphere.yml @@ -41,7 +41,7 @@ jobs: shell: bash - name: Cache vsphere cli sources - uses: actions/cache/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: vmware-vsphere-cli-distrib key: ${{ github.sha }}-${{ github.run_id }}-sources-perl-vmware-vsphere @@ -98,7 +98,7 @@ jobs: uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - name: Import source files - uses: actions/cache/restore@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: vmware-vsphere-cli-distrib key: ${{ github.sha }}-${{ github.run_id }}-sources-perl-vmware-vsphere diff --git a/.github/workflows/plink.yml b/.github/workflows/plink.yml index 1b1f64c23..6feea0c67 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/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + - uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 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/restore@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + - uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 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/save@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + - uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 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 6966f69b8..9f80aaaf4 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@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + - uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: ./build/ key: fatpacked-plugins-${{ github.sha }}-${{ github.run_id }} diff --git a/.github/workflows/plugins.yml b/.github/workflows/plugins.yml index 9a788e960..036bddac9 100644 --- a/.github/workflows/plugins.yml +++ b/.github/workflows/plugins.yml @@ -33,11 +33,11 @@ jobs: with: fetch-depth: 0 - - uses: actions/setup-python@0a5c61591373683505ea898e09a3ea4f39ef2b9c # v5.0.0 + - uses: actions/setup-python@82c7e631bb3cdc910f68e0081d67478d79c6982d # v5.1.0 with: python-version: '3.9' - - uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 id: filter with: base: ${{ github.ref }} @@ -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@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + - uses: actions/cache/save@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: ./build/ key: fatpacked-plugins-${{ github.sha }}-${{ github.run_id }} @@ -163,7 +163,7 @@ jobs: fail-on-cache-miss: true - if: ${{ matrix.distrib != 'el7' }} - uses: actions/cache/restore@13aacd865c20de90d75de3b17ebe84f7a17d57d2 # v4.0.0 + uses: actions/cache/restore@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 with: path: ./build/ key: fatpacked-plugins-${{ github.sha }}-${{ github.run_id }} diff --git a/.github/workflows/spellchecker.yml b/.github/workflows/spellchecker.yml index 1ccb28fbf..a526a450c 100644 --- a/.github/workflows/spellchecker.yml +++ b/.github/workflows/spellchecker.yml @@ -20,7 +20,7 @@ jobs: steps: - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1 - - uses: dorny/paths-filter@ebc4d7e9ebcb0b1eb21480bb8f43113e996ac77a # v3.0.1 + - uses: dorny/paths-filter@de90cc6fb38fc0963ad72b210f1f284cd68cea36 # v3.0.2 id: filter with: base: ${{ github.ref }} diff --git a/packaging/centreon-plugin-Applications-Eclipse-Mosquitto-Mqtt/deb.json b/packaging/centreon-plugin-Applications-Eclipse-Mosquitto-Mqtt/deb.json new file mode 100644 index 000000000..02113754b --- /dev/null +++ b/packaging/centreon-plugin-Applications-Eclipse-Mosquitto-Mqtt/deb.json @@ -0,0 +1,5 @@ +{ + "dependencies": [ + "libnet-mqtt-simple-perl" + ] +} diff --git a/packaging/centreon-plugin-Applications-Eclipse-Mosquitto-Mqtt/pkg.json b/packaging/centreon-plugin-Applications-Eclipse-Mosquitto-Mqtt/pkg.json new file mode 100644 index 000000000..5d6e1b50f --- /dev/null +++ b/packaging/centreon-plugin-Applications-Eclipse-Mosquitto-Mqtt/pkg.json @@ -0,0 +1,10 @@ +{ + "pkg_name": "centreon-plugin-Applications-Eclipse-Mosquitto-Mqtt", + "pkg_summary": "Centreon Plugin to monitor Eclipse Mosquitto throught MQTT", + "plugin_name": "centreon_eclipse_mosquitto_mqtt.pl", + "files": [ + "centreon/plugins/script_mqtt.pm", + "centreon/plugins/mqtt.pm", + "apps/eclipse/mosquitto/mqtt/" + ] +} diff --git a/packaging/centreon-plugin-Applications-Eclipse-Mosquitto-Mqtt/rpm.json b/packaging/centreon-plugin-Applications-Eclipse-Mosquitto-Mqtt/rpm.json new file mode 100644 index 000000000..2a11858f1 --- /dev/null +++ b/packaging/centreon-plugin-Applications-Eclipse-Mosquitto-Mqtt/rpm.json @@ -0,0 +1,5 @@ +{ + "dependencies": [ + "perl(Net::MQTT::Simple)" + ] +} diff --git a/packaging/centreon-plugin-Applications-Protocol-Http/deb.json b/packaging/centreon-plugin-Applications-Protocol-Http/deb.json index e79bebd9d..1fee8f83c 100644 --- a/packaging/centreon-plugin-Applications-Protocol-Http/deb.json +++ b/packaging/centreon-plugin-Applications-Protocol-Http/deb.json @@ -1,7 +1,9 @@ { "dependencies": [ + "libjson-maybexs-perl", "libjson-perl", "libxml-xpath-perl", + "libxml-libxml-perl", "libxml-libxml-simple-perl" ] } diff --git a/packaging/centreon-plugin-Applications-TrendMicro-Iwsva/pkg.json b/packaging/centreon-plugin-Applications-TrendMicro-Iwsva/pkg.json index 6d4f3c736..fd18e5498 100644 --- a/packaging/centreon-plugin-Applications-TrendMicro-Iwsva/pkg.json +++ b/packaging/centreon-plugin-Applications-TrendMicro-Iwsva/pkg.json @@ -1,20 +1,20 @@ { "pkg_name": "centreon-plugin-Applications-TrendMicro-Iwsva", - "pkg_summary": "Centreon Plugin", + "pkg_summary": "Centreon Plugin to monitor TrendMicro Iwsva throught SNMP", "plugin_name": "centreon_trendmicro_iwsva.pl", "files": [ "centreon/plugins/script_snmp.pm", "centreon/plugins/snmp.pm", "snmp_standard/mode/cpu.pm", "snmp_standard/mode/interfaces.pm", - "snmp_standard/mode/loadaverage.pm", "snmp_standard/mode/listinterfaces.pm", - "snmp_standard/mode/resources/", "snmp_standard/mode/liststorages.pm", + "snmp_standard/mode/loadaverage.pm", "snmp_standard/mode/memory.pm", + "snmp_standard/mode/resources/", "snmp_standard/mode/storage.pm", "snmp_standard/mode/swap.pm", "snmp_standard/mode/tcpcon.pm", - "os/linux/snmp/" + "apps/trendmicro/iwsva/snmp/" ] } diff --git a/packaging/centreon-plugin-Cloud-Azure-PolicyInsights-PolicyStates-Api/rpm.json b/packaging/centreon-plugin-Cloud-Azure-PolicyInsights-PolicyStates-Api/rpm.json index 2a6bcc090..9a7616643 100644 --- a/packaging/centreon-plugin-Cloud-Azure-PolicyInsights-PolicyStates-Api/rpm.json +++ b/packaging/centreon-plugin-Cloud-Azure-PolicyInsights-PolicyStates-Api/rpm.json @@ -1,4 +1,5 @@ { "dependencies": [ + "perl(DateTime)" ] } \ No newline at end of file diff --git a/src/apps/eclipse/mosquitto/mqtt/mode/clients.pm b/src/apps/eclipse/mosquitto/mqtt/mode/clients.pm new file mode 100644 index 000000000..9da133659 --- /dev/null +++ b/src/apps/eclipse/mosquitto/mqtt/mode/clients.pm @@ -0,0 +1,90 @@ +# +# Copyright 2024 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::eclipse::mosquitto::mqtt::mode::clients; + +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 } + ]; + + $self->{maps_counters}->{global} = []; + for my $label (('connected', 'maximum', 'active', 'inactive')) { + push @{$self->{maps_counters}->{global}}, + { label => 'clients-' . $label, + nlabel => 'clients.' . $label . '.count', + set => { + key_values => [{ name => $label }], + output_template => ucfirst($label) . ' clients: %d', + perfdatas => [ + { label => $label . '_clients', template => '%d', + min => 0 } + ] + } + }; + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my %results = $options{mqtt}->queries( + base_topic => '$SYS/broker/clients/', + topics => ['connected', 'maximum', 'active', 'inactive'] + ); + + for my $topic (keys %results) { + $self->{global}->{$topic} = $results{$topic}; + } +} + +1; + +__END__ + +=head1 MODE + +Check clients statistics. + +=over 8 + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'clients-connected', 'clients-maximum', 'clients-active', 'clients-inactive'. + +=back + +=cut \ No newline at end of file diff --git a/src/apps/eclipse/mosquitto/mqtt/mode/messages.pm b/src/apps/eclipse/mosquitto/mqtt/mode/messages.pm new file mode 100644 index 000000000..43d019857 --- /dev/null +++ b/src/apps/eclipse/mosquitto/mqtt/mode/messages.pm @@ -0,0 +1,89 @@ +# +# Copyright 2024 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::eclipse::mosquitto::mqtt::mode::messages; + +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 } + ]; + + $self->{maps_counters}->{global} = []; + for my $label (('stored', 'received', 'sent')) { + push @{$self->{maps_counters}->{global}}, + { label => 'messages-' . $label, + nlabel => 'messages.' . $label . '.count', + set => { + key_values => [{ name => $label }], + output_template => ucfirst($label) . ' messages: %d', + perfdatas => [ + { label => $label . '_messages', template => '%d', + min => 0 } + ] + } + }; + } +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + return $self; +} + +sub manage_selection { + my ($self, %options) = @_; + + my %results = $options{mqtt}->queries( + base_topic => '$SYS/broker/messages/', + topics => ['stored', 'received', 'sent'] + ); + for my $topic (keys %results) { + $self->{global}->{$topic} = $results{$topic}; + } +} + +1; + +__END__ + +=head1 MODE + +Check messages statistics. + +=over 8 + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'messages-stored', 'messages-received', 'messages-sent'. + +=back + +=cut \ No newline at end of file diff --git a/src/apps/eclipse/mosquitto/mqtt/mode/numericvalue.pm b/src/apps/eclipse/mosquitto/mqtt/mode/numericvalue.pm new file mode 100644 index 000000000..ef0120765 --- /dev/null +++ b/src/apps/eclipse/mosquitto/mqtt/mode/numericvalue.pm @@ -0,0 +1,205 @@ +# +# Copyright 2024 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::eclipse::mosquitto::mqtt::mode::numericvalue; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::misc; +use Time::HiRes qw(time); +use POSIX qw(floor); + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'topic:s' => { name => 'topic' }, + 'warning:s' => { name => 'warning' }, + 'critical:s' => { name => 'critical' }, + 'extracted-pattern:s' => { name => 'extracted_pattern' }, + 'format:s' => { name => 'format' }, + 'format-custom:s' => { name => 'format_custom' }, + 'perfdata-unit:s' => { name => 'perfdata_unit' }, + 'perfdata-name:s' => { name => 'perfdata_name', default => 'value' }, + 'perfdata-min:s' => { name => 'perfdata_min' }, + 'perfdata-max:s' => { name => 'perfdata_max' }, + }); + + return $self; +} + +sub custom_generic_output { + my ($self, %options) = @_; + + my $format = $self->{instance_mode}{option_results}->{perfdata_name} . ' is: %s'; + if (defined($self->{instance_mode}{option_results}->{format})) { + $format = $self->{instance_mode}{option_results}->{format}; + } + + my $value = $self->{result_values}->{numericvalue}; + if (!centreon::plugins::misc::is_empty($self->{instance_mode}{option_results}->{format_custom})) { + $value = eval "$value $self->{instance_mode}{option_results}->{format_custom}"; + } + + return sprintf($format, $value); +} + +sub custom_generic_perfdata { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + label => $options{option_results}->{perfdata_name}, + unit => $options{option_results}->{perfdata_unit}, + value => $self->{result_values}->{numericvalue}, + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => $options{option_results}->{perfdata_min}, + max => $options{option_results}->{perfdata_max} + ); +} + +sub custom_generic_threshold { + my ($self, %options) = @_; + + return $self->{perfdata}->threshold_check( + value => $self->{result_values}->{numericvalue}, + threshold => [ + { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, + { label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' }, + { label => 'unknown-' . $self->{thlabel}, exit_litteral => 'unknown' } + ] + ); +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0 } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'generic', + set => { + key_values => [{ name => 'numericvalue' }], + closure_custom_output => $self->can('custom_generic_output'), + closure_custom_perfdata => $self->can('custom_generic_perfdata'), + closure_custom_threshold_check => $self->can('custom_generic_threshold') + } + } + ]; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (centreon::plugins::misc::is_empty($options{option_results}->{topic})) { + $self->{output}->add_option_msg(short_msg => 'Missing parameter --topic.'); + $self->{output}->option_exit(); + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my $value = $options{mqtt}->query( + topic => $self->{option_results}->{topic} + ); + + if (!centreon::plugins::misc::is_empty($self->{option_results}->{extracted_pattern})) { + if ($value =~ /$self->{option_results}->{extracted_pattern}/ && defined($1)) { + $value = $1; + } + } + if ($value !~ /^-?\d+(?:\.\d+)?$/) { + $self->{output}->output_add( + severity => 'UNKNOWN', + short_msg => 'topic value is not numeric (' . $value . ')' + ); + return; + } + + if (!defined($value)) { + $self->{output}->add_option_msg(short_msg => "Cannot find information"); + $self->{output}->option_exit(); + } + + $self->{global} = { numericvalue => $value }; +} + +1; + +__END__ + +=head1 MODE + +Check an Eclipse Mosquitto MQTT topic numeric value. + +=over 8 + +=item B<--topic> + +Topic value to check. + +=item B<--warning> + +Warning threshold. + +=item B<--critical> + +Critical threshold. + +=item B<--extracted-pattern> + +Define a pattern to extract a number from the returned string. + +=item B<--format> + +Output format (default: 'current value is %s') + +=item B<--format-custom> + +Apply a custom change on the value +(example to multiply the value: --format-custom='* 8'). + +=item B<--perfdata-unit> + +Perfdata unit in perfdata output (default: '') + +=item B<--perfdata-name> + +Perfdata name in perfdata output (default: 'value') + +=item B<--perfdata-min> + +Minimum value to add in perfdata output (default: '') + +=item B<--perfdata-max> + +Maximum value to add in perfdata output (default: '') + +=back + +=cut \ No newline at end of file diff --git a/src/apps/eclipse/mosquitto/mqtt/mode/stringvalue.pm b/src/apps/eclipse/mosquitto/mqtt/mode/stringvalue.pm new file mode 100644 index 000000000..acef3073f --- /dev/null +++ b/src/apps/eclipse/mosquitto/mqtt/mode/stringvalue.pm @@ -0,0 +1,180 @@ +# +# Copyright 2024 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::eclipse::mosquitto::mqtt::mode::stringvalue; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::misc; +use Time::HiRes qw(time); +use POSIX qw(floor); + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'topic:s' => { name => 'topic' }, + 'format-custom' => { name => 'format_custom' }, + + 'warning-regexp:s' => { name => 'warning_regexp' }, + 'critical-regexp:s' => { name => 'critical_regexp' }, + 'unknown-regexp:s' => { name => 'unknown_regexp' }, + 'regexp-insensitive' => { name => 'use_iregexp' }, + + 'format-ok:s' => { name => 'format_ok', default => 'value: %{value}' }, + 'format-warning:s' => { name => 'format_warning', default => 'value: %{value}' }, + 'format-critical:s' => { name => 'format_critical', default => 'value: %{value}' }, + 'format-unknown:s' => { name => 'format_unknown', default => 'value: %{value}' }, + }); + + return $self; +} + +sub custom_stringvalue_output { + my ($self, %options) = @_; + + my $value = $self->{result_values}->{stringvalue}; + + if (!centreon::plugins::misc::is_empty($self->{instance_mode}->{option_results}->{'format_' . $self->{severity}})) { + my $format_value = $self->{instance_mode}->{option_results}->{'format_' . $self->{severity}}; + $format_value =~ s/%\{value\}/$value/g; + $format_value =~ s/%\{(.*?)\}/$format_value->{$1}/g; + $value = $format_value; + } + + return $value; +} + +sub custom_stringvalue_threshold { + my ($self, %options) = @_; + + my $severity = 'ok'; + foreach my $check_severity (('critical', 'warning', 'unknown')) { + next if (centreon::plugins::misc::is_empty($self->{option_results}->{$check_severity . '_regexp'})); + my $regexp = $self->{option_results}->{$check_severity . '_regexp'}; + if (defined($self->{option_results}->{use_iregexp}) && $options{value} =~ /$regexp/i) { + $severity = $check_severity; + } elsif (!defined($self->{option_results}->{use_iregexp}) && $options{value} =~ /$regexp/) { + $severity = $check_severity; + } + } + $self->{severity} = $severity; + return $severity; +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0 } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'generic', + set => { + key_values => [{ name => 'stringvalue' }], + closure_custom_output => $self->can('custom_stringvalue_output'), + closure_custom_threshold_check => \&custom_stringvalue_threshold + } + } + ]; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if (centreon::plugins::misc::is_empty($options{option_results}->{topic})) { + $self->{output}->add_option_msg(short_msg => 'Missing parameter --topic.'); + $self->{output}->option_exit(); + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my $value = $options{mqtt}->query( + topic => $self->{option_results}->{topic} + ); + + if (!centreon::plugins::misc::is_empty($self->{option_results}->{format_custom})) { + if ($value =~ /$self->{option_results}->{format_custom}/ && defined($1)) { + $value = $1; + } + } + + if (!defined($value)) { + $self->{output}->add_option_msg(short_msg => "Cannot find information"); + $self->{output}->option_exit(); + } + + $self->{global} = { stringvalue => $value }; +} + +1; + +__END__ + +=head1 MODE + +Check an Eclipse Mosquitto MQTT topic value against regular expression. + +=over 8 + +=item B<--topic> + +Topic value to check. + +=item B<--format-custom> + +Apply a custom change on the value. + +=item B<--warning-regexp> + +Return Warning if the topic value match the regexp. + +=item B<--critical-regexp> + +Return Critical if the topic value match the regexp. + +=item B<--regexp-insensitive> + +Allows to use case-insensitive regexp. + +=item B<--format-*> + +Output format according to the threshold. +Can be: +'ok' (default: 'value: %{value}'), +'warning' (default: 'value: %{value}'), +'critical' (default: 'value: %{value}'), +'unknown' (default: 'value: %{value}'). + +=item B<--format-custom> + +Apply a custom change on the value. + +=back + +=cut \ No newline at end of file diff --git a/src/apps/eclipse/mosquitto/mqtt/mode/uptime.pm b/src/apps/eclipse/mosquitto/mqtt/mode/uptime.pm new file mode 100644 index 000000000..8cd041870 --- /dev/null +++ b/src/apps/eclipse/mosquitto/mqtt/mode/uptime.pm @@ -0,0 +1,153 @@ +# +# Copyright 2024 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::eclipse::mosquitto::mqtt::mode::uptime; + +use base qw(centreon::plugins::templates::counter); + +use strict; +use warnings; +use centreon::plugins::misc; +use Time::HiRes qw(time); +use POSIX qw(floor); + +my $unitdiv = { s => 1, w => 604800, d => 86400, h => 3600, m => 60 }; +my $unitdiv_long = { s => 'seconds', w => 'weeks', d => 'days', h => 'hours', m => 'minutes' }; + +sub custom_uptime_output { + my ($self, %options) = @_; + + return sprintf( + 'uptime is: %s', + centreon::plugins::misc::change_seconds(value => $self->{result_values}->{uptime}, start => 'd') + ); +} + +sub custom_uptime_perfdata { + my ($self, %options) = @_; + + $self->{output}->perfdata_add( + label => 'uptime', unit => $self->{instance_mode}->{option_results}->{unit}, + nlabel => 'system.uptime.' . $unitdiv_long->{ $self->{instance_mode}->{option_results}->{unit} }, + value => floor($self->{result_values}->{uptime} / $unitdiv->{ $self->{instance_mode}->{option_results}->{unit} }), + warning => $self->{perfdata}->get_perfdata_for_output(label => 'warning-' . $self->{thlabel}), + critical => $self->{perfdata}->get_perfdata_for_output(label => 'critical-' . $self->{thlabel}), + min => 0 + ); +} + +sub custom_uptime_threshold { + my ($self, %options) = @_; + + return $self->{perfdata}->threshold_check( + value => floor($self->{result_values}->{uptime} / $unitdiv->{ $self->{instance_mode}->{option_results}->{unit} }), + threshold => [ + { label => 'critical-' . $self->{thlabel}, exit_litteral => 'critical' }, + { label => 'warning-' . $self->{thlabel}, exit_litteral => 'warning' }, + { label => 'unknown-' . $self->{thlabel}, exit_litteral => 'unknown' } + ] + ); +} + +sub set_counters { + my ($self, %options) = @_; + + $self->{maps_counters_type} = [ + { name => 'global', type => 0 } + ]; + + $self->{maps_counters}->{global} = [ + { label => 'uptime', + set => { + key_values => [{ name => 'uptime' }], + closure_custom_output => $self->can('custom_uptime_output'), + closure_custom_perfdata => $self->can('custom_uptime_perfdata'), + closure_custom_threshold_check => $self->can('custom_uptime_threshold') + } + } + ]; +} + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $options{options}->add_options(arguments => { + 'unit:s' => { name => 'unit', default => 's' } + }); + + return $self; +} + +sub check_options { + my ($self, %options) = @_; + $self->SUPER::check_options(%options); + + if ($self->{option_results}->{unit} eq '' || !defined($unitdiv->{$self->{option_results}->{unit}})) { + $self->{option_results}->{unit} = 's'; + } +} + +sub manage_selection { + my ($self, %options) = @_; + + my $topic = '$SYS/broker/uptime'; + my $uptime = $options{mqtt}->query( + topic => $topic + ); + + if ($uptime =~ /^(\d+) seconds$/) { + $uptime = $1; + } + + if (centreon::plugins::misc::is_empty($uptime)) { + $self->{output}->add_option_msg(short_msg => "Cannot find uptime information"); + $self->{output}->option_exit(); + } + + $self->{global} = { uptime => $uptime }; +} + +1; + +__END__ + +=head1 MODE + +Check system uptime. + +=over 8 + +=item B<--warning-uptime> + +Warning threshold. + +=item B<--critical-uptime> + +Critical threshold. + +=item B<--unit> + +Select the time unit for thresholds. May be 's' for seconds, 'm' for minutes, 'h' for hours, 'd' for days, 'w' for weeks. Default is seconds. + +=back + +=cut \ No newline at end of file diff --git a/src/apps/eclipse/mosquitto/mqtt/plugin.pm b/src/apps/eclipse/mosquitto/mqtt/plugin.pm new file mode 100644 index 000000000..f55321043 --- /dev/null +++ b/src/apps/eclipse/mosquitto/mqtt/plugin.pm @@ -0,0 +1,52 @@ +# +# Copyright 2024 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::eclipse::mosquitto::mqtt::plugin; + +use strict; +use warnings; +use base qw(centreon::plugins::script_mqtt); + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options); + bless $self, $class; + + $self->{version} = '1.0'; + $self->{modes} = { + 'uptime' => 'apps::eclipse::mosquitto::mqtt::mode::uptime', + 'clients' => 'apps::eclipse::mosquitto::mqtt::mode::clients', + 'messages' => 'apps::eclipse::mosquitto::mqtt::mode::messages', + 'numeric-value' => 'apps::eclipse::mosquitto::mqtt::mode::numericvalue', + 'string-value' => 'apps::eclipse::mosquitto::mqtt::mode::stringvalue' + }; + + return $self; +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check Eclipse Mosquitto using MQTT. + +=cut \ No newline at end of file diff --git a/src/apps/hashicorp/vault/restapi/custom/api.pm b/src/apps/hashicorp/vault/restapi/custom/api.pm index 8969d3595..a3274a7b9 100644 --- a/src/apps/hashicorp/vault/restapi/custom/api.pm +++ b/src/apps/hashicorp/vault/restapi/custom/api.pm @@ -50,6 +50,7 @@ sub new { 'proto:s' => { name => 'proto' }, 'warning-http-status:s' => { name => 'warning_http_status' }, 'auth-method:s' => { name => 'auth_method', default => 'token' }, + 'auth-path:s' => { name => 'auth_path' }, 'auth-settings:s%' => { name => 'auth_settings' }, 'unknown-http-status:s' => { name => 'unknown_http_status' }, 'vault-token:s' => { name => 'vault_token'} @@ -80,6 +81,10 @@ sub check_options { $self->{output}->option_exit(); }; + if (defined($options{option_results}->{auth_path})) { + $self->{auth_path} = lc($options{option_results}->{auth_path}); + }; + $self->{hostname} = (defined($self->{option_results}->{hostname})) ? $self->{option_results}->{hostname} : ''; $self->{port} = (defined($self->{option_results}->{port})) ? $self->{option_results}->{port} : 8200; $self->{proto} = (defined($self->{option_results}->{proto})) ? $self->{option_results}->{proto} : 'http'; @@ -151,7 +156,10 @@ sub get_access_token { my $decoded; my $login = $self->parse_auth_method(method => $self->{auth_method}, settings => $self->{auth_settings}); my $post_json = JSON::XS->new->utf8->encode($login); - my $url_path = '/' . $self->{api_version} . '/auth/'. $self->{auth_method} . '/login/'; + if (!defined($self->{auth_path}) || $self->{auth_path} eq '') { + $self->{auth_path} = $self->{auth_method}; + } + my $url_path = '/' . $self->{api_version} . '/auth/'. $self->{auth_path} . '/login/'; $url_path .= $self->{auth_settings}->{username} if (defined($self->{auth_settings}->{username}) && $self->{auth_method} =~ 'userpass|login') ; my $content = $self->{http}->request( @@ -284,6 +292,12 @@ Specify the Vault authentication specific settings. Syntax: --auth-settings='='.Example for the 'userpass' method: --auth-method='userpass' --auth-settings='username=my_account' --auth-settings='password=my_password' +=item B<--auth-path> + +Authentication path for 'userpass'. Is an optional setting. + +More information here: https://developer.hashicorp.com/vault/docs/auth/userpass#configuration + =item B<--timeout> Set timeout in seconds (default: 10). diff --git a/src/apps/monitoring/loggly/restapi/custom/api.pm b/src/apps/monitoring/loggly/restapi/custom/api.pm index 9cd2e704c..937ae1f67 100644 --- a/src/apps/monitoring/loggly/restapi/custom/api.pm +++ b/src/apps/monitoring/loggly/restapi/custom/api.pm @@ -29,7 +29,7 @@ use JSON::XS; sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); + my $self = $class->SUPER::new(package => __PACKAGE__, %options); bless $self, $class; if (!defined($options{output})) { @@ -42,12 +42,12 @@ sub new { } if (!defined($options{noptions})) { - $options{options}->add_options(arguments => { + $options{options}->add_options(arguments => { 'hostname:s' => { name => 'hostname' }, - 'port:s' => { name => 'port'}, + 'port:s' => { name => 'port' }, 'proto:s' => { name => 'proto' }, 'api-password:s' => { name => 'api_password' }, - 'timeout:s' => { name => 'timeout', default => 30 }, + 'timeout:s' => { name => 'timeout'}, 'unknown-http-status:s' => { name => 'unknown_http_status' }, 'warning-http-status:s' => { name => 'warning_http_status' }, 'critical-http-status:s' => { name => 'critical_http_status' } @@ -57,7 +57,7 @@ sub new { $options{options}->add_help(package => __PACKAGE__, sections => 'REST API OPTIONS', once => 1); $self->{output} = $options{output}; - $self->{http} = centreon::plugins::http->new(%options); + $self->{http} = centreon::plugins::http->new(%options); return $self; } @@ -73,14 +73,14 @@ sub set_defaults {} sub check_options { my ($self, %options) = @_; - $self->{hostname} = (defined($self->{option_results}->{hostname})) ? $self->{option_results}->{hostname} : ''; - $self->{port} = (defined($self->{option_results}->{port})) ? $self->{option_results}->{port} : 443; - $self->{proto} = (defined($self->{option_results}->{proto})) ? $self->{option_results}->{proto} : 'https'; - $self->{timeout} = (defined($self->{option_results}->{timeout})) ? $self->{option_results}->{timeout} : 30; - $self->{ssl_opt} = (defined($self->{option_results}->{ssl_opt})) ? $self->{option_results}->{ssl_opt} : undef; - $self->{api_password} = (defined($self->{option_results}->{api_password})) ? $self->{option_results}->{api_password} : ''; - $self->{unknown_http_status} = (defined($self->{option_results}->{unknown_http_status})) ? $self->{option_results}->{unknown_http_status} : '%{http_code} < 200 or %{http_code} >= 300'; - $self->{warning_http_status} = (defined($self->{option_results}->{warning_http_status})) ? $self->{option_results}->{warning_http_status} : ''; + $self->{hostname} = (defined($self->{option_results}->{hostname})) ? $self->{option_results}->{hostname} : ''; + $self->{port} = (defined($self->{option_results}->{port})) ? $self->{option_results}->{port} : 443; + $self->{proto} = (defined($self->{option_results}->{proto})) ? $self->{option_results}->{proto} : 'https'; + $self->{timeout} = (defined($self->{option_results}->{timeout})) ? $self->{option_results}->{timeout} : 30; + $self->{ssl_opt} = (defined($self->{option_results}->{ssl_opt})) ? $self->{option_results}->{ssl_opt} : undef; + $self->{api_password} = (defined($self->{option_results}->{api_password})) ? $self->{option_results}->{api_password} : ''; + $self->{unknown_http_status} = (defined($self->{option_results}->{unknown_http_status})) ? $self->{option_results}->{unknown_http_status} : '%{http_code} < 200 or %{http_code} >= 300'; + $self->{warning_http_status} = (defined($self->{option_results}->{warning_http_status})) ? $self->{option_results}->{warning_http_status} : ''; $self->{critical_http_status} = (defined($self->{option_results}->{critical_http_status})) ? $self->{option_results}->{critical_http_status} : ''; if ($self->{hostname} eq '') { @@ -99,10 +99,10 @@ sub build_options_for_httplib { my ($self, %options) = @_; $self->{option_results}->{hostname} = $self->{hostname}; - $self->{option_results}->{port} = $self->{port}; - $self->{option_results}->{proto} = $self->{proto}; - $self->{option_results}->{ssl_opt} = $self->{ssl_opt}; - $self->{option_results}->{timeout} = $self->{timeout}; + $self->{option_results}->{port} = $self->{port}; + $self->{option_results}->{proto} = $self->{proto}; + $self->{option_results}->{ssl_opt} = $self->{ssl_opt}; + $self->{option_results}->{timeout} = $self->{timeout}; } sub settings { @@ -119,9 +119,9 @@ sub request_api { $self->settings(); my $content = $self->{http}->request( - %options, - unknown_status => $self->{unknown_http_status}, - warning_status => $self->{warning_http_status}, + %options, + unknown_status => $self->{unknown_http_status}, + warning_status => $self->{warning_http_status}, critical_status => $self->{critical_http_status} ); @@ -145,8 +145,8 @@ sub internal_search { my ($self, %options) = @_; my $status = $self->request_api( - method => 'GET', - url_path => '/apiv2/search', + method => 'GET', + url_path => '/apiv2/search', get_param => [ 'size=1', 'from=-' . $options{time_period} . 'm', @@ -160,8 +160,8 @@ sub internal_events { my ($self, %options) = @_; my $status = $self->request_api( - method => 'GET', - url_path => '/apiv2/events', + method => 'GET', + url_path => '/apiv2/events', get_param => ['rsid=' . $options{id}] ); return $status; @@ -172,7 +172,7 @@ sub api_events { my $id = $self->internal_search( time_period => $options{time_period}, - query => $options{query} + query => $options{query} ); my $status = $self->internal_events(id => $id); @@ -207,8 +207,8 @@ sub internal_fields { # 300 limitation comes from the API : https://documentation.solarwinds.com/en/Success_Center/loggly/Content/admin/api-retrieving-data.htm my $status = $self->request_api( - method => 'GET', - url_path => '/apiv2/fields/' . $options{field} . '/', + method => 'GET', + url_path => '/apiv2/fields/' . $options{field} . '/', get_param => [ 'facet_size=300', 'from=-' . $options{time_period} . 'm', @@ -223,12 +223,12 @@ sub api_fields { my $status = $self->internal_fields( time_period => $options{time_period}, - field => $options{field}, - query => $options{query} + field => $options{field}, + query => $options{query} ); # Fields may be messed-up with wrongly encoded characters, let's force some cleanup - for (my $i = 0; $i < scalar(@{$status->{ $options{field} }}); $i++) { + for (my $i = 0 ; $i < scalar(@{$status->{ $options{field} }}) ; $i++) { $status->{ $options{field} }->[$i]->{term} =~ s/[\r\n]//g; $status->{ $options{field} }->[$i]->{term} =~ s/^\s+|\s+$//g; } diff --git a/src/apps/monitoring/loggly/restapi/mode/events.pm b/src/apps/monitoring/loggly/restapi/mode/events.pm index c492a87f7..beba9bdf1 100644 --- a/src/apps/monitoring/loggly/restapi/mode/events.pm +++ b/src/apps/monitoring/loggly/restapi/mode/events.pm @@ -34,19 +34,19 @@ sub set_counters { $self->{maps_counters}->{global} = [ { label => 'events', nlabel => 'events.count', set => { - key_values => [ { name => 'events' } ], - output_template => 'Matching events: %s', - perfdatas => [ - { template => '%s', value => 'events', min => 0 } - ] - } + key_values => [{ name => 'events' }], + output_template => 'Matching events: %s', + perfdatas => [ + { template => '%s', value => 'events', min => 0 } + ] + } } ]; } sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); bless $self, $class; $self->{version} = '1.0'; @@ -77,8 +77,8 @@ sub manage_selection { my ($self, %options) = @_; my $results = $options{custom}->api_events( - time_period => $self->{option_results}->{time_period}, - query => $self->{option_results}->{query}, + time_period => $self->{option_results}->{time_period}, + query => $self->{option_results}->{query}, output_field => $self->{option_results}->{output_field} ); $self->{global} = { events => $results->{total_events} }; @@ -99,11 +99,11 @@ Count events matching the query. =item B<--time-period> -Set request period, in minutes. +Set request period, in minutes (mandatory option). =item B<--query> -Set the query. +Set the query (mandatory option). =item B<--output-field> diff --git a/src/apps/monitoring/loggly/restapi/mode/fields.pm b/src/apps/monitoring/loggly/restapi/mode/fields.pm index 5e32da01d..8cb7f84f1 100644 --- a/src/apps/monitoring/loggly/restapi/mode/fields.pm +++ b/src/apps/monitoring/loggly/restapi/mode/fields.pm @@ -35,31 +35,31 @@ sub set_counters { $self->{maps_counters}->{global} = [ { label => 'events', nlabel => 'events.count', display_ok => 1, set => { - key_values => [ { name => 'events' } ], - output_template => 'Matching events: %s', - perfdatas => [ - { template => '%s', min => 0 } - ] - } + key_values => [{ name => 'events' }], + output_template => 'Matching events: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } }, { label => 'fields', nlabel => 'fields.count', display_ok => 1, set => { - key_values => [ { name => 'fields' } ], - output_template => 'Matching fields: %s', - perfdatas => [ - { template => '%s', min => 0 } - ] - } + key_values => [{ name => 'fields' }], + output_template => 'Matching fields: %s', + perfdatas => [ + { template => '%s', min => 0 } + ] + } }, ]; $self->{maps_counters}->{field} = [ { label => 'field-events', nlabel => 'field.events.count', set => { - key_values => [ { name => 'count' }, { name => 'display' } ], - output_template => 'matching events: %s', - perfdatas => [ - { template => '%s', min => 0, label_extra_instance => 1, instance_use => 'display' } - ] - } + key_values => [{ name => 'count' }, { name => 'display' }], + output_template => 'matching events: %s', + perfdatas => [ + { template => '%s', min => 0, label_extra_instance => 1, instance_use => 'display' } + ] + } } ]; } @@ -72,7 +72,7 @@ sub prefix_field_output { sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); bless $self, $class; $self->{version} = '1.0'; @@ -118,8 +118,8 @@ sub manage_selection { my $results = $options{custom}->api_fields( time_period => $self->{option_results}->{time_period}, - query => $self->{option_results}->{query}, - field => $self->{option_results}->{field} + query => $self->{option_results}->{query}, + field => $self->{option_results}->{field} ); my ($events, $fields) = (0, 0); @@ -128,10 +128,10 @@ sub manage_selection { foreach (@{$results->{$self->{option_results}->{field}}}) { if (!defined($self->{option_results}->{filter_field}) || ($_->{term} =~ /$self->{option_results}->{filter_field}/i)) { $fields++; - $events += $_->{count}; + $events+= $_->{count}; $self->{field}->{$fields} = { display => $_->{term}, - count => $_->{count} + count => $_->{count} }; } } @@ -151,19 +151,19 @@ Count unique field-values from events matching the query. =item B<--time-period> -Set request period, in minutes. +Set request period, in minutes (mandatory option). =item B<--query> -Set the query. +Set the query (mandatory option). =item B<--field> -Set the field to count unique values for (example: json.host). +Set the field to count unique values for example: json.host (mandatory option). =item B<--filter-field> -Set the a field filter. +Define which fields should be counted. This option will be treated as a regular expression. If this option is empty, all fields will be counted. =item B<--warning-*> B<--critical-*> diff --git a/src/apps/monitoring/loggly/restapi/plugin.pm b/src/apps/monitoring/loggly/restapi/plugin.pm index a09a8e48c..df7ef7ca0 100644 --- a/src/apps/monitoring/loggly/restapi/plugin.pm +++ b/src/apps/monitoring/loggly/restapi/plugin.pm @@ -26,11 +26,11 @@ use base qw(centreon::plugins::script_custom); sub new { my ($class, %options) = @_; - my $self = $class->SUPER::new(package => __PACKAGE__, %options); + my $self = $class->SUPER::new(package => __PACKAGE__, %options); bless $self, $class; $self->{version} = '1.0'; - $self->{modes} = { + $self->{modes} = { 'events' => 'apps::monitoring::loggly::restapi::mode::events', 'fields' => 'apps::monitoring::loggly::restapi::mode::fields' }; diff --git a/src/apps/protocols/http/mode/collection.pm b/src/apps/protocols/http/mode/collection.pm index 1ddddb697..df87efd84 100644 --- a/src/apps/protocols/http/mode/collection.pm +++ b/src/apps/protocols/http/mode/collection.pm @@ -87,7 +87,7 @@ sub custom_select_output { if (defined($format)) { return sprintf( - $format->{printf_msg}, @{$format->{printf_var}} + $format->{printf_msg}, @{$format->{printf_var}} ); } @@ -123,7 +123,7 @@ 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 => { 'config:s' => { name => 'config' }, 'filter-selection:s%' => { name => 'filter_selection' }, @@ -192,7 +192,7 @@ sub get_map_value { my ($self, %options) = @_; return undef if ( - !defined($self->{config}->{mapping}) || + !defined($self->{config}->{mapping}) || !defined($self->{config}->{mapping}->{ $options{map} }) ); return '' if (!defined($self->{config}->{mapping}->{ $options{map} }->{ $options{value} })); @@ -254,8 +254,9 @@ sub get_payload { sub call_http { my ($self, %options) = @_; - if (!defined($options{rq}->{hostname}) || $options{rq}->{hostname} eq '') { - $self->{output}->add_option_msg(short_msg => "hostname attribute is missing [http > requests > $options{rq}->{name}]"); + if ((!defined($options{rq}->{full_url}) || $options{rq}->{full_url} eq '') && + (!defined($options{rq}->{hostname}) || $options{rq}->{hostname} eq '')) { + $self->{output}->add_option_msg(short_msg => "hostname or full_url attribute is missing [http > requests > $options{rq}->{name}]"); $self->{output}->option_exit(); } if (!defined($options{rq}->{rtype}) || $options{rq}->{rtype} !~ /^(?:txt|json|xml)$/) { @@ -298,11 +299,19 @@ sub call_http { $http = centreon::plugins::http->new(noptions => 1, output => $self->{output}); } + my $full_url; + my $hostname = $self->substitute_string(value => $options{rq}->{hostname}); + if (defined($options{rq}->{full_url}) && $options{rq}->{full_url} ne '') { + $full_url = $self->substitute_string(value => $options{rq}->{full_url}); + $hostname = ''; + } + my $timing0 = [gettimeofday]; my ($content) = $http->request( - backend => $self->substitute_string(value => $options{rq}->{backend}), + http_backend => $self->substitute_string(value => $options{rq}->{backend}), method => $self->substitute_string(value => $options{rq}->{method}), - hostname => $self->substitute_string(value => $options{rq}->{hostname}), + full_url => $full_url, + hostname => $hostname, proto => $self->substitute_string(value => $options{rq}->{proto}), port => $self->substitute_string(value => $options{rq}->{port}), url_path => $self->substitute_string(value => $options{rq}->{endpoint}), @@ -321,26 +330,6 @@ sub call_http { $self->add_builtin(name => 'httpCode.' . $options{rq}->{name}, value => $http->get_code()); $self->add_builtin(name => 'httpMessage.' . $options{rq}->{name}, value => $http->get_message()); - if ($options{rq}->{rtype} eq 'json') { - eval { - $content = JSON::XS->new->utf8->decode($content); - }; - } elsif ($options{rq}->{rtype} eq 'xml') { - eval { - $SIG{__WARN__} = sub {}; - $content = XMLin($content, ForceArray => $options{rq}->{force_array}, KeyAttr => []); - }; - } - if ($@) { - $self->{output}->add_option_msg(short_msg => "Cannot decode response (add --debug option to display returned content)"); - $self->{output}->output_add(long_msg => "$@", debug => 1); - $self->{output}->option_exit(); - } - - my $encoded = JSON::XS->new->utf8->pretty->encode($content); - $self->{output}->output_add(long_msg => '======> returned JSON structure:', debug => 1); - $self->{output}->output_add(long_msg => "$encoded", debug => 1); - return ($http->get_header(), $content, $http); } @@ -441,8 +430,31 @@ sub parse_structure { $options{conf}->{path} = $self->substitute_string(value => $options{conf}->{path}); + my $content; + if ($options{rtype} eq 'json') { + eval { + $content = JSON::XS->new->utf8->decode($options{content}); + }; + } elsif ($options{rtype} eq 'xml') { + eval { + $SIG{__WARN__} = sub {}; + $content = XMLin($options{content}, ForceArray => $options{force_array}, KeyAttr => []); + }; + } + if ($@) { + $self->{output}->add_option_msg(short_msg => "Cannot decode response (add --debug option to display returned content)"); + $self->{output}->output_add(long_msg => "$@", debug => 1); + $self->{output}->option_exit(); + } + + if ($self->{output}->is_debug()) { + my $encoded = JSON::XS->new->allow_nonref(1)->utf8->pretty->encode($content); + $self->{output}->output_add(long_msg => '======> returned JSON structure:', debug => 1); + $self->{output}->output_add(long_msg => "$encoded", debug => 1); + } + my $jpath = JSON::Path->new($options{conf}->{path}); - my @values = $jpath->values($options{content}); + my @values = $jpath->values($content); my $local = {}; my $i = 0; @@ -534,26 +546,50 @@ sub collect_http_tables { ($headers, $content, $http) = $self->call_http(rq => $options{requests}->[$i], http => $options{http}); $self->set_builtin(); - next if (!defined($options{requests}->[$i]->{parse})); - - my $local; - foreach my $conf (@{$options{requests}->[$i]->{parse}}) { - if ($options{requests}->[$i]->{rtype} eq 'txt') { - $local = $self->parse_txt(name => $options{requests}->[$i]->{name}, headers => $headers, content => $content, conf => $conf); - } else { - $local = $self->parse_structure(name => $options{requests}->[$i]->{name}, content => $content, conf => $conf); - } - } - - if (defined($options{requests}->[$i]->{scenario_stopped}) && $options{requests}->[$i]->{scenario_stopped} && - $self->check_filter2(filter => $options{requests}->[$i]->{scenario_stopped}, values => $self->{expand})) { + if (defined($options{requests}->[$i]->{scenario_stopped_first}) && $options{requests}->[$i]->{scenario_stopped_first} && + $self->check_filter2(filter => $options{requests}->[$i]->{scenario_stopped_first}, values => $self->{expand})) { $self->{scenario_stopped} = 1; if (defined($options{requests}->[$i]->{scenario_retry}) && $options{requests}->[$i]->{scenario_retry} =~ /^true|1$/i) { $self->{scenario_loop}++; $self->{scenario_retry} = 1; } } else { - $self->save_local_http_cache(local_http_cache => $local_http_cache, local => $local); + my $local = {}; + if (defined($options{requests}->[$i]->{parse})) { + foreach my $conf (@{$options{requests}->[$i]->{parse}}) { + my $lentries = {}; + if ($options{requests}->[$i]->{rtype} eq 'txt') { + $lentries = $self->parse_txt(name => $options{requests}->[$i]->{name}, headers => $headers, content => $content, conf => $conf); + } else { + $lentries = $self->parse_structure( + name => $options{requests}->[$i]->{name}, + content => $content, + conf => $conf, + rtype => $options{requests}->[$i]->{rtype}, + force_array => $options{requests}->[$i]->{force_array} + ); + } + + $local = { %$local, %$lentries }; + } + } + + $self->set_functions( + section => "http > requests > $options{requests}->[$i]->{name}", + functions => $options{requests}->[$i]->{functions}, + default => 1 + ); + + if (defined($options{requests}->[$i]->{scenario_stopped}) && $options{requests}->[$i]->{scenario_stopped} && + $self->check_filter2(filter => $options{requests}->[$i]->{scenario_stopped}, values => $self->{expand})) { + $self->{scenario_stopped} = 1; + if (defined($options{requests}->[$i]->{scenario_retry}) && $options{requests}->[$i]->{scenario_retry} =~ /^true|1$/i) { + $self->{scenario_loop}++; + $self->{scenario_retry} = 1; + } + } else { + $self->save_local_http_cache(local_http_cache => $local_http_cache, local => $local); + } } } @@ -625,6 +661,16 @@ sub use_local_http_cache { } } + my $builtin = $local_http_cache->get(name => 'builtin'); + foreach my $name (keys %$builtin) { + $self->add_builtin(name => $name, value => $builtin->{$name}); + } + + my $local_vars = $local_http_cache->get(name => 'local_vars'); + foreach my $name (keys %$local_vars) { + $self->set_local_variable(name => $name, value => $local_vars->{$name}); + } + return 1; } @@ -632,12 +678,20 @@ sub save_local_http_cache { my ($self, %options) = @_; if (defined($options{local_http_cache})) { + my $expand = {}; + foreach my $name (keys %{$self->{expand}}) { + next if ($name =~ /^(builtin|constants)\./); + $expand->{$name} = $self->{expand}->{$name}; + } + $options{local_http_cache}->write( data => { http_collected => { tables => $options{local}, epoch => time() - } + }, + builtin => $self->{builtin}, + local_vars => $expand } ); } @@ -737,6 +791,17 @@ sub display_variables { } } } + + foreach my $name (keys %{$self->{expand}}) { + $self->{output}->output_add( + long_msg => sprintf( + ' %s = %s', + $name, + $self->{expand}->{$name} + ), + debug => 1 + ); + } } sub collect_http { @@ -765,6 +830,13 @@ sub collect_http { $self->collect_http_sampling(); + # can use local_var set for selection/selection_loop + $self->{local_vars} = {}; + foreach my $name (keys %{$self->{expand}}) { + next if ($name =~ /^(builtin|constants)\./); + $self->{local_vars}->{$name} = $self->{expand}->{$name}; + } + if ($self->{output}->is_debug()) { $self->display_variables(); } @@ -790,6 +862,14 @@ sub get_local_variable { } +sub set_local_variables { + my ($self, %options) = @_; + + foreach (keys %{$self->{local_vars}}) { + $self->set_local_variable(name => $_, value => $self->{local_vars}->{$_}); + } +} + sub set_local_variable { my ($self, %options) = @_; @@ -934,7 +1014,7 @@ sub parse_http_tables { ($code, $msg_error, $end, $table_label) = $self->parse_forward( chars => $options{chars}, start => $options{start}, - allowed => '[a-zA-Z0-9_]', + allowed => '[a-zA-Z0-9_\-]', stop => '[).]' ); if ($code) { @@ -999,7 +1079,7 @@ sub parse_http_tables { ($code, $msg_error, $end, $label) = $self->parse_forward( chars => $options{chars}, start => $end + 2, - allowed => '[a-zA-Z0-9_]', + allowed => '[a-zA-Z0-9_\-]', stop => '[)]' ); if ($code) { @@ -1039,7 +1119,7 @@ sub parse_special_variable { my ($code, $msg_error, $end, $label) = $self->parse_forward( chars => $options{chars}, start => $start + 2, - allowed => '[a-zA-Z0-9\._]', + allowed => '[a-zA-Z0-9\._\-]', stop => '[)]' ); if ($code) { @@ -1630,6 +1710,7 @@ sub exec_func_capture { $self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable type not allowed in save attribute"); $self->{output}->option_exit(); } + $self->set_special_variable_value(value => $value, %$save); } } @@ -1707,7 +1788,7 @@ sub prepare_variables { return undef if (!defined($options{value})); - while ($options{value} =~ /%\(([a-zA-Z0-9\.]+?)\)/g) { + while ($options{value} =~ /%\(([a-zA-Z0-9\.\-]+?)\)/g) { next if ($1 =~ /^http\./); $options{value} =~ s/%\(($1)\)/\$expand->{'$1'}/g; } @@ -1721,7 +1802,7 @@ sub check_filter { return 0 if (!defined($options{filter}) || $options{filter} eq ''); our $expand = $options{values}; - $options{filter} =~ s/%\(([a-zA-Z0-9\._:]+?)\)/\$expand->{'$1'}/g; + $options{filter} =~ s/%\(([a-zA-Z0-9\._:\-]+?)\)/\$expand->{'$1'}/g; my $result = $self->{safe}->reval("$options{filter}"); if ($@) { $self->{output}->add_option_msg(short_msg => 'Unsafe code evaluation: ' . $@); @@ -1737,7 +1818,7 @@ sub check_filter2 { return 0 if (!defined($options{filter}) || $options{filter} eq ''); our $expand = $options{values}; - $options{filter} =~ s/%\(([a-zA-Z0-9\._:]+?)\)/\$expand->{'$1'}/g; + $options{filter} =~ s/%\(([a-zA-Z0-9\._:\-]+?)\)/\$expand->{'$1'}/g; my $result = $self->{safe}->reval("$options{filter}"); if ($@) { $self->{output}->add_option_msg(short_msg => 'Unsafe code evaluation: ' . $@); @@ -1820,6 +1901,7 @@ sub add_selection { my $config = {}; $self->{expand} = $self->set_constants(); $self->set_builtin(); + $self->set_local_variables(); $self->{expand}->{name} = $_->{name} if (defined($_->{name})); $self->set_functions(section => "selection > $i > functions", functions => $_->{functions}, position => 'before_expand'); $self->set_expand_table(section => "selection > $i > expand_table", expand => $_->{expand_table}); @@ -1857,20 +1939,26 @@ sub add_selection_loop { next if (!defined($_->{source}) || $_->{source} eq ''); $self->{current_section} = '[selection_loop > ' . $i . ' > source]'; + my $result = $self->parse_special_variable(chars => [split //, $_->{source}], start => 0); if ($result->{type} != 2) { $self->{output}->add_option_msg(short_msg => $self->{current_section} . " special variable type not allowed"); $self->{output}->option_exit(); } + next if (!defined($self->{http_collected}->{tables}->{ $result->{table} })); + foreach my $instance (keys %{$self->{http_collected}->{tables}->{ $result->{table} }}) { $self->{expand} = $self->set_constants(); $self->set_builtin(); + $self->set_local_variables(); $self->{expand}->{ $result->{table} . '.instance' } = $instance; + foreach my $label (keys %{$self->{http_collected}->{tables}->{ $result->{table} }->{$instance}}) { $self->{expand}->{ $result->{table} . '.' . $label } = $self->{http_collected}->{tables}->{ $result->{table} }->{$instance}->{$label}; } + my $config = {}; $self->{expand}->{name} = $_->{name} if (defined($_->{name})); $self->set_functions(section => "selection_loop > $i > functions", functions => $_->{functions}, position => 'before_expand'); diff --git a/src/apps/trendmicro/iwsva/snmp/mode/interfaces.pm b/src/apps/trendmicro/iwsva/snmp/mode/interfaces.pm new file mode 100644 index 000000000..a49dfca05 --- /dev/null +++ b/src/apps/trendmicro/iwsva/snmp/mode/interfaces.pm @@ -0,0 +1,180 @@ +# +# Copyright 2024 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::trendmicro::iwsva::snmp::mode::interfaces; + +use base qw(snmp_standard::mode::interfaces); + +use strict; +use warnings; + +sub new { + my ($class, %options) = @_; + my $self = $class->SUPER::new(package => __PACKAGE__, %options, force_new_perfdata => 1); + bless $self, $class; + + return $self; +} + +1; + +__END__ + +=head1 MODE + +Check interfaces. + +=over 8 + +=item B<--add-global> + +Check global port statistics (by default if no --add-* option is set). + +=item B<--add-status> + +Check interface status. + +=item B<--add-duplex-status> + +Check duplex status (with --warning-status and --critical-status). + +=item B<--add-traffic> + +Check interface traffic. + +=item B<--add-errors> + +Check interface errors. + +=item B<--add-cast> + +Check interface cast. + +=item B<--add-speed> + +Check interface speed. + +=item B<--add-volume> + +Check interface data volume between two checks (not supposed to be graphed, useful for BI reporting). + +=item B<--check-metrics> + +If the expression is true, metrics are checked (default: '%{opstatus} eq "up"'). + +=item B<--warning-status> + +Define the conditions to match for the status to be WARNING. +You can use the following variables: %{admstatus}, %{opstatus}, %{duplexstatus}, %{display} + +=item B<--critical-status> + +Define the conditions to match for the status to be CRITICAL (default: '%{admstatus} eq "up" and %{opstatus} ne "up"'). +You can use the following variables: %{admstatus}, %{opstatus}, %{duplexstatus}, %{display} + +=item B<--warning-*> B<--critical-*> + +Thresholds. +Can be: 'total-port', 'total-admin-up', 'total-admin-down', 'total-oper-up', 'total-oper-down', +'in-traffic', 'out-traffic', 'in-error', 'in-discard', 'out-error', 'out-discard', +'in-ucast', 'in-bcast', 'in-mcast', 'out-ucast', 'out-bcast', 'out-mcast', +'speed' (b/s). + +=item B<--units-traffic> + +Units of thresholds for the traffic (default: 'percent_delta') ('percent_delta', 'bps', 'counter'). + +=item B<--units-errors> + +Units of thresholds for errors/discards (default: 'percent_delta') ('percent_delta', 'percent', 'delta', 'deltaps', 'counter'). + +=item B<--units-cast> + +Units of thresholds for communication types (default: 'percent_delta') ('percent_delta', 'percent', 'delta', 'deltaps', 'counter'). + +=item B<--nagvis-perfdata> + +Display traffic perfdata to be compatible with NagVis widget. + +=item B<--interface> + +Set the interface (number expected) example: 1,2,... (empty means 'check all interfaces'). + +=item B<--name> + +Allows you to define the interface (in option --interface) by name instead of OID index. The name matching mode supports regular expressions. + +=item B<--speed> + +Set interface speed for incoming/outgoing traffic (in Mb). + +=item B<--speed-in> + +Set interface speed for incoming traffic (in Mb). + +=item B<--speed-out> + +Set interface speed for outgoing traffic (in Mb). + +=item B<--map-speed-dsl> + +Get interface speed configuration for interface type 'ADSL' and 'VDSL2'. + +Syntax: --map-speed-dsl=interface-src-name,interface-dsl-name + +E.g: --map-speed-dsl=Et0.835,Et0-vdsl2 + +=item B<--force-counters64> + +Force to use 64 bits counters only. Can be used to improve performance. + +=item B<--force-counters32> + +Force to use 32 bits counters (even in SNMP version 2c and version 3). Should be used when 64 bits counters are buggy. + +=item B<--reload-cache-time> + +Time in minutes before reloading cache file (default: 180). + +=item B<--oid-filter> + +Define the OID to be used to filter interfaces (default: ifName) (values: ifDesc, ifAlias, ifName, IpAddr). + +=item B<--oid-display> + +Define the OID that will be used to name the interfaces (default: ifName) (values: ifDesc, ifAlias, ifName, IpAddr). + +=item B<--oid-extra-display> + +Add an OID to display. + +=item B<--display-transform-src> B<--display-transform-dst> + +Modify the interface name displayed by using a regular expression. + +Example: adding --display-transform-src='eth' --display-transform-dst='ens' will replace all occurrences of 'eth' with 'ens' + +=item B<--show-cache> + +Display cache interface data. + +=back + +=cut diff --git a/src/apps/trendmicro/iwsva/snmp/plugin.pm b/src/apps/trendmicro/iwsva/snmp/plugin.pm new file mode 100644 index 000000000..2e46ac9a7 --- /dev/null +++ b/src/apps/trendmicro/iwsva/snmp/plugin.pm @@ -0,0 +1,55 @@ +# +# Copyright 2024 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package apps::trendmicro::iwsva::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' => 'snmp_standard::mode::cpu', + 'interfaces' => 'apps::trendmicro::iwsva::snmp::mode::interfaces', + 'list-interfaces' => 'snmp_standard::mode::listinterfaces', + 'list-storages' => 'snmp_standard::mode::liststorages', + 'load' => 'snmp_standard::mode::loadaverage', + 'memory' => 'snmp_standard::mode::memory', + 'storage' => 'snmp_standard::mode::storage', + 'swap' => 'snmp_standard::mode::swap', + 'tcpcon' => 'snmp_standard::mode::tcpcon' + }; + + return $self; +} + +1; + +__END__ + +=head1 PLUGIN DESCRIPTION + +Check TendMicro Iwsva equipments in SNMP. + +=cut diff --git a/src/centreon/plugins/mqtt.pm b/src/centreon/plugins/mqtt.pm new file mode 100644 index 000000000..3f08a4596 --- /dev/null +++ b/src/centreon/plugins/mqtt.pm @@ -0,0 +1,210 @@ +# +# Copyright 2024 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package centreon::plugins::mqtt; + +use strict; +use warnings; +use Time::HiRes; +use Net::MQTT::Simple; +use Net::MQTT::Simple::SSL; + +sub new { + my ($class, %options) = @_; + my $self = {}; + bless $self, $class; + + if (!defined($options{noptions}) || $options{noptions} != 1) { + $options{options}->add_options(arguments => { + 'hostname|host:s' => { name => 'host' }, + 'mqtt-port:s' => { name => 'mqtt_port', default => 8883 }, + 'mqtt-ssl:s' => { name => 'mqtt_ssl', default => 1 }, + 'mqtt-ca-certificate:s' => { name => 'mqtt_ca_certificate' }, + 'mqtt-ssl-certificate:s' => { name => 'mqtt_ssl_certificate' }, + 'mqtt-ssl-key:s' => { name => 'mqtt_ssl_key' }, + 'mqtt-username:s' => { name => 'mqtt_username' }, + 'mqtt-password:s' => { name => 'mqtt_password' }, + 'mqtt-allow-insecure' => { name => 'mqtt_allow_insecure', default => 0 }, + 'mqtt-timeout:s' => { name => 'mqtt_timeout', default => 5 } + }); + $options{options}->add_help(package => __PACKAGE__, sections => 'MQTT GLOBAL OPTIONS'); + } + + $self->{output} = $options{output}; + $self->{connection_set} = 0; + return $self; +} + +sub check_options { + my ($self, %options) = @_; + + if (!defined($options{option_results}->{host})) { + $self->{output}->add_option_msg(short_msg => 'Missing parameter --hostname.'); + $self->{output}->option_exit(); + } + $self->{mqtt_host} = $options{option_results}->{host}; + $self->{mqtt_port} = defined($options{option_results}->{mqtt_port}) && $options{option_results}->{mqtt_port} =~ /(\d+)/ ? $1 : 8883; + $self->{mqtt_ssl} = $options{option_results}->{mqtt_ssl}; + $self->{mqtt_ca_certificate} = $options{option_results}->{mqtt_ca_certificate}; + $self->{mqtt_ssl_certificate} = $options{option_results}->{mqtt_ssl_certificate}; + $self->{mqtt_ssl_key} = $options{option_results}->{mqtt_ssl_key}; + $self->{mqtt_username} = $options{option_results}->{mqtt_username}; + $self->{mqtt_password} = $options{option_results}->{mqtt_password}; + $self->{mqtt_allow_insecure} = $options{option_results}->{mqtt_allow_insecure}; + $self->{mqtt_timeout} = $options{option_results}->{mqtt_timeout}; +} + +# Prepare the MQTT connection +sub set_mqtt_options { + my ($self, %options) = @_; + + if ($self->{connection_set} == 1) { + return; + } + + if (!centreon::plugins::misc::is_empty($self->{mqtt_allow_insecure}) && $self->{mqtt_allow_insecure} == 1) { + $ENV{MQTT_SIMPLE_ALLOW_INSECURE_LOGIN} = 1; + } + + if (!centreon::plugins::misc::is_empty($self->{mqtt_ssl}) && $self->{mqtt_ssl} == 1) { + $self->{mqtt} = Net::MQTT::Simple::SSL->new($self->{mqtt_host}, { + LocalPort => $self->{mqtt_port}, + SSL_ca_file => $self->{mqtt_ca_certificate}, + SSL_cert_file => $self->{mqtt_ssl_certificate}, + SSL_key_file => $self->{mqtt_ssl_key} + }); + } else { + $self->{mqtt} = Net::MQTT::Simple->new($self->{mqtt_host} . ':' . $self->{mqtt_port}); + } + $self->{mqtt}->login($self->{mqtt_username}, $self->{mqtt_password}) if (!centreon::plugins::misc::is_empty($self->{mqtt_username}) && !centreon::plugins::misc::is_empty($self->{mqtt_password})); + + $self->{connection_set} = 1; +} + +# Query a single topic +# Returns the message +# If no message is received, the script will exit with a message indicating that no message was received in the topic +sub query { + my ($self, %options) = @_; + + $self->set_mqtt_options(%options); + + my %mqtt_received; + my $starttime = Time::HiRes::time(); + my $endtime = $starttime + $self->{mqtt_timeout}; + $self->{mqtt}->subscribe($options{topic}, sub { + my ($topic, $message) = @_; + $mqtt_received{$topic} = $message; + }); + my $messages_received = 0; + while ($messages_received == 0 and Time::HiRes::time() < $endtime) { + $self->{mqtt}->tick(5); + $messages_received = scalar keys %mqtt_received; + } + eval { + $self->{mqtt}->unsubscribe($options{topic}); + }; + if (%mqtt_received) { + return %mqtt_received{$options{topic}}; + } else { + $self->{output}->add_option_msg(short_msg => 'No message in topic: ' . $options{topic}); + $self->{output}->option_exit(); + } +} + +# Query multiple topics +# Returns a hash with the topics as keys and the messages as values +sub queries { + my ($self, %options) = @_; + + $self->set_mqtt_options(%options); + + my %mqtt_received; + foreach my $topic (@{$options{topics}}) { + my $topic_for_query = defined($options{base_topic}) ? $options{base_topic} . $topic : $topic; + my $result = $self->query(topic => $topic_for_query); + $mqtt_received{$topic} = $result; + } + return %mqtt_received; +} + +1; + +__END__ + +=head1 NAME + +MQTT global + +=head1 SYNOPSIS + +MQTT class + +=head1 MQTT OPTIONS + +=over 8 + +=item B<--hostname> + +Name or address of the host to monitor (mandatory). + +=item B<--mqtt-port> + +Port used by MQTT (default: 8883). + +=item B<--mqtt-ssl> + +Use SSL for MQTT connection (default: 1). + +=item B<--mqtt-ca-certificate> + +CA certificate file. + +=item B<--mqtt-ssl-certificate> + +Client SSL certificate file. + +=item B<--mqtt-ssl-key> + +Client SSL key file. + +=item B<--mqtt-username> + +MQTT username. + +=item B<--mqtt-password> + +MQTT password. + +=item B<--mqtt-allow-insecure> + +Allow insecure login (default: 0). + +=item B<--mqtt-timeout> + +MQTT timeout (default: 5). + +=back + +=head1 DESCRIPTION + +B. + +=cut diff --git a/src/centreon/plugins/passwordmgr/hashicorpvault.pm b/src/centreon/plugins/passwordmgr/hashicorpvault.pm index 09756b6e5..ef5a75a00 100644 --- a/src/centreon/plugins/passwordmgr/hashicorpvault.pm +++ b/src/centreon/plugins/passwordmgr/hashicorpvault.pm @@ -45,6 +45,7 @@ sub new { $options{options}->add_options(arguments => { 'auth-method:s' => { name => 'auth_method', default => 'token' }, + 'auth-path:s' => { name => 'auth_path' }, 'auth-settings:s%' => { name => 'auth_settings' }, 'map-option:s@' => { name => 'map_option' }, 'secret-path:s@' => { name => 'secret_path' }, @@ -66,7 +67,10 @@ sub get_access_token { my $decoded; my $login = $self->parse_auth_method(method => $self->{auth_method}, settings => $self->{auth_settings}); my $post_json = JSON::XS->new->utf8->encode($login); - my $url_path = '/v1/auth/'. $self->{auth_method} . '/login/'; + if (!defined($self->{auth_path}) || $self->{auth_path} eq '') { + $self->{auth_path} = $self->{auth_method}; + } + my $url_path = '/v1/auth/'. $self->{auth_path} . '/login/'; $url_path .= $self->{auth_settings}->{username} if (defined($self->{auth_settings}->{username}) && $self->{auth_method} =~ 'userpass|login') ; my $content = $self->{http}->request( @@ -145,6 +149,10 @@ sub settings { $self->{output}->option_exit(); } + if (defined($options{option_results}->{auth_path})) { + $self->{auth_path} = lc($options{option_results}->{auth_path}); + } + $self->{auth_method} = lc($options{option_results}->{auth_method}); $self->{auth_settings} = defined($options{option_results}->{auth_settings}) && $options{option_results}->{auth_settings} ne '' ? $options{option_results}->{auth_settings} : {}; $self->{vault_address} = $options{option_results}->{vault_address}; @@ -277,6 +285,12 @@ Can be: 'http', 'https' (default: http). Authentication method to log in against the Vault server. Can be: 'azure', 'cert', 'github', 'ldap', 'okta', 'radius', 'userpass' (default: 'token'); +=item B<--auth-path> + +Authentication path for 'userpass'. Is an optional setting. + +More information here: https://developer.hashicorp.com/vault/docs/auth/userpass#configuration + =item B<--vault-token> Directly specify a valid token to log in (only for --auth-method='token'). diff --git a/src/centreon/plugins/script_mqtt.pm b/src/centreon/plugins/script_mqtt.pm new file mode 100644 index 000000000..ba6b31577 --- /dev/null +++ b/src/centreon/plugins/script_mqtt.pm @@ -0,0 +1,242 @@ +# +# Copyright 2024 Centreon (http://www.centreon.com/) +# +# Centreon is a full-fledged industry-strength solution that meets +# the needs in IT infrastructure and application monitoring for +# service performance. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +package centreon::plugins::script_mqtt; + +use strict; +use warnings; +use centreon::plugins::mqtt; +use centreon::plugins::misc; + +sub new { + my ($class, %options) = @_; + my $self = {}; + bless $self, $class; + $self->{options} = $options{options}; + $self->{output} = $options{output}; + + $self->{options}->add_options( + arguments => { + 'mode:s' => { name => 'mode_name' }, + 'dyn-mode:s' => { name => 'dynmode_name' }, + 'list-mode' => { name => 'list_mode' }, + 'mode-version:s' => { name => 'mode_version' }, + 'no-sanity-options' => { name => 'no_sanity_options' }, + 'pass-manager:s' => { name => 'pass_manager' }, + } + ); + $self->{version} = '1.0'; + %{$self->{modes}} = (); + $self->{default} = undef; + + $self->{options}->parse_options(); + $self->{option_results} = $self->{options}->get_options(); + foreach (keys %{$self->{option_results}}) { + $self->{$_} = $self->{option_results}->{$_}; + } + $self->{options}->clean(); + + $self->{options}->add_help(package => $options{package}, sections => 'PLUGIN DESCRIPTION'); + $self->{options}->add_help(package => __PACKAGE__, sections => 'GLOBAL OPTIONS'); + $self->{output}->mode(name => $self->{mode_name}); + + return $self; +} + +sub init { + my ($self, %options) = @_; + + # add meta mode + $self->{modes}->{multi} = 'centreon::plugins::multi'; + if (defined($options{help}) && !defined($self->{mode_name}) && !defined($self->{dynmode_name})) { + $self->{options}->display_help(); + $self->{output}->option_exit(); + } + if (defined($options{version}) && !defined($self->{mode_name}) && !defined($self->{dynmode_name})) { + $self->version(); + } + if (defined($self->{list_mode})) { + $self->list_mode(); + } + $self->{options}->set_sanity() if (!defined($self->{no_sanity_options})); + + # Output HELP + $self->{options}->add_help(package => 'centreon::plugins::output', sections => 'OUTPUT OPTIONS'); + + $self->load_password_mgr(); + + # MQTT + $self->{mqtt} = centreon::plugins::mqtt->new(options => $self->{options}, output => $self->{output}); + + # Load mode + if (defined($self->{mode_name}) && $self->{mode_name} ne '') { + $self->is_mode(mode => $self->{mode_name}); + centreon::plugins::misc::mymodule_load(output => $self->{output}, module => $self->{modes}{$self->{mode_name}}, + error_msg => "Cannot load module --mode."); + $self->{mode} = $self->{modes}{$self->{mode_name}}->new(options => $self->{options}, output => $self->{output}, mode => $self->{mode_name}); + } elsif (defined($self->{dynmode_name}) && $self->{dynmode_name} ne '') { + (undef, $self->{dynmode_name}) = centreon::plugins::misc::mymodule_load(output => $self->{output}, module => $self->{dynmode_name}, + error_msg => "Cannot load module --dyn-mode."); + $self->{mode} = $self->{dynmode_name}->new(options => $self->{options}, output => $self->{output}, mode => $self->{dynmode_name}); + } else { + $self->{output}->add_option_msg(short_msg => "Need to specify '--mode' or '--dyn-mode' option."); + $self->{output}->option_exit(); + } + + if (defined($options{help})) { + if (defined($self->{mode_name}) && $self->{mode_name} ne '') { + $self->{options}->add_help(package => $self->{modes}{$self->{mode_name}}, sections => 'MODE'); + } else { + $self->{options}->add_help(package => $self->{dynmode_name}, sections => 'MODE'); + } + $self->{options}->display_help(); + $self->{output}->option_exit(); + } + if (defined($options{version})) { + $self->{mode}->version(); + $self->{output}->option_exit(nolabel => 1); + } + if (centreon::plugins::misc::minimal_version($self->{mode}->{version}, $self->{mode_version}) == 0) { + $self->{output}->add_option_msg(short_msg => "Not good version for plugin mode. Excepted at least: " . $self->{mode_version} . ". Get: " . $self->{mode}->{version}); + $self->{output}->option_exit(); + } + + $self->{options}->parse_options(); + $self->{option_results} = $self->{options}->get_options(); + + $self->{pass_mgr}->manage_options(option_results => $self->{option_results}) if (defined($self->{pass_mgr})); + + $self->{mqtt}->check_options(option_results => $self->{option_results}); + $self->{mode}->check_options( + option_results => $self->{option_results}, + default => $self->{default}, + modes => $self->{modes} # for meta mode multi + ); +} + +sub load_password_mgr { + my ($self, %options) = @_; + + return if (!defined($self->{option_results}->{pass_manager}) || $self->{option_results}->{pass_manager} eq ''); + + (undef, my $pass_mgr_name) = centreon::plugins::misc::mymodule_load( + output => $self->{output}, module => "centreon::plugins::passwordmgr::" . $self->{option_results}->{pass_manager}, + error_msg => "Cannot load module 'centreon::plugins::passwordmgr::" . $self->{option_results}->{pass_manager} . "'" + ); + $self->{pass_mgr} = $pass_mgr_name->new(options => $self->{options}, output => $self->{output}); +} + +sub run { + my $self = shift; + + if ($self->{output}->is_disco_format()) { + $self->{mode}->disco_format(); + $self->{output}->display_disco_format(); + $self->{output}->exit(exit_litteral => 'ok'); + } + $self->{mqtt}->set_mqtt_options(); + if ($self->{output}->is_disco_show()) { + $self->{mode}->disco_show(snmp => $self->{snmp}); + $self->{output}->display_disco_show(); + $self->{output}->exit(exit_litteral => 'ok'); + } else { + $self->{mode}->run(mqtt => $self->{mqtt}); + } +} + +sub is_mode { + my ($self, %options) = @_; + + # $options->{mode} = mode + if (!defined($self->{modes}{$options{mode}})) { + $self->{output}->add_option_msg(short_msg => "mode '" . $options{mode} . "' doesn't exist (use --list-mode option to show available modes)."); + $self->{output}->option_exit(); + } +} + +sub version { + my $self = shift; + $self->{output}->add_option_msg(short_msg => "Plugin Version: " . $self->{version}); + $self->{output}->option_exit(nolabel => 1); +} + +sub list_mode { + my $self = shift; + $self->{options}->display_help(); + + $self->{output}->add_option_msg(long_msg => 'Modes Meta:'); + $self->{output}->add_option_msg(long_msg => ' multi'); + $self->{output}->add_option_msg(long_msg => ''); + $self->{output}->add_option_msg(long_msg => 'Modes Available:'); + foreach (sort keys %{$self->{modes}}) { + next if ($_ eq 'multi'); + $self->{output}->add_option_msg(long_msg => ' ' . $_); + } + $self->{output}->option_exit(nolabel => 1); +} + +1; + +__END__ + +=head1 NAME + +- + +=head1 SYNOPSIS + +- + +=head1 GLOBAL OPTIONS + +=over 8 + +=item B<--mode> + +Define the mode in which you want the plugin to be executed (see --list-mode). + +=item B<--dyn-mode> + +Specify a mode with the module's path (advanced). + +=item B<--list-mode> + +List all available modes. + +=item B<--mode-version> + +Check minimal version of mode. If not, unknown error. + +=item B<--version> + +Return the version of the plugin. + +=item B<--pass-manager> + +Define the password manager you want to use. +Supported managers are: environment, file, keepass, hashicorpvault and teampass. + +=back + +=head1 DESCRIPTION + +B<>. + +=cut diff --git a/src/storage/datacore/restapi/custom/api.pm b/src/storage/datacore/restapi/custom/api.pm index 4f0de4d1a..e43b25182 100644 --- a/src/storage/datacore/restapi/custom/api.pm +++ b/src/storage/datacore/restapi/custom/api.pm @@ -102,6 +102,7 @@ sub settings { # output : deserialized json from the api if not error found in http call. sub request_api { my ($self, %options) = @_; + $self->settings(); # datacore api require a ServerHost header with the hostname used to query the api to respond. # authentication is http standard basic auth. diff --git a/src/storage/datacore/restapi/mode/poolspaceusage.pm b/src/storage/datacore/restapi/mode/poolspaceusage.pm index 3fe233bc7..87b43d995 100644 --- a/src/storage/datacore/restapi/mode/poolspaceusage.pm +++ b/src/storage/datacore/restapi/mode/poolspaceusage.pm @@ -84,7 +84,7 @@ sub manage_selection { my ($self, %options) = @_; my $data = $options{custom}->request_api( - url_path => '/RestService/rest.svc/1.0/performances/' . $self->{option_results}->{pool_id}, + url_path => '/RestService/rest.svc/1.0/performance/' . $self->{option_results}->{pool_id}, ); if (defined($data->[1])) { $self->{output}->add_option_msg(short_msg => 'multiples pools found in api response, only one is expected. Please check pool_id and datacore versions.'); @@ -100,17 +100,17 @@ __END__ =head1 MODE -Check Datacore pool space and over subscribed usage exposed through the rest api. +Check Datacore pool space and over subscribed usage exposed through the Rest API. =over 8 =item B<--pool-id> -Id of the pool to check. See list-pool autodiscovery mode to list pools id (required). +Id of the pool to check. See list-pool auto discovery mode to list pools id (required). =item B<--warning-oversubscribed> B<--critical-oversubscribed> -Warning and critical threshold on the number of Bytes suscribed over the real space of the pool. +Warning and critical threshold on the number of Bytes subscribed over the real space of the pool. =item B<--warning-bytesallocatedpercentage> B<--critical-bytesallocatedpercentage> diff --git a/tests/resources/resources.resource b/tests/resources/resources.resource index 0aad4d644..542c4ef90 100644 --- a/tests/resources/resources.resource +++ b/tests/resources/resources.resource @@ -18,6 +18,6 @@ Start Mockoon ... ${MOCKOON_JSON} ... --port ... 3000 - Sleep 5s + Sleep 10s Stop Mockoon Terminate All Processes \ No newline at end of file diff --git a/tests/resources/spellcheck/stopwords.t b/tests/resources/spellcheck/stopwords.t index 6b95c44b2..fcdc4a293 100644 --- a/tests/resources/spellcheck/stopwords.t +++ b/tests/resources/spellcheck/stopwords.t @@ -1,6 +1,10 @@ --add-sysdesc +--api-password +--api-version +--critical-bytesallocatedpercentage --display-transform-dst --display-transform-src +--dyn-mode --exclude-fs --filter-fs --filter-vdom @@ -8,10 +12,21 @@ --force-counters64 --force-oid --map-speed-dsl +--mqtt +--mqtt-allow-insecure +--mqtt-ca-certificate +--mqtt-password +--mqtt-port +--mqtt-ssl +--mqtt-ssl-certificate +--mqtt-ssl-key +--mqtt-timeout +--mqtt-username --nagvis-perfdata --oid-display --oid-extra-display --oid-filter +--warning-bytesallocatedpercentage 2c ADSL Avigilon @@ -23,6 +38,8 @@ eth fanspeed Fortigate Fortinet +HashiCorp +hashicorpvault ifAlias ifDesc ifName @@ -31,11 +48,18 @@ in-mcast in-ucast interface-dsl-name IpAddr +Iwsva +keepass +ldap license-instances-usage-prct +Loggly MBean +Mosquitto +MQTT NagVis Netscaler OID +okta oneaccess-sys-mib out-bcast out-mcast @@ -51,11 +75,16 @@ SNMP space-usage-prct SSH SureBackup +teampass timeframe topic-messages-inflighted total-oper-down total-oper-up +TendMicro uptime +userpass VDSL2 Veeam +v1 +v2 WSMAN diff --git a/tests/robot/apps/eclipse/mosquitto/mqtt/eclipse-mosquitto-mqtt.robot b/tests/robot/apps/eclipse/mosquitto/mqtt/eclipse-mosquitto-mqtt.robot new file mode 100644 index 000000000..da14c64d4 --- /dev/null +++ b/tests/robot/apps/eclipse/mosquitto/mqtt/eclipse-mosquitto-mqtt.robot @@ -0,0 +1,74 @@ +*** Settings *** +Documentation Eclipse Mosquitto MQTT plugin tests + +Resource ${CURDIR}${/}..${/}..${/}..${/}..${/}..${/}resources/import.resource + +Test Timeout 120s + +Keyword Tags notauto + + +*** Variables *** +${HOSTNAME} mosquitto_openssl +${MQTT_PORT} 8883 +${MQTT_CA_CERTIFICATE} /home/code/tests/robot/apps/eclipse/mosquitto/mqtt/certs/ca.crt +${MQTT_SSL_CERTIFICATE} /home/code/tests/robot/apps/eclipse/mosquitto/mqtt/certs/client.crt +${MQTT_SSL_KEY} /home/code/tests/robot/apps/eclipse/mosquitto/mqtt/certs/client.key +${CMD} ${CENTREON_PLUGINS} --plugin=apps::eclipse::mosquitto::mqtt::plugin --hostname=${HOSTNAME} --mqtt-port=${MQTT_PORT} --mqtt-ca-certificate=${MQTT_CA_CERTIFICATE} --mqtt-ssl-certificate=${MQTT_SSL_CERTIFICATE} --mqtt-ssl-key=${MQTT_SSL_KEY} + + +*** Test Cases *** +Mosquitto MQTT uptime + [Documentation] Check Mosquitto MQTT uptime + [Tags] eclipse mosquitto mqtt + ${command} Catenate + ... ${CMD} + ... --mode=uptime + ... --help + + ${output} Run ${command} + ${output} Strip String ${output} + +Mosquitto MQTT clients + [Documentation] Check Mosquitto MQTT uptime + [Tags] eclipse mosquitto mqtt + ${command} Catenate + ... ${CMD} + ... --mode=clients + ... --help + + ${output} Run ${command} + ${output} Strip String ${output} + +Mosquitto MQTT messages + [Documentation] Check Mosquitto MQTT uptime + [Tags] eclipse mosquitto mqtt + ${command} Catenate + ... ${CMD} + ... --mode=messages + ... --help + + ${output} Run ${command} + ${output} Strip String ${output} + +Mosquitto MQTT numeric-value + [Documentation] Check Mosquitto MQTT uptime + [Tags] eclipse mosquitto mqtt + ${command} Catenate + ... ${CMD} + ... --mode=numeric-value + ... --help + + ${output} Run ${command} + ${output} Strip String ${output} + +Mosquitto MQTT string-value + [Documentation] Check Mosquitto MQTT uptime + [Tags] eclipse mosquitto mqtt + ${command} Catenate + ... ${CMD} + ... --mode=string-value + ... --help + + ${output} Run ${command} + ${output} Strip String ${output} diff --git a/tests/robot/apps/protocols/http/collection-centreon-web-check-auth.collection.json b/tests/robot/apps/protocols/http/collection-centreon-web-check-auth.collection.json new file mode 100644 index 000000000..bb80be606 --- /dev/null +++ b/tests/robot/apps/protocols/http/collection-centreon-web-check-auth.collection.json @@ -0,0 +1,61 @@ +{ + "constants": { + "protocol": "https", + "port": "443", + "customPath": "centreon" + }, + "http": { + "requests": [ + { + "name": "authenticationRequest", + "hostname": "%(constants.hostname)", + "proto": "%(constants.protocol)", + "port": "%(constants.port)", + "endpoint": "/%(constants.customPath)/api/latest/login", + "method": "POST", + "headers": [ + "Accept:application/json", + "Content-Type:application/json" + ], + "timeout": 30, + "payload": { + "type": "json", + "value": { + "security": { + "credentials": { + "login": "%(constants.username)", + "password": "%(constants.password)" + } + } + } + }, + "backend": "curl", + "rtype": "json", + "parse": [ + { + "name": "token", + "path": "$.security.token", + "entries": [ + { + "id": "value" + } + ] + } + ] + } + ] + }, + "selection": [ + { + "name": "authenticationSelection", + "critical": "defined(%(builtin.httpCode.authenticationRequest)) and %(builtin.httpCode.authenticationRequest) != 200", + "formatting": { + "printf_msg": "Authentication resulted in %s HTTP code", + "printf_var": [ + "%(builtin.httpCode.authenticationRequest)" + ], + "display_ok": true + } + } + ] +} diff --git a/tests/robot/apps/protocols/http/collection-centreon-web-check-broken-commands.collection.json b/tests/robot/apps/protocols/http/collection-centreon-web-check-broken-commands.collection.json new file mode 100644 index 000000000..1c3fc7d90 --- /dev/null +++ b/tests/robot/apps/protocols/http/collection-centreon-web-check-broken-commands.collection.json @@ -0,0 +1,160 @@ +{ + "constants": { + "protocol": "https", + "port": "443", + "customPath": "centreon" + }, + "http": { + "requests": [ + { + "name": "authenticationRequest", + "hostname": "%(constants.hostname)", + "proto": "%(constants.protocol)", + "port": "%(constants.port)", + "endpoint": "/%(constants.customPath)/api/latest/login", + "method": "POST", + "headers": [ + "Accept:application/json", + "Content-Type:application/json" + ], + "timeout": 30, + "payload": { + "type": "json", + "value": { + "security": { + "credentials": { + "login": "%(constants.username)", + "password": "%(constants.password)" + } + } + } + }, + "scenario_stopped": "%(builtin.httpCode.authenticationRequest) != 200", + "backend": "curl", + "rtype": "json", + "parse": [ + { + "name": "token", + "path": "$.security.token", + "entries": [ + { + "id": "value" + } + ] + } + ] + }, + { + "name": "resourcesRequest", + "hostname": "%(constants.hostname)", + "proto": "%(constants.protocol)", + "port": "%(constants.port)", + "endpoint": "/%(constants.customPath)/api/latest/monitoring/resources?limit=1000&search={\"information\": {\"$eq\": \"(Execute command failed)\"}}", + "method": "GET", + "headers": [ + "X-AUTH-TOKEN: %(http.tables.authenticationRequestToken.[0].value)", + "Accept: text/json" + ], + "timeout": 30, + "scenario_stopped": "%(builtin.httpCode.authenticationRequest) != 200", + "backend": "curl", + "rtype": "json", + "parse": [ + { + "name": "meta", + "type": "body", + "path": "$.meta", + "entries": [ + { + "id": "total" + } + ] + }, + { + "name": "entries", + "type": "body", + "path": "$.result[*]", + "entries": [ + { + "id": "parent.name" + }, + { + "id": "name" + }, + { + "id": "type" + }, + { + "id": "information" + } + ] + } + ] + } + ] + }, + "selection_loop": [ + { + "name": "HostsLoop", + "source": "%(http.tables.resourcesRequestEntries)", + "filter": "%(resourcesRequestEntries.type) eq 'host'", + "formatting": { + "display_ok": "false", + "printf_msg": "Host %s's output is '%s'", + "printf_var": [ + "%(resourcesRequestEntries.name)", + "%(resourcesRequestEntries.information)" + ] + }, + "warning": "%(resourcesRequestEntries.information) =~ /No output returned from plugin|Execute command failed/" + }, + { + "name": "ServicesLoop", + "source": "%(http.tables.resourcesRequestEntries)", + "filter": "%(resourcesRequestEntries.type) eq 'service'", + "formatting": { + "display_ok": "false", + "printf_msg": "Service %s/%s output is '%s'", + "printf_var": [ + "%(resourcesRequestEntries.parent.name)", + "%(resourcesRequestEntries.name)", + "%(resourcesRequestEntries.information)" + ] + }, + "warning": "%(resourcesRequestEntries.information) =~ /No output returned from plugin|Execute command failed/" + } + ], + "selection": [ + { + "name": "totalSelection", + "functions": [ + { + "type": "assign", + "expression": "%(http.tables.resourcesRequestMeta.[0].total)", + "save": "%(brokenCommandsCount)" + } + ], + "perfdatas": [ + { + "nlabel": "commands.broken.count", + "value": "%(brokenCommandsCount)", + "warning": "0", + "min": 0 + } + ], + "exit": "%(brokenCommandsCount) == 0", + "warning": "%(brokenCommandsCount) > 0", + "formatting_warning": { + "printf_msg": "", + "display_ok": false, + "separator": " " + }, + "formatting": { + "printf_msg": "All commands are fine", + "display_ok": true, + "separator": "" + } + } + ] +} + diff --git a/tests/robot/apps/protocols/http/collection-centreon-web-check-down-hosts.collection.json b/tests/robot/apps/protocols/http/collection-centreon-web-check-down-hosts.collection.json new file mode 100644 index 000000000..1d71f43d1 --- /dev/null +++ b/tests/robot/apps/protocols/http/collection-centreon-web-check-down-hosts.collection.json @@ -0,0 +1,132 @@ +{ + "constants": { + "protocol": "https", + "port": "443", + "customPath": "centreon" + }, + "http": { + "requests": [ + { + "name": "authenticationRequest", + "hostname": "%(constants.hostname)", + "proto": "%(constants.protocol)", + "port": "%(constants.port)", + "endpoint": "/%(constants.customPath)/api/latest/login", + "method": "POST", + "headers": [ + "Accept:application/json", + "Content-Type:application/json" + ], + "timeout": 30, + "payload": { + "type": "json", + "value": { + "security": { + "credentials": { + "login": "%(constants.username)", + "password": "%(constants.password)" + } + } + } + }, + "scenario_stopped": "%(builtin.httpCode.authenticationRequest) != 200", + "backend": "curl", + "rtype": "json", + "parse": [ + { + "name": "token", + "path": "$.security.token", + "entries": [ + { + "id": "value" + } + ] + } + ] + }, + { + "name": "hostsRequest", + "hostname": "%(constants.hostname)", + "proto": "%(constants.protocol)", + "port": "%(constants.port)", + "endpoint": "/%(constants.customPath)/api/latest/monitoring/hosts?limit=1000", + "method": "GET", + "headers": [ + "X-AUTH-TOKEN: %(http.tables.authenticationRequestToken.[0].value)", + "Accept: text/json" + ], + "timeout": 30, + "backend": "curl", + "rtype": "json", + "parse": [ + { + "name": "entries", + "type": "body", + "path": "$.result[*]", + "entries": [ + { + "id": "name" + }, + { + "id": "state" + } + ] + } + ] + } + ] + }, + "selection": [ + { + "name": "authenticationSelection", + "critical": "defined(%(builtin.httpCode.authenticationRequest)) and %(builtin.httpCode.authenticationRequest) != 200", + "exit": "defined(%(builtin.httpCode.authenticationRequest)) and %(builtin.httpCode.authenticationRequest) != 200", + "formatting": { + "printf_msg": "Authentication resulted in %s HTTP code", + "printf_var": [ + "%(builtin.httpCode.authenticationRequest)" + ], + "display_ok": false + } + }, + { + "name": "hostsSelection", + "functions": [ + { + "type": "count", + "src": "%(http.tables.hostsRequestEntries)", + "filter": "%(src.state) != 0", + "save": "%(downCount)" + }, + { + "type": "count", + "src": "%(http.tables.hostsRequestEntries)", + "save": "%(hostsCount)" + } + ], + "perfdatas": [ + { + "nlabel": "hostsRequest.down.count", + "value": "%(downCount)", + "warning": "0", + "min": 0, + "max": "%(hostsCount)" + } + ], + "warning": "%(downCount) > 0", + "formatting": { + "printf_msg": "Number of down hosts: %s out of %s", + "printf_var": [ + "%(downCount)", + "%(hostsCount)" + ], + "display_ok": true + } + } + ], + "formatting": { + "custom_message_global": "All hosts are UP", + "separator": "-" + } +} + diff --git a/tests/robot/apps/protocols/http/collection-centreon-web.mockoon.json b/tests/robot/apps/protocols/http/collection-centreon-web.mockoon.json new file mode 100644 index 000000000..fd6109081 --- /dev/null +++ b/tests/robot/apps/protocols/http/collection-centreon-web.mockoon.json @@ -0,0 +1,210 @@ +{ + "uuid": "919382d8-0f30-447f-abcd-45c98e84d7fe", + "lastMigration": 32, + "name": "Centreon web mock for tests of HTTP Collections", + "endpointPrefix": "", + "latency": 0, + "port": 3001, + "hostname": "", + "folders": [], + "routes": [ + { + "uuid": "82abcb5a-0a65-409f-badd-5e881b6786df", + "type": "http", + "documentation": "Authentication request", + "method": "post", + "endpoint": "centreon/api/latest/login", + "responses": [ + { + "uuid": "b4229c90-76b3-4f8c-be0f-aceeb5566051", + "body": "{}", + "latency": 0, + "statusCode": 200, + "label": "", + "headers": [ + { + "key": "content-type", + "value": "application/json; charset=utf-8" + }, + { + "key": "content-length", + "value": "2" + } + ], + "bodyType": "DATABUCKET", + "filePath": "", + "databucketID": "0ibb", + "sendFileAsBody": false, + "rules": [], + "rulesOperator": "OR", + "disableTemplating": false, + "fallbackTo404": false, + "default": false, + "crudKey": "id", + "callbacks": [] + } + ], + "responseMode": null + }, + { + "uuid": "d67aa94e-09c5-434d-b00a-e9e147e90220", + "type": "http", + "documentation": "Monitoring of hosts, used to look for down hosts", + "method": "get", + "endpoint": "centreon/api/latest/monitoring/hosts", + "responses": [ + { + "uuid": "c98ea5bd-143b-414e-ae28-d094e7059682", + "body": "", + "latency": 0, + "statusCode": 200, + "label": "", + "headers": [ + { + "key": "content-security-policy", + "value": "default-src 'none'" + }, + { + "key": "content-type", + "value": "text/html; charset=utf-8" + }, + { + "key": "x-content-type-options", + "value": "nosniff" + } + ], + "bodyType": "DATABUCKET", + "filePath": "", + "databucketID": "fdau", + "sendFileAsBody": false, + "rules": [], + "rulesOperator": "OR", + "disableTemplating": false, + "fallbackTo404": false, + "default": false, + "crudKey": "id", + "callbacks": [] + } + ], + "responseMode": null + }, + { + "uuid": "9622753c-4c89-4f37-aa27-6088a4c5557a", + "type": "http", + "documentation": "Monitoring of resources, used to look for broken commands", + "method": "get", + "endpoint": "centreon/api/latest/monitoring/resources", + "responses": [ + { + "uuid": "1d5391f0-9edc-4b84-b9ed-b78524ae1782", + "latency": 0, + "statusCode": 200, + "label": "", + "headers": [ + { + "key": "content-security-policy", + "value": "default-src 'none'" + }, + { + "key": "content-type", + "value": "text/html; charset=utf-8" + }, + { + "key": "x-content-type-options", + "value": "nosniff" + } + ], + "bodyType": "DATABUCKET", + "filePath": "", + "databucketID": "tpm8", + "sendFileAsBody": false, + "rules": [], + "rulesOperator": "OR", + "disableTemplating": false, + "fallbackTo404": false, + "default": false, + "crudKey": "id", + "callbacks": [], + "body": "{}" + } + ], + "responseMode": null + } + ], + "rootChildren": [ + { + "type": "route", + "uuid": "82abcb5a-0a65-409f-badd-5e881b6786df" + }, + { + "type": "route", + "uuid": "d67aa94e-09c5-434d-b00a-e9e147e90220" + }, + { + "type": "route", + "uuid": "9622753c-4c89-4f37-aa27-6088a4c5557a" + } + ], + "proxyMode": false, + "proxyHost": "", + "proxyRemovePrefix": false, + "tlsOptions": { + "enabled": false, + "type": "CERT", + "pfxPath": "", + "certPath": "", + "keyPath": "", + "caPath": "", + "passphrase": "" + }, + "cors": true, + "headers": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "proxyReqHeaders": [ + { + "key": "", + "value": "" + } + ], + "proxyResHeaders": [ + { + "key": "", + "value": "" + } + ], + "data": [ + { + "uuid": "497b64fa-7c29-4741-8c57-c818aafc9482", + "id": "fdcz", + "name": "Authentication payload", + "documentation": "Authentication payload", + "value": "{\"security\":{\"credentials\":{\"password\":\"***\",\"login\":\"admin\"}}}" + }, + { + "uuid": "e9b76766-90a5-496e-8102-3941d22feb32", + "id": "0ibb", + "name": "Authentication response", + "documentation": "Authentication response", + "value": "{\n \"security\" : {\n \"token\" : \"Vj77k9p53L+FTXon1UDvaYBZU8P3MnUK2siU7mst3HJ1QcnjTDWVW6TX3RlccjpV\"\n },\n \"contact\" : {\n \"name\" : \"Administrateur_Centreon\",\n \"is_admin\" : true,\n \"email\" : \"null@localhost.local\",\n \"alias\" : \"admin\",\n \"id\" : 1\n }\n}" + }, + { + "uuid": "18e9cb4a-d822-44cd-b6a3-83dbead20130", + "id": "fdau", + "name": "Monitoring/hosts response", + "documentation": "Monitoring/hosts response to count down hosts", + "value": "{\n \"meta\": {\n \"search\": {},\n \"total\": 1,\n \"limit\": 1000,\n \"sort_by\": {},\n \"page\": 1\n },\n \"result\": [\n {\n \"passive_checks\": false,\n \"timezone\": \"\",\n \"last_check\": \"2023-11-21T21:21:14+01:00\",\n \"checked\": true,\n \"state\": 0,\n \"last_time_up\": \"2023-11-21T21:21:18+01:00\",\n \"icon_image\": \"ppm/applications-monitoring-centreon-central-centreon-128-2.png\",\n \"icon_image_alt\": \"\",\n \"state_type\": 1,\n \"address_ip\": \"127.0.0.1\",\n \"criticality\": null,\n \"last_time_down\": null,\n \"scheduled_downtime_depth\": 0,\n \"name\": \"CENTREON\",\n \"last_time_unreachable\": null,\n \"alias\": \"Centreon Central Server\",\n \"poller_id\": 1,\n \"last_hard_state_change\": \"2023-09-07T20:03:53+02:00\",\n \"execution_time\": 0.112673,\n \"last_state_change\": \"2023-09-07T20:03:53+02:00\",\n \"output\": \"OK - 127.0.0.1 rta 0.079ms lost 0%\\n\",\n \"id\": 13,\n \"max_check_attempts\": 3,\n \"last_update\": \"2023-11-21T08:57:13+01:00\",\n \"acknowledged\": false,\n \"display_name\": \"CENTREON\",\n \"check_attempt\": 1\n }\n ]\n}" + }, + { + "uuid": "0fcda655-3209-4726-8ab2-18f93666b57c", + "id": "tpm8", + "name": "Monitoring/resources response", + "documentation": "Monitoring/resources response to check errors in commands", + "value": "{\n \"meta\" : {\n \"page\" : 1,\n \"sort_by\" : {},\n \"search\" : {\n \"$and\" : {\n \"information\" : {\n \"$eq\" : \"(Execute command failed)\"\n }\n }\n },\n \"limit\" : 1000,\n \"total\" : 1\n },\n \"result\" : [\n {\n \"uuid\" : \"h254-s1616\",\n \"host_id\" : 254,\n \"monitoring_server_name\" : \"Central\",\n \"status\" : {\n \"name\" : \"UNKNOWN\",\n \"code\" : 3,\n \"severity_code\" : 3\n },\n \"icon\" : null,\n \"alias\" : null,\n \"last_status_change\" : \"2023-11-22T11:55:30+01:00\",\n \"short_type\" : \"s\",\n \"name\" : \"Svc-BadCommand\",\n \"last_check\" : \"1m 2s\",\n \"duration\" : \"4h 28m\",\n \"acknowledged\" : false,\n \"in_downtime\" : false,\n \"chart_url\" : null,\n \"tries\" : \"1/3 (H)\",\n \"information\" : \"(Execute command failed)\",\n \"performance_data\" : null,\n \"parent\" : {\n \"status\" : {\n \"severity_code\" : 1,\n \"name\" : \"DOWN\",\n \"code\" : 1\n },\n \"host_id\" : null,\n \"uuid\" : \"h254\",\n \"alias\" : \"Down\",\n \"icon\" : null,\n \"links\" : {\n \"externals\" : {\n \"action_url\" : null,\n \"notes\" : null\n },\n \"uris\" : {\n \"configuration\" : null,\n \"reporting\" : null,\n \"logs\" : null\n },\n \"endpoints\" : {}\n },\n \"id\" : 254,\n \"fqdn\" : \"1.2.3.4\",\n \"name\" : \"FakeHostThatIsDown\",\n \"type\" : \"host\",\n \"short_type\" : \"h\",\n \"service_id\" : null\n },\n \"links\" : {\n \"externals\" : {\n \"action_url\" : \"\",\n \"notes\" : {\n \"url\" : \"\",\n \"label\" : \"\"\n }\n },\n \"uris\" : {\n \"logs\" : \"/centreon/main.php?p=20301&svc=254_1616\",\n \"configuration\" : \"/centreon/main.php?p=60201&o=c&service_id=1616\",\n \"reporting\" : \"/centreon/main.php?p=30702&period=yesterday&start=&end=&host_id=254&item=1616\"\n },\n \"endpoints\" : {\n \"check\" : \"/centreon/api/latest/monitoring/hosts/254/services/1616/check\",\n \"acknowledgement\" : \"/centreon/api/latest/monitoring/hosts/254/services/1616/acknowledgements?limit=1\",\n \"timeline\" : \"/centreon/api/latest/monitoring/hosts/254/services/1616/timeline\",\n \"performance_graph\" : null,\n \"downtime\" : \"/centreon/api/latest/monitoring/hosts/254/services/1616/downtimes?search=%7B%22%24and%22:%5B%7B%22start_time%22:%7B%22%24lt%22:1700666614%7D,%22end_time%22:%7B%22%24gt%22:1700666614%7D,%220%22:%7B%22%24or%22:%7B%22is_cancelled%22:%7B%22%24neq%22:1%7D,%22deletion_time%22:%7B%22%24gt%22:1700666614%7D%7D%7D%7D%5D%7D\",\n \"forced_check\" : \"/centreon/api/latest/monitoring/hosts/254/services/1616/check\",\n \"status_graph\" : \"/centreon/api/latest/monitoring/hosts/254/services/1616/metrics/status\",\n \"details\" : \"/centreon/api/latest/monitoring/resources/hosts/254/services/1616\"\n }\n },\n \"passive_checks\" : false,\n \"notification_enabled\" : false,\n \"service_id\" : 1616,\n \"type\" : \"service\",\n \"severity\" : null,\n \"fqdn\" : null,\n \"active_checks\" : true,\n \"id\" : 1616\n }\n ]\n}" + } + ], + "callbacks": [] +} \ No newline at end of file diff --git a/tests/robot/apps/protocols/http/collection-centreon-web.robot b/tests/robot/apps/protocols/http/collection-centreon-web.robot new file mode 100644 index 000000000..240800dc2 --- /dev/null +++ b/tests/robot/apps/protocols/http/collection-centreon-web.robot @@ -0,0 +1,33 @@ +*** Settings *** +Documentation Collections of HTTP Protocol plugin testing a mock of Centreon-web API + +Resource ${CURDIR}${/}..${/}..${/}..${/}..${/}resources/import.resource + +Suite Setup Start Mockoon ${MOCKOON_JSON} +Suite Teardown Stop Mockoon +Test Timeout 120s + + +*** Variables *** +${MOCKOON_JSON} ${CURDIR}${/}collection-centreon-web.mockoon.json + +${CMD} ${CENTREON_PLUGINS} --plugin apps::protocols::http::plugin --mode collection +... --constant='hostname=127.0.0.1' --constant='protocol=http' --constant='port=3000' +... --constant='username=admin' --constant='password=myPassword' + + +*** Test Cases *** +Check if ${test_desc} on Centreon + [Tags] centreon collections http + ${output} Run + ... ${CMD} --config=${CURDIR}/${collection} + ${output} Strip String ${output} + Should Be Equal As Strings + ... ${output} + ... ${expected} + ... Wrong output result:\n\n ${output}\nInstead of:\n ${expected}\n\n + + Examples: test_desc collection expected -- + ... authentication succeeds collection-centreon-web-check-auth.collection.json OK: Authentication resulted in 200 HTTP code + ... hosts are down collection-centreon-web-check-down-hosts.collection.json OK: All hosts are UP | 'hostsRequest.down.count'=0;0;;0;1 + ... commands are broken collection-centreon-web-check-broken-commands.collection.json WARNING:${SPACE} - Service FakeHostThatIsDown/Svc-BadCommand output is '(Execute command failed)' | 'commands.broken.count'=1;0;;0; diff --git a/tests/robot/apps/protocols/snmp/hashicorp-password-manager.robot b/tests/robot/apps/protocols/snmp/hashicorp-password-manager.robot new file mode 100644 index 000000000..625848d57 --- /dev/null +++ b/tests/robot/apps/protocols/snmp/hashicorp-password-manager.robot @@ -0,0 +1,48 @@ +*** Settings *** +Resource ${CURDIR}${/}..${/}..${/}..${/}..${/}resources/import.resource + +Suite Setup Start Mockoon ${MOCKOON_JSON} +Suite Teardown Stop Mockoon +Test Timeout 120s + + +*** Variables *** +${MOCKOON_JSON} ${CURDIR}${/}vault-authentication-hashicorp.json + +${CMD} ${CENTREON_PLUGINS} --plugin apps::protocols::snmp::plugin --hostname=127.0.0.1 + + +*** Test Cases *** +check hashicorp vault manager${Name} + [Documentation] Check hashicorp vaultmanager + [Tags] snmp vault + ${cmd_hashicorp} Catenate + ... ${CMD} + ... --pass-manager=hashicorpvault + ... --vault-address=127.0.0.1 + ... --vault-port=3000 + ... --vault-protocol=http + ... --auth-method=userpass + ... --auth-settings="username=hcvaultuser" + ... --secret-path="path/of/the/secret" + ... --snmp-port=2024 + ... --map-option="snmp_community=\\%{value_path/of/the/secret}" + ... --mode=string-value + ... --snmp-version=2c + ... --snmp-community=apps/protocols/snmp/snmp-single-oid + ... --oid='.1.3.6.1.2.1.1.1.0' ${path-param} + ... --format-ok='current value is: \\%{details_ok}' + ... --format-details-warning='current value is: \\%{details_warning}' + ... --format-details-critical='current value is: \\%{details_critical}' + ${output} Run + ... ${cmd_hashicorp} + ${output} Strip String ${output} + Should Be Equal As Strings + ... ${output} + ... ${result} + ... ${cmd_hashicorp}\n\n Wrong output result for hashicorp auth manager on snmp generic plugin, output got :\n${output} \nExpected : \n ${result}\n + + Examples: Name path-param result -- + ... default path --auth-path='' --auth-settings="password=secrethashicorpPassword" OK: current value is: Linux centreon-devbox 5.10.0-28-amd64 #1 SMP Debian 5.10.209-2 (2024-01-31) x86_64 + ... wrong path --auth-path='specific-url' --auth-settings="password=secrethashicorpPassword" OK: current value is: Linux centreon-devbox 5.10.0-28-amd64 #1 SMP Debian 5.10.209-2 (2024-01-31) x86_64 + ... wrong password --auth-path='' --auth-settings="password=WrongPassword" UNKNOWN: 401 Unauthorized diff --git a/tests/robot/apps/protocols/snmp/snmp-single-oid.snmpwalk b/tests/robot/apps/protocols/snmp/snmp-single-oid.snmpwalk new file mode 100644 index 000000000..117727ae2 --- /dev/null +++ b/tests/robot/apps/protocols/snmp/snmp-single-oid.snmpwalk @@ -0,0 +1 @@ +.1.3.6.1.2.1.1.1.0 = STRING: "Linux centreon-devbox 5.10.0-28-amd64 #1 SMP Debian 5.10.209-2 (2024-01-31) x86_64" \ No newline at end of file diff --git a/tests/robot/apps/protocols/snmp/vault-authentication-hashicorp.json b/tests/robot/apps/protocols/snmp/vault-authentication-hashicorp.json new file mode 100644 index 000000000..7be98a830 --- /dev/null +++ b/tests/robot/apps/protocols/snmp/vault-authentication-hashicorp.json @@ -0,0 +1,238 @@ +{ + "uuid": "98b9aab1-da6e-46a5-a2c2-5c001be49806", + "lastMigration": 27, + "name": "Apps hashicorp vault", + "endpointPrefix": "", + "latency": 0, + "port": 3000, + "hostname": "", + "folders": [], + "routes": [ + { + "uuid": "6b8dd80b-3ea0-48c0-8e9d-609d618e980e", + "type": "http", + "documentation": "", + "method": "post", + "endpoint": "v1/auth/userpass/login/hcvaultuser", + "responses": [ + { + "uuid": "edc924ee-c73b-44e9-8402-d3d75a514083", + "body": "{\r\n \"request_id\":\r\n \"9a423954-2109-1e23-b0e4-f694d557031f\", \"lease_id\":\r\n \"\", \"renewable\":\r\n false, \"lease_duration\":\r\n 0, \"data\":\r\n null, \"wrap_info\":\r\n null, \"warnings\":\r\n [ \"Endpoint replaced the value of these parameters with the values captured from the endpoint's path: [username]\" ], \"auth\":\r\n {\r\n \"client_token\":\r\n \"hvs.CAESIHR511IiIwmAXLTrXQnLJ0Pq-NHQYgfiv4m1ZYVQHVt_Gh4KHGh2cy5HRTZidHZ0b0s3NzE5UG41cE10aUtrQjg\", \"accessor\":\r\n \"fYX782sU7MPQH2Xhf8q0BfSP\", \"policies\":\r\n [ \"default\", \"inf-icinga.ro\" ], \"token_policies\":\r\n [ \"default\", \"inf-icinga.ro\" ], \"metadata\":\r\n {\r\n \"username\":\r\n \"hcvaultuser\"\r\n }, \"lease_duration\":\r\n 604800, \"renewable\":\r\n true, \"entity_id\":\r\n \"cc0f1543-6838-46d1-c97e-d61a5899fc9b\", \"token_type\":\r\n \"service\", \"orphan\":\r\n true, \"mfa_requirement\":\r\n null, \"num_uses\":\r\n 0\r\n }\r\n}", + "latency": 0, + "statusCode": 200, + "label": "if password ok", + "headers": [], + "bodyType": "INLINE", + "filePath": "", + "databucketID": "", + "sendFileAsBody": false, + "rules": [ + { + "target": "body", + "modifier": "password", + "value": "secrethashicorpPassword", + "invert": false, + "operator": "equals" + }, + { + "target": "body", + "modifier": "username", + "value": "hcvaultuser", + "invert": false, + "operator": "equals" + } + ], + "rulesOperator": "AND", + "disableTemplating": false, + "fallbackTo404": false, + "default": false + }, + { + "uuid": "fc4cc190-618b-480d-ae22-296248292297", + "body": "{\r\n \"errors\": [\r\n \"wrong user/password\"\r\n ]\r\n}", + "latency": 0, + "statusCode": 401, + "label": "error", + "headers": [], + "bodyType": "INLINE", + "filePath": "", + "databucketID": "", + "sendFileAsBody": false, + "rules": [], + "rulesOperator": "OR", + "disableTemplating": false, + "fallbackTo404": false, + "default": true + } + ], + "enabled": true, + "responseMode": null + }, + { + "uuid": "8fdb70c1-a874-40eb-8b9f-542dca268992", + "type": "http", + "documentation": "", + "method": "get", + "endpoint": "v1/path/of/the/secret", + "responses": [ + { + "uuid": "2dec61d5-f84d-4223-b993-a91d127e0e71", + "body": "{\r\n \"request_id\":\"76aa492b-acc0-52dc-1f2c-3e2f959a5dfd\",\r\n \"lease_id\":\"\",\r\n \"renewable\":false,\r\n \"lease_duration\":0,\r\n \"data\":{\r\n \"data\":{\r\n \"monitor\":\"apps/protocols/snmp/snmp-single-oid\"\r\n },\r\n \"metadata\":{\r\n \"created_time\":\"2023-11-17T13:46:39.240097987Z\",\r\n \"custom_metadata\":null,\r\n \"deletion_time\":\"\",\r\n \"destroyed\":false,\r\n \"version\":1\r\n }\r\n },\r\n \"wrap_info\":null,\r\n \"warnings\":null,\r\n \"auth\":null\r\n}", + "latency": 0, + "statusCode": 200, + "label": "", + "headers": [], + "bodyType": "INLINE", + "filePath": "", + "databucketID": "", + "sendFileAsBody": false, + "rules": [], + "rulesOperator": "OR", + "disableTemplating": false, + "fallbackTo404": false, + "default": true + } + ], + "enabled": true, + "responseMode": null + }, + { + "uuid": "8ef8c935-ff40-4817-8211-52cc1d0c64b4", + "type": "http", + "documentation": "", + "method": "get", + "endpoint": "v1/otherPath", + "responses": [ + { + "uuid": "894d68aa-3f3b-463c-a1dd-cf9dd3565d7c", + "body": "{}", + "latency": 0, + "statusCode": 200, + "label": "", + "headers": [], + "bodyType": "INLINE", + "filePath": "", + "databucketID": "", + "sendFileAsBody": false, + "rules": [], + "rulesOperator": "OR", + "disableTemplating": false, + "fallbackTo404": false, + "default": true + } + ], + "enabled": true, + "responseMode": null + }, + { + "uuid": "2686745a-9783-4b64-9376-068c159aa725", + "type": "http", + "documentation": "", + "method": "post", + "endpoint": "v1/auth/specific-url/login/hcvaultuser", + "responses": [ + { + "uuid": "400e5fea-c3f3-4abc-bc24-73afa75111c6", + "body": "{\r\n \"request_id\":\r\n \"9a423954-2109-1e23-b0e4-f694d557031f\", \"lease_id\":\r\n \"\", \"renewable\":\r\n false, \"lease_duration\":\r\n 0, \"data\":\r\n null, \"wrap_info\":\r\n null, \"warnings\":\r\n [ \"Endpoint replaced the value of these parameters with the values captured from the endpoint's path: [username]\" ], \"auth\":\r\n {\r\n \"client_token\":\r\n \"hvs.CAESIHR511IiIwmAXLTrXQnLJ0Pq-NHQYgfiv4m1ZYVQHVt_Gh4KHGh2cy5HRTZidHZ0b0s3NzE5UG41cE10aUtrQjg\", \"accessor\":\r\n \"fYX782sU7MPQH2Xhf8q0BfSP\", \"policies\":\r\n [ \"default\", \"inf-icinga.ro\" ], \"token_policies\":\r\n [ \"default\", \"inf-icinga.ro\" ], \"metadata\":\r\n {\r\n \"username\":\r\n \"hcvaultuser\"\r\n }, \"lease_duration\":\r\n 604800, \"renewable\":\r\n true, \"entity_id\":\r\n \"cc0f1543-6838-46d1-c97e-d61a5899fc9b\", \"token_type\":\r\n \"service\", \"orphan\":\r\n true, \"mfa_requirement\":\r\n null, \"num_uses\":\r\n 0\r\n }\r\n}", + "latency": 0, + "statusCode": 200, + "label": "if password ok", + "headers": [], + "bodyType": "INLINE", + "filePath": "", + "databucketID": "", + "sendFileAsBody": false, + "rules": [ + { + "target": "body", + "modifier": "password", + "value": "secrethashicorpPassword", + "invert": false, + "operator": "equals" + }, + { + "target": "body", + "modifier": "username", + "value": "hcvaultuser", + "invert": false, + "operator": "equals" + } + ], + "rulesOperator": "AND", + "disableTemplating": false, + "fallbackTo404": false, + "default": false + }, + { + "uuid": "21593d10-e496-4a39-ac84-0ef9e0de6bbf", + "body": "{\r\n \"errors\": [\r\n \"wrong user/password\"\r\n ]\r\n}", + "latency": 0, + "statusCode": 401, + "label": "error", + "headers": [], + "bodyType": "INLINE", + "filePath": "", + "databucketID": "", + "sendFileAsBody": false, + "rules": [], + "rulesOperator": "OR", + "disableTemplating": false, + "fallbackTo404": false, + "default": true + } + ], + "enabled": true, + "responseMode": null + } + ], + "rootChildren": [ + { + "type": "route", + "uuid": "6b8dd80b-3ea0-48c0-8e9d-609d618e980e" + }, + { + "type": "route", + "uuid": "8fdb70c1-a874-40eb-8b9f-542dca268992" + }, + { + "type": "route", + "uuid": "8ef8c935-ff40-4817-8211-52cc1d0c64b4" + }, + { + "type": "route", + "uuid": "2686745a-9783-4b64-9376-068c159aa725" + } + ], + "proxyMode": false, + "proxyHost": "", + "proxyRemovePrefix": false, + "tlsOptions": { + "enabled": false, + "type": "CERT", + "pfxPath": "", + "certPath": "", + "keyPath": "", + "caPath": "", + "passphrase": "" + }, + "cors": true, + "headers": [ + { + "key": "Content-Type", + "value": "application/json" + } + ], + "proxyReqHeaders": [ + { + "key": "", + "value": "" + } + ], + "proxyResHeaders": [ + { + "key": "", + "value": "" + } + ], + "data": [] +} \ No newline at end of file diff --git a/tests/robot/cloud/aws/cloudtrail/cloud-aws-cloudtrail.json b/tests/robot/cloud/aws/cloudtrail/cloud-aws-cloudtrail.json deleted file mode 100644 index fc680bb46..000000000 --- a/tests/robot/cloud/aws/cloudtrail/cloud-aws-cloudtrail.json +++ /dev/null @@ -1,133 +0,0 @@ -{ - "uuid": "e59ad81e-2050-480d-bbae-0e71c607c927", - "lastMigration": 32, - "name": "Aws cloudtrail", - "endpointPrefix": "", - "latency": 0, - "port": 3000, - "hostname": "", - "folders": [], - "routes": [ - { - "uuid": "b5e25f3a-a8e3-4128-9e45-f2654c5a599d", - "type": "http", - "documentation": "", - "method": "post", - "endpoint": "cloudtrail/gettrailstatus/:islogging", - "responses": [ - { - "uuid": "76483999-2022-4610-8e8c-9c0bd535e4c5", - "body": "{\r\n \"IsLogging\": {{ urlParam 'islogging' 'true' }},\r\n \"LatestCloudWatchLogsDeliveryError\": \"error\",\r\n \"LatestCloudWatchLogsDeliveryTime\": 1683298944.125,\r\n \"LatestDeliveryAttemptSucceeded\": \"2023-05-05T15:02:24Z\",\r\n \"LatestDeliveryAttemptTime\": \"2023-05-05T15:02:24Z\",\r\n \"LatestDeliveryError\": \"error\",\r\n \"LatestDeliveryTime\": 1683298944.125,\r\n \"LatestDigestDeliveryError\": \"error\",\r\n \"LatestDigestDeliveryTime\": 1683298944.125,\r\n \"LatestNotificationAttemptSucceeded\": \"2023-05-05T15:02:24Z\",\r\n \"LatestNotificationAttemptTime\": \"2023-05-05T15:02:24Z\",\r\n \"LatestNotificationError\": \"error\",\r\n \"LatestNotificationTime\": 1683298944.125,\r\n \"StartLoggingTime\": 1683298944.125,\r\n \"StopLoggingTime\": 1683298477.918,\r\n \"TimeLoggingStarted\": \"2023-05-05T15:02:24Z\",\r\n \"TimeLoggingStopped\": \"2023-05-05T14:54:37Z\"\r\n}", - "latency": 0, - "statusCode": 200, - "label": "", - "headers": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "bodyType": "INLINE", - "filePath": "", - "databucketID": "", - "sendFileAsBody": false, - "rules": [], - "rulesOperator": "OR", - "disableTemplating": false, - "fallbackTo404": false, - "default": true, - "crudKey": "id", - "callbacks": [] - } - ], - "responseMode": null - }, - { - "uuid": "77f82f1c-b06e-478a-8366-ab325830f00e", - "type": "http", - "documentation": "", - "method": "post", - "endpoint": "cloudtrail/events/AwsApiCall/:AwsApiCall/AwsServiceEvent/:AwsServiceEvent/AwsConsoleAction/:AwsConsoleAction/AwsConsoleSignIn/:AwsConsoleSignIn/NextToken/:NextToken", - "responses": [ - { - "uuid": "7dd41177-8d63-458a-abcc-b3af3ea8c9cd", - "body": "{\r\n\t\"Events\": [\r\n\t\t{{#each (dataRaw 'EventsData')}}\r\n\t\t {{#if (gt @index 0)}}\r\n\t\t ,\r\n\t\t {{/if}}\r\n \t\t{\r\n \t\t\t\"AccessKeyId\": \"{{AccessKeyId}}\",\r\n \t\t\t\"CloudTrailEvent\": \"{\\\"awsRegion\\\": \\\"eu-west-1\\\", {{#if Error}}\\\"errorCode\\\": \\\"{{ErrorCode}}\\\", \\\"errorMessage\\\": \\\"{{ErrorMessage}}\\\",{{/if}} \\\"eventCategory\\\": \\\"Management\\\", \\\"eventID\\\": \\\"{{EventId}}\\\", \\\"eventName\\\": \\\"{{EventName}}\\\", \\\"eventSource\\\": \\\"{{EventSource}}\\\", \\\"eventTime\\\": \\\"{{EventTime}}\\\", \\\"eventType\\\": \\\"{{EventType}}\\\", \\\"eventVersion\\\": \\\"1.08\\\", \\\"managementEvent\\\": true, \\\"readOnly\\\": true, \\\"recipientAccountId\\\": \\\"{{AccountId}}\\\", \\\"requestID\\\": \\\"{{ faker 'string.uuid' }}\\\", \\\"requestParameters\\\": null, \\\"responseElements\\\": null, \\\"sourceIPAddress\\\": \\\"{{ faker 'internet.ip' }}\\\", \\\"tlsDetails\\\": {\\\"cipherSuite\\\": \\\"ECDHE-RSA-AES128-GCM-SHA256\\\", \\\"clientProvidedHostHeader\\\": \\\"cloudtrail.eu-west-1.amazonaws.com\\\", \\\"tlsVersion\\\": \\\"TLSv1.2\\\"}, \\\"userAgent\\\": \\\"aws-cli/2.11.0 Python/3.11.2 Darwin/22.2.0 source/x86_64 prompt/off command/cloudtrail.lookup-events\\\", \\\"userIdentity\\\": {\\\"accessKeyId\\\": \\\"{{AccessKeyId}}\\\", \\\"accountId\\\": \\\"{{AccountId}}\\\", \\\"arn\\\": \\\"arn:aws:sts::{{AccountId}}:assumed-role/{{UserRole}}/{{UserName}}\\\", \\\"principalId\\\": \\\"{{PrincipalId}}:{{UserName}}\\\", \\\"sessionContext\\\": {\\\"attributes\\\": {\\\"creationDate\\\": \\\"{{ faker 'date.past' EventTime }}\\\", \\\"mfaAuthenticated\\\": \\\"false\\\"}, \\\"sessionIssuer\\\": {\\\"accountId\\\": \\\"{{AccountId}}\\\", \\\"arn\\\": \\\"arn:aws:iam::{{AccountId}}:role/{{UserRole}}\\\", \\\"principalId\\\": \\\"{{PrincipalId}}\\\", \\\"type\\\": \\\"Role\\\", \\\"userName\\\": \\\"{{UserRole}}\\\"}, \\\"webIdFederationData\\\": {}}, \\\"type\\\": \\\"{{ faker 'person.jobArea' }}\\\"}}\",\r\n \t\t\t\"EventId\": \"{{EventId}}\",\r\n \t\t\t\"EventName\": \"{{EventName}}\",\r\n \t\t\t\"EventSource\": \"{{EventSource}}\",\r\n \t\t\t\"EventTime\": \"{{EventTime}}\",\r\n \t\t\t\"ReadOnly\": \"true\",\r\n \t\t\t\"Resources\": [\r\n \t\t\t],\r\n \t\t\t\"Username\": \"{{UserName}}\"\r\n \t\t}\r\n\t\t{{/each}}\r\n\t]\r\n\t{{#if (gte (indexOf (urlParam 'NextToken') 'true' 0) 0)}}\r\n\t {{#unless (includes (stringify (body)) 'NextToken')}}\r\n\t\t ,\"NextToken\": \"{{ faker 'string.alphanumeric' 64 casing='upper' }}\"\r\n\t\t{{/unless}}\r\n\t{{/if}}\r\n}", - "latency": 0, - "statusCode": 200, - "label": "", - "headers": [], - "bodyType": "INLINE", - "filePath": "", - "databucketID": "c5kh", - "sendFileAsBody": false, - "rules": [], - "rulesOperator": "OR", - "disableTemplating": false, - "fallbackTo404": false, - "default": true, - "crudKey": "id", - "callbacks": [] - } - ], - "responseMode": null - } - ], - "rootChildren": [ - { - "type": "route", - "uuid": "b5e25f3a-a8e3-4128-9e45-f2654c5a599d" - }, - { - "type": "route", - "uuid": "77f82f1c-b06e-478a-8366-ab325830f00e" - } - ], - "proxyMode": false, - "proxyHost": "", - "proxyRemovePrefix": false, - "tlsOptions": { - "enabled": false, - "type": "CERT", - "pfxPath": "", - "certPath": "", - "keyPath": "", - "caPath": "", - "passphrase": "" - }, - "cors": true, - "headers": [ - { - "key": "Content-Type", - "value": "application/json" - } - ], - "proxyReqHeaders": [ - { - "key": "", - "value": "" - } - ], - "proxyResHeaders": [ - { - "key": "", - "value": "" - } - ], - "data": [ - { - "uuid": "5dce6340-bade-4336-8041-50fd22570055", - "id": "nu28", - "name": "EventsTypeData", - "documentation": "", - "value": "[\n {\n \"name\": \"AwsApiCall\",\n \"error\": false\n },\n {\n \"name\": \"AwsServiceEvent\",\n \"error\": false\n },\n {\n \"name\": \"AwsConsoleAction\",\n \"error\": true,\n \t\"errorCode\": \"ThrottlingException\",\n \t\"errorMessage\": \"Rate exceeded error\"\n },\n {\n \"name\": \"AwsConsoleSignIn\",\n \"error\": true,\n \"errorCode\": \"LoginErrorException\",\n \"errorMessage\": \"Login error\"\n }\n]" - }, - { - "uuid": "76dec2a5-ff63-4e81-9611-94b900ab16e1", - "id": "c5kh", - "name": "EventsData", - "documentation": "", - "value": "[\n {{#each (dataRaw 'EventsTypeData')}}\n {{#if (gte @isEvent 1)}}\n ,\n {{/if}}\n {{setVar 'isEvent' (add (urlParam name) @isEvent)}}\n {{#repeat (urlParam name comma=true)}}\n {\n \"AccessKeyId\": \"{{ faker 'string.alphanumeric' 20 casing='upper' }}\",\n \"AccountId\": \"{{ faker 'string.numeric' 12 }}\",\n \"Error\": {{error}},\n {{#if error}}\n \"ErrorCode\": \"{{errorCode}}\",\n\t \"ErrorMessage\": \"{{errorMessage}}\",\n {{/if}}\n \"EventId\": \"{{ faker 'string.uuid' }}\",\n \"EventName\": \"{{oneOf (array 'LookupEvents' 'ListInstanceAssociations' 'AssumeRoleWithWebIdentity')}}\",\n \"EventSource\": \"{{oneOf (array 'cloudtrail.amazonaws.com' 'ssm.amazonaws.com' 'sts.amazonaws.com')}}\",\n \"EventTime\": \"{{ faker 'date.recent' }}\",\n \"EventType\": \"{{name}}\",\n \"PrincipalId\": \"{{ faker 'string.alphanumeric' 20 casing='upper' }}\",\n \"UserName\": \"{{ faker 'internet.userName' }}\",\n \"UserRole\": \"{{ faker 'person.jobType' }}\"\n }\n {{/repeat}}\n {{/each}}\n]" - } - ], - "callbacks": [] -} \ No newline at end of file diff --git a/tests/robot/cloud/aws/cloudtrail/cloud-aws-cloudtrail.robot b/tests/robot/cloud/aws/cloudtrail/cloud-aws-cloudtrail.robot deleted file mode 100644 index 97bdea7ea..000000000 --- a/tests/robot/cloud/aws/cloudtrail/cloud-aws-cloudtrail.robot +++ /dev/null @@ -1,194 +0,0 @@ -*** Settings *** -Documentation AWS CloudTrail plugin - -Resource ${CURDIR}${/}..${/}..${/}..${/}..${/}resources/import.resource - -Suite Setup Start Mockoon ${MOCKOON_JSON} -Suite Teardown Stop Mockoon -Test Timeout 120s - - -*** Variables *** -${MOCKOON_JSON} ${CURDIR}${/}cloud-aws-cloudtrail.json - -${CMD} ${CENTREON_PLUGINS} --plugin=cloud::aws::cloudtrail::plugin --custommode=paws --region=eu-west --aws-secret-key=secret --aws-access-key=key - -&{checktrailstatus_value1} -... trailstatus=true -... trailname=TrailName -... result=OK: Trail is logging: 1 | 'trail_is_logging'=1;;;0; -&{checktrailstatus_value2} -... trailstatus=false -... trailname=TrailName -... result=CRITICAL: Trail is logging: 0 | 'trail_is_logging'=0;;;0; -@{checktrailstatus_values} &{checktrailstatus_value1} &{checktrailstatus_value2} - -&{countevents_value1} -... AwsApiCall=4 -... AwsServiceEvent=2 -... AwsConsoleAction=1 -... AwsConsoleSignIn=3 -... NextToken=false -... eventtype= -... delta= -... errormessage= -... warningcount= -... criticalcount= -... result=OK: Number of events: 10.00 | 'events_count'=10.00;;;0; -&{countevents_value2} -... AwsApiCall=4 -... AwsServiceEvent=2 -... AwsConsoleAction=1 -... AwsConsoleSignIn=3 -... NextToken=true -... eventtype= -... delta= -... errormessage= -... warningcount= -... criticalcount= -... result=OK: Number of events: 20.00 | 'events_count'=20.00;;;0; -&{countevents_value3} -... AwsApiCall=4 -... AwsServiceEvent=2 -... AwsConsoleAction=1 -... AwsConsoleSignIn=3 -... NextToken=false -... eventtype=AwsApiCall -... delta= -... errormessage= -... warningcount= -... criticalcount= -... result=OK: Number of events: 4.00 | 'events_count'=4.00;;;0; -&{countevents_value4} -... AwsApiCall=4 -... AwsServiceEvent=2 -... AwsConsoleAction=1 -... AwsConsoleSignIn=3 -... NextToken=true -... eventtype=AwsServiceEvent -... delta= -... errormessage= -... warningcount= -... criticalcount= -... result=OK: Number of events: 4.00 | 'events_count'=4.00;;;0; -&{countevents_value5} -... AwsApiCall=4 -... AwsServiceEvent=2 -... AwsConsoleAction=1 -... AwsConsoleSignIn=3 -... NextToken=false -... eventtype=AwsApiCall -... delta=10 -... errormessage= -... warningcount= -... criticalcount= -... result=OK: Number of events: 4.00 | 'events_count'=4.00;;;0; -&{countevents_value6} -... AwsApiCall=4 -... AwsServiceEvent=2 -... AwsConsoleAction=1 -... AwsConsoleSignIn=3 -... NextToken=false -... eventtype= -... delta= -... errormessage='Login error' -... warningcount= -... criticalcount= -... result=OK: Number of events: 3.00 | 'events_count'=3.00;;;0; -&{countevents_value7} -... AwsApiCall=4 -... AwsServiceEvent=2 -... AwsConsoleAction=1 -... AwsConsoleSignIn=3 -... NextToken=false -... eventtype= -... delta= -... errormessage='.*error' -... warningcount= -... criticalcount= -... result=OK: Number of events: 4.00 | 'events_count'=4.00;;;0; -&{countevents_value8} -... AwsApiCall=4 -... AwsServiceEvent=2 -... AwsConsoleAction=1 -... AwsConsoleSignIn=3 -... NextToken=false -... eventtype= -... delta= -... errormessage= -... warningcount=3 -... criticalcount= -... result=WARNING: Number of events: 10.00 | 'events_count'=10.00;;;0; -&{countevents_value9} -... AwsApiCall=4 -... AwsServiceEvent=2 -... AwsConsoleAction=1 -... AwsConsoleSignIn=3 -... NextToken=false -... eventtype= -... delta= -... errormessage= -... warningcount= -... criticalcount=5 -... result=CRITICAL: Number of events: 10.00 | 'events_count'=10.00;;;0; -@{countevents_values} -... &{countevents_value1} -... &{countevents_value2} -... &{countevents_value3} -... &{countevents_value4} -... &{countevents_value5} -... &{countevents_value6} -... &{countevents_value7} -... &{countevents_value8} -... &{countevents_value9} - - -*** Test Cases *** -AWS CloudTrail check trail status - [Documentation] Check AWS CloudTrail trail status - [Tags] cloud aws cloudtrail - FOR ${checktrailstatus_value} IN @{checktrailstatus_values} - ${output} Run - ... ${CMD} --mode=checktrailstatus --endpoint=http://localhost:3000/cloudtrail/gettrailstatus/${checktrailstatus_value.trailstatus} --trail-name=${checktrailstatus_value.trailname} - ${output} Strip String ${output} - Should Be Equal As Strings - ... ${output} - ... ${checktrailstatus_value.result} - ... Wrong output result for check trail status of ${checktrailstatus_value}.{\n}Command output:{\n}${output} - END - -AWS CloudTrail count events - [Documentation] Check AWS CloudTrail count events - [Tags] cloud aws cloudtrail - FOR ${countevents_value} IN @{countevents_values} - ${command} Catenate - ... ${CMD} - ... --mode=countevents - ... --endpoint=http://localhost:3000/cloudtrail/events/AwsApiCall/${countevents_value.AwsApiCall}/AwsServiceEvent/${countevents_value.AwsServiceEvent}/AwsConsoleAction/${countevents_value.AwsConsoleAction}/AwsConsoleSignIn/${countevents_value.AwsConsoleSignIn}/NextToken/${countevents_value.NextToken} - ${length} Get Length ${countevents_value.eventtype} - IF ${length} > 0 - ${command} Catenate ${command} --event-type=${countevents_value.eventtype} - END - ${length} Get Length ${countevents_value.delta} - IF ${length} > 0 - ${command} Catenate ${command} --delta=${countevents_value.delta} - END - ${length} Get Length ${countevents_value.errormessage} - IF ${length} > 0 - ${command} Catenate ${command} --error-message=${countevents_value.errormessage} - END - ${length} Get Length ${countevents_value.warningcount} - IF ${length} > 0 - ${command} Catenate ${command} --warning-count=${countevents_value.warningcount} - END - ${length} Get Length ${countevents_value.criticalcount} - IF ${length} > 0 - ${command} Catenate ${command} --critical-count=${countevents_value.criticalcount} - END - ${output} Run ${command} - ${output} Strip String ${output} - Should Be Equal As Strings - ... ${output} - ... ${countevents_value.result} - ... Wrong output result for count events of ${countevents_value}.{\n}Command output:{\n}${output} - END diff --git a/tests/robot/cloud/azure/policyinsights/policystates/cloud-azure-policyinsights-policystates.robot b/tests/robot/cloud/azure/policyinsights/policystates/cloud-azure-policyinsights-policystates.robot index 4e6c274e0..b5f29c723 100644 --- a/tests/robot/cloud/azure/policyinsights/policystates/cloud-azure-policyinsights-policystates.robot +++ b/tests/robot/cloud/azure/policyinsights/policystates/cloud-azure-policyinsights-policystates.robot @@ -12,7 +12,7 @@ Test Timeout 120s ${MOCKOON_JSON} ${CURDIR}${/}cloud-azure-policyinsights-policystates.json ${LOGIN_ENDPOINT} http://localhost:3000/login -${CMD} ${CENTREON_PLUGINS} --plugin=cloud::azure::policyinsights::policystates::plugin --subscription=subscription --tenant=tenant --client-id=client_id --client-secret=secret --login-endpoint=${LOGIN_ENDPOINT} +${CMD} ${CENTREON_PLUGINS} --plugin=cloud::azure::policyinsights::policystates::plugin --subscription=subscription --tenant=tenant --client-id=client_id --client-secret=secret --statefile-dir=/tmp/cache/ --login-endpoint=${LOGIN_ENDPOINT} &{compliance_value1} ... endpoint=http://localhost:3000/ok diff --git a/tests/robot/hardware/devices/camera/avigilon/snmp/memory.robot b/tests/robot/hardware/devices/camera/avigilon/snmp/memory.robot index 5456ec47c..748028e14 100644 --- a/tests/robot/hardware/devices/camera/avigilon/snmp/memory.robot +++ b/tests/robot/hardware/devices/camera/avigilon/snmp/memory.robot @@ -35,4 +35,3 @@ Avigilon camera Memory ${tc}/3 ... 1 ${EMPTY} ${EMPTY} OK: total system memory available: 464.85 KB | 'memory.available'=476004B;;;0; ... 2 5000 ${EMPTY} WARNING: total system memory available: 464.85 KB | 'memory.available'=476004B;0:5000;;0; ... 3 ${EMPTY} 5000 CRITICAL: total system memory available: 464.85 KB | 'memory.available'=476004B;;0:5000;0; - diff --git a/tests/robot/hardware/devices/camera/avigilon/snmp/temperature.robot b/tests/robot/hardware/devices/camera/avigilon/snmp/temperature.robot index d4ca5c318..10ce589f7 100644 --- a/tests/robot/hardware/devices/camera/avigilon/snmp/temperature.robot +++ b/tests/robot/hardware/devices/camera/avigilon/snmp/temperature.robot @@ -39,4 +39,3 @@ Avigilon camera Temperature ${tc}/5 ... 3 ${EMPTY} 20 ${EMPTY} ${EMPTY} CRITICAL: temperature: 23.00 C | 'sensor.temperature.celsius'=23C;;0:20;0; ... 4 ${EMPTY} ${EMPTY} \\%\{status\} =~ /ok/ ${EMPTY} WARNING: sensor 1 [type:mainSensor] status: ok | 'sensor.temperature.celsius'=23C;;;0; ... 5 ${EMPTY} ${EMPTY} ${EMPTY} \\%\{status\} =~ /ok/ CRITICAL: sensor 1 [type:mainSensor] status: ok | 'sensor.temperature.celsius'=23C;;;0; - diff --git a/tests/robot/hardware/kvm/avocent/acs/8000/hardware-kvm-avocent-acs-8000.robot b/tests/robot/hardware/kvm/avocent/acs/8000/hardware-kvm-avocent-acs-8000.robot index fc600c081..80c050225 100644 --- a/tests/robot/hardware/kvm/avocent/acs/8000/hardware-kvm-avocent-acs-8000.robot +++ b/tests/robot/hardware/kvm/avocent/acs/8000/hardware-kvm-avocent-acs-8000.robot @@ -18,14 +18,14 @@ Cpu-Detailed [Documentation] cpu-detailed mode [Tags] hardware kvm avocent cpu snmp Remove File /dev/shm/snmpstandard_127.0.0.1_2024_cpu-detailed* - ${output} Run Avocent 8000 Plugin "cpu-detailed" --statefile-dir=/dev/shm/ + ${output} Run Avocent 8000 Plugin "cpu-detailed" --statefile-dir=/tmp/cache/ ${output} Strip String ${output} Should Be Equal As Strings ... ${output} ... OK: CPU Usage: user : Buffer creation, nice : Buffer creation, system : Buffer creation, idle : Buffer creation, wait : Buffer creation, kernel : Buffer creation, interrupt : Buffer creation, softirq : Buffer creation, steal : Buffer creation, guest : Buffer creation, guestnice : Buffer creation ... Wrong output result for command:{\n}${output}{\n}{\n}{\n} - ${output} Run Avocent 8000 Plugin "cpu-detailed" --statefile-dir=/dev/shm/ + ${output} Run Avocent 8000 Plugin "cpu-detailed" --statefile-dir=/tmp/cache/ ${output} Strip String ${output} Remove File /dev/shm/snmpstandard_127.0.0.1_2024_cpu-detailed* Should Be Equal As Strings @@ -70,14 +70,14 @@ Serial Ports [Documentation] serial-ports mode [Tags] hardware kvm avocent serial snmp Remove File /dev/shm/avocent_acs_8000_127.0.0.1_2024_serial-ports* - ${output} Run Avocent 8000 Plugin "serial-ports" --statefile-dir=/dev/shm/ + ${output} Run Avocent 8000 Plugin "serial-ports" --statefile-dir=/tmp/cache/ ${output} Strip String ${output} Should Be Equal As Strings ... ${output} ... OK: All serial ports are ok ... Wrong output result for command:{\n}${output}{\n}{\n}{\n} - ${output} Run Avocent 8000 Plugin "serial-ports" --statefile-dir=/dev/shm/ + ${output} Run Avocent 8000 Plugin "serial-ports" --statefile-dir=/tmp/cache/ ${output} Strip String ${output} Remove File /dev/shm/avocent_acs_8000_127.0.0.1_2024_serial-ports* Should Be Equal As Strings diff --git a/tests/robot/network/citrix/netscaler/snmp/mode/components/netscaler-health.robot b/tests/robot/network/citrix/netscaler/snmp/mode/components/netscaler-health.robot index 06e56300b..127ae7db0 100644 --- a/tests/robot/network/citrix/netscaler/snmp/mode/components/netscaler-health.robot +++ b/tests/robot/network/citrix/netscaler/snmp/mode/components/netscaler-health.robot @@ -7,7 +7,8 @@ Test Timeout 120s *** Variables *** -${CMD} ${CENTREON_PLUGINS} --plugin=network::citrix::netscaler::snmp::plugin +${CMD} ${CENTREON_PLUGINS} --plugin=network::citrix::netscaler::snmp::plugin + *** Test Cases *** check psu components ${tc}/2 @@ -32,5 +33,3 @@ check psu components ${tc}/2 Examples: tc alternative_status_mapping community expected_result -- ... 1 true psu-citrix-v13 OK: All 4 components are ok [4/4 psus]. | 'count_psu'=4;;;; ... 2 ${EMPTY} psu-citrix-v13 UNKNOWN: Power supply '1' status is 'not supported' - Power supply '2' status is 'not supported' - Power supply '3' status is 'not supported' - Power supply '4' status is 'not supported' | 'count_psu'=4;;;; - - diff --git a/tests/robot/os/linux/snmp/network-interfaces.robot b/tests/robot/os/linux/snmp/network-interfaces.robot index 3c292d0dc..1284ef19a 100644 --- a/tests/robot/os/linux/snmp/network-interfaces.robot +++ b/tests/robot/os/linux/snmp/network-interfaces.robot @@ -13,7 +13,7 @@ ${CMD} ${CENTREON_PLUGINS} ... --hostname=127.0.0.1 ... --snmp-port=2024 ... --snmp-community=os/linux/snmp/network-interfaces -... --statefile-dir=/tmp/ +... --statefile-dir=/tmp/cache/ ${COND} ${PERCENT}\{sub\} =~ /exited/ && ${PERCENT}{display} =~ /network/' diff --git a/tests/robot/os/linux/snmp/os-linux-snmp.robot b/tests/robot/os/linux/snmp/os-linux-snmp.robot index 1000d7acb..de69eb79a 100644 --- a/tests/robot/os/linux/snmp/os-linux-snmp.robot +++ b/tests/robot/os/linux/snmp/os-linux-snmp.robot @@ -32,7 +32,7 @@ Linux SNMP list diskio devices ... --snmp-version=2 ... --snmp-port=2024 ... --disco-show - ${command} Catenate ${command} --snmp-community=${list_diskio_test.snmpcommunity} + ... --snmp-community=${list_diskio_test.snmpcommunity} ${output} Run ${command} Log To Console ${command} ${nb_results} Get Element Count diff --git a/tests/robot/storage/datacore/restapi/storage-datacore-api.json b/tests/robot/storage/datacore/restapi/storage-datacore-api.json index 15938230b..666ee89e8 100644 --- a/tests/robot/storage/datacore/restapi/storage-datacore-api.json +++ b/tests/robot/storage/datacore/restapi/storage-datacore-api.json @@ -41,7 +41,7 @@ "type": "http", "documentation": "", "method": "get", - "endpoint": "RestService/rest.svc/1.0/performances/B5C140F5-6B13-4CAD-AF9D-F7C4172B3A1D:%7B4dec1b5a-2577-11e5-80c3-00155d651622%7D", + "endpoint": "RestService/rest.svc/1.0/performance/B5C140F5-6B13-4CAD-AF9D-F7C4172B3A1D:%7B4dec1b5a-2577-11e5-80c3-00155d651622%7D", "responses": [ { "uuid": "a5bf53e2-5edf-437e-a684-68315cfa7824",