Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions tests/rptest/services/cluster.py
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ def _do_post_test_checks(
redpanda.cloud_storage_diagnostics()
raise

redpanda.export_cluster_config()

if isinstance(redpanda, RedpandaService):
if test_failed:
redpanda.cloud_storage_diagnostics()
Expand Down
42 changes: 22 additions & 20 deletions tests/rptest/services/redpanda.py
Original file line number Diff line number Diff line change
Expand Up @@ -1212,13 +1212,13 @@ class has both implementation and abstract methods, only for methods which

def __init__(self, *args, **kwargs) -> None:
super().__init__(*args, **kwargs)
# Now ensure that this base is part of the right type of object.
# For these checks to work, this __init__ method should appear in
# the MRO after all the __init__ methods that would set these properties
self._check_attr("context", TestContext)
self._check_attr("logger", Logger)
self._usage_stats = UsageStats()

@property
@abstractmethod
def logger(self) -> Logger:
pass

@property
def usage_stats(self) -> UsageStats:
"""
Expand Down Expand Up @@ -1248,6 +1248,9 @@ def kafka_client_security(self) -> KafkaClientSecurity:
on this broker."""
pass

def export_cluster_config(self) -> None:
self.logger.debug("export_cluster_config not implemented for this service")

def wait_until(
self,
fn: Callable[[], Any],
Expand Down Expand Up @@ -1331,16 +1334,6 @@ def wrapped():
logger=logger,
)

def _check_attr(self, name: str, t: Type) -> None:
v = getattr(self, name, None)
mro = self.__class__.__mro__
assert v is not None, (
f"RedpandaServiceABC was missing attribute {name} after __init__: {mro}\n"
)
assert isinstance(v, t), (
f"{name} had wrong type, expected {t} but was {type(v)}"
)

def _extract_samples(
self, metrics: Generator[Metric, Any, None], sample_pattern: str, node: Any
) -> list[MetricSample]:
Expand Down Expand Up @@ -1582,7 +1575,6 @@ def __init__(
# we save the test context under both names since RedpandaService and Service
# save them under these two names, respetively
self.context = self._context = context
self.logger = context.logger

super().__init__()

Expand Down Expand Up @@ -1667,6 +1659,10 @@ def __init__(
f"Not enough brokers: test needs {self._min_brokers} but cluster has {node_count}"
)

@property
def logger(self) -> Logger:
return self._context.logger

@property
def kubectl(self) -> KubectlTool:
assert self.__kubectl, "kubectl accessed before cluster was started?"
Expand Down Expand Up @@ -2379,7 +2375,7 @@ def copy_from_pod(params):
return {}


class RedpandaService(RedpandaServiceABC, Service):
class RedpandaService(Service, RedpandaServiceABC):
PERSISTENT_ROOT = "/var/lib/redpanda"
TRIM_LOGS_KEY = "trim_logs"
DATA_DIR = os.path.join(PERSISTENT_ROOT, "data")
Expand Down Expand Up @@ -4449,11 +4445,11 @@ def get_version_if_not_head(self, node):
return self.get_version(node)
return None

def stop(self, **kwargs: Any) -> None:
def export_cluster_config(self) -> None:
"""
Override default stop() to execude stop_node in parallel
Export the cluster configuration of all nodes to the ducktape log
directory for later inspection.
"""
self._stop_time = time.time() # The last time stop is invoked
self.logger.info("%s: exporting cluster config" % self.who_am_i())

service_dir = os.path.join(
Expand All @@ -4477,6 +4473,12 @@ def stop(self, **kwargs: Any) -> None:
# will not be able to get it from the admin API
self.logger.info(f"{self.who_am_i()}: error getting config: {e}")

def stop(self, **kwargs: Any) -> None:
"""
Override default stop() to execude stop_node in parallel
"""
self._stop_time = time.time() # The last time stop is invoked

self.logger.info("%s: stopping service" % self.who_am_i())

self.for_nodes(self.nodes, lambda n: self.stop_node(n, **kwargs))
Expand Down