Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
96 commits
Select commit Hold shift + click to select a range
e44ee36
DAOS-17519 test: Automate dlck testing (basic/fault_injection)
rpadma2 Dec 23, 2025
1dfe0ef
DAOS-17519 test: Fix linting issues.
rpadma2 Dec 23, 2025
a376c98
DAOS-17519 test: Merge branch 'master' into rpadma2/daos_17519
rpadma2 Jan 6, 2026
1f16a51
DAOS-17519 test: Merge branch 'master' into rpadma2/daos_17519
rpadma2 Mar 12, 2026
aa8ede9
DAOS-17519 test: Some of the review updates.
rpadma2 Mar 12, 2026
5213ba6
DAOS-17519 test: Merge branch 'master' into rpadma2/daos_17519
rpadma2 Mar 31, 2026
0cea354
DAOS-17519 test: Fix Linting issues.
rpadma2 Mar 31, 2026
585528a
DAOS-17519 test: Fix python/flake8 lint and copyright issues.
rpadma2 Mar 31, 2026
593f473
DAOS-17519 test: Merge branch 'master' into rpadma2/daos_17519
rpadma2 May 22, 2026
e4508aa
DAOS-17519 test: Update the control_meta_dir.
rpadma2 May 22, 2026
10920ac
DAOS-17519 test: Fix typo on control_metadata_dir path.
rpadma2 May 23, 2026
2b4bc8a
DAOS-17519 test: Merge branch 'master' into rpadma2/daos_17519
rpadma2 Aug 12, 2026
4103769
DAOS-17519 test: Fix some of the pylint errors.
rpadma2 Aug 12, 2026
2191472
DAOS-17519 test: Fix more pylint issues.
rpadma2 Aug 12, 2026
fb11310
DAOS-17519 test: Update test timeouts.
rpadma2 Aug 12, 2026
7284649
DAOS-17519 test: add_pool needed parameter.
rpadma2 Aug 13, 2026
3b870dc
DAOS-17519 test: Fix flake8 newline issue.
rpadma2 Aug 13, 2026
3c8a19a
DAOS-17519 test: Merge branch 'master' into rpadma2/daos_17519
rpadma2 Aug 17, 2026
68b4f6b
DAOS-17519 test: Python script review updates.
rpadma2 Aug 17, 2026
a30908f
DAOS-17519 test: Fix the dlck_utils class.
rpadma2 Aug 18, 2026
6031604
DAOS-17519 test: Address dlck_basic_fault test failure.
rpadma2 Aug 18, 2026
1dcadf5
DAOS-17519 test: Implement dlck_utils.py to use ExecutableCommand class.
rpadma2 Aug 18, 2026
391e926
DAOS-17519 test: Fix the error checking issues.
rpadma2 Aug 19, 2026
a0406f1
DAOS-17519 test: Run basic test without passing env.
rpadma2 Aug 20, 2026
9c314c7
DAOS-17519 test: Create a separate dlck logger.
rpadma2 Aug 20, 2026
04898a8
DAOS-17519 test: Removed unused variable.
rpadma2 Aug 20, 2026
903d016
DAOS-17519 test: Fix the pylint issue.
rpadma2 Aug 20, 2026
7d3f84e
DAOS-17519 test: Update the pool size to 80 percent.
rpadma2 Aug 20, 2026
035fc95
DAOS-17519 test: Remove the fault injection file after test completion.
rpadma2 Aug 23, 2026
47973fc
DAOS-17519 test: Fix minor lint issue.
rpadma2 Aug 23, 2026
e0cba86
DAOS-17519 test: Pass user information as string.
rpadma2 Aug 23, 2026
1e89fc4
DAOS-17519 test: Remove with_exports property.
rpadma2 Aug 24, 2026
c682b97
DAOS-17519 test: Merge branch 'master' into rpadma2/daos_17519
rpadma2 Aug 24, 2026
6eea9f3
DAOS-17519 test: Set the system_ram_reserved to 16.
rpadma2 Aug 24, 2026
e870619
DAOS-17519 test: Add with_exports back to the dlck_utils.
rpadma2 Aug 24, 2026
becb001
DAOS-17519 test: Add the --log_dir parameter to dlck.
rpadma2 Aug 24, 2026
890c976
DAOS-17519 test: Pass the log_dir path while calling dlck.
rpadma2 Aug 24, 2026
3f038d8
DAOS-17519 test: Revert the system_ram_reserved changes.
rpadma2 Aug 24, 2026
b4dd96a
DAOS-17519 test: Fix the DAOS build error.
rpadma2 Aug 24, 2026
20b7cb7
DAOS-17519 test: Merge branch 'master' into rpadma2/daos_17519
rpadma2 Aug 24, 2026
50253bc
DAOS-17519 test: Add the logfile to the YAML file.
rpadma2 Aug 24, 2026
ee085bc
DAOS-17519 test: fix pylint issue.
rpadma2 Aug 24, 2026
7fd7d82
DAOS-17519 test: Adding --verbose to dlck command.
rpadma2 Aug 25, 2026
5af0ef1
DAOS-17519 test: Fix C lint issues.
rpadma2 Aug 25, 2026
f9f6c02
DAOS-17519 test: Merge branch 'master' into rpadma2/daos_17519
rpadma2 Aug 25, 2026
067c4d1
DAOS-17519 test: Modified the files based on all the code review upda…
rpadma2 Aug 25, 2026
0b0c783
DAOS-17519 test: Update the Copyright information.
rpadma2 Aug 25, 2026
edf4949
DAOS-17519 test: Reduce the pool size to 10 percent.
rpadma2 Aug 25, 2026
5178e62
DAOS-17519 test: Updated new faults and allow exception for dlck faul…
rpadma2 Aug 25, 2026
09e6bd9
DAOS-17519 test: Address the scons dlck compile error.
rpadma2 Aug 25, 2026
0a6b0be
DAOS-17519 test: More review updates and check errors.
rpadma2 Aug 27, 2026
e8a4309
DAOS-17519 test: Remove unwanted code.
rpadma2 Aug 27, 2026
f32bea4
DAOS-17519 test: Address the dlck build error.
rpadma2 Aug 27, 2026
82a724d
DAOS-17519 test: Minor space issue.
rpadma2 Aug 27, 2026
3d4781f
DAOS-17519 test: Fix clang errors.
rpadma2 Aug 27, 2026
33590aa
DAOS-17519 test: More clang errors.
rpadma2 Aug 27, 2026
3479901
DAOS-17519 test: Merge branch 'master' into rpadma2/daos_17519
rpadma2 Aug 27, 2026
e061e56
DAOS-17519 test: Reduce the test_servers. Review updates.
rpadma2 Aug 27, 2026
767de9a
DAOS-17519 test: Modify fault injection mechanism for dlck utility.
rpadma2 Aug 28, 2026
0891a3c
DAOS-17519 test: Remove the unwanted comment.
rpadma2 Aug 28, 2026
db479c6
DAOS-17519 test: Fix pylint issue.
rpadma2 Aug 28, 2026
ee205a0
DAOS-17519 test: Merged both the test cases to a single python file.
rpadma2 Aug 28, 2026
9c8b347
DAOS-17519 test: Missed to remove add_pool import.
rpadma2 Aug 28, 2026
9d199de
DAOS-17519 test: Removed unused variable.
rpadma2 Aug 28, 2026
f78c858
DAOS-17519 test: Fixed the get_pool call.
rpadma2 Aug 29, 2026
e48754d
DAOS-17519 test: Renamed dlck_utils.py to dlck_test_base.py.
rpadma2 Aug 30, 2026
0e72f41
DAOS-17519 test: Minor lint issue.
rpadma2 Aug 30, 2026
e3234a0
DAOS-17519 test: Merge branch 'master' into rpadma2/daos_17519
rpadma2 Aug 30, 2026
3e60841
DAOS-17519 test: Remove some of the fault injection flags.
rpadma2 Aug 31, 2026
3627519
DAOS-17591 test: Add the log_dir and verbose parameter.
rpadma2 Aug 31, 2026
5f60d20
DAOS-17519 test: Merge branch 'master' into rpadma2/daos_17519
rpadma2 Sep 2, 2026
4b8578d
DAOS-17519 test: Revert dlck_test_base to dlck_utils.
rpadma2 Sep 2, 2026
07a494b
DAOS-17519 test: Merge branch 'master' into rpadma2/daos_17519
rpadma2 Sep 8, 2026
41217f4
DAOS-17519 test: Make daos_server as default run_user.
rpadma2 Sep 8, 2026
e7f30a4
DAOS-17519 test: Updated archive scripts for dlck.
rpadma2 Sep 9, 2026
5451f8f
DAOS-17519 test: Fix some pylint issues.
rpadma2 Sep 9, 2026
ad94528
DAOS-17519 test: Fix the verbose formatting.
rpadma2 Sep 9, 2026
2198f7c
DAOS-17519 test: Reduce the complexity in dlck file archiving process.
rpadma2 Sep 9, 2026
6c8b6a4
DAOS-17519 test: Archive the dlck log directories.
rpadma2 Sep 10, 2026
f7befc0
DAOS-17519 test: Merge branch 'master' into rpadma2/daos_17519
rpadma2 Sep 10, 2026
d30d476
DAOS-17519 test: Merge branch 'master' into rpadma2/daos_17519
rpadma2 Sep 17, 2026
6892c0a
DAOS-17519 test: Remove DLCK_FAULT_ENGINE_START/STOP fault flag.
rpadma2 Sep 17, 2026
003343d
DAOS-17519 test: Minor pylint issue.
rpadma2 Sep 17, 2026
b9d170d
DAOS-17519 test: Missed some review updates.
rpadma2 Sep 17, 2026
d80c44b
DAOS-17519 test: Increasing the pool size to check whether MDonSSD wo…
rpadma2 Sep 17, 2026
3aa10ef
DAOS-17519 test: Add debug commands: mount, df
rpadma2 Sep 18, 2026
4110fc4
DAOS-17519 test:Merge branch 'master' into rpadma2/daos_17519
rpadma2 Oct 1, 2026
0c49e51
DAOS-17519 test: Update the dlck_basic.yaml.
rpadma2 Oct 1, 2026
8bcc6c2
DAOS-17519 test: Re-create tmpfs mount for MDonSSD environment.
rpadma2 Oct 1, 2026
3badfd2
DAOS-17519 test: Update the storage mount to dlck_test.
rpadma2 Oct 7, 2026
4027995
DAOS-17519 test: Merge branch 'master' into rpadma2/daos_17519
rpadma2 Oct 7, 2026
b3e195e
DAOS-17519 test: Merge branch 'master' into rpadma2/daos_17519
rpadma2 Oct 19, 2026
6534a44
DAOS-17519 test: Enable DAOS_FAULT_POOL_OPEN_BIO for MDonSSD.
rpadma2 Oct 19, 2026
f8a72ea
DAOS-17519 test: mkdir /mnt/dlck_test directory.
rpadma2 Oct 20, 2026
1a3aaeb
DAOS-17519 test: Add sudo to mount command.
rpadma2 Oct 21, 2026
4d19ea9
DAOS-17519 test: Typo issue while executing the mount command.
rpadma2 Oct 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
152 changes: 152 additions & 0 deletions src/tests/ftest/recovery/dlck_basic.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
"""
Copyright 2026 Hewlett Packard Enterprise Development LP

SPDX-License-Identifier: BSD-2-Clause-Patent
"""
import os
import re

import yaml
from dlck_utils import TestDlck
from fault_config_utils import FaultInjection
from file_utils import distribute_files
from run_utils import run_remote


class DlckBasicTest(TestDlck):
"""Test class for dlck command line utility.

:avocado: recursive
"""
def check_dlck_result(self, result, fault_name):
"""Check that dlck reported the expected error for an injected fault.
Args:
result (dict): The result object returned by the dlck command.
fault_name (str): The name of the injected fault.
"""
expected_errors = ("DER_INVAL", "DER_NONEXIST", "DER_ID_MISMATCH",
"DER_DF_INCOMPT", "DER_DF_INVAL", "WARNING:", "DER_PROTO")
warning_pattern = r"\b[1-9]\d*\s+warning(?:\(s\)|s?)\b"
output = f"{result.joined_stdout}\n{result.joined_stderr}"
expected_error_found = any(error in output for error in expected_errors)
warning_found = re.search(warning_pattern, output)
if not (expected_error_found or warning_found):
return f"{fault_name}: no expected error found in dlck output: {output}"
return None

def test_dlck_basic(self):
"""Basic Test: Run 'dlck' command

:avocado: tags=all,daily_regression
:avocado: tags=hw,medium
:avocado: tags=recovery,dlck_cmd
:avocado: tags=DlckBasicTest,test_dlck_basic
"""
dmg = self.get_dmg_command()
self.log_step("Create a pool to run dlck")
pool = self.get_pool()
dlck = self.get_dlck_command()
dlck.pool_uuid.value = pool.uuid
dlck.log_dir = self.test_env.log_dir
dlck.storage.value = self.server_managers[0].get_config_value("scm_mount")
if self.server_managers[0].manager.job.using_control_metadata:
dlck.nvme.value = os.path.join(
self.server_managers[0].get_config_value("path"), "daos_control", "engine0",
"daos_nvme.conf")

self.log_step("Perform dmg system stop to run dlck command")
dmg.system_stop()

if self.server_managers[0].manager.job.using_control_metadata:
dlck.nvme.value = os.path.join(
self.server_managers[0].get_config_value("path"), "daos_control", "engine0",
"daos_nvme.conf")
# Mount 128G of memory-backed tmpfs for testing purposes
cmd = 'sudo "mkdir -p /mnt/dlck_test && ' \
'mount -t tmpfs -o size=128G tmpfs /mnt/dlck_test"'
run_remote(log=self.log, hosts=self.hostlist_servers, command=cmd)
# Display the tmpfs mount
run_remote(log=self.log, hosts=self.hostlist_servers, command="mount")
run_remote(log=self.log, hosts=self.hostlist_servers, command="df -h")
dlck.storage.value = "/mnt/dlck_test"

self.log_step("Run dlck command to check the health of the pool and storage")
result = dlck.run()

self.log_step("Perform dmg system start after running dlck command")
dmg.system_start()
if not result.passed:
self.fail(f"dlck failed on {result.failed_hosts}")
self.log.info("dlck basic test passed with no errors")

def test_dlck_basic_fault(self):
"""Basic Fault Test: Run 'dlck' injecting basic faults.

:avocado: tags=all,full_regression
:avocado: tags=hw,medium
:avocado: tags=recovery,dlck_cmd,faults
:avocado: tags=DlckBasicTest,test_dlck_basic_fault
"""
errors = []
faults_object = FaultInjection()
faults_dict = faults_object.get_faults_dict()
fault_list = self.params.get("fault_list", '/run/dlck_test_faults/*')
self.log.info("Test log dir %s", self.test_env.log_dir)
fault_inject_file = os.path.join(self.test_env.log_dir, "fi.yaml")
self.log.info("Fault injection file: %s", fault_inject_file)
self.log.info("Faults: %s", fault_list)
self.log.info("Faults dict: %s", faults_dict)
dmg = self.get_dmg_command()
pool = self.get_pool()
dlck = self.get_dlck_command()
dlck.pool_uuid.value = pool.uuid
dlck.log_dir.value = self.test_env.log_dir
dlck.exit_status_exception = False
dlck.env["D_FI_CONFIG"] = fault_inject_file
dlck.storage.value = self.server_managers[0].get_config_value("scm_mount")

self.log_step("Perform dmg system stop to run dlck command")
dmg.system_stop()

if self.server_managers[0].manager.job.using_control_metadata:
dlck.nvme.value = os.path.join(
self.server_managers[0].get_config_value("path"), "daos_control", "engine0",
"daos_nvme.conf")
# Mount 128G of memory-backed tmpfs for testing purposes
cmd = 'sudo "mkdir -p /mnt/dlck_test && ' \
'mount -t tmpfs -o size=128G tmpfs /mnt/dlck_test"'
run_remote(log=self.log, hosts=self.hostlist_servers, command=cmd)
# Display the tmpfs mount
run_remote(log=self.log, hosts=self.hostlist_servers, command="mount")
run_remote(log=self.log, hosts=self.hostlist_servers, command="df -h")
dlck.storage.value = "/mnt/dlck_test"

for test_fault in fault_list:
if test_fault == "DAOS_FAULT_POOL_OPEN_BIO" and \
not self.server_managers[0].manager.job.using_control_metadata:
self.log.info("Skipping test fault %s as control metadata is not used", test_fault)
continue
fault_config = {
'fault_config': [
{key: str(value) for key, value in faults_dict[test_fault].items()}]}
with open(fault_inject_file, 'w') as f:
yaml.dump(fault_config, f)
self.log.info("Reading the updated fault injection file contents")

with open(fault_inject_file, 'r') as f:
file_data = f.read()
self.log.info("\n %s", file_data)
distribute_files(self.log, self.hostlist_servers, fault_inject_file,
fault_inject_file)
self.log_step("Run dlck command after injecting fault")
result = dlck.run()
error = self.check_dlck_result(result, test_fault)
if error:
errors.append(error)

self.log_step("Perform dmg system start after running dlck command")
dmg.system_start()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no line break from beginning of the test to here. IMO, it would be easier to read by adding a few line breaks to separate many lines of code into blocks of code that runs similar tasks.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will do it later... Let the present PR run complete.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

if errors:
self.fail(f"dlck basic test failed with errors: {errors}")
self.log.info("dlck basic fault test passed with no errors")
Comment on lines +82 to +152

@phender phender Sep 1, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The TestWithoutServers - inherited by TestWithServers - class sets up self.fault_injection as part of the test set up. It even calls FaultInjection.start(self.params.get("fault_list", '/run/faults/*'), self.test_dir) which will:

  • read the faults to inject during the test from the faults: entry in the test's yaml file
  • if it finds a faults defined in the test yaml faults: entry, it will write a self.test_dir/fi.yaml fault injection file with the specified faults (using yaml.dump)
  • after writing the file it sets os.environ["D_FI_CONFIG"] equal to the file it wrote

TearDown() will even call FaultInjection.stop() to ensure all the fault injection files are removed from all the hosts - as not to adversely affect any subsequent tests.

If you then also need to copy the generated fi.yaml file to other/remote hosts we have the FaultInjection.copy_fault_files() method.

So this can all be simplified down to:

Suggested change
def test_dlck_basic_fault(self):
"""Basic Fault Test: Run 'dlck' injecting basic faults.
:avocado: tags=all,full_regression
:avocado: tags=hw,medium
:avocado: tags=recovery,dlck_cmd,faults
:avocado: tags=DlckBasicTest,test_dlck_basic_fault
"""
errors = []
faults_object = FaultInjection()
faults_dict = faults_object.get_faults_dict()
fault_list = self.params.get("fault_list", '/run/dlck_test_faults/*')
self.log.info("Test log dir %s", self.test_env.log_dir)
fault_inject_file = os.path.join(self.test_env.log_dir, "fi.yaml")
self.log.info("Fault injection file: %s", fault_inject_file)
self.log.info("Faults: %s", fault_list)
self.log.info("Faults dict: %s", faults_dict)
dmg = self.get_dmg_command()
pool = self.get_pool()
dlck = self.get_dlck_command()
dlck.pool_uuid.value = pool.uuid
dlck.log_dir.value = self.test_env.log_dir
dlck.run_user = 'daos_server'
dlck.exit_status_exception = False
dlck.env["D_FI_CONFIG"] = fault_inject_file
dlck.storage.value = self.server_managers[0].get_config_value("scm_mount")
if self.server_managers[0].manager.job.using_control_metadata:
dlck.nvme.value = os.path.join(
self.server_managers[0].get_config_value("path"), "daos_control", "engine0",
"daos_nvme.conf")
self.log_step("Perform dmg system stop to run dlck command")
dmg.system_stop()
for test_fault in fault_list:
with open(fault_inject_file, 'w') as f:
f.write("fault_config:\n")
for count, (key, value) in enumerate(faults_dict[test_fault].items()):
if count == 0:
f.write(f"- {key}: \'{value}\'\n")
else:
f.write(f" {key}: \'{value}\'\n")
self.log.info("Reading the updated fault injection file contents")
with open(fault_inject_file, 'r') as f:
file_data = f.read()
self.log.info("\n %s", file_data)
distribute_files(self.log, self.hostlist_servers, fault_inject_file,
fault_inject_file)
self.log_step("Run dlck command after injecting fault")
result = dlck.run()
error = self.check_dlck_result(result, test_fault)
if error:
errors.append(error)
self.log_step("Perform dmg system start after running dlck command")
dmg.system_start()
if errors:
self.fail(f"dlck basic test failed with errors: {errors}")
self.log.info("dlck basic fault test passed with no errors")
def test_dlck_basic_fault(self):
"""Basic Fault Test: Run 'dlck' injecting basic faults.
:avocado: tags=all,full_regression
:avocado: tags=hw,medium
:avocado: tags=recovery,dlck_cmd,faults
:avocado: tags=DlckBasicTest,test_dlck_basic_fault
"""
dmg = self.get_dmg_command()
pool = self.get_pool()
dlck = self.get_dlck_command()
dlck.pool_uuid.value = pool.uuid
dlck.log_dir.value = self.test_env.log_dir
dlck.run_user = 'daos_server'
dlck.exit_status_exception = False
dlck.env["D_FI_CONFIG"] = os.environ["D_FI_CONFIG"]
dlck.storage.value = self.server_managers[0].get_config_value("scm_mount")
if self.server_managers[0].manager.job.using_control_metadata:
dlck.nvme.value = os.path.join(
self.server_managers[0].get_config_value("path"), "daos_control", "engine0",
"daos_nvme.conf")
self.log_step("Perform dmg system stop to run dlck command")
dmg.system_stop()
self.log_step("Copy fault injection file to server hosts")
self.fault_injection.copy_fault_files(self.log, self.hostlist_servers)
self.log_step("Perform dmg system start after running dlck command")
dmg.system_start()
self.log.info("dlck basic fault test passed with no errors")

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI, self.test_dir = os.path.join(self.test_env.log_dir, self.test_id) and self.test_dir is created on each host as part of TestWithServers.setUp().

37 changes: 37 additions & 0 deletions src/tests/ftest/recovery/dlck_basic.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
hosts:
test_servers: 1
test_clients: 1

timeout: 420
server_config:
name: daos_server
engines_per_host: 1
engines:
0:
targets: 4
storage: auto
Comment thread
janekmi marked this conversation as resolved.

pool:
size: 30%

dlck_test_faults:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make use of the built-in self.fault_injection object:

Suggested change
dlck_test_faults:
faults:

@rpadma2 rpadma2 Sep 1, 2026 •

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@phender : Just to be clear.... Based on my discussion with @janekmi , dlck doesn't need fault injection to be added as part of DAOS server startup. It needs the fault YAML only after stopping DAOS system. dlck fault injection framework is independent on DAOS.

Based on my understanding if we add faults: tag in the YAML, DAOS server will have the faults enabled at server startup. Am I right? If so, we don't need that mechanism for dlck testing.

Here is dlck test steps:

  1. Start the DAOS server without any fault injection.
  2. Create pools, containers, etc. Perform some testing.
  3. Stop the DAOS system (eg: dmg system stop).
  4. Create a fault injection YAML file (based what DLCK supports presently). [eg: <test_env_log_dir>/fi.yaml]
  5. Run dlck in the following format:
    • D_FI_CONFIG=<test_env_log_dir>/fi.yaml sudo dlck

Hope things are clear now. We don't want fault injection similar to DAOS here.

fault_list:
- DLCK_FAULT_GETGRNAM
- DLCK_MOCK_NO_DAOS_SERVER_GROUP
- DLCK_FAULT_CREATE_POOL_DIR
- DLCK_FAULT_CREATE_LOG_DIR
- DLCK_FAULT_ENGINE_START
- DAOS_FAULT_POOL_NVME_HEALTH
- DAOS_FAULT_POOL_OPEN_UMEM
- DAOS_FAULT_POOL_OPEN_MAGIC
- DAOS_FAULT_POOL_OPEN_VERSION
- DAOS_FAULT_POOL_OPEN_UUID
- DAOS_FAULT_BTREE_OPEN_INV_CLASS_28
- DAOS_FAULT_BTREE_OPEN_INV_CLASS_29
- DAOS_FAULT_BTREE_OPEN_UNREG_CLASS_28
- DAOS_FAULT_BTREE_OPEN_UNREG_CLASS_29
- DAOS_FAULT_BTREE_FEATURES_28
- DAOS_FAULT_BTREE_FEATURES_29
- DAOS_FAULT_POOL_EXT_PADDING
- DAOS_FAULT_POOL_EXT_RESERVED
- DAOS_FAULT_POOL_OPEN_BIO
56 changes: 41 additions & 15 deletions src/tests/ftest/util/collection_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
"""
(C) Copyright 2022-2024 Intel Corporation.
(C) Copyright 2025 Hewlett Packard Enterprise Development LP
(C) Copyright 2025-2026 Hewlett Packard Enterprise Development LP

SPDX-License-Identifier: BSD-2-Clause-Patent
"""
Expand Down Expand Up @@ -30,7 +30,8 @@
FAILURE_TRIGGER = "00_trigger-launch-failure_00"
TEST_EXPECT_CORE_FILES = ["./harness/core_files.py"]
TEST_RESULTS_DIRS = (
"daos_configs", "daos_logs", "cart_logs", "daos_dumps", "valgrind_logs", "stacktraces")
"daos_configs", "daos_logs", "cart_logs", "daos_dumps", "valgrind_logs", "stacktraces",
"dlck_check")


def stop_daos_agent_services(logger, test):
Expand Down Expand Up @@ -225,7 +226,7 @@ def check_server_storage(logger, test, test_result, stage):


def archive_files(logger, summary, hosts, source, pattern, destination, depth, threshold, timeout,
test_result, test=None):
test_result, test=None, file_type="f"):
# pylint: disable=too-many-arguments
"""Archive the files from the source to the destination.

Expand All @@ -241,6 +242,7 @@ def archive_files(logger, summary, hosts, source, pattern, destination, depth, t
timeout (int): number of seconds to wait for the command to complete.
test_result (TestResult): the test result used to update the status of the test
test (TestInfo, optional): the test information. Defaults to None.
file_type (str, optional): type of file to search for. Defaults to "f".

Returns:
int: status code: 0 = success, 16 = failure
Expand All @@ -255,7 +257,8 @@ def archive_files(logger, summary, hosts, source, pattern, destination, depth, t
logger.debug(" Local host: %s", hosts.intersection(get_local_host()))

# List any remote files and their sizes and determine which hosts contain these files
return_code, file_hosts = list_files(logger, hosts, source, pattern, depth, test_result)
return_code, file_hosts = list_files(logger, hosts, source, pattern, depth,
test_result, file_type)
if not file_hosts:
# If no files are found then there is nothing else to do
logger.debug("No %s files found on %s", os.path.join(source, pattern), hosts)
Expand All @@ -281,7 +284,7 @@ def archive_files(logger, summary, hosts, source, pattern, destination, depth, t

# Move the test files to the test-results directory on this host
return_code |= move_files(
logger, file_hosts, source, pattern, destination, depth, timeout, test_result)
logger, file_hosts, source, pattern, destination, depth, timeout, test_result, file_type)

if test and "core files" in summary:
# Process the core files
Expand All @@ -290,16 +293,17 @@ def archive_files(logger, summary, hosts, source, pattern, destination, depth, t
return return_code


def list_files(logger, hosts, source, pattern, depth, test_result):
def list_files(logger, hosts, source, pattern, depth, test_result, file_type="f"):
"""List the files in source with that match the pattern.

Args:
logger (Logger): logger for the messages produced by this method
hosts (NodSet): hosts on which the files are located
hosts (NodeSet): hosts on which the files are located
source (str): where the files are currently located
pattern (str): pattern used to limit which files are processed
depth (int): max depth for find command
test_result (TestResult): the test result used to update the status of the test
file_type (str, optional): type of file to search for. Defaults to "f".

Returns:
tuple: a tuple containing:
Expand All @@ -313,15 +317,16 @@ def list_files(logger, hosts, source, pattern, depth, test_result):
logger.debug("-" * 80)
logger.debug("Listing any %s files on %s", source_files, hosts)
other = ["-printf", "'%M %n %-12u %-12g %12k %t %p\n'"]
result = run_remote(logger, hosts, find_command(source, pattern, depth, other))
result = run_remote(logger, hosts, find_command(source, pattern, depth,
other, file_type))
if not result.passed:
message = f"Error determining if {source_files} files exist on {result.failed_hosts}"
test_result.fail_test(logger, "Process", message)
status = 16
else:
for data in result.output:
for line in data.stdout:
if source in line:
if (source in line) or re.search(source, line):
Comment thread
janekmi marked this conversation as resolved.
logger.debug("Found at least one file match on %s: %s", data.hosts, line)
hosts_with_files.add(data.hosts)
break
Expand Down Expand Up @@ -466,18 +471,20 @@ def compress_files(logger, hosts, source, pattern, depth, test_result):
return 0


def move_files(logger, hosts, source, pattern, destination, depth, timeout, test_result):
def move_files(logger, hosts, source, pattern, destination, depth,
timeout, test_result, file_type="f"):
"""Move files from the source to the destination.

Args:
logger (Logger): logger for the messages produced by this method
hosts (NodSet): hosts on which the files are located
hosts (NodeSet): hosts on which the files are located
source (str): where the files are currently located
pattern (str): pattern used to limit which files are processed
destination (str): where the files should be moved to on this host
depth (int): max depth for find command
timeout (int): number of seconds to wait for the command to complete.
test_result (TestResult): the test result used to update the status of the test
file_type (str, optional): type of file to search for. Defaults to "f".

Returns:
int: status code: 0 = success, 16 = failure
Expand All @@ -491,7 +498,8 @@ def move_files(logger, hosts, source, pattern, destination, depth, timeout, test
if "stacktrace" in destination or "daos_dumps" in destination:
# pylint: disable=import-outside-toplevel
other = ["-print0", "|", "xargs", "-0", "-r0", "sudo", "-n", get_chown_command()]
result = run_remote(logger, hosts, find_command(source, pattern, depth, other))
result = run_remote(logger, hosts, find_command(source, pattern, depth,
other, file_type))
if not result.passed:
message = (f"Error changing {os.path.join(source, pattern)} file permissions on "
f"{result.failed_hosts}")
Expand Down Expand Up @@ -528,8 +536,8 @@ def move_files(logger, hosts, source, pattern, destination, depth, timeout, test
return return_code

# Move all the source files matching the pattern into the temporary remote directory
other = f"-print0 | xargs -0 -r0 -I '{{}}' {sudo_command}mv '{{}}' '{tmp_copy_dir}'/"
result = run_remote(logger, hosts, find_command(source, pattern, depth, other))
other = f"-print0 | xargs -0 -r0 -I '{{}}' {sudo_command} mv '{{}}' '{tmp_copy_dir}'/"
result = run_remote(logger, hosts, find_command(source, pattern, depth, other, file_type))
if not result.passed:
message = (f"Error moving files to temporary remote copy directory '{tmp_copy_dir}' on "
f"{result.failed_hosts}")
Expand Down Expand Up @@ -997,6 +1005,15 @@ def collect_test_result(logger, test, test_result, job_results_dir, stop_daos, a
# size exceeding the threshold.
test_env = TestEnvironment()
if archive:
logger.debug("Making all '%s' files accessible for archiving", test_env.log_dir)
result = run_remote(logger, test.host_info.all_hosts,
"sudo -n {}".format(get_chown_command(options="-R",
file=test_env.log_dir)))
if not result.passed:
message = f"Error making {test_env.log_dir} files accessible for archiving"
test_result.fail_test(logger, "Process", message)
return_code = 16

remote_files = OrderedDict()
remote_files["local configuration files"] = {
"source": test_env.log_dir,
Expand Down Expand Up @@ -1047,6 +1064,15 @@ def collect_test_result(logger, test, test_result, job_results_dir, stop_daos, a
"depth": 1,
"timeout": 900,
}
remote_files["dlck files"] = {
"source": test_env.log_dir,
"destination": os.path.join(job_results_dir, "latest", TEST_RESULTS_DIRS[6]),
"pattern": "dlck_check_*",
"hosts": test.host_info.all_hosts,
"depth": 1,
"file_type": "d",
"timeout": 900,
}
for index, hosts in enumerate(core_files):
remote_files[f"core files {index + 1}/{len(core_files)}"] = {
"source": core_files[hosts]["path"],
Expand All @@ -1062,7 +1088,7 @@ def collect_test_result(logger, test, test_result, job_results_dir, stop_daos, a
return_code |= archive_files(
logger, summary, data["hosts"].copy(), data["source"], data["pattern"],
data["destination"], data["depth"], threshold, data["timeout"],
test_result, test)
test_result, test, file_type=data.get("file_type", "f"))

# Generate a steps.log file
return_code |= create_steps_log(logger, job_results_dir, test_result)
Expand Down
Loading
Loading