summaryrefslogtreecommitdiffstats
path: root/cns-libs/cnslibs/common/openshift_ops.py
diff options
context:
space:
mode:
Diffstat (limited to 'cns-libs/cnslibs/common/openshift_ops.py')
-rw-r--r--cns-libs/cnslibs/common/openshift_ops.py1507
1 files changed, 0 insertions, 1507 deletions
diff --git a/cns-libs/cnslibs/common/openshift_ops.py b/cns-libs/cnslibs/common/openshift_ops.py
deleted file mode 100644
index 0d44df1f..00000000
--- a/cns-libs/cnslibs/common/openshift_ops.py
+++ /dev/null
@@ -1,1507 +0,0 @@
-"""Library for openshift operations.
-
-Various utility functions for interacting with OCP/OpenShift.
-"""
-
-import base64
-import json
-import re
-import types
-
-from glusto.core import Glusto as g
-from glustolibs.gluster import volume_ops
-import mock
-import yaml
-
-from cnslibs.common import command
-from cnslibs.common import exceptions
-from cnslibs.common import openshift_version
-from cnslibs.common import utils
-from cnslibs.common import waiter
-from cnslibs.common.heketi_ops import (
- heketi_blockvolume_info,
- heketi_volume_info,
-)
-
-PODS_WIDE_RE = re.compile(
- r'(\S+)\s+(\S+)\s+(\w+)\s+(\d+)\s+(\S+)\s+(\S+)\s+(\S+).*\n')
-SERVICE_STATUS = "systemctl status %s"
-SERVICE_RESTART = "systemctl restart %s"
-SERVICE_STATUS_REGEX = r"Active: active \((.*)\) since .*;.*"
-
-
-def oc_get_pods(ocp_node, selector=None):
- """Gets the pods info with 'wide' option in the current project.
-
- Args:
- ocp_node (str): Node in which ocp command will be executed.
- selector (str): optional option. Selector for OCP pods.
- example: "glusterfs-node=pod" for filtering out only Gluster PODs.
-
- Returns:
- dict : dict of pods info in the current project.
- """
-
- cmd = "oc get -o wide --no-headers=true pods"
- if selector:
- cmd += " --selector %s" % selector
- ret, out, err = g.run(ocp_node, cmd)
- if ret != 0:
- g.log.error("Failed to get ocp pods on node %s" % ocp_node)
- raise AssertionError('failed to get pods: %r' % (err,))
- return _parse_wide_pods_output(out)
-
-
-def _parse_wide_pods_output(output):
- """Parse the output of `oc get -o wide pods`.
- """
- # Interestingly, the output of get pods is "cooked" in such a way that
- # the values in the ready, status, & restart fields are not accessible
- # from YAML/JSON/templating forcing us to scrape the output for
- # these values
- # (at the time of this writing the logic is in
- # printPodBase in kubernetes/pkg/printers/internalversion/printers.go )
- # Possibly obvious, but if you don't need those values you can
- # use the YAML output directly.
- #
- # TODO: Add unit tests for this parser
- pods_info = {}
- for each_pod_info in PODS_WIDE_RE.findall(output):
- pods_info[each_pod_info[0]] = {
- 'ready': each_pod_info[1],
- 'status': each_pod_info[2],
- 'restarts': each_pod_info[3],
- 'age': each_pod_info[4],
- 'ip': each_pod_info[5],
- 'node': each_pod_info[6],
- }
- return pods_info
-
-
-def oc_get_pods_full(ocp_node):
- """Gets all the pod info via YAML in the current project.
-
- Args:
- ocp_node (str): Node in which ocp command will be executed.
-
- Returns:
- dict: The YAML output converted to python objects
- (a top-level dict)
- """
-
- cmd = "oc get -o yaml pods"
- ret, out, err = g.run(ocp_node, cmd)
- if ret != 0:
- g.log.error("Failed to get ocp pods on node %s" % ocp_node)
- raise AssertionError('failed to get pods: %r' % (err,))
- return yaml.load(out)
-
-
-def get_ocp_gluster_pod_names(ocp_node):
- """Gets the gluster pod names in the current project.
-
- Args:
- ocp_node (str): Node in which ocp command will be executed.
-
- Returns:
- list : list of gluster pod names in the current project.
- Empty list, if there are no gluster pods.
-
- Example:
- get_ocp_gluster_pod_names(ocp_node)
- """
-
- pod_names = oc_get_pods(ocp_node).keys()
- return [pod for pod in pod_names if pod.startswith('glusterfs-')]
-
-
-def get_amount_of_gluster_nodes(ocp_node):
- """Calculate amount of Gluster nodes.
-
- Args:
- ocp_node (str): node to run 'oc' commands on.
- Returns:
- Integer value as amount of either GLuster PODs or Gluster nodes.
- """
- # Containerized Gluster
- gluster_pods = get_ocp_gluster_pod_names(ocp_node)
- if gluster_pods:
- return len(gluster_pods)
-
- # Standalone Gluster
- configured_gluster_nodes = len(g.config.get("gluster_servers", {}))
- if configured_gluster_nodes:
- return configured_gluster_nodes
-
- raise exceptions.ConfigError(
- "Haven't found neither Gluster PODs nor Gluster nodes.")
-
-
-def switch_oc_project(ocp_node, project_name):
- """Switch to the given project.
-
- Args:
- ocp_node (str): Node in which ocp command will be executed.
- project_name (str): Project name.
- Returns:
- bool : True on switching to given project.
- False otherwise
-
- Example:
- switch_oc_project(ocp_node, "storage-project")
- """
-
- cmd = "oc project %s" % project_name
- ret, _, _ = g.run(ocp_node, cmd)
- if ret != 0:
- g.log.error("Failed to switch to project %s" % project_name)
- return False
- return True
-
-
-def oc_rsync(ocp_node, pod_name, src_dir_path, dest_dir_path):
- """Sync file from 'src_dir_path' path on ocp_node to
- 'dest_dir_path' path on 'pod_name' using 'oc rsync' command.
-
- Args:
- ocp_node (str): Node on which oc rsync command will be executed
- pod_name (str): Name of the pod on which source directory to be
- mounted
- src_dir_path (path): Source path from which directory to be mounted
- dest_dir_path (path): destination path to which directory to be
- mounted
- """
- ret, out, err = g.run(ocp_node, ['oc',
- 'rsync',
- src_dir_path,
- '%s:%s' % (pod_name, dest_dir_path)])
- if ret != 0:
- error_msg = 'failed to sync directory in pod: %r; %r' % (out, err)
- g.log.error(error_msg)
- raise AssertionError(error_msg)
-
-
-def oc_rsh(ocp_node, pod_name, command, log_level=None):
- """Run a command in the ocp pod using `oc rsh`.
-
- Args:
- ocp_node (str): Node on which oc rsh command will be executed.
- pod_name (str): Name of the pod on which the command will
- be executed.
- command (str|list): command to run.
- log_level (str|None): log level to be passed to glusto's run
- method.
-
- Returns:
- A tuple consisting of the command return code, stdout, and stderr.
- """
- prefix = ['oc', 'rsh', pod_name]
- if isinstance(command, types.StringTypes):
- cmd = ' '.join(prefix + [command])
- else:
- cmd = prefix + command
-
- # unpack the tuple to make sure our return value exactly matches
- # our docstring
- ret, stdout, stderr = g.run(ocp_node, cmd, log_level=log_level)
- return (ret, stdout, stderr)
-
-
-def oc_create(ocp_node, value, value_type='file'):
- """Create a resource based on the contents of the given file name.
-
- Args:
- ocp_node (str): Node on which the ocp command will run
- value (str): Filename (on remote) or file data
- to be passed to oc create command.
- value_type (str): either 'file' or 'stdin'.
- Raises:
- AssertionError: Raised when resource fails to create.
- """
- if value_type == 'file':
- cmd = ['oc', 'create', '-f', value]
- else:
- cmd = ['echo', '\'%s\'' % value, '|', 'oc', 'create', '-f', '-']
- ret, out, err = g.run(ocp_node, cmd)
- if ret != 0:
- msg = 'Failed to create resource: %r; %r' % (out, err)
- g.log.error(msg)
- raise AssertionError(msg)
- g.log.info('Created resource from %s.' % value_type)
-
-
-def oc_process(ocp_node, params, filename):
- """Create a resource template based on the contents of the
- given filename and params provided.
- Args:
- ocp_node (str): Node on which the ocp command will run
- filename (str): Filename (on remote) to be passed to
- oc process command.
- Returns: template generated through process command
- Raises:
- AssertionError: Raised when resource fails to create.
- """
-
- ret, out, err = g.run(ocp_node, ['oc', 'process', '-f', filename, params])
- if ret != 0:
- error_msg = 'failed to create process: %r; %r' % (out, err)
- g.log.error(error_msg)
- raise AssertionError(error_msg)
- g.log.info('Created resource from file (%s)', filename)
-
- return out
-
-
-def oc_create_secret(hostname, secret_name_prefix="autotests-secret-",
- namespace="default",
- data_key="password",
- secret_type="kubernetes.io/glusterfs"):
- """Create secret using data provided as stdin input.
-
- Args:
- hostname (str): Node on which 'oc create' command will be executed.
- secret_name_prefix (str): secret name will consist of this prefix and
- random str.
- namespace (str): name of a namespace to create a secret in
- data_key (str): plain text value for secret which will be transformed
- into base64 string automatically.
- secret_type (str): type of the secret, which will be created.
- Returns: name of a secret
- """
- secret_name = "%s-%s" % (secret_name_prefix, utils.get_random_str())
- secret_data = json.dumps({
- "apiVersion": "v1",
- "data": {"key": base64.b64encode(data_key)},
- "kind": "Secret",
- "metadata": {
- "name": secret_name,
- "namespace": namespace,
- },
- "type": secret_type,
- })
- oc_create(hostname, secret_data, 'stdin')
- return secret_name
-
-
-def oc_create_sc(hostname, sc_name_prefix="autotests-sc",
- provisioner="kubernetes.io/glusterfs",
- allow_volume_expansion=False,
- reclaim_policy="Delete", **parameters):
- """Create storage class using data provided as stdin input.
-
- Args:
- hostname (str): Node on which 'oc create' command will be executed.
- sc_name_prefix (str): sc name will consist of this prefix and
- random str.
- provisioner (str): name of the provisioner
- allow_volume_expansion (bool): Set it to True if need to allow
- volume expansion.
- Kvargs:
- All the keyword arguments are expected to be key and values of
- 'parameters' section for storage class.
- """
- allowed_parameters = (
- 'resturl', 'secretnamespace', 'restuser', 'secretname',
- 'restauthenabled', 'restsecretnamespace', 'restsecretname',
- 'hacount', 'clusterids', 'chapauthenabled', 'volumenameprefix',
- 'volumeoptions', 'volumetype'
- )
- for parameter in parameters.keys():
- if parameter.lower() not in allowed_parameters:
- parameters.pop(parameter)
- sc_name = "%s-%s" % (sc_name_prefix, utils.get_random_str())
- sc_data = json.dumps({
- "kind": "StorageClass",
- "apiVersion": "storage.k8s.io/v1",
- "metadata": {"name": sc_name},
- "provisioner": provisioner,
- "reclaimPolicy": reclaim_policy,
- "parameters": parameters,
- "allowVolumeExpansion": allow_volume_expansion,
- })
- oc_create(hostname, sc_data, 'stdin')
- return sc_name
-
-
-def oc_create_pvc(hostname, sc_name=None, pvc_name_prefix="autotests-pvc",
- pvc_size=1):
- """Create PVC using data provided as stdin input.
-
- Args:
- hostname (str): Node on which 'oc create' command will be executed.
- sc_name (str): name of a storage class to create PVC in.
- pvc_name_prefix (str): PVC name will consist of this prefix and
- random str.
- pvc_size (int/str): size of PVC in Gb
- """
- pvc_name = "%s-%s" % (pvc_name_prefix, utils.get_random_str())
- metadata = {"name": pvc_name}
- if sc_name:
- metadata["annotations"] = {
- "volume.kubernetes.io/storage-class": sc_name,
- "volume.beta.kubernetes.io/storage-class": sc_name,
- }
- pvc_data = json.dumps({
- "kind": "PersistentVolumeClaim",
- "apiVersion": "v1",
- "metadata": metadata,
- "spec": {
- "accessModes": ["ReadWriteOnce"],
- "resources": {"requests": {"storage": "%sGi" % pvc_size}}
- },
- })
- oc_create(hostname, pvc_data, 'stdin')
- return pvc_name
-
-
-def oc_create_app_dc_with_io(
- hostname, pvc_name, dc_name_prefix="autotests-dc-with-app-io",
- replicas=1, space_to_use=1048576):
- """Create DC with app PODs and attached PVC, constantly running I/O.
-
- Args:
- hostname (str): Node on which 'oc create' command will be executed.
- pvc_name (str): name of the Persistent Volume Claim to attach to
- the application PODs where constant I/O will run.
- dc_name_prefix (str): DC name will consist of this prefix and
- random str.
- replicas (int): amount of application POD replicas.
- space_to_use (int): value in bytes which will be used for I/O.
- """
- dc_name = "%s-%s" % (dc_name_prefix, utils.get_random_str())
- container_data = {
- "name": dc_name,
- "image": "cirros",
- "volumeMounts": [{"mountPath": "/mnt", "name": dc_name}],
- "command": ["sh"],
- "args": [
- "-ec",
- "trap \"rm -f /mnt/random-data-$HOSTNAME.log ; exit 0\" SIGTERM; "
- "while true; do "
- " (mount | grep '/mnt') && "
- " (head -c %s < /dev/urandom > /mnt/random-data-$HOSTNAME.log) ||"
- " exit 1; "
- " sleep 1 ; "
- "done" % space_to_use,
- ],
- "livenessProbe": {
- "initialDelaySeconds": 3,
- "periodSeconds": 3,
- "exec": {"command": [
- "sh", "-ec",
- "mount | grep '/mnt' && "
- " head -c 1 < /dev/urandom >> /mnt/random-data-$HOSTNAME.log"
- ]},
- },
- }
- dc_data = json.dumps({
- "kind": "DeploymentConfig",
- "apiVersion": "v1",
- "metadata": {"name": dc_name},
- "spec": {
- "replicas": replicas,
- "triggers": [{"type": "ConfigChange"}],
- "paused": False,
- "revisionHistoryLimit": 2,
- "template": {
- "metadata": {"labels": {"name": dc_name}},
- "spec": {
- "restartPolicy": "Always",
- "volumes": [{
- "name": dc_name,
- "persistentVolumeClaim": {"claimName": pvc_name},
- }],
- "containers": [container_data],
- "terminationGracePeriodSeconds": 20,
- }
- }
- }
- })
- oc_create(hostname, dc_data, 'stdin')
- return dc_name
-
-
-def oc_create_tiny_pod_with_volume(hostname, pvc_name, pod_name_prefix='',
- mount_path='/mnt'):
- """Create tiny POD from image in 10Mb with attached volume at /mnt"""
- pod_name = "%s-%s" % (pod_name_prefix, utils.get_random_str())
- pod_data = json.dumps({
- "apiVersion": "v1",
- "kind": "Pod",
- "metadata": {
- "name": pod_name,
- },
- "spec": {
- "terminationGracePeriodSeconds": 20,
- "containers": [{
- "name": pod_name,
- "image": "cirros", # noqa: 10 Mb! linux image
- "volumeMounts": [{"mountPath": mount_path, "name": "vol"}],
- "command": [
- "/bin/sh", "-ec",
- "trap 'exit 0' SIGTERM ; "
- "while :; do echo '.'; sleep 5 ; done",
- ]
- }],
- "volumes": [{
- "name": "vol",
- "persistentVolumeClaim": {"claimName": pvc_name},
- }],
- "restartPolicy": "Never",
- }
- })
- oc_create(hostname, pod_data, 'stdin')
- return pod_name
-
-
-def oc_delete(ocp_node, rtype, name, raise_on_absence=True):
- """Delete an OCP resource by name.
-
- Args:
- ocp_node (str): Node on which the ocp command will run.
- rtype (str): Name of the resource type (pod, storageClass, etc).
- name (str): Name of the resource to delete.
- raise_on_absence (bool): if resource absent raise
- exception if value is true,
- else return
- default value: True
- """
- if not oc_get_yaml(ocp_node, rtype, name,
- raise_on_error=raise_on_absence):
- return
- cmd = ['oc', 'delete', rtype, name]
- if openshift_version.get_openshift_version() >= '3.11':
- cmd.append('--wait=false')
-
- ret, out, err = g.run(ocp_node, cmd)
- if ret != 0:
- g.log.error('Failed to delete resource: %s, %s: %r; %r',
- rtype, name, out, err)
- raise AssertionError('failed to delete resource: %r; %r' % (out, err))
- g.log.info('Deleted resource: %r %r', rtype, name)
-
-
-def oc_get_custom_resource(ocp_node, rtype, custom, name=None, selector=None,
- raise_on_error=True):
- """Get an OCP resource by custom column names.
-
- Args:
- ocp_node (str): Node on which the ocp command will run.
- rtype (str): Name of the resource type (pod, storageClass, etc).
- custom (str): Name of the custom columm to fetch.
- name (str|None): Name of the resource to fetch.
- selector (str|list|None): Column Name or list of column
- names select to.
- raise_on_error (bool): If set to true a failure to fetch
- resource inforation will raise an error, otherwise
- an empty dict will be returned.
- Returns:
- list: List containting data about the resource custom column
- Raises:
- AssertionError: Raised when unable to get resource and
- `raise_on_error` is true.
- Example:
- Get all "pvc" with "metadata.name" parameter values:
- pvc_details = oc_get_custom_resource(
- ocp_node, "pvc", ":.metadata.name"
- )
- """
- cmd = ['oc', 'get', rtype, '--no-headers']
-
- cmd.append('-o=custom-columns=%s' % (
- ','.join(custom) if isinstance(custom, list) else custom))
-
- if selector:
- cmd.append('--selector %s' % (
- ','.join(selector) if isinstance(selector, list) else selector))
-
- if name:
- cmd.append(name)
-
- ret, out, err = g.run(ocp_node, cmd)
- if ret != 0:
- g.log.error('Failed to get %s: %s: %r', rtype, name, err)
- if raise_on_error:
- raise AssertionError('failed to get %s: %s: %r'
- % (rtype, name, err))
- return []
-
- if name:
- return filter(None, map(str.strip, (out.strip()).split(' ')))
- else:
- out_list = []
- for line in (out.strip()).split('\n'):
- out_list.append(filter(None, map(str.strip, line.split(' '))))
- return out_list
-
-
-def oc_get_yaml(ocp_node, rtype, name=None, raise_on_error=True):
- """Get an OCP resource by name.
-
- Args:
- ocp_node (str): Node on which the ocp command will run.
- rtype (str): Name of the resource type (pod, storageClass, etc).
- name (str|None): Name of the resource to fetch.
- raise_on_error (bool): If set to true a failure to fetch
- resource inforation will raise an error, otherwise
- an empty dict will be returned.
- Returns:
- dict: Dictionary containting data about the resource
- Raises:
- AssertionError: Raised when unable to get resource and
- `raise_on_error` is true.
- """
- cmd = ['oc', 'get', '-oyaml', rtype]
- if name is not None:
- cmd.append(name)
- ret, out, err = g.run(ocp_node, cmd)
- if ret != 0:
- g.log.error('Failed to get %s: %s: %r', rtype, name, err)
- if raise_on_error:
- raise AssertionError('failed to get %s: %s: %r'
- % (rtype, name, err))
- return {}
- return yaml.load(out)
-
-
-def oc_get_pvc(ocp_node, name):
- """Get information on a persistant volume claim.
-
- Args:
- ocp_node (str): Node on which the ocp command will run.
- name (str): Name of the PVC.
- Returns:
- dict: Dictionary containting data about the PVC.
- """
- return oc_get_yaml(ocp_node, 'pvc', name)
-
-
-def oc_get_pv(ocp_node, name):
- """Get information on a persistant volume.
-
- Args:
- ocp_node (str): Node on which the ocp command will run.
- name (str): Name of the PV.
- Returns:
- dict: Dictionary containting data about the PV.
- """
- return oc_get_yaml(ocp_node, 'pv', name)
-
-
-def oc_get_all_pvs(ocp_node):
- """Get information on all persistent volumes.
-
- Args:
- ocp_node (str): Node on which the ocp command will run.
- Returns:
- dict: Dictionary containting data about the PV.
- """
- return oc_get_yaml(ocp_node, 'pv', None)
-
-
-def create_namespace(hostname, namespace):
- '''
- This function creates namespace
- Args:
- hostname (str): hostname on which we need to
- create namespace
- namespace (str): project name
- Returns:
- bool: True if successful and if already exists,
- otherwise False
- '''
- cmd = "oc new-project %s" % namespace
- ret, out, err = g.run(hostname, cmd, "root")
- if ret == 0:
- g.log.info("new namespace %s successfully created" % namespace)
- return True
- output = out.strip().split("\n")[0]
- if "already exists" in output:
- g.log.info("namespace %s already exists" % namespace)
- return True
- g.log.error("failed to create namespace %s" % namespace)
- return False
-
-
-def wait_for_resource_absence(ocp_node, rtype, name,
- interval=5, timeout=300):
- _waiter = waiter.Waiter(timeout=timeout, interval=interval)
- resource, pv_name = None, None
- for w in _waiter:
- try:
- resource = oc_get_yaml(ocp_node, rtype, name, raise_on_error=True)
- except AssertionError:
- break
- if rtype == 'pvc':
- cmd = "oc get pv -o=custom-columns=:.spec.claimRef.name | grep %s" % (
- name)
- for w in _waiter:
- ret, out, err = g.run(ocp_node, cmd, "root")
- _pv_name = out.strip()
- if _pv_name and not pv_name:
- pv_name = _pv_name
- if ret != 0:
- break
- if w.expired:
- # Gather more info for ease of debugging
- try:
- r_events = get_events(ocp_node, obj_name=name)
- except Exception:
- r_events = '?'
- error_msg = (
- "%s '%s' still exists after waiting for it %d seconds.\n"
- "Resource info: %s\n"
- "Resource related events: %s" % (
- rtype, name, timeout, resource, r_events))
- if rtype == 'pvc' and pv_name:
- try:
- pv_events = get_events(ocp_node, obj_name=pv_name)
- except Exception:
- pv_events = '?'
- error_msg += "\nPV events: %s" % pv_events
-
- g.log.error(error_msg)
- raise exceptions.ExecutionError(error_msg)
-
-
-def scale_dc_pod_amount_and_wait(hostname, dc_name,
- pod_amount=1, namespace=None):
- """Scale amount of PODs for a DC.
-
- If pod_amount is 0, then wait for it's absence.
- If pod_amount => 1, then wait for all of a DC PODs to be ready.
-
- Args:
- hostname (str): Node on which the ocp command will run
- dc_name (str): Name of heketi dc
- pod_amount (int): Number of PODs to scale. Default is 1.
- namespace (str): Namespace of a DC.
- """
- namespace_arg = "--namespace=%s" % namespace if namespace else ""
- scale_cmd = "oc scale --replicas=%d dc/%s %s" % (
- pod_amount, dc_name, namespace_arg)
- command.cmd_run(scale_cmd, hostname=hostname)
-
- pod_names = get_pod_names_from_dc(hostname, dc_name)
- for pod_name in pod_names:
- if pod_amount == 0:
- wait_for_resource_absence(hostname, 'pod', pod_name)
- else:
- wait_for_pod_be_ready(hostname, pod_name)
- return pod_names
-
-
-def get_gluster_pod_names_by_pvc_name(ocp_node, pvc_name):
- """Get Gluster POD names, whose nodes store bricks for specified PVC.
-
- Args:
- ocp_node (str): Node to execute OCP commands on.
- pvc_name (str): Name of a PVC to get related Gluster PODs.
- Returns:
- list: List of dicts, which consist of following 3 key-value pairs:
- pod_name=<pod_name_value>,
- host_name=<host_name_value>,
- host_ip=<host_ip_value>
- """
- # Check storage provisioner
- sp_cmd = (
- r'oc get pvc %s --no-headers -o=custom-columns='
- r':.metadata.annotations."volume\.beta\.kubernetes\.io\/'
- r'storage\-provisioner"' % pvc_name)
- sp_raw = command.cmd_run(sp_cmd, hostname=ocp_node)
- sp = sp_raw.strip()
-
- # Get node IPs
- if sp == "kubernetes.io/glusterfs":
- pv_info = get_gluster_vol_info_by_pvc_name(ocp_node, pvc_name)
- gluster_pod_nodes_ips = [
- brick["name"].split(":")[0]
- for brick in pv_info["bricks"]["brick"]
- ]
- elif sp == "gluster.org/glusterblock":
- get_gluster_pod_node_ip_cmd = (
- r"""oc get pv --template '{{range .items}}""" +
- r"""{{if eq .spec.claimRef.name "%s"}}""" +
- r"""{{.spec.iscsi.targetPortal}}{{" "}}""" +
- r"""{{.spec.iscsi.portals}}{{end}}{{end}}'""") % (
- pvc_name)
- node_ips_raw = command.cmd_run(
- get_gluster_pod_node_ip_cmd, hostname=ocp_node)
- node_ips_raw = node_ips_raw.replace(
- "[", " ").replace("]", " ").replace(",", " ")
- gluster_pod_nodes_ips = [
- s.strip() for s in node_ips_raw.split(" ") if s.strip()
- ]
- else:
- assert False, "Unexpected storage provisioner: %s" % sp
-
- # Get node names
- get_node_names_cmd = (
- "oc get node -o wide | grep -e '%s ' | awk '{print $1}'" % (
- " ' -e '".join(gluster_pod_nodes_ips)))
- gluster_pod_node_names = command.cmd_run(
- get_node_names_cmd, hostname=ocp_node)
- gluster_pod_node_names = [
- node_name.strip()
- for node_name in gluster_pod_node_names.split("\n")
- if node_name.strip()
- ]
- node_count = len(gluster_pod_node_names)
- err_msg = "Expected more than one node hosting Gluster PODs. Got '%s'." % (
- node_count)
- assert (node_count > 1), err_msg
-
- # Get Gluster POD names which are located on the filtered nodes
- get_pod_name_cmd = (
- "oc get pods --all-namespaces "
- "-o=custom-columns=:.metadata.name,:.spec.nodeName,:.status.hostIP | "
- "grep 'glusterfs-' | grep -e '%s '" % "' -e '".join(
- gluster_pod_node_names)
- )
- out = command.cmd_run(
- get_pod_name_cmd, hostname=ocp_node)
- data = []
- for line in out.split("\n"):
- pod_name, host_name, host_ip = [
- el.strip() for el in line.split(" ") if el.strip()]
- data.append({
- "pod_name": pod_name,
- "host_name": host_name,
- "host_ip": host_ip,
- })
- pod_count = len(data)
- err_msg = "Expected 3 or more Gluster PODs to be found. Actual is '%s'" % (
- pod_count)
- assert (pod_count > 2), err_msg
- return data
-
-
-def cmd_run_on_gluster_pod_or_node(ocp_client_node, cmd, gluster_node=None):
- """Run shell command on either Gluster PODs or Gluster nodes.
-
- Args:
- ocp_client_node (str): Node to execute OCP commands on.
- cmd (str): shell command to run.
- gluster_node (str): optional. Allows to chose specific gluster node,
- keeping abstraction from deployment type. Can be either IP address
- or node name from "oc get nodes" command.
- Returns:
- Output of a shell command as string object.
- """
- # Containerized Glusterfs
- gluster_pods = oc_get_pods(ocp_client_node, selector="glusterfs-node=pod")
- err_msg = ""
- if gluster_pods:
- if gluster_node:
- for pod_name, pod_data in gluster_pods.items():
- if gluster_node in (pod_data["ip"], pod_data["node"]):
- gluster_pod_names = [pod_name]
- break
- else:
- raise exceptions.ExecutionError(
- "Could not find Gluster PODs with node filter as "
- "'%s'." % gluster_node)
- else:
- gluster_pod_names = gluster_pods.keys()
-
- for gluster_pod_name in gluster_pod_names:
- try:
- pod_cmd = "oc exec %s -- %s" % (gluster_pod_name, cmd)
- return command.cmd_run(pod_cmd, hostname=ocp_client_node)
- except Exception as e:
- err = ("Failed to run '%s' command on '%s' Gluster POD. "
- "Error: %s\n" % (cmd, gluster_pod_name, e))
- err_msg += err
- g.log.error(err)
- raise exceptions.ExecutionError(err_msg)
-
- # Standalone Glusterfs
- if gluster_node:
- g_hosts = [gluster_node]
- else:
- g_hosts = g.config.get("gluster_servers", {}).keys()
- for g_host in g_hosts:
- try:
- return command.cmd_run(cmd, hostname=g_host)
- except Exception as e:
- err = ("Failed to run '%s' command on '%s' Gluster node. "
- "Error: %s\n" % (cmd, g_host, e))
- err_msg += err
- g.log.error(err)
-
- if not err_msg:
- raise exceptions.ExecutionError(
- "Haven't found neither Gluster PODs nor Gluster nodes.")
- raise exceptions.ExecutionError(err_msg)
-
-
-def get_gluster_vol_info_by_pvc_name(ocp_node, pvc_name):
- """Get Gluster volume info based on the PVC name.
-
- Args:
- ocp_node (str): Node to execute OCP commands on.
- pvc_name (str): Name of a PVC to get bound Gluster volume info.
- Returns:
- dict: Dictionary containting data about a Gluster volume.
- """
-
- # Get PV ID from PVC
- get_pvc_cmd = "oc get pvc %s -o=custom-columns=:.spec.volumeName" % (
- pvc_name)
- pv_name = command.cmd_run(get_pvc_cmd, hostname=ocp_node)
- assert pv_name, "PV name should not be empty: '%s'" % pv_name
-
- # Get volume ID from PV
- get_pv_cmd = "oc get pv %s -o=custom-columns=:.spec.glusterfs.path" % (
- pv_name)
- vol_id = command.cmd_run(get_pv_cmd, hostname=ocp_node)
- assert vol_id, "Gluster volume ID should not be empty: '%s'" % vol_id
-
- vol_info_cmd = "gluster v info %s --xml" % vol_id
- vol_info = cmd_run_on_gluster_pod_or_node(ocp_node, vol_info_cmd)
-
- # Parse XML output to python dict
- with mock.patch('glusto.core.Glusto.run', return_value=(0, vol_info, '')):
- vol_info = volume_ops.get_volume_info(vol_id)
- vol_info = vol_info[list(vol_info.keys())[0]]
- vol_info["gluster_vol_id"] = vol_id
- return vol_info
-
-
-def get_gluster_blockvol_info_by_pvc_name(ocp_node, heketi_server_url,
- pvc_name):
- """Get Gluster block volume info based on the PVC name.
-
- Args:
- ocp_node (str): Node to execute OCP commands on.
- heketi_server_url (str): Heketi server url
- pvc_name (str): Name of a PVC to get bound Gluster block volume info.
- Returns:
- dict: Dictionary containting data about a Gluster block volume.
- """
-
- # Get block volume Name and ID from PV which is bound to our PVC
- get_block_vol_data_cmd = (
- r'oc get pv --no-headers -o custom-columns='
- r':.metadata.annotations.glusterBlockShare,'
- r':.metadata.annotations."gluster\.org\/volume\-id",'
- r':.spec.claimRef.name | grep "%s"' % pvc_name)
- out = command.cmd_run(get_block_vol_data_cmd, hostname=ocp_node)
- parsed_out = filter(None, map(str.strip, out.split(" ")))
- assert len(parsed_out) == 3, "Expected 3 fields in following: %s" % out
- block_vol_name, block_vol_id = parsed_out[:2]
-
- # Get block hosting volume ID
- block_hosting_vol_id = heketi_blockvolume_info(
- ocp_node, heketi_server_url, block_vol_id, json=True
- )["blockhostingvolume"]
-
- # Get block hosting volume name by it's ID
- block_hosting_vol_name = heketi_volume_info(
- ocp_node, heketi_server_url, block_hosting_vol_id, json=True)['name']
-
- # Get Gluster block volume info
- vol_info_cmd = "gluster-block info %s/%s --json" % (
- block_hosting_vol_name, block_vol_name)
- vol_info = cmd_run_on_gluster_pod_or_node(ocp_node, vol_info_cmd)
-
- return json.loads(vol_info)
-
-
-def wait_for_pod_be_ready(hostname, pod_name,
- timeout=1200, wait_step=60):
- '''
- This funciton waits for pod to be in ready state
- Args:
- hostname (str): hostname on which we want to check the pod status
- pod_name (str): pod_name for which we need the status
- timeout (int): timeout value,,
- default value is 1200 sec
- wait_step( int): wait step,
- default value is 60 sec
- Returns:
- bool: True if pod status is Running and ready state,
- otherwise Raise Exception
- '''
- for w in waiter.Waiter(timeout, wait_step):
- # command to find pod status and its phase
- cmd = ("oc get pods %s -o=custom-columns="
- ":.status.containerStatuses[0].ready,"
- ":.status.phase") % pod_name
- ret, out, err = g.run(hostname, cmd, "root")
- if ret != 0:
- msg = "Failed to execute cmd: %s\nout: %s\nerr: %s" % (
- cmd, out, err)
- g.log.error(msg)
- raise exceptions.ExecutionError(msg)
- output = out.strip().split()
-
- # command to find if pod is ready
- if output[0] == "true" and output[1] == "Running":
- g.log.info("pod %s is in ready state and is "
- "Running" % pod_name)
- return True
- elif output[1] == "Error":
- msg = ("pod %s status error" % pod_name)
- g.log.error(msg)
- raise exceptions.ExecutionError(msg)
- else:
- g.log.info("pod %s ready state is %s,"
- " phase is %s,"
- " sleeping for %s sec" % (
- pod_name, output[0],
- output[1], wait_step))
- continue
- if w.expired:
- err_msg = ("exceeded timeout %s for waiting for pod %s "
- "to be in ready state" % (timeout, pod_name))
- g.log.error(err_msg)
- raise exceptions.ExecutionError(err_msg)
-
-
-def get_pod_names_from_dc(hostname, dc_name, timeout=180, wait_step=3):
- """Return list of POD names by their DC.
-
- Args:
- hostname (str): hostname on which 'oc' commands will be executed.
- dc_name (str): deployment_confidg name
- timeout (int): timeout value. Default value is 180 sec.
- wait_step( int): Wait step, default value is 3 sec.
- Returns:
- list: list of strings which are POD names
- Raises: exceptions.ExecutionError
- """
- get_replicas_amount_cmd = (
- "oc get dc --no-headers --all-namespaces "
- "-o=custom-columns=:.spec.replicas,:.metadata.name "
- "| grep '%s' | awk '{print $1}'" % dc_name)
- replicas = int(command.cmd_run(
- get_replicas_amount_cmd, hostname=hostname))
-
- get_pod_names_cmd = (
- "oc get pods --all-namespaces -o=custom-columns=:.metadata.name "
- "--no-headers=true --selector deploymentconfig=%s" % dc_name)
- for w in waiter.Waiter(timeout, wait_step):
- out = command.cmd_run(get_pod_names_cmd, hostname=hostname)
- pod_names = [o.strip() for o in out.split('\n') if o.strip()]
- if len(pod_names) != replicas:
- continue
- g.log.info(
- "POD names for '%s' DC are '%s'. "
- "Expected amount of PODs is '%s'.", dc_name, out, replicas)
- return pod_names
- if w.expired:
- err_msg = ("Exceeded %s sec timeout waiting for PODs to appear "
- "in amount of %s." % (timeout, replicas))
- g.log.error(err_msg)
- raise exceptions.ExecutionError(err_msg)
-
-
-def get_pod_name_from_dc(hostname, dc_name, timeout=180, wait_step=3):
- return get_pod_names_from_dc(
- hostname, dc_name, timeout=timeout, wait_step=wait_step)[0]
-
-
-def get_pvc_status(hostname, pvc_name):
- '''
- This function verifies the if pod is running
- Args:
- hostname (str): hostname on which we want
- to check the pvc status
- pvc_name (str): pod_name for which we
- need the status
- Returns:
- bool, status (str): True, status of pvc
- otherwise False, error message.
- '''
- cmd = "oc get pvc | grep %s | awk '{print $2}'" % pvc_name
- ret, out, err = g.run(hostname, cmd, "root")
- if ret != 0:
- g.log.error("failed to execute cmd %s" % cmd)
- return False, err
- output = out.strip().split("\n")[0].strip()
- return True, output
-
-
-def verify_pvc_status_is_bound(hostname, pvc_name, timeout=120, wait_step=3):
- """Verify that PVC gets 'Bound' status in required time.
-
- Args:
- hostname (str): hostname on which we will execute oc commands
- pvc_name (str): name of PVC to check status of
- timeout (int): total time in seconds we are ok to wait
- for 'Bound' status of a PVC
- wait_step (int): time in seconds we will sleep before checking a PVC
- status again.
- Returns: None
- Raises: exceptions.ExecutionError in case of errors.
- """
- pvc_not_found_counter = 0
- for w in waiter.Waiter(timeout, wait_step):
- ret, output = get_pvc_status(hostname, pvc_name)
- if ret is not True:
- msg = ("Failed to execute 'get' command for '%s' PVC. "
- "Got following responce: %s" % (pvc_name, output))
- g.log.error(msg)
- raise exceptions.ExecutionError(msg)
- if output == "":
- g.log.info("PVC '%s' not found, sleeping for %s "
- "sec." % (pvc_name, wait_step))
- if pvc_not_found_counter > 0:
- msg = ("PVC '%s' has not been found 2 times already. "
- "Make sure you provided correct PVC name." % pvc_name)
- else:
- pvc_not_found_counter += 1
- continue
- elif output == "Pending":
- g.log.info("PVC '%s' is in Pending state, sleeping for %s "
- "sec" % (pvc_name, wait_step))
- continue
- elif output == "Bound":
- g.log.info("PVC '%s' is in Bound state." % pvc_name)
- return pvc_name
- elif output == "Error":
- msg = "PVC '%s' is in 'Error' state." % pvc_name
- g.log.error(msg)
- else:
- msg = "PVC %s has different status - %s" % (pvc_name, output)
- g.log.error(msg)
- if msg:
- raise AssertionError(msg)
- if w.expired:
- msg = ("Exceeded timeout of '%s' seconds for verifying PVC '%s' "
- "to reach the 'Bound' state." % (timeout, pvc_name))
-
- # Gather more info for ease of debugging
- try:
- pvc_events = get_events(hostname, obj_name=pvc_name)
- except Exception:
- pvc_events = '?'
- msg += "\nPVC events: %s" % pvc_events
-
- g.log.error(msg)
- raise AssertionError(msg)
-
-
-def resize_pvc(hostname, pvc_name, size):
- '''
- Resize PVC
- Args:
- hostname (str): hostname on which we want
- to edit the pvc status
- pvc_name (str): pod_name for which we
- edit the storage capacity
- size (int): size of pvc to change
- Returns:
- bool: True, if successful
- otherwise raise Exception
- '''
- cmd = ("oc patch pvc %s "
- "-p='{\"spec\": {\"resources\": {\"requests\": "
- "{\"storage\": \"%dGi\"}}}}'" % (pvc_name, size))
- ret, out, err = g.run(hostname, cmd, "root")
- if ret != 0:
- error_msg = ("failed to execute cmd %s "
- "out- %s err %s" % (cmd, out, err))
- g.log.error(error_msg)
- raise exceptions.ExecutionError(error_msg)
-
- g.log.info("successfully edited storage capacity"
- "of pvc %s . out- %s" % (pvc_name, out))
- return True
-
-
-def verify_pvc_size(hostname, pvc_name, size,
- timeout=120, wait_step=5):
- '''
- Verify size of PVC
- Args:
- hostname (str): hostname on which we want
- to verify the size of pvc
- pvc_name (str): pvc_name for which we
- verify its size
- size (int): size of pvc
- timeout (int): timeout value,
- verifies the size after wait_step
- value till timeout
- default value is 120 sec
- wait_step( int): wait step,
- default value is 5 sec
- Returns:
- bool: True, if successful
- otherwise raise Exception
- '''
- cmd = ("oc get pvc %s -o=custom-columns="
- ":.spec.resources.requests.storage,"
- ":.status.capacity.storage" % pvc_name)
- for w in waiter.Waiter(timeout, wait_step):
- sizes = command.cmd_run(cmd, hostname=hostname).split()
- spec_size = int(sizes[0].replace("Gi", ""))
- actual_size = int(sizes[1].replace("Gi", ""))
- if spec_size == actual_size == size:
- g.log.info("verification of pvc %s of size %d "
- "successful" % (pvc_name, size))
- return True
- else:
- g.log.info("sleeping for %s sec" % wait_step)
- continue
-
- err_msg = ("verification of pvc %s size of %d failed -"
- "spec_size- %d actual_size %d" % (
- pvc_name, size, spec_size, actual_size))
- g.log.error(err_msg)
- raise AssertionError(err_msg)
-
-
-def verify_pv_size(hostname, pv_name, size,
- timeout=120, wait_step=5):
- '''
- Verify size of PV
- Args:
- hostname (str): hostname on which we want
- to verify the size of pv
- pv_name (str): pv_name for which we
- verify its size
- size (int): size of pv
- timeout (int): timeout value,
- verifies the size after wait_step
- value till timeout
- default value is 120 sec
- wait_step( int): wait step,
- default value is 5 sec
- Returns:
- bool: True, if successful
- otherwise raise Exception
- '''
- cmd = ("oc get pv %s -o=custom-columns=:."
- "spec.capacity.storage" % pv_name)
- for w in waiter.Waiter(timeout, wait_step):
- pv_size = command.cmd_run(cmd, hostname=hostname).split()[0]
- pv_size = int(pv_size.replace("Gi", ""))
- if pv_size == size:
- g.log.info("verification of pv %s of size %d "
- "successful" % (pv_name, size))
- return True
- else:
- g.log.info("sleeping for %s sec" % wait_step)
- continue
-
- err_msg = ("verification of pv %s size of %d failed -"
- "pv_size- %d" % (pv_name, size, pv_size))
- g.log.error(err_msg)
- raise AssertionError(err_msg)
-
-
-def get_pv_name_from_pvc(hostname, pvc_name):
- '''
- Returns PV name of the corresponding PVC name
- Args:
- hostname (str): hostname on which we want
- to find pv name
- pvc_name (str): pvc_name for which we
- want to find corresponding
- pv name
- Returns:
- pv_name (str): pv name if successful,
- otherwise raise Exception
- '''
- cmd = ("oc get pvc %s -o=custom-columns=:."
- "spec.volumeName" % pvc_name)
- pv_name = command.cmd_run(cmd, hostname=hostname)
- g.log.info("pv name is %s for pvc %s" % (
- pv_name, pvc_name))
-
- return pv_name
-
-
-def get_vol_names_from_pv(hostname, pv_name):
- '''
- Returns the heketi and gluster
- vol names of the corresponding PV
- Args:
- hostname (str): hostname on which we want
- to find vol names
- pv_name (str): pv_name for which we
- want to find corresponding
- vol names
- Returns:
- volname (dict): dict if successful
- {"heketi_vol": heketi_vol_name,
- "gluster_vol": gluster_vol_name
- ex: {"heketi_vol": " xxxx",
- "gluster_vol": "vol_xxxx"]
- otherwise raise Exception
- '''
- vol_dict = {}
- cmd = (r"oc get pv %s -o=custom-columns="
- r":.metadata.annotations."
- r"'gluster\.kubernetes\.io\/heketi\-volume\-id',"
- r":.spec.glusterfs.path" % pv_name)
- vol_list = command.cmd_run(cmd, hostname=hostname).split()
- vol_dict = {"heketi_vol": vol_list[0],
- "gluster_vol": vol_list[1]}
- g.log.info("gluster vol name is %s and heketi vol name"
- " is %s for pv %s"
- % (vol_list[1], vol_list[0], pv_name))
- return vol_dict
-
-
-def get_events(hostname,
- obj_name=None, obj_namespace=None, obj_type=None,
- event_reason=None, event_type=None):
- """Return filtered list of events.
-
- Args:
- hostname (str): hostname of oc client
- obj_name (str): name of an object
- obj_namespace (str): namespace where object is located
- obj_type (str): type of an object, i.e. PersistentVolumeClaim or Pod
- event_reason (str): reason why event was created,
- i.e. Created, Started, Unhealthy, SuccessfulCreate, Scheduled ...
- event_type (str): type of an event, i.e. Normal or Warning
- Returns:
- List of dictionaries, where the latter are of following structure:
- {
- "involvedObject": {
- "kind": "ReplicationController",
- "name": "foo-object-name",
- "namespace": "foo-object-namespace",
- },
- "message": "Created pod: foo-object-name",
- "metadata": {
- "creationTimestamp": "2018-10-19T18:27:09Z",
- "name": "foo-object-name.155f15db4e72cc2e",
- "namespace": "foo-object-namespace",
- },
- "reason": "SuccessfulCreate",
- "reportingComponent": "",
- "reportingInstance": "",
- "source": {"component": "replication-controller"},
- "type": "Normal"
- }
- """
- field_selector = []
- if obj_name:
- field_selector.append('involvedObject.name=%s' % obj_name)
- if obj_namespace:
- field_selector.append('involvedObject.namespace=%s' % obj_namespace)
- if obj_type:
- field_selector.append('involvedObject.kind=%s' % obj_type)
- if event_reason:
- field_selector.append('reason=%s' % event_reason)
- if event_type:
- field_selector.append('type=%s' % event_type)
- cmd = "oc get events -o yaml --field-selector %s" % ",".join(
- field_selector or "''")
- return yaml.load(command.cmd_run(cmd, hostname=hostname))['items']
-
-
-def wait_for_events(hostname,
- obj_name=None, obj_namespace=None, obj_type=None,
- event_reason=None, event_type=None,
- timeout=120, wait_step=3):
- """Wait for appearence of specific set of events."""
- for w in waiter.Waiter(timeout, wait_step):
- events = get_events(
- hostname=hostname, obj_name=obj_name, obj_namespace=obj_namespace,
- obj_type=obj_type, event_reason=event_reason,
- event_type=event_type)
- if events:
- return events
- if w.expired:
- err_msg = ("Exceeded %ssec timeout waiting for events." % timeout)
- g.log.error(err_msg)
- raise exceptions.ExecutionError(err_msg)
-
-
-def match_pvc_and_pv(hostname, prefix):
- """Match OCP PVCs and PVs generated
-
- Args:
- hostname (str): hostname of oc client
- prefix (str): pv prefix used by user at time
- of pvc creation
- """
- pvc_list = sorted([
- pvc[0]
- for pvc in oc_get_custom_resource(hostname, "pvc", ":.metadata.name")
- if pvc[0].startswith(prefix)
- ])
-
- pv_list = sorted([
- pv[0]
- for pv in oc_get_custom_resource(
- hostname, "pv", ":.spec.claimRef.name"
- )
- if pv[0].startswith(prefix)
- ])
-
- if cmp(pvc_list, pv_list) != 0:
- err_msg = "PVC and PV list match failed"
- err_msg += "\nPVC list: %s, " % pvc_list
- err_msg += "\nPV list %s" % pv_list
- err_msg += "\nDifference: %s" % (set(pvc_list) ^ set(pv_list))
- raise AssertionError(err_msg)
-
-
-def match_pv_and_heketi_block_volumes(
- hostname, heketi_block_volumes, pvc_prefix):
- """Match heketi block volumes and OC PVCs
-
- Args:
- hostname (str): hostname on which we want to check heketi
- block volumes and OCP PVCs
- heketi_block_volumes (list): list of heketi block volume names
- pvc_prefix (str): pv prefix given by user at the time of pvc creation
- """
- custom_columns = [
- r':.spec.claimRef.name',
- r':.metadata.annotations."pv\.kubernetes\.io\/provisioned\-by"',
- r':.metadata.annotations."gluster\.org\/volume\-id"'
- ]
- pv_block_volumes = sorted([
- pv[2]
- for pv in oc_get_custom_resource(hostname, "pv", custom_columns)
- if pv[0].startswith(pvc_prefix) and pv[1] == "gluster.org/glusterblock"
- ])
-
- if cmp(pv_block_volumes, heketi_block_volumes) != 0:
- err_msg = "PV block volumes and Heketi Block volume list match failed"
- err_msg += "\nPV Block Volumes: %s, " % pv_block_volumes
- err_msg += "\nHeketi Block volumes %s" % heketi_block_volumes
- err_msg += "\nDifference: %s" % (set(pv_block_volumes) ^
- set(heketi_block_volumes))
- raise AssertionError(err_msg)
-
-
-def check_service_status_on_pod(
- ocp_client, podname, service, status, timeout=180, wait_step=3):
- """Check a service state on a pod.
-
- Args:
- ocp_client (str): node with 'oc' client
- podname (str): pod name on which service needs to be checked
- service (str): service which needs to be checked
- status (str): status to be checked
- timeout (int): seconds to wait before service starts having
- specified 'status'
- wait_step (int): interval in seconds to wait before checking
- service again.
- """
- err_msg = ("Exceeded timeout of %s sec for verifying %s service to start "
- "having '%s' status" % (timeout, service, status))
-
- for w in waiter.Waiter(timeout, wait_step):
- ret, out, err = oc_rsh(ocp_client, podname, SERVICE_STATUS % service)
- if ret != 0:
- err_msg = ("failed to get service %s's status on pod %s" %
- (service, podname))
- g.log.error(err_msg)
- raise AssertionError(err_msg)
-
- for line in out.splitlines():
- status_match = re.search(SERVICE_STATUS_REGEX, line)
- if status_match and status_match.group(1) == status:
- return True
-
- if w.expired:
- g.log.error(err_msg)
- raise exceptions.ExecutionError(err_msg)
-
-
-def wait_for_service_status_on_gluster_pod_or_node(
- ocp_client, service, status, gluster_node, timeout=180, wait_step=3):
- """Wait for a service specific status on a Gluster POD or node.
-
- Args:
- ocp_client (str): hostname on which we want to check service
- service (str): target service to be checked
- status (str): service status which we wait for
- gluster_node (str): Gluster node IPv4 which stores either Gluster POD
- or Gluster services directly.
- timeout (int): seconds to wait before service starts having
- specified 'status'
- wait_step (int): interval in seconds to wait before checking
- service again.
- """
- err_msg = ("Exceeded timeout of %s sec for verifying %s service to start "
- "having '%s' status" % (timeout, service, status))
-
- for w in waiter.Waiter(timeout, wait_step):
- out = cmd_run_on_gluster_pod_or_node(
- ocp_client, SERVICE_STATUS % service, gluster_node)
- for line in out.splitlines():
- status_match = re.search(SERVICE_STATUS_REGEX, line)
- if status_match and status_match.group(1) == status:
- return True
- if w.expired:
- g.log.error(err_msg)
- raise exceptions.ExecutionError(err_msg)
-
-
-def restart_service_on_gluster_pod_or_node(ocp_client, service, gluster_node):
- """Restart service on Gluster either POD or node.
-
- Args:
- ocp_client (str): host on which we want to run 'oc' commands.
- service (str): service which needs to be restarted
- gluster_node (str): Gluster node IPv4 which stores either Gluster POD
- or Gluster services directly.
- Raises:
- AssertionError in case restart of a service fails.
- """
- cmd_run_on_gluster_pod_or_node(
- ocp_client, SERVICE_RESTART % service, gluster_node)
-
-
-def oc_adm_manage_node(
- ocp_client, operation, nodes=None, node_selector=None):
- """Manage common operations on nodes for administrators.
-
- Args:
- ocp_client (str): host on which we want to run 'oc' commands.
- operations (str):
- eg. --schedulable=true.
- nodes (list): list of nodes to manage.
- node_selector (str): selector to select the nodes.
- Note: 'nodes' and 'node_selector' are are mutually exclusive.
- Only either of them should be passed as parameter not both.
- Returns:
- str: In case of success.
- Raises:
- AssertionError: In case of any failures.
- """
-
- if (not nodes) == (not node_selector):
- raise AssertionError(
- "'nodes' and 'node_selector' are mutually exclusive. "
- "Only either of them should be passed as parameter not both.")
-
- cmd = "oc adm manage-node %s" % operation
- if node_selector:
- cmd += " --selector %s" % node_selector
- else:
- node = ' '.join(nodes)
- cmd += " " + node
-
- return command.cmd_run(cmd, ocp_client)
-
-
-def oc_get_schedulable_nodes(ocp_client):
- """Get the list of schedulable nodes.
-
- Args:
- ocp_client (str): host on which we want to run 'oc' commands.
-
- Returns:
- list: list of nodes if present.
- Raises:
- AssertionError: In case of any failures.
- """
- cmd = ("oc get nodes --field-selector=spec.unschedulable!=true "
- "-o=custom-columns=:.metadata.name,:.spec.taints[*].effect "
- "--no-headers | awk '!/NoSchedule/{print $1}'")
-
- out = command.cmd_run(cmd, ocp_client)
-
- return out.split('\n') if out else out