From fefa587f63ba2685da537e91f6184106a87e88a9 Mon Sep 17 00:00:00 2001 From: sfarouq-ext <116093375+sfarouq-ext@users.noreply.github.com> Date: Tue, 24 Jun 2025 16:17:18 +0200 Subject: [PATCH] Ensure my changes work correctly with GitHub integration --- .../testing/Dockerfile.testing-plugins-alma8 | 8 +- .../testing/Dockerfile.testing-plugins-alma9 | 11 +- .../Dockerfile.testing-plugins-bookworm | 20 +- .../Dockerfile.testing-plugins-bullseye | 16 +- .../testing/Dockerfile.testing-plugins-jammy | 17 +- .../testing/Dockerfile.testing-plugins-noble | 15 +- tests/os/linux/snmp/arp-connector.robot | 38 ++++ tests/os/linux/snmp/cpu-connector.robot | 38 ++++ tests/resources/connector.py | 183 ++++++++++++++++++ tests/resources/import.resource | 3 + tests/resources/resources.resource | 17 ++ 11 files changed, 352 insertions(+), 14 deletions(-) create mode 100644 tests/os/linux/snmp/arp-connector.robot create mode 100644 tests/os/linux/snmp/cpu-connector.robot create mode 100644 tests/resources/connector.py diff --git a/.github/docker/testing/Dockerfile.testing-plugins-alma8 b/.github/docker/testing/Dockerfile.testing-plugins-alma8 index 71abc1608..2f9d73501 100644 --- a/.github/docker/testing/Dockerfile.testing-plugins-alma8 +++ b/.github/docker/testing/Dockerfile.testing-plugins-alma8 @@ -60,9 +60,15 @@ gpgcheck=1\n\ gpgkey=https://yum-gpg.centreon.com/RPM-GPG-KEY-CES\n'\ >> /etc/yum.repos.d/centreon-plugins.repo +dnf config-manager --add-repo https://packages.centreon.com/rpm-standard/24.10/el8/centreon-24.10.repo +dnf update -y +dnf install -y centreon-connector-perl +dnf install -y centreon-clib +dnf clean all --enablerepo=* + mkdir -p /var/lib/centreon/centplugins/ chmod 777 /var/lib/centreon/centplugins/ dnf clean all -EOF +EOF \ No newline at end of file diff --git a/.github/docker/testing/Dockerfile.testing-plugins-alma9 b/.github/docker/testing/Dockerfile.testing-plugins-alma9 index 95edbe764..8371fe745 100644 --- a/.github/docker/testing/Dockerfile.testing-plugins-alma9 +++ b/.github/docker/testing/Dockerfile.testing-plugins-alma9 @@ -59,9 +59,18 @@ gpgcheck=1\n\ gpgkey=https://yum-gpg.centreon.com/RPM-GPG-KEY-CES\n'\ >> /etc/yum.repos.d/centreon-plugins.repo +# Add Centreon plugins repositories +dnf config-manager --add-repo https://packages.centreon.com/rpm-standard/24.10/el9/centreon-24.10.repo +dnf update -y +dnf clean all --enablerepo=* +dnf install -y centreon-connector-perl +dnf install -y centreon-clib + +dnf update -y + mkdir -p /var/lib/centreon/centplugins/ chmod 777 /var/lib/centreon/centplugins/ dnf clean all -EOF +EOF \ No newline at end of file diff --git a/.github/docker/testing/Dockerfile.testing-plugins-bookworm b/.github/docker/testing/Dockerfile.testing-plugins-bookworm index 48d6e0022..a1a4a936e 100644 --- a/.github/docker/testing/Dockerfile.testing-plugins-bookworm +++ b/.github/docker/testing/Dockerfile.testing-plugins-bookworm @@ -7,8 +7,13 @@ ENV DEBIAN_FRONTEND=noninteractive # fix locale RUN bash -e < /dev/null 2>&1 + +# Update apt-get update +apt-get install -y centreon-clib centreon-connector-perl centreon-plugins + +rm -f /etc/apt/sources.list.d/centreon.list + mkdir -p /var/lib/centreon/centplugins/ chmod 777 /var/lib/centreon/centplugins/ apt-get clean -EOF +EOF \ No newline at end of file diff --git a/.github/docker/testing/Dockerfile.testing-plugins-bullseye b/.github/docker/testing/Dockerfile.testing-plugins-bullseye index 87700be3a..7fa6d943a 100644 --- a/.github/docker/testing/Dockerfile.testing-plugins-bullseye +++ b/.github/docker/testing/Dockerfile.testing-plugins-bullseye @@ -7,8 +7,13 @@ ENV DEBIAN_FRONTEND=noninteractive # fix locale RUN bash -e < /dev/null 2>&1 apt-get update +apt-get install -y centreon-clib centreon-connector-perl + +rm -f /etc/apt/sources.list.d/centreon.list + mkdir -p /var/lib/centreon/centplugins/ chmod 777 /var/lib/centreon/centplugins/ apt-get clean - -EOF +EOF \ No newline at end of file diff --git a/.github/docker/testing/Dockerfile.testing-plugins-jammy b/.github/docker/testing/Dockerfile.testing-plugins-jammy index 7519cd710..5df89624c 100644 --- a/.github/docker/testing/Dockerfile.testing-plugins-jammy +++ b/.github/docker/testing/Dockerfile.testing-plugins-jammy @@ -7,8 +7,13 @@ ENV DEBIAN_FRONTEND=noninteractive # fix locale RUN bash -e < /dev/null 2>&1 apt-get update +apt-get install -y centreon-clib centreon-connector-perl + +rm -f /etc/apt/sources.list.d/centreon.list + mkdir -p /var/lib/centreon/centplugins/ chmod 777 /var/lib/centreon/centplugins/ apt-get clean -EOF +EOF \ No newline at end of file diff --git a/.github/docker/testing/Dockerfile.testing-plugins-noble b/.github/docker/testing/Dockerfile.testing-plugins-noble index 4b89178e3..b9d61d3d5 100644 --- a/.github/docker/testing/Dockerfile.testing-plugins-noble +++ b/.github/docker/testing/Dockerfile.testing-plugins-noble @@ -7,8 +7,13 @@ ENV DEBIAN_FRONTEND=noninteractive # fix locale RUN bash -e < /dev/null 2>&1 apt-get update +apt-get install -y centreon-clib centreon-connector-perl + mkdir -p /var/lib/centreon/centplugins/ chmod 777 /var/lib/centreon/centplugins/ apt-get clean -EOF +EOF \ No newline at end of file diff --git a/tests/os/linux/snmp/arp-connector.robot b/tests/os/linux/snmp/arp-connector.robot new file mode 100644 index 000000000..d885e3824 --- /dev/null +++ b/tests/os/linux/snmp/arp-connector.robot @@ -0,0 +1,38 @@ +*** Settings *** +Documentation Check arp table + +Resource ${CURDIR}${/}..${/}..${/}..${/}resources/import.resource + +Suite Setup Ctn Generic Suite Setup +Test Timeout 120s + + +*** Variables *** +${CMD} /usr/lib/centreon/plugins/centreon_linux_snmp.pl --plugin=os::linux::snmp::plugin + + +*** Test Cases *** +arp-connectors ${tc} + [Tags] os linux + ${command} Catenate + ... ${CMD} + ... --mode=arp + ... --hostname=${HOSTNAME} + ... --snmp-version=${SNMPVERSION} + ... --snmp-port=${SNMPPORT} + ... --snmp-community=os/linux/snmp/network-interfaces + ... --snmp-timeout=1 + ... ${extra_options} + + Ctn Run Command With Connector And Check Result As Strings ${tc} ${command} ${expected_result} + + Examples: tc extra_options expected_result -- + ... 1 --filter-macaddr OK: total entries 3 - duplicate mac address 0 - duplicate ip address 0 | 'arp.total.entries.count'=3;;;0; 'arp.duplicate.macaddr.count'=0;;;0; 'arp.duplicate.ipaddr.count'=0;;;0; + ... 2 --filter-ipaddr OK: total entries 3 - duplicate mac address 0 - duplicate ip address 0 | 'arp.total.entries.count'=3;;;0; 'arp.duplicate.macaddr.count'=0;;;0; 'arp.duplicate.ipaddr.count'=0;;;0; + ... 3 --warning-total-entries OK: total entries 3 - duplicate mac address 0 - duplicate ip address 0 | 'arp.total.entries.count'=3;;;0; 'arp.duplicate.macaddr.count'=0;;;0; 'arp.duplicate.ipaddr.count'=0;;;0; + ... 4 --critical-total-entries OK: total entries 3 - duplicate mac address 0 - duplicate ip address 0 | 'arp.total.entries.count'=3;;;0; 'arp.duplicate.macaddr.count'=0;;;0; 'arp.duplicate.ipaddr.count'=0;;;0; + ... 5 --critical-duplicate-ipaddr OK: total entries 3 - duplicate mac address 0 - duplicate ip address 0 | 'arp.total.entries.count'=3;;;0; 'arp.duplicate.macaddr.count'=0;;;0; 'arp.duplicate.ipaddr.count'=0;;;0; + ... 6 --critical-duplicate-macaddr OK: total entries 3 - duplicate mac address 0 - duplicate ip address 0 | 'arp.total.entries.count'=3;;;0; 'arp.duplicate.macaddr.count'=0;;;0; 'arp.duplicate.ipaddr.count'=0;;;0; + ... 7 --warning-duplicate-ipaddr OK: total entries 3 - duplicate mac address 0 - duplicate ip address 0 | 'arp.total.entries.count'=3;;;0; 'arp.duplicate.macaddr.count'=0;;;0; 'arp.duplicate.ipaddr.count'=0;;;0; + ... 8 --warning-duplicate-macaddr OK: total entries 3 - duplicate mac address 0 - duplicate ip address 0 | 'arp.total.entries.count'=3;;;0; 'arp.duplicate.macaddr.count'=0;;;0; 'arp.duplicate.ipaddr.count'=0;;;0; + ... 9 ${EMPTY} OK: total entries 3 - duplicate mac address 0 - duplicate ip address 0 | 'arp.total.entries.count'=3;;;0; 'arp.duplicate.macaddr.count'=0;;;0; 'arp.duplicate.ipaddr.count'=0;;;0; diff --git a/tests/os/linux/snmp/cpu-connector.robot b/tests/os/linux/snmp/cpu-connector.robot new file mode 100644 index 000000000..9dcc42f8d --- /dev/null +++ b/tests/os/linux/snmp/cpu-connector.robot @@ -0,0 +1,38 @@ +*** Settings *** +Documentation Check cpu table + + +Resource ${CURDIR}${/}..${/}..${/}..${/}resources/import.resource + +Suite Setup Ctn Generic Suite Setup +Test Timeout 120s + + +*** Variables *** +${CMD} /usr/lib/centreon/plugins/centreon_linux_snmp.pl --plugin=os::linux::snmp::plugin + + +*** Test Cases *** +cpu-connector ${tc} + [Tags] os linux + ${command} Catenate + ... ${CMD} + ... --mode=cpu + ... --hostname=${HOSTNAME} + ... --snmp-version=${SNMPVERSION} + ... --snmp-port=${SNMPPORT} + ... --snmp-community=os/linux/snmp/network-interfaces + ... ${extra_options} + + Ctn Run Command With Connector And Check Result As Strings ${tc} ${command} ${expected_result} + + Examples: tc extra_options expected_result -- + ... 1 --use-ucd='0' OK: 1 CPU(s) average usage is 2.00 % - CPU '0' usage : 2.00 % | 'total_cpu_avg'=2.00%;;;0;100 'cpu'=2.00%;;;0;100 + ... 2 --warning-average OK: 1 CPU(s) average usage is 2.00 % - CPU '0' usage : 2.00 % | 'total_cpu_avg'=2.00%;;;0;100 'cpu'=2.00%;;;0;100 + ... 3 --critical-average OK: 1 CPU(s) average usage is 2.00 % - CPU '0' usage : 2.00 % | 'total_cpu_avg'=2.00%;;;0;100 'cpu'=2.00%;;;0;100 + ... 4 --warning-core OK: 1 CPU(s) average usage is 2.00 % - CPU '0' usage : 2.00 % | 'total_cpu_avg'=2.00%;;;0;100 'cpu'=2.00%;;;0;100 + ... 5 --critical-core OK: 1 CPU(s) average usage is 2.00 % - CPU '0' usage : 2.00 % | 'total_cpu_avg'=2.00%;;;0;100 'cpu'=2.00%;;;0;100 + ... 6 --warning-average='0' WARNING: 1 CPU(s) average usage is 2.00 % | 'total_cpu_avg'=2.00%;0:0;;0;100 'cpu'=2.00%;;;0;100 + ... 7 --critical-average='0' CRITICAL: 1 CPU(s) average usage is 2.00 % | 'total_cpu_avg'=2.00%;;0:0;0;100 'cpu'=2.00%;;;0;100 + ... 8 --warning-core='0' WARNING: CPU '0' usage : 2.00 % | 'total_cpu_avg'=2.00%;;;0;100 'cpu'=2.00%;0:0;;0;100 + ... 9 --critical-core='0' CRITICAL: CPU '0' usage : 2.00 % | 'total_cpu_avg'=2.00%;;;0;100 'cpu'=2.00%;;0:0;0;100 diff --git a/tests/resources/connector.py b/tests/resources/connector.py new file mode 100644 index 000000000..85cdcb788 --- /dev/null +++ b/tests/resources/connector.py @@ -0,0 +1,183 @@ +import subprocess +import time +import os +from robot.api.deco import keyword +import re + +connector = None + +class ConnectorLibrary: + def __init__(self): + self.process = None + + def start_connector(self, command=["/usr/lib64/centreon-connector/centreon_connector_perl", "--log-file=/tmp/connector.log", "--debug"]): + if self.process is None or self.process.poll() is not None: + self.process = subprocess.Popen( + command, + stdin=subprocess.PIPE, + stdout=subprocess.PIPE, # Capture stdout! + text=True + ) + print("Connector started") + + def send_to_connector(self, idf: int, command: str, timeout: int, command_log="/tmp/connector.commands.log"): + now = int(time.time()) + + # Log to console + print(f"[Connector] Sending command (id={idf}, timeout={timeout}): {command}") + + # Log to file + try: + with open(command_log, "a") as logf: + logf.write(f"{time.strftime('%Y-%m-%d %H:%M:%S')} id={idf} timeout={timeout} command={command}\n") + except Exception as e: + print(f"[Connector] Could not write to command log file: {e}") + + buf = bytearray() + buf.extend(b"2\0") + buf.extend(f"{idf}\0".encode('utf-8')) + buf.extend(f"{timeout}\0".encode('utf-8')) + buf.extend(f"{now}\0".encode('utf-8')) + buf.extend(f"{command}\0\0\0\0".encode('utf-8')) + + if self.process and self.process.stdin: + self.process.stdin.write(buf.decode('utf-8')) + self.process.stdin.flush() + else: + raise RuntimeError("Connector is not running.") + + def write_next_output_to_file(self, output_file="/tmp/connector.output"): + """ + Reads the next line from the connector's stdout and appends it to output_file. + """ + if self.process and self.process.stdout: + line = self.process.stdout.readline() + if line: + with open(output_file, "a") as f: + f.write(line) + return line + return None + + def stop_connector(self): + if self.process: + self.process.terminate() + self.process = None + print("Connector stopped") + +def wait_for_output_file(output_file="/tmp/connector.output", timeout=10, poll_interval=0.2): + end_time = time.time() + timeout + while time.time() < end_time: + if os.path.exists(output_file): + return True + time.sleep(poll_interval) + raise FileNotFoundError(f"Output file {output_file} not found after {timeout} seconds") + +def read_from_output_file(idf: int, output_file="/tmp/connector.output", wait_timeout=10): + wait_for_output_file(output_file, wait_timeout) + with open(output_file, "r") as f: + lines = f.readlines() + for line in lines: + if line.strip().startswith(str(idf)): + return line.strip().split(" ", 1)[1] + return None + +def start_connector(): + global connector + connector = ConnectorLibrary() + connector.start_connector() + return connector + +def stop_connector(): + global connector + if connector: + connector.stop_connector() + connector = None + else: + print("No connector to stop.") + +def send_to_connector(idf: int, command: str, timeout: int = 5, output_file=None, command_log="/tmp/connector.commands.log"): + global connector + if connector: + connector.send_to_connector(idf, command, timeout, command_log) + # Capture the output line after sending command + output_file = output_file or f"/tmp/connector.output.{idf}" + line = connector.write_next_output_to_file(output_file) + # Copy per-test file to common output + if output_file != "/tmp/connector.output": + import shutil + shutil.copyfile(output_file, "/tmp/connector.output") + return line # Return the actual line written! + else: + raise RuntimeError("Connector is not running.") + + +def wait_for_result(idf: int, timeout: int = 5, poll_interval=0.2): + end_time = time.time() + timeout + while time.time() < end_time: + result = read_from_output_file(idf) + if result: + return result + time.sleep(poll_interval) + raise TimeoutError(f"No result found for id {idf} within {timeout} seconds.") + +def clean_connector_output(line): + if not isinstance(line, str): + line = str(line) + line = line.strip() + print(f"CLEAN DEBUG RAW: {repr(line)}") # This will show hidden chars + # If 'OK:' is in the line, just return everything from 'OK:' onward! + idx = line.find("OK:") + if idx != -1: + cleaned = line[idx:] + else: + # Fallback to regex if 'OK:' not found + cleaned = re.sub(r"^[^\w]*", "", line) + print(f"CLEANED: {repr(cleaned)}") + return cleaned + +def extract_result_from_log(tc, log_path="/tmp/connector.log", output_path=None): + """ + Find the line with 'reporting check result' and the right check id. + Write the 'output:' content to output_path. + """ + with open(log_path, 'r') as f: + for line in f: + # Pattern: reporting check result # ... + m = re.search(r'reporting check result #(\d+).*output:(.*)', line) + if m: + found_id, output = m.group(1), m.group(2).strip() + if str(found_id) == str(tc): + # Write the output to the file + output_path = output_path or f"/tmp/connector.output.{tc}" + with open(output_path, 'w') as out: + out.write(output + "\n") + # Also copy to shared output + if output_path != "/tmp/connector.output": + import shutil + shutil.copyfile(output_path, "/tmp/connector.output") + return output + # If not found, raise or return None + raise Exception(f"No result found for id {tc} in log {log_path}") + +@keyword +def extract_result_from_log(tc, log_path="/tmp/connector.log", output_path=None): + """ + Find the line with 'reporting check result' and the right check id. + Write the 'output:' content to output_path. + """ + import re + with open(log_path, 'r') as f: + for line in f: + m = re.search(r'reporting check result #(\d+).*output:(.*)', line) + if m: + found_id, output = m.group(1), m.group(2).strip() + if str(found_id) == str(tc): + output_path = output_path or f"/tmp/connector.output.{tc}" + with open(output_path, 'w') as out: + out.write(output + "\n") + # Also copy to shared output + if output_path != "/tmp/connector.output": + import shutil + shutil.copyfile(output_path, "/tmp/connector.output") + return output + raise Exception(f"No result found for id {tc} in log {log_path}") \ No newline at end of file diff --git a/tests/resources/import.resource b/tests/resources/import.resource index 0323ec5d4..3519b7d90 100644 --- a/tests/resources/import.resource +++ b/tests/resources/import.resource @@ -8,3 +8,6 @@ Library String Library XML Library Collections Resource resources.resource +Library BuiltIn +Library connector.py +Library Process \ No newline at end of file diff --git a/tests/resources/resources.resource b/tests/resources/resources.resource index c50c74ae8..dbacb6995 100644 --- a/tests/resources/resources.resource +++ b/tests/resources/resources.resource @@ -14,6 +14,7 @@ ${SNMPPORT} 2024 ${SNMPVERSION} 2c ${PERCENT} % ${MOCKOON_LOG_FILE} /tmp/mockoon.log +${TIMEOUT} 30 *** Keywords *** Start Mockoon @@ -53,6 +54,9 @@ Ctn Cleanup Cache Ctn Generic Suite Setup Ctn Cleanup Cache Set Environment Variable TZ UTC + Remove Files /tmp/connector.output.* + Remove File /tmp/connector.log + Start Connector Ctn Run Command And Check Result As Regexp [Arguments] ${command} ${expected_result} @@ -86,6 +90,19 @@ Ctn Verify Command Output ... values=False ... collapse_spaces=True +Ctn Run Command With Connector And Check Result As Strings + [Arguments] ${tc} ${command} ${expected_result} ${timeout}=5 + Remove File /tmp/connector.output + Remove File /tmp/connector.command.log + Send To Connector ${tc} ${command} ${timeout} + # 1. Extract the result from the log and write to /tmp/connector.output + Extract Result From Log ${tc} + # 2. Read the file + ${output} Get File /tmp/connector.output + ${output} Strip String ${output} + # 3. Compare with expected + Should Be Equal As Strings ${output} ${expected_result} + Ctn Run Command And Check Result As Json [Arguments] ${command} ${expected} Log To Console ${command}