Small improvements to prometheus_client and zone migration test

Improves prometheus clients with additional method documentation
and some debug log messages.
Adds calls to wait for compute model updates in zone
migration tests, which was missing from previous patch[1].

Related-Bug: #2099737

[1] https://review.opendev.org/c/openstack/watcher-tempest-plugin/+/942308

Change-Id: Iba55fee8628819bae5ee12195301177000e88b48
This commit is contained in:
Douglas Viroel 2025-02-28 14:40:37 -03:00
parent 32dc5bd61e
commit 7faed28e23
3 changed files with 51 additions and 12 deletions

View File

@ -21,11 +21,13 @@ import subprocess
import urllib.parse as urlparse
from oslo_log import log
from tempest import config
from tempest.lib.common import rest_client
from tempest.lib.common import ssh
CONF = config.CONF
LOG = log.getLogger(__name__)
def handle_errors(f):
@ -163,7 +165,7 @@ class BaseClient(rest_client.RestClient, metaclass=abc.ABCMeta):
:param resource: The name of the REST resource, e.g., 'audits'.
:param uuid: The unique identifier of an object in UUID format.
:return: A tuple with the server response and the response body.
:returns: A tuple with the server response and the response body.
"""
uri = self._get_uri(resource, uuid)
@ -177,7 +179,7 @@ class BaseClient(rest_client.RestClient, metaclass=abc.ABCMeta):
:param resource: The name of the REST resource, e.g., 'audits'.
:param uuid: The unique identifier of an object in UUID format.
:return: A tuple with the server response and the serialized patched
:returns: A tuple with the server response and the serialized patched
object.
"""
@ -225,7 +227,6 @@ class BaseCmdClient(metaclass=abc.ABCMeta):
or a sequence of arguments.
:param input_data: data to be sent to process stdin
:param timeout: communication timeout in seconds
:return: output written to stdout.
:raises: Exception when command fails.
"""
@ -242,10 +243,10 @@ class SubProcessCmdClient(BaseCmdClient):
or a sequence of arguments.
:param input_data: data to be sent to process stdin
:param timeout: communication timeout in seconds
:return: output written to stdout.
:raises: Exception when command fails.
"""
LOG.debug(f"Executing command '{cmd}' with input data '{input_data}'")
sp = subprocess.Popen(cmd,
stdout=subprocess.PIPE,
stdin=subprocess.PIPE,
@ -289,7 +290,7 @@ class SshCmdClient(BaseCmdClient, ssh.Client):
:param input_data: data to be sent to process stdin
:param timeout: communication timeout in seconds
:return: output written to stdout.
:returns: output written to stdout.
:raises: Exception when command fails.
"""
cmd_str = " ".join(cmd) if isinstance(cmd, list) else cmd
@ -304,6 +305,8 @@ class SshCmdClient(BaseCmdClient, ssh.Client):
if self.cmd_prefix:
cmd_str = f"{self.cmd_prefix} {cmd_str}"
LOG.debug(f"Executing command '{cmd_str}' on host '{self.host}'")
if timeout:
original_timeout = self.timeout
self.timeout = timeout

View File

@ -36,12 +36,6 @@ class PromtoolClient:
self.is_podified = ("podified" == openstack_type)
LOG.debug(f"Configuring PromtoolClient for {openstack_type} "
" deployment.")
self.podified_ns = podified_ns
self.oc_cmd = ['oc']
if podified_kubeconfig:
self.oc_cmd.insert(0, f"KUBECONFIG={podified_kubeconfig}")
if podified_ns:
self.oc_cmd += ['-n', self.podified_ns]
if proxy_host_address and proxy_host_user:
self.client = base.SshCmdClient(
@ -54,6 +48,12 @@ class PromtoolClient:
self.client = base.SubProcessCmdClient()
if self.is_podified:
self.podified_ns = podified_ns
self.oc_cmd = ['oc']
if podified_kubeconfig:
self.oc_cmd.insert(0, f"KUBECONFIG={podified_kubeconfig}")
if podified_ns:
self.oc_cmd += ['-n', self.podified_ns]
# podified control plane will run promtool inside
# prometheus container
self.prometheus_pod = self.get_prometheus_pod()
@ -79,7 +79,8 @@ class PromtoolClient:
def _build_host_fqdn_maps(self):
# NOTE(dviroel): Promtool does not support 'targets'
# endpoint.
# endpoint. curl is preferred here since this command
# will run inside a container in podified deployments.
cmd = ['curl', '-k', '-s', self.prometheus_targets_url]
out = self.client.exec_cmd(cmd)
@ -110,6 +111,11 @@ class PromtoolClient:
:param expr: promql query expression to be sent
to Prometheus.
:raises: SSHExecCommandFailed if command fails.
:raises: TimeoutException if command doesn't end when
timeout expires.
:returns: Query response.
"""
cmd = self.promtool_cmd + [
"query", "instant", self.prometheus_url, expr]
@ -121,6 +127,13 @@ class PromtoolClient:
:param input_data: metric data in exposition format,
to be pushed to prometheus.
:raises: Exception when push metrics call doesn't return
success.
:raises: SSHExecCommandFailed if command fails.
:raises: TimeoutException if command doesn't end when
timeout expires.
:returns: Stdout output generated by the command.
"""
cmd = self.promtool_cmd + [
"push", "metrics", self.prometheus_write_url]
@ -133,6 +146,21 @@ class PromtoolClient:
raise Exception(f"Promtool failed to push metrics: {out}")
def get_pods(self, labels={}, pod_state='Running'):
"""Retrive pods based on matching labels and pod status.
:param labels: (Optional) A comma separeted list of labels,
used to filter pods available in the namespace.
:param pod_state: (Optional) Status of the pods, used to
filter pods available in the namespace.
:raises: Exception if the environment is not a podified
deployment.
:returns: A list of pod names or an empty list.
"""
if not self.is_podified:
raise Exception("This method is only available in a "
"podified deployment.")
# pod_state as empty string can be used to get all pod states
if pod_state:
pod_state = f"--field-selector=status.phase={pod_state}"
@ -152,6 +180,11 @@ class PromtoolClient:
return [pod.strip() for pod in pods_output.splitlines()]
def get_prometheus_pod(self):
"""Returns the name of a prometheus pod.
:raises: Exception if no prometheus pod is found.
:returns: Name of a prometheus pod.
"""
labels = "app.kubernetes.io/name=prometheus"
LOG.debug("Getting prometheus service pod names.")
pods = self.get_pods(labels)

View File

@ -55,12 +55,15 @@ class TestExecuteZoneMigrationStrategy(base.BaseInfraOptimScenarioTest):
def test_execute_zone_migration_live_migration(self):
"""Execute an action plan using the zone migration strategy"""
self.addCleanup(self.rollback_compute_nodes_status)
self.addCleanup(self.wait_delete_instances_from_model)
instance = self.create_server(image_id=CONF.compute.image_ref,
wait_until='ACTIVE',
clients=self.os_primary)
instance = self.mgr.servers_client.show_server(
instance['id'])['server']
node = instance.get('OS-EXT-SRV-ATTR:hypervisor_hostname')
# Wait for the instance to be added in compute model
self.wait_for_instances_in_model([instance])
vacant_node = [hyp['hypervisor_hostname'] for hyp
in self.get_hypervisors_setup()