diff --git a/watcher_tempest_plugin/services/base.py b/watcher_tempest_plugin/services/base.py index 7cd1229..1c609ec 100644 --- a/watcher_tempest_plugin/services/base.py +++ b/watcher_tempest_plugin/services/base.py @@ -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 diff --git a/watcher_tempest_plugin/services/metric/prometheus_client.py b/watcher_tempest_plugin/services/metric/prometheus_client.py index e9e2f26..2f898a4 100644 --- a/watcher_tempest_plugin/services/metric/prometheus_client.py +++ b/watcher_tempest_plugin/services/metric/prometheus_client.py @@ -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) diff --git a/watcher_tempest_plugin/tests/scenario/test_execute_zone_migration.py b/watcher_tempest_plugin/tests/scenario/test_execute_zone_migration.py index a55fef8..097f9d9 100644 --- a/watcher_tempest_plugin/tests/scenario/test_execute_zone_migration.py +++ b/watcher_tempest_plugin/tests/scenario/test_execute_zone_migration.py @@ -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()