mirror of
https://github.com/kernelkit/infix.git
synced 2026-07-31 04:53:01 +02:00
test: new test, verify support data collection
Signed-off-by: Joachim Wiberg <troglobit@gmail.com>
This commit is contained in:
@@ -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[]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
test.adoc
|
||||
@@ -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
|
||||
|
||||
|
||||
Executable
+185
@@ -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()
|
||||
@@ -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--target -->
|
||||
<g id="edge1" class="edge">
|
||||
<title>host:mgmt--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 |
Reference in New Issue
Block a user