diff options
-rw-r--r-- | cns-libs/cnslibs/common/cns_libs.py | 8 | ||||
-rw-r--r-- | cns-libs/cnslibs/common/openshift_ops.py | 33 | ||||
-rw-r--r-- | cns-libs/cnslibs/common/openshift_version.py | 173 | ||||
-rw-r--r-- | tests/functional/common/provisioning/test_pv_resize.py | 5 |
4 files changed, 181 insertions, 38 deletions
diff --git a/cns-libs/cnslibs/common/cns_libs.py b/cns-libs/cnslibs/common/cns_libs.py index 68951784..16c050ca 100644 --- a/cns-libs/cnslibs/common/cns_libs.py +++ b/cns-libs/cnslibs/common/cns_libs.py @@ -4,7 +4,7 @@ import yaml from cnslibs.common.exceptions import ( ExecutionError, NotSupportedException) -from cnslibs.common.openshift_ops import oc_version +from cnslibs.common.openshift_version import get_openshift_version MASTER_CONFIG_FILEPATH = "/etc/origin/master/master-config.yaml" @@ -74,8 +74,8 @@ def enable_pvc_resize(master_node): bool: True if successful, otherwise raise Exception ''' - version = oc_version(master_node) - if any(v in version for v in ("3.6", "3.7", "3.8")): + version = get_openshift_version() + if version < "3.9": msg = ("pv resize is not available in openshift " "version %s " % version) g.log.error(msg) @@ -118,7 +118,7 @@ def enable_pvc_resize(master_node): g.log.info("successfully edited master-config.yaml file " "%s" % master_node) - if "3.9" in version: + if version == "3.9": cmd = ("systemctl restart atomic-openshift-master-api " "atomic-openshift-master-controllers") else: diff --git a/cns-libs/cnslibs/common/openshift_ops.py b/cns-libs/cnslibs/common/openshift_ops.py index eac0f994..cc84098e 100644 --- a/cns-libs/cnslibs/common/openshift_ops.py +++ b/cns-libs/cnslibs/common/openshift_ops.py @@ -19,6 +19,7 @@ import yaml from cnslibs.common import command from cnslibs.common import exceptions +from cnslibs.common import openshift_version from cnslibs.common import podcmd from cnslibs.common import utils from cnslibs.common import waiter @@ -32,7 +33,6 @@ PODS_WIDE_RE = re.compile( SERVICE_STATUS = "systemctl status %s" SERVICE_RESTART = "systemctl restart %s" SERVICE_STATUS_REGEX = r"Active: active \((.*)\) since .*;.*" -OC_VERSION = None def oc_get_pods(ocp_node): @@ -495,13 +495,7 @@ def oc_delete(ocp_node, rtype, name, raise_on_absence=True): raise_on_error=raise_on_absence): return cmd = ['oc', 'delete', rtype, name] - - global OC_VERSION - if not OC_VERSION: - OC_VERSION = oc_version(ocp_node) - - versions = ['v3.6', 'v3.7', 'v3.9', 'v3.10'] - if not OC_VERSION.rsplit('.', 1)[0] in versions: + if openshift_version.get_openshift_version() >= '3.11': cmd.append('--wait=false') ret, out, err = g.run(ocp_node, cmd) @@ -1078,29 +1072,6 @@ def verify_pvc_status_is_bound(hostname, pvc_name, timeout=120, wait_step=3): raise AssertionError(msg) -def oc_version(hostname): - ''' - Get Openshift version from oc version command - Args: - hostname (str): Node on which the ocp command will run. - Returns: - str : oc version if successful, - otherwise raise Exception - ''' - cmd = "oc version | grep openshift | cut -d ' ' -f 2" - ret, out, err = g.run(hostname, cmd, "root") - if ret != 0: - msg = ("failed to get oc version err %s; out %s" % (err, out)) - g.log.error(msg) - raise AssertionError(msg) - if not out: - error_msg = "Empty string found for oc version" - g.log.error(error_msg) - raise exceptions.ExecutionError(error_msg) - - return out.strip() - - def resize_pvc(hostname, pvc_name, size): ''' Resize PVC diff --git a/cns-libs/cnslibs/common/openshift_version.py b/cns-libs/cnslibs/common/openshift_version.py new file mode 100644 index 00000000..a532d837 --- /dev/null +++ b/cns-libs/cnslibs/common/openshift_version.py @@ -0,0 +1,173 @@ +""" +Use this module for any OpenShift version comparisons. + +Usage example: + + # Assume OpenShift version is '3.10.45'. Then we have following: + from cnslibs.common import openshift_version + version = openshift_version.get_openshift_version() + if version < '3.10': + # False + if version <= '3.10': + # True + if version < '3.10.46': + # True + if version < '3.10.13': + # False + if '3.9' < version <= '3.11': + # True + +Notes: +- If one of comparison operands has empty/zero-like 'micro' part of version, + then it is ignored during comparison, where only 'major' and 'minor' parts of + the OpenShift versions are used. + +""" +import re + +from glusto.core import Glusto as g +import six + +from cnslibs.common import exceptions + + +OPENSHIFT_VERSION_RE = r"(?:v?)(\d+)(?:\.)(\d+)(?:\.(\d+))?$" +OPENSHIFT_VERSION = None + + +def _get_openshift_version_str(hostname=None): + """Gets OpenShift version from 'oc version' command. + + Args: + hostname (str): Node on which the ocp command should run. + Returns: + str : oc version, i.e. 'v3.10.47' + Raises: 'exceptions.ExecutionError' if failed to get version + """ + if not hostname: + hostname = list(g.config['ocp_servers']['client'].keys())[0] + cmd = "oc version | grep openshift | cut -d ' ' -f 2" + ret, out, err = g.run(hostname, cmd, "root") + if ret != 0: + msg = "Failed to get oc version. \n'err': %s\n 'out': %s" % (err, out) + g.log.error(msg) + raise AssertionError(msg) + out = out.strip() + if not out: + error_msg = "Empty output from 'oc version' command: '%s'" % out + g.log.error(error_msg) + raise exceptions.ExecutionError(error_msg) + + return out + + +def _parse_openshift_version(openshift_version_str): + """Parses OpenShift version str into tuple of 3 values. + + Args: + openshift_version_str (str): OpenShift version like '3.10' or '3.10.45' + Returns: + Tuple object of 3 values - major, minor and micro version parts. + """ + groups = re.findall(OPENSHIFT_VERSION_RE, openshift_version_str) + err_msg = ( + "Failed to parse '%s' str into 3 OpenShift version parts - " + "'major', 'minor' and 'micro'. " + "Expected value like '3.10' or '3.10.45'" % openshift_version_str) + assert groups, err_msg + assert len(groups) == 1, err_msg + assert len(groups[0]) == 3, err_msg + return (int(groups[0][0]), int(groups[0][1]), int(groups[0][2] or 0)) + + +class OpenshiftVersion(object): + """Eases OpenShift versions comparison. + + Instance of this class can be used for comparison with other instance of + it or to string-like objects. + + Input str version is required to have, at least, 2 version parts - + 'major' and 'minor'. Third part is optional - 'micro' version. + Examples: '3.10', 'v3.10', '3.10.45', 'v3.10.45'. + + Before each comparison, both operands are checked for zero value in 'micro' + part. If one or both are false, then 'micro' part not used for comparison. + + Usage example (1) - compare to string object: + version_3_10 = OpenshiftVersion('3.10') + cmp_result = '3.9' < version_3_10 <= '3.11' + + Usage example (2) - compare to the same type of an object: + version_3_10 = OpenshiftVersion('3.10') + version_3_11 = OpenshiftVersion('3.11') + cmp_result = version_3_10 < version_3_11 + """ + def __init__(self, openshift_version_str): + self.v = _parse_openshift_version(openshift_version_str) + self.major, self.minor, self.micro = self.v + + def _adapt_other(self, other): + if isinstance(other, six.string_types): + return OpenshiftVersion(other) + elif isinstance(other, OpenshiftVersion): + return other + else: + raise NotImplementedError( + "'%s' type is not supported for OpenShift version " + "comparison." % type(other)) + + def __lt__(self, other): + adapted_other = self._adapt_other(other) + if not all((self.micro, adapted_other.micro)): + return self.v[0:2] < adapted_other.v[0:2] + return self.v < adapted_other.v + + def __le__(self, other): + adapted_other = self._adapt_other(other) + if not all((self.micro, adapted_other.micro)): + return self.v[0:2] <= adapted_other.v[0:2] + return self.v <= adapted_other.v + + def __eq__(self, other): + adapted_other = self._adapt_other(other) + if not all((self.micro, adapted_other.micro)): + return self.v[0:2] == adapted_other.v[0:2] + return self.v == adapted_other.v + + def __ge__(self, other): + adapted_other = self._adapt_other(other) + if not all((self.micro, adapted_other.micro)): + return self.v[0:2] >= adapted_other.v[0:2] + return self.v >= adapted_other.v + + def __gt__(self, other): + adapted_other = self._adapt_other(other) + if not all((self.micro, adapted_other.micro)): + return self.v[0:2] > adapted_other.v[0:2] + return self.v > adapted_other.v + + def __ne__(self, other): + adapted_other = self._adapt_other(other) + if not all((self.micro, adapted_other.micro)): + return self.v[0:2] != adapted_other.v[0:2] + return self.v != adapted_other.v + + +def get_openshift_version(hostname=None): + """Cacher of an OpenShift version. + + Version of an OpenShift cluster is constant value. So, we call API just + once and then reuse it's output. + + Args: + hostname (str): a node with 'oc' client where command should run on. + If not specified, then first key + from 'ocp_servers.client' config option will be picked up. + Returns: + OpenshiftVersion object instance. + """ + global OPENSHIFT_VERSION + if not OPENSHIFT_VERSION: + version_str = _get_openshift_version_str(hostname=hostname) + OPENSHIFT_VERSION = OpenshiftVersion(version_str) + return OPENSHIFT_VERSION diff --git a/tests/functional/common/provisioning/test_pv_resize.py b/tests/functional/common/provisioning/test_pv_resize.py index 353aa220..41f5e113 100644 --- a/tests/functional/common/provisioning/test_pv_resize.py +++ b/tests/functional/common/provisioning/test_pv_resize.py @@ -9,13 +9,13 @@ from cnslibs.common.openshift_ops import ( oc_create_app_dc_with_io, oc_delete, oc_rsh, - oc_version, scale_dc_pod_amount_and_wait, verify_pv_size, verify_pvc_size, wait_for_events, wait_for_pod_be_ready, wait_for_resource_absence) +from cnslibs.common.openshift_version import get_openshift_version from cnslibs.cns.cns_baseclass import CnsBaseClass from cnslibs.common.exceptions import ExecutionError from glusto.core import Glusto as g @@ -29,8 +29,7 @@ class TestPvResizeClass(CnsBaseClass): def setUpClass(cls): super(TestPvResizeClass, cls).setUpClass() cls.node = cls.ocp_master_node[0] - cls.version = oc_version(cls.node) - if any(v in cls.version for v in ("3.6", "3.7", "3.8")): + if get_openshift_version() < "3.9": cls.skip_me = True return enable_pvc_resize(cls.node) |