From 29dd3b2330d8dd42583c258cb05a30819365d0b8 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 16 Apr 2020 16:12:29 -0500 Subject: [PATCH 1/7] Adding daemonset ready check and tests Signed-off-by: Chris --- chaosk8s/daemonset/__init__.py | 0 chaosk8s/daemonset/probes.py | 47 ++++++++++++++++++++++++ tests/test_daemonset.py | 66 ++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 chaosk8s/daemonset/__init__.py create mode 100644 chaosk8s/daemonset/probes.py create mode 100644 tests/test_daemonset.py diff --git a/chaosk8s/daemonset/__init__.py b/chaosk8s/daemonset/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/chaosk8s/daemonset/probes.py b/chaosk8s/daemonset/probes.py new file mode 100644 index 0000000..fecff68 --- /dev/null +++ b/chaosk8s/daemonset/probes.py @@ -0,0 +1,47 @@ +# -*- coding: utf-8 -*- +from typing import Union +import urllib3 +from chaoslib.types import Secrets +from chaoslib.exceptions import ActivityFailed +from kubernetes import client +from logzero import logger +from chaosk8s import create_k8s_api_client + +__all__ = ["daemonset_ready"] + + +def daemonset_ready(name: str, ns: str = "default", + label_selector: str = "name in ({name})", + timeout: int = 30, + secrets: Secrets = None): + """ + Check that the DaemonSet has no misscheduled or unavailable pods + + Raises :exc:`chaoslib.exceptions.ActivityFailed` when the state is not + as expected. + """ + api = create_k8s_api_client(secrets) + + v1 = client.AppsV1Api(api) + + ret = v1.list_namespaced_daemon_set(ns, label_selector=label_selector) + logger.debug("Found {d} daemonsets".format(d=len(ret.items))) + + if not ret.items: + raise ActivityFailed( + "DaemonSet '{name}' was not found".format(name=name)) + + for ds in ret.items: + logger.debug("DaemonSet has '{u}' unavailable replicas and \ + '{m}' misscheduled".format( + u=ds.status.number_unavailable, + m=ds.status.number_misscheduled)) + if ((ds.status.number_unavailable is not None + and ds.status.number_unavailable != 0) + or ds.status.number_misscheduled != 0): + raise ActivityFailed( + "DaemonSet has '{u}' unavailable replicas \ + and '{m}' misscheduled".format( + u=ds.status.number_unavailable, + m=ds.status.number_misscheduled)) + return True diff --git a/tests/test_daemonset.py b/tests/test_daemonset.py new file mode 100644 index 0000000..6afbe76 --- /dev/null +++ b/tests/test_daemonset.py @@ -0,0 +1,66 @@ +# -*- coding: utf-8 -*- +from unittest.mock import MagicMock, patch, ANY, call + +import pytest +from kubernetes import stream +from chaoslib.exceptions import ActivityFailed, InvalidActivity +from chaoslib.provider.python import validate_python_activity + +from chaosk8s.daemonset.probes import daemonset_ready + + +@patch('chaosk8s.has_local_config_file', autospec=True) +@patch('chaosk8s.daemonset.probes.client', autospec=True) +@patch('chaosk8s.client') +def test_daemonset_ready(cl, client, has_conf): + has_conf.return_value = False + + ds = MagicMock() + ds.status.number_unavailable = None + ds.status.number_misscheduled = 0 + result = MagicMock() + result.items = [ds,ds] + + v1 = MagicMock() + v1.list_namespaced_daemon_set.return_value = result + client.AppsV1Api.return_value = v1 + + assert daemonset_ready("test") + + +@patch('chaosk8s.has_local_config_file', autospec=True) +@patch('chaosk8s.daemonset.probes.client', autospec=True) +@patch('chaosk8s.client') +def test_daemonset_not_ready(cl, client, has_conf): + has_conf.return_value = False + + ds = MagicMock() + ds.status.number_unavailable = 1 + ds.status.number_misscheduled = 0 + result = MagicMock() + result.items = [ds,ds] + + v1 = MagicMock() + v1.list_namespaced_daemon_set.return_value = result + client.AppsV1Api.return_value = v1 + + with pytest.raises(ActivityFailed) as excinfo: + daemonset_ready("test") + assert "DaemonSet has '1' unavailable replicas and '0' misscheduled" in str(excinfo.value) + +@patch('chaosk8s.has_local_config_file', autospec=True) +@patch('chaosk8s.daemonset.probes.client', autospec=True) +@patch('chaosk8s.client') +def test_daemonset_ready_not_found(cl, client, has_conf): + has_conf.return_value = False + result = MagicMock() + result.items = [] + + v1 = MagicMock() + v1.list_namespaced_daemon_set.return_value = result + client.AppsV1Api.return_value = v1 + + name = "test" + with pytest.raises(ActivityFailed) as excinfo: + daemonset_ready(name) + assert "DaemonSet '{name}' was not found".format(name=name) in str(excinfo.value) \ No newline at end of file From f34dd0e4477014c0ae0863639145c637ed2a95bf Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 16 Apr 2020 16:16:39 -0500 Subject: [PATCH 2/7] testfix Signed-off-by: Chris --- chaosk8s/daemonset/probes.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/chaosk8s/daemonset/probes.py b/chaosk8s/daemonset/probes.py index fecff68..d4c87f8 100644 --- a/chaosk8s/daemonset/probes.py +++ b/chaosk8s/daemonset/probes.py @@ -40,8 +40,8 @@ def daemonset_ready(name: str, ns: str = "default", and ds.status.number_unavailable != 0) or ds.status.number_misscheduled != 0): raise ActivityFailed( - "DaemonSet has '{u}' unavailable replicas \ - and '{m}' misscheduled".format( + "DaemonSet has '{u}' unavailable replicas" + "and '{m}' misscheduled".format( u=ds.status.number_unavailable, m=ds.status.number_misscheduled)) return True From aecd3636c8d7d758700db25c8dc9e4b1b47c9693 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 16 Apr 2020 16:16:56 -0500 Subject: [PATCH 3/7] testfix Signed-off-by: Chris --- chaosk8s/daemonset/probes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chaosk8s/daemonset/probes.py b/chaosk8s/daemonset/probes.py index d4c87f8..af0edda 100644 --- a/chaosk8s/daemonset/probes.py +++ b/chaosk8s/daemonset/probes.py @@ -40,7 +40,7 @@ def daemonset_ready(name: str, ns: str = "default", and ds.status.number_unavailable != 0) or ds.status.number_misscheduled != 0): raise ActivityFailed( - "DaemonSet has '{u}' unavailable replicas" + "DaemonSet has '{u}' unavailable replicas " "and '{m}' misscheduled".format( u=ds.status.number_unavailable, m=ds.status.number_misscheduled)) From 8d436e2cd0842a914c5f19961c03d5ab926ba423 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 16 Apr 2020 16:25:33 -0500 Subject: [PATCH 4/7] formatting fixes Signed-off-by: Chris --- chaosk8s/daemonset/probes.py | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/chaosk8s/daemonset/probes.py b/chaosk8s/daemonset/probes.py index af0edda..c88b4e7 100644 --- a/chaosk8s/daemonset/probes.py +++ b/chaosk8s/daemonset/probes.py @@ -36,12 +36,13 @@ def daemonset_ready(name: str, ns: str = "default", '{m}' misscheduled".format( u=ds.status.number_unavailable, m=ds.status.number_misscheduled)) - if ((ds.status.number_unavailable is not None - and ds.status.number_unavailable != 0) - or ds.status.number_misscheduled != 0): - raise ActivityFailed( + if ( + (ds.status.number_unavailable is not None + and ds.status.number_unavailable != 0) + or ds.status.number_misscheduled != 0 + ) raise ActivityFailed( "DaemonSet has '{u}' unavailable replicas " "and '{m}' misscheduled".format( - u=ds.status.number_unavailable, - m=ds.status.number_misscheduled)) + u=ds.status.number_unavailable, + m=ds.status.number_misscheduled)) return True From 85217c20afe540119d9912a4d8032709594e6ba7 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 16 Apr 2020 16:31:06 -0500 Subject: [PATCH 5/7] formatting fixes Signed-off-by: Chris --- chaosk8s/daemonset/probes.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/chaosk8s/daemonset/probes.py b/chaosk8s/daemonset/probes.py index c88b4e7..6ad1eb0 100644 --- a/chaosk8s/daemonset/probes.py +++ b/chaosk8s/daemonset/probes.py @@ -40,7 +40,8 @@ def daemonset_ready(name: str, ns: str = "default", (ds.status.number_unavailable is not None and ds.status.number_unavailable != 0) or ds.status.number_misscheduled != 0 - ) raise ActivityFailed( + ): + raise ActivityFailed( "DaemonSet has '{u}' unavailable replicas " "and '{m}' misscheduled".format( u=ds.status.number_unavailable, From c8afff7c32bbaee68f1f6ce96f0616d0c675c21f Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 16 Apr 2020 16:38:17 -0500 Subject: [PATCH 6/7] formatting fixes Signed-off-by: Chris --- chaosk8s/daemonset/probes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chaosk8s/daemonset/probes.py b/chaosk8s/daemonset/probes.py index 6ad1eb0..6560ec8 100644 --- a/chaosk8s/daemonset/probes.py +++ b/chaosk8s/daemonset/probes.py @@ -40,7 +40,7 @@ def daemonset_ready(name: str, ns: str = "default", (ds.status.number_unavailable is not None and ds.status.number_unavailable != 0) or ds.status.number_misscheduled != 0 - ): + ): raise ActivityFailed( "DaemonSet has '{u}' unavailable replicas " "and '{m}' misscheduled".format( From 12bd4ae52a022443ea6eff15d5802cc8ed884437 Mon Sep 17 00:00:00 2001 From: Chris Date: Thu, 16 Apr 2020 16:45:18 -0500 Subject: [PATCH 7/7] formatting fixes Signed-off-by: Chris --- chaosk8s/daemonset/probes.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/chaosk8s/daemonset/probes.py b/chaosk8s/daemonset/probes.py index 6560ec8..e357f33 100644 --- a/chaosk8s/daemonset/probes.py +++ b/chaosk8s/daemonset/probes.py @@ -40,7 +40,7 @@ def daemonset_ready(name: str, ns: str = "default", (ds.status.number_unavailable is not None and ds.status.number_unavailable != 0) or ds.status.number_misscheduled != 0 - ): + ): raise ActivityFailed( "DaemonSet has '{u}' unavailable replicas " "and '{m}' misscheduled".format(