Remove hardcoded nodes for package checkers
Reworked test
Update pillar for nodes with rsync, with octavia
Removed rule for gnocchi and ujson because they should exist on all ctl* nodes
Added optimized call of the test.ping request for nodes
Fixes-Bug: #PROD-36531
Change-Id: I3512a8f159e40cfaa70dc5e6ab3673e5eb70ed64
diff --git a/test_set/cvp-sanity/fixtures/base.py b/test_set/cvp-sanity/fixtures/base.py
index bd62ed4..aabf8d1 100644
--- a/test_set/cvp-sanity/fixtures/base.py
+++ b/test_set/cvp-sanity/fixtures/base.py
@@ -25,7 +25,8 @@
@pytest.fixture(scope='session')
def local_salt_client():
- return utils.init_salt_client()
+ pytest.local_salt_client = utils.init_salt_client()
+ return pytest.local_salt_client
nodes = utils.calculate_groups()
diff --git a/test_set/cvp-sanity/tests/test_packet_checker.py b/test_set/cvp-sanity/tests/test_packet_checker.py
index 0b574cf..f534aad 100644
--- a/test_set/cvp-sanity/tests/test_packet_checker.py
+++ b/test_set/cvp-sanity/tests/test_packet_checker.py
@@ -2,14 +2,32 @@
import json
import utils
import logging
+import itertools
+from functools import lru_cache
-def is_deb_in_exception(inconsistency_rule, package_name, error_node_list):
- short_names_in_error_nodes = [n.split('.')[0] for n in error_node_list]
- for node, excluded_packages in inconsistency_rule.items():
- if package_name in excluded_packages and node in short_names_in_error_nodes:
+
+@lru_cache(maxsize=32)
+def targeted_minions(target):
+ """
+ Returns nodes associated with salt target
+ :param target: str, salt target in COMPOUND notation like I@nova:server
+ More here https://docs.saltproject.io/en/latest/topics/targeting/compound.html
+ :return: list of nodes or []
+ """
+ salt_client = pytest.local_salt_client
+ return list(salt_client.test_ping(
+ tgt=target,
+ expr_form='compound'))
+
+
+def is_deb_in_exception(inconsistency_rule, package_name, node_hostname):
+ for salt_target, excluded_packages in inconsistency_rule.items():
+ if package_name in excluded_packages \
+ and node_hostname in targeted_minions(salt_target):
return True
return False
+
@pytest.mark.full
def test_check_package_versions(local_salt_client, nodes_in_group):
"""Validate package has same versions on all the nodes.
@@ -19,73 +37,66 @@
2) Exclude nodes without packages and exceptions
3) Go through each package and save it with version from each node to the
list. Mark 'No version' if package is not found.
- If pachage name in the eception list or in inconsistency_rule, ignore it.
+ If package name in the exception list or in inconsistency_rule,
+ ignore it.
4) Compare items in that list - they should be equal and match the amout of nodes
"""
- # defines packages specific to the concrete nodes
- inconsistency_rule = {"kvm03": ["rsync", "sysstat", "xz-utils"], "log01": ["python-elasticsearch"], "ctl01": ["python-gnocchiclient", "python-ujson"]}
+ salt = local_salt_client
+ # defines packages specific to the nodes
+ inconsistency_rule = {
+ "I@backupninja:server": [
+ "rsync", "sysstat", "xz-utils"],
+ "I@elasticsearch:server": [
+ "python-elasticsearch"],
+ # PROD-30833
+ "I@octavia:manager:controller_worker:loadbalancer_topology:SINGLE": [
+ "netfilter-persistent",
+ "gunicorn",
+ "octavia-worker",
+ "octavia-health-manager",
+ "octavia-housekeeping"]
+ }
exclude_packages = utils.get_configuration().get("skipped_packages", [])
- group, nodes = nodes_in_group
- packages_versions = local_salt_client.cmd(tgt="L@"+','.join(nodes),
+
+ group_name, nodes = nodes_in_group
+ packages_versions_by_nodes = salt.cmd(tgt="L@"+','.join(nodes),
fun='lowpkg.list_pkgs',
expr_form='compound')
# Let's exclude cid01 and dbs01 nodes from this check
- exclude_nodes = list(local_salt_client.test_ping(tgt="I@galera:master or I@gerrit:client",
- expr_form='compound').keys())
- # PROD-30833
- gtw01 = local_salt_client.pillar_get(
- param='_param:openstack_gateway_node01_hostname') or 'gtw01'
- cluster_domain = local_salt_client.pillar_get(
- param='_param:cluster_domain') or '.local'
- gtw01 += '.' + cluster_domain
- if gtw01 in nodes:
- octavia = local_salt_client.cmd(tgt="L@" + ','.join(nodes),
- fun='pillar.get',
- param='octavia:manager:enabled',
- expr_form='compound')
- gtws = [gtw for gtw in list(octavia.values()) if gtw]
- if len(gtws) == 1:
- exclude_nodes.append(gtw01)
- logging.info("gtw01 node is skipped in test_check_package_versions")
+ exclude_nodes = targeted_minions("I@galera:master or I@gerrit:client")
- total_nodes = [i for i in nodes if i not in exclude_nodes]
+ total_nodes = [i
+ for i in nodes
+ if i not in exclude_nodes]
if len(total_nodes) < 2:
pytest.skip("Nothing to compare - only 1 node")
- nodes_with_packages = []
- packages_with_different_versions = []
- packages_names = set()
- for node in total_nodes:
- if not packages_versions[node]:
- # TODO: do not skip node
- logging.warning("Node {} is skipped".format(node))
- continue
- nodes_with_packages.append(node)
- packages_names.update(list(packages_versions[node].keys()))
+ packages_with_different_versions = dict()
+ packages_names = set(itertools.chain.from_iterable(
+ [packages_versions_by_nodes[node].keys()
+ for node in total_nodes])
+ )
+
for deb in packages_names:
if deb in exclude_packages:
continue
- diff = []
- row = []
- for node in nodes_with_packages:
- if not packages_versions[node]:
- continue
- if deb in list(packages_versions[node].keys()):
- diff.append(packages_versions[node][deb])
- row.append("{}: {}".format(node, packages_versions[node][deb]))
- else:
- row.append("{}: No package".format(node))
- if diff.count(diff[0]) < len(nodes_with_packages):
- if not is_deb_in_exception(inconsistency_rule, deb, row):
- row.sort()
- row.insert(0, deb)
- packages_with_different_versions.append(row)
+ node_and_version = [
+ (node, packages_versions_by_nodes[node].get(deb, "No package"))
+ for node in total_nodes
+ if not is_deb_in_exception(inconsistency_rule, deb, node)
+ ]
+
+ if set([version for node, version in node_and_version]).__len__() > 1:
+ packages_with_different_versions[deb] = [
+ f"{node}: {version}"
+ for node, version in node_and_version]
+
assert len(packages_with_different_versions) == 0, (
"Non-uniform package versions are installed on '{}' group of nodes:\n"
"{}".format(
- group, json.dumps(packages_with_different_versions, indent=4))
+ group_name, json.dumps(packages_with_different_versions, indent=4))
)
@@ -117,7 +128,7 @@
@pytest.mark.full
def test_check_module_versions(local_salt_client, nodes_in_group):
# defines modules specific to the concrete nodes
- inconsistency_rule = {"ctl01": ["gnocchiclient", "ujson"], "log01": ["elasticsearch"]}
+ inconsistency_rule = {"I@elasticsearch:server": ["elasticsearch"]}
exclude_modules = utils.get_configuration().get("skipped_modules", [])
group, nodes = nodes_in_group
pre_check = local_salt_client.cmd(
@@ -127,8 +138,7 @@
if list(pre_check.values()).count('') > 0:
pytest.skip("pip is not installed on one or more nodes")
- exclude_nodes = list(local_salt_client.test_ping(tgt="I@galera:master or I@gerrit:client",
- expr_form='compound').keys())
+ exclude_nodes = targeted_minions("I@galera:master or I@gerrit:client")
# PROD-30833
gtw01 = local_salt_client.pillar_get(
@@ -194,7 +204,7 @@
param='_param:updates_mirantis_login',
expr_form='compound')
if not restricted_repo_enabled:
- pytest.skip("This env doesn't required the restricted ubuntu repo")
+ pytest.skip("This env doesn't require the restricted ubuntu repo")
repos_by_nodes=local_salt_client.cmd(
tgt="*",