test: new test, verify support data collection

Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
Joachim Wiberg
2025-12-02 14:11:00 +01:00
parent d1f053b41c
commit d6721742c4
7 changed files with 256 additions and 0 deletions
+9
View File
@@ -1,4 +1,13 @@
:testgroup:
== Miscellaneous Tests
Tests verifying system utilities and operational features:
- Operational datastore query for all configuration
- Support data collection with work-dir and GPG encryption
include::operational_all/Readme.adoc[]
<<<
include::support_collect/Readme.adoc[]
+3
View File
@@ -2,5 +2,8 @@
- name: Get operational
case: operational_all/test.py
- name: Support data collection
case: support_collect/test.py
#- name: start_from_startup
# case: start_from_startup.py
+1
View File
@@ -0,0 +1 @@
test.adoc
+24
View File
@@ -0,0 +1,24 @@
=== Support data collection
ifdef::topdoc[:imagesdir: {topdoc}../../test/case/misc/support_collect]
==== Description
Verify that the support collect command works and produces a valid tarball
with expected content. Tests both the --work-dir global option and GPG
encryption (when available on target).
==== Topology
image::topology.svg[Support data collection topology, align=center, scaledwidth=75%]
==== Sequence
. Set up topology and attach to target DUT
. Check for GPG availability on target
. Run support collect with --work-dir and short log tail
. Verify tarball was created and is valid
. Run support collect with GPG encryption
. Verify encrypted file and decrypt it
+185
View File
@@ -0,0 +1,185 @@
#!/usr/bin/env python3
"""Support data collection
Verify that the support collect command works and produces a valid tarball
with expected content. Tests both the --work-dir global option and GPG
encryption (when available on target).
"""
import os
import subprocess
import tarfile
import tempfile
import infamy
import infamy.ssh as ssh
with infamy.Test() as test:
with test.step("Set up topology and attach to target DUT"):
env = infamy.Env()
target = env.attach("target", "mgmt")
tgtssh = env.attach("target", "mgmt", "ssh")
with test.step("Check for GPG availability on target"):
result = tgtssh.run("command -v gpg >/dev/null 2>&1", check=False)
has_gpg = (result.returncode == 0)
if has_gpg:
print("GPG is available on target - will test encryption")
else:
print("GPG not available on target - skipping encryption tests")
with test.step("Run support collect with --work-dir and short log tail"):
# Create temporary file for output
with tempfile.NamedTemporaryFile(suffix=".tar.gz", delete=False) as tmp:
output_file = tmp.name
# Use /tmp as work-dir to test the --work-dir option
# Run support collect via SSH with short log tail for testing
# Capture stdout (the tarball) to file
# Note: timeout is generous to handle systems with many network ports
# (ethtool collection scales with number of interfaces)
with open(output_file, 'wb') as f:
result = tgtssh.run("support --work-dir /tmp collect --log-sec 2",
stdout=f,
stderr=subprocess.PIPE,
timeout=120)
if result.returncode != 0:
stderr_output = result.stderr.decode('utf-8') if result.stderr else ""
print(f"support collect failed with return code {result.returncode}")
print(f"stderr: {stderr_output}")
raise Exception("support collect command failed")
with test.step("Verify tarball was created and is valid"):
if not os.path.exists(output_file):
raise Exception(f"Output file {output_file} was not created")
file_size = os.path.getsize(output_file)
if file_size == 0:
raise Exception("Output tarball is empty")
print(f"Tarball created: {file_size} bytes")
# Verify it's a valid tar.gz
try:
with tarfile.open(output_file, 'r:gz') as tar:
members = tar.getnames()
print(f"Tarball contains {len(members)} files/directories")
# Verify some expected files exist
expected_files = [
'collection.log',
'operational-config.json',
'system/dmesg.txt',
'system/meminfo.txt',
'network/ip/addr.json'
]
root_dir = members[0] if members else None
for expected in expected_files:
full_path = f"{root_dir}/{expected}" if root_dir else expected
if full_path not in members:
print(f"Warning: Expected file '{expected}' not found in tarball")
else:
print(f"Found: {expected}")
except tarfile.TarError as e:
raise Exception(f"Invalid tarball: {e}")
finally:
# Clean up
if os.path.exists(output_file):
os.remove(output_file)
if has_gpg:
with test.step("Run support collect with GPG encryption"):
# Create temporary file for encrypted output
with tempfile.NamedTemporaryFile(suffix=".tar.gz.gpg", delete=False) as tmp:
encrypted_file = tmp.name
# Use a test password
test_password = "test-support-password-123"
# Run support collect with encryption
with open(encrypted_file, 'wb') as f:
result = tgtssh.run(f"support --work-dir /tmp collect --log-sec 2 --password {test_password}",
stdout=f,
stderr=subprocess.PIPE,
timeout=120)
if result.returncode != 0:
stderr_output = result.stderr.decode('utf-8') if result.stderr else ""
print(f"support collect with encryption failed: {stderr_output}")
raise Exception("support collect with --password failed")
with test.step("Verify encrypted file and decrypt it"):
if not os.path.exists(encrypted_file):
raise Exception(f"Encrypted output file {encrypted_file} was not created")
file_size = os.path.getsize(encrypted_file)
if file_size == 0:
raise Exception("Encrypted output file is empty")
print(f"Encrypted file created: {file_size} bytes")
# Create temporary file for decrypted output
with tempfile.NamedTemporaryFile(suffix=".tar.gz", delete=False) as tmp:
decrypted_file = tmp.name
try:
# Decrypt the file using gpg
with open(encrypted_file, 'rb') as ef:
with open(decrypted_file, 'wb') as df:
decrypt_result = subprocess.run(
["gpg", "--batch", "--yes", "--passphrase", test_password,
"--pinentry-mode", "loopback", "-d"],
stdin=ef,
stdout=df,
stderr=subprocess.PIPE,
timeout=30
)
if decrypt_result.returncode != 0:
stderr_output = decrypt_result.stderr.decode('utf-8') if decrypt_result.stderr else ""
print(f"GPG decryption failed: {stderr_output}")
raise Exception("Failed to decrypt GPG-encrypted support data")
print("Successfully decrypted GPG file")
# Verify the decrypted file is a valid tarball
with tarfile.open(decrypted_file, 'r:gz') as tar:
members = tar.getnames()
print(f"Decrypted tarball contains {len(members)} files/directories")
# Verify some expected files exist
expected_files = [
'collection.log',
'operational-config.json',
'system/dmesg.txt'
]
root_dir = members[0] if members else None
for expected in expected_files:
full_path = f"{root_dir}/{expected}" if root_dir else expected
if full_path not in members:
print(f"Warning: Expected file '{expected}' not found in decrypted tarball")
else:
print(f"Found in decrypted tarball: {expected}")
except tarfile.TarError as e:
raise Exception(f"Decrypted file is not a valid tarball: {e}")
except subprocess.TimeoutExpired:
raise Exception("GPG decryption timed out")
except FileNotFoundError:
print("Warning: gpg not available on host system - skipping decryption verification")
finally:
# Clean up
if os.path.exists(encrypted_file):
os.remove(encrypted_file)
if os.path.exists(decrypted_file):
os.remove(decrypted_file)
test.succeed()
+1
View File
@@ -0,0 +1 @@
../../../infamy/topologies/1x1.dot
@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN"
"http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Title: 1x1 Pages: 1 -->
<svg width="424pt" height="45pt"
viewBox="0.00 0.00 424.03 45.00" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<g id="graph0" class="graph" transform="scale(1 1) rotate(0) translate(4 41)">
<title>1x1</title>
<polygon fill="white" stroke="transparent" points="-4,4 -4,-41 420.03,-41 420.03,4 -4,4"/>
<!-- host -->
<g id="node1" class="node">
<title>host</title>
<polygon fill="none" stroke="black" points="0,-0.5 0,-36.5 100,-36.5 100,-0.5 0,-0.5"/>
<text text-anchor="middle" x="25" y="-14.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">host</text>
<polyline fill="none" stroke="black" points="50,-0.5 50,-36.5 "/>
<text text-anchor="middle" x="75" y="-14.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
</g>
<!-- target -->
<g id="node2" class="node">
<title>target</title>
<polygon fill="none" stroke="black" points="300.03,-0.5 300.03,-36.5 416.03,-36.5 416.03,-0.5 300.03,-0.5"/>
<text text-anchor="middle" x="325.03" y="-14.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">mgmt</text>
<polyline fill="none" stroke="black" points="350.03,-0.5 350.03,-36.5 "/>
<text text-anchor="middle" x="383.03" y="-14.8" font-family="DejaVu Sans Mono, Book" font-size="14.00">target</text>
</g>
<!-- host&#45;&#45;target -->
<g id="edge1" class="edge">
<title>host:mgmt&#45;&#45;target:mgmt</title>
<path fill="none" stroke="lightgray" stroke-width="2" d="M100,-18.5C100,-18.5 300.03,-18.5 300.03,-18.5"/>
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB