krkn-lib 5.0.2__tar.gz → 5.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/PKG-INFO +1 -1
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/pyproject.toml +1 -1
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/k8s/krkn_kubernetes.py +207 -96
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/k8s/pods_monitor_pool.py +14 -3
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/k8s/templates/node_exec_pod.j2 +6 -1
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/models/k8s/models.py +4 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/prometheus/krkn_prometheus.py +1 -1
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/telemetry/k8s/krkn_telemetry_kubernetes.py +0 -2
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/base_test.py +7 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_check.py +2 -3
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_create.py +3 -5
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_delete.py +2 -3
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_get.py +104 -5
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_list.py +13 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_monitor.py +168 -137
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_pods_monitor_pool.py +7 -3
- krkn_lib-5.1.0/src/krkn_lib/tests/test_krkn_prometheus.py +234 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_telemetry_kubernetes.py +57 -51
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_version.py +1 -1
- krkn_lib-5.0.2/src/krkn_lib/tests/test_krkn_prometheus.py +0 -229
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/LICENSE +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/README.md +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/elastic/__init__.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/elastic/krkn_elastic.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/k8s/__init__.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/k8s/templates/hog_pod.j2 +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/k8s/templates/service_hijacking_config_map.j2 +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/k8s/templates/service_hijacking_pod.j2 +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/k8s/templates/syn_flood_pod.j2 +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/models/__init__.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/models/elastic/__init__.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/models/elastic/models.py +1 -1
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/models/k8s/__init__.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/models/krkn/__init__.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/models/krkn/models.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/models/telemetry/__init__.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/models/telemetry/models.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/ocp/__init__.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/ocp/krkn_openshift.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/prometheus/__init__.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/telemetry/__init__.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/telemetry/k8s/__init__.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/telemetry/ocp/__init__.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/telemetry/ocp/krkn_telemetry_openshift.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/__init__.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_elastic.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_elastic_models.py +1 -1
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_exec.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_misc.py +2 -2
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_models.py +1 -1
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_openshift.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_telemetry_models.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_telemetry_openshift.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_utils.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/utils/__init__.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/utils/functions.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/utils/safe_logger.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/version/__init__.py +0 -0
- {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/version/version.py +0 -0
|
@@ -529,7 +529,10 @@ class KrknKubernetes:
|
|
|
529
529
|
return managedclusters
|
|
530
530
|
|
|
531
531
|
def list_pods(
|
|
532
|
-
self,
|
|
532
|
+
self,
|
|
533
|
+
namespace: str,
|
|
534
|
+
label_selector: str = None,
|
|
535
|
+
field_selector: str = None,
|
|
533
536
|
) -> list[str]:
|
|
534
537
|
"""
|
|
535
538
|
List pods in the given namespace
|
|
@@ -537,11 +540,15 @@ class KrknKubernetes:
|
|
|
537
540
|
:param namespace: namespace to search for pods
|
|
538
541
|
:param label_selector: filter by label selector
|
|
539
542
|
(optional default `None`)
|
|
543
|
+
:param field_selector: filter results by config details
|
|
544
|
+
select only running pods by setting "status.phase=Running"
|
|
540
545
|
:return: a list of pod names
|
|
541
546
|
"""
|
|
542
547
|
pods = []
|
|
543
548
|
try:
|
|
544
|
-
ret = self.get_all_pod_info(
|
|
549
|
+
ret = self.get_all_pod_info(
|
|
550
|
+
namespace, label_selector, field_selector
|
|
551
|
+
)
|
|
545
552
|
except ApiException as e:
|
|
546
553
|
logging.error(
|
|
547
554
|
"Exception when calling list_pods: %s\n",
|
|
@@ -734,12 +741,16 @@ class KrknKubernetes:
|
|
|
734
741
|
logging.error("Failed to get deployment data %s", str(e))
|
|
735
742
|
raise e
|
|
736
743
|
|
|
737
|
-
def get_all_pods(
|
|
744
|
+
def get_all_pods(
|
|
745
|
+
self, label_selector: str = None, field_selector: str = None
|
|
746
|
+
) -> list[[str, str]]:
|
|
738
747
|
"""
|
|
739
748
|
Return a list of tuples containing pod name [0] and namespace [1]
|
|
740
749
|
|
|
741
750
|
:param label_selector: filter by label_selector
|
|
742
751
|
(optional default `None`)
|
|
752
|
+
:param field_selector: filter results by config details
|
|
753
|
+
select only running pods by setting "status.phase=Running"
|
|
743
754
|
:return: list of tuples pod,namespace
|
|
744
755
|
"""
|
|
745
756
|
pods = []
|
|
@@ -749,12 +760,14 @@ class KrknKubernetes:
|
|
|
749
760
|
pretty=True,
|
|
750
761
|
label_selector=label_selector,
|
|
751
762
|
limit=self.request_chunk_size,
|
|
763
|
+
field_selector=field_selector,
|
|
752
764
|
)
|
|
753
765
|
else:
|
|
754
766
|
ret = self.list_continue_helper(
|
|
755
767
|
self.cli.list_pod_for_all_namespaces,
|
|
756
768
|
pretty=True,
|
|
757
769
|
limit=self.request_chunk_size,
|
|
770
|
+
field_selector=field_selector,
|
|
758
771
|
)
|
|
759
772
|
for ret_list in ret:
|
|
760
773
|
for pod in ret_list.items:
|
|
@@ -854,11 +867,15 @@ class KrknKubernetes:
|
|
|
854
867
|
self,
|
|
855
868
|
namespace: str = "default",
|
|
856
869
|
label_selector: str = None,
|
|
870
|
+
field_selector: str = None,
|
|
857
871
|
) -> list[str]:
|
|
858
872
|
"""
|
|
859
873
|
Get details of all pods in a namespace
|
|
860
874
|
|
|
861
875
|
:param namespace: namespace (optional default `default`)
|
|
876
|
+
:param field_selector: filter results by config details
|
|
877
|
+
select only running pods by setting "status.phase=Running"
|
|
878
|
+
|
|
862
879
|
:return list of pod details
|
|
863
880
|
"""
|
|
864
881
|
try:
|
|
@@ -869,12 +886,14 @@ class KrknKubernetes:
|
|
|
869
886
|
pretty=True,
|
|
870
887
|
label_selector=label_selector,
|
|
871
888
|
limit=self.request_chunk_size,
|
|
889
|
+
field_selector=field_selector,
|
|
872
890
|
)
|
|
873
891
|
else:
|
|
874
892
|
ret = self.list_continue_helper(
|
|
875
893
|
self.cli.list_namespaced_pod,
|
|
876
894
|
namespace,
|
|
877
895
|
limit=self.request_chunk_size,
|
|
896
|
+
field_selector=field_selector,
|
|
878
897
|
)
|
|
879
898
|
except ApiException as e:
|
|
880
899
|
logging.error(
|
|
@@ -1493,7 +1512,9 @@ class KrknKubernetes:
|
|
|
1493
1512
|
except Exception as e:
|
|
1494
1513
|
logging.error("Error trying to apply_yaml" + str(e))
|
|
1495
1514
|
|
|
1496
|
-
def get_pod_info(
|
|
1515
|
+
def get_pod_info(
|
|
1516
|
+
self, name: str, namespace: str = "default"
|
|
1517
|
+
) -> Optional[Pod]:
|
|
1497
1518
|
"""
|
|
1498
1519
|
Retrieve information about a specific pod
|
|
1499
1520
|
|
|
@@ -1503,63 +1524,70 @@ class KrknKubernetes:
|
|
|
1503
1524
|
kubectl command in the given format if the pod exists.
|
|
1504
1525
|
Returns None if the pod doesn't exist
|
|
1505
1526
|
"""
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
if pod_exists:
|
|
1527
|
+
try:
|
|
1528
|
+
pod_info = None
|
|
1509
1529
|
response = self.cli.read_namespaced_pod(
|
|
1510
1530
|
name=name, namespace=namespace, pretty="true"
|
|
1511
1531
|
)
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1532
|
+
if response:
|
|
1533
|
+
container_list = []
|
|
1534
|
+
|
|
1535
|
+
# Create a list of containers present in the pod
|
|
1536
|
+
for container in response.spec.containers:
|
|
1537
|
+
volume_mount_list = []
|
|
1538
|
+
for volume_mount in container.volume_mounts:
|
|
1539
|
+
volume_mount_list.append(
|
|
1540
|
+
VolumeMount(
|
|
1541
|
+
name=volume_mount.name,
|
|
1542
|
+
mountPath=volume_mount.mount_path,
|
|
1543
|
+
)
|
|
1544
|
+
)
|
|
1545
|
+
container_list.append(
|
|
1546
|
+
Container(
|
|
1547
|
+
name=container.name,
|
|
1548
|
+
image=container.image,
|
|
1549
|
+
volumeMounts=volume_mount_list,
|
|
1522
1550
|
)
|
|
1523
1551
|
)
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1552
|
+
|
|
1553
|
+
for i, container in enumerate(
|
|
1554
|
+
response.status.container_statuses
|
|
1555
|
+
):
|
|
1556
|
+
container_list[i].ready = container.ready
|
|
1557
|
+
container_list[i].containerId = (
|
|
1558
|
+
response.status.container_statuses[i].container_id
|
|
1529
1559
|
)
|
|
1530
|
-
)
|
|
1531
1560
|
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1561
|
+
# Create a list of volumes associated with the pod
|
|
1562
|
+
volume_list = []
|
|
1563
|
+
for volume in response.spec.volumes:
|
|
1564
|
+
volume_name = volume.name
|
|
1565
|
+
pvc_name = (
|
|
1566
|
+
volume.persistent_volume_claim.claim_name
|
|
1567
|
+
if volume.persistent_volume_claim is not None
|
|
1568
|
+
else None
|
|
1569
|
+
)
|
|
1570
|
+
volume_list.append(
|
|
1571
|
+
Volume(name=volume_name, pvcName=pvc_name)
|
|
1572
|
+
)
|
|
1573
|
+
|
|
1574
|
+
# Create the Pod data class object
|
|
1575
|
+
pod_info = Pod(
|
|
1576
|
+
name=response.metadata.name,
|
|
1577
|
+
podIP=response.status.pod_ip,
|
|
1578
|
+
namespace=response.metadata.namespace,
|
|
1579
|
+
containers=container_list,
|
|
1580
|
+
nodeName=response.spec.node_name,
|
|
1581
|
+
volumes=volume_list,
|
|
1582
|
+
status=response.status.phase,
|
|
1583
|
+
creation_timestamp=response.metadata.creation_timestamp,
|
|
1543
1584
|
)
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
# Create the Pod data class object
|
|
1547
|
-
pod_info = Pod(
|
|
1548
|
-
name=response.metadata.name,
|
|
1549
|
-
podIP=response.status.pod_ip,
|
|
1550
|
-
namespace=response.metadata.namespace,
|
|
1551
|
-
containers=container_list,
|
|
1552
|
-
nodeName=response.spec.node_name,
|
|
1553
|
-
volumes=volume_list,
|
|
1554
|
-
status=response.status.phase,
|
|
1555
|
-
creation_timestamp=response.metadata.creation_timestamp,
|
|
1556
|
-
)
|
|
1557
|
-
return pod_info
|
|
1558
|
-
else:
|
|
1585
|
+
except Exception:
|
|
1559
1586
|
logging.error(
|
|
1560
1587
|
"Pod '%s' doesn't exist in namespace '%s'", name, namespace
|
|
1561
1588
|
)
|
|
1562
1589
|
return None
|
|
1590
|
+
return pod_info
|
|
1563
1591
|
|
|
1564
1592
|
def check_if_namespace_exists(self, name: str) -> bool:
|
|
1565
1593
|
"""
|
|
@@ -2612,24 +2640,21 @@ class KrknKubernetes:
|
|
|
2612
2640
|
)
|
|
2613
2641
|
return None
|
|
2614
2642
|
|
|
2615
|
-
def select_pods_by_label(
|
|
2643
|
+
def select_pods_by_label(
|
|
2644
|
+
self, label_selector: str, field_selector: str = None
|
|
2645
|
+
) -> list[(str, str)]:
|
|
2616
2646
|
"""
|
|
2617
2647
|
Selects the pods identified by a label_selector
|
|
2618
2648
|
|
|
2619
2649
|
:param label_selector: a label selector string
|
|
2620
2650
|
in the format "key=value"
|
|
2621
|
-
:param
|
|
2622
|
-
|
|
2651
|
+
:param field_selector: filter results by config details
|
|
2652
|
+
select only running pods by setting "status.phase=Running"
|
|
2623
2653
|
:return: a list of pod_name and namespace tuples
|
|
2624
2654
|
"""
|
|
2625
|
-
pods_and_namespaces = self.get_all_pods(label_selector)
|
|
2655
|
+
pods_and_namespaces = self.get_all_pods(label_selector, field_selector)
|
|
2626
2656
|
pods_and_namespaces = [(pod[0], pod[1]) for pod in pods_and_namespaces]
|
|
2627
|
-
|
|
2628
|
-
pods_and_namespaces = [
|
|
2629
|
-
pod
|
|
2630
|
-
for pod in pods_and_namespaces
|
|
2631
|
-
if not self.is_pod_terminating(pod[0], pod[1])
|
|
2632
|
-
]
|
|
2657
|
+
|
|
2633
2658
|
return pods_and_namespaces
|
|
2634
2659
|
|
|
2635
2660
|
def select_service_by_label(
|
|
@@ -2661,7 +2686,10 @@ class KrknKubernetes:
|
|
|
2661
2686
|
return selected_services
|
|
2662
2687
|
|
|
2663
2688
|
def select_pods_by_name_pattern_and_namespace_pattern(
|
|
2664
|
-
self,
|
|
2689
|
+
self,
|
|
2690
|
+
pod_name_pattern: str,
|
|
2691
|
+
namespace_pattern: str,
|
|
2692
|
+
field_selector: str = None,
|
|
2665
2693
|
) -> list[(str, str)]:
|
|
2666
2694
|
"""
|
|
2667
2695
|
Selects the pods identified by a namespace_pattern
|
|
@@ -2671,6 +2699,8 @@ class KrknKubernetes:
|
|
|
2671
2699
|
:param namespace_pattern: a namespace pattern to match
|
|
2672
2700
|
:param max_timeout: the maximum time in seconds to wait
|
|
2673
2701
|
before considering the pod "not recovered" after the Chaos
|
|
2702
|
+
:param field_selector: filter results by config details
|
|
2703
|
+
select only running pods by setting "status.phase=Running"
|
|
2674
2704
|
:return: a list of pod_name and namespace tuples
|
|
2675
2705
|
"""
|
|
2676
2706
|
namespace_re = re.compile(namespace_pattern)
|
|
@@ -2679,20 +2709,18 @@ class KrknKubernetes:
|
|
|
2679
2709
|
pods_and_namespaces = []
|
|
2680
2710
|
for namespace in namespaces:
|
|
2681
2711
|
if namespace_re.match(namespace):
|
|
2682
|
-
pods = self.list_pods(namespace)
|
|
2712
|
+
pods = self.list_pods(namespace, field_selector=field_selector)
|
|
2683
2713
|
for pod in pods:
|
|
2684
2714
|
if podname_re.match(pod):
|
|
2685
2715
|
pods_and_namespaces.append((pod, namespace))
|
|
2686
|
-
|
|
2687
|
-
pods_and_namespaces = [
|
|
2688
|
-
(pod[0], pod[1])
|
|
2689
|
-
for pod in pods_and_namespaces
|
|
2690
|
-
if not self.is_pod_terminating(pod[0], pod[1])
|
|
2691
|
-
]
|
|
2716
|
+
|
|
2692
2717
|
return pods_and_namespaces
|
|
2693
2718
|
|
|
2694
2719
|
def select_pods_by_namespace_pattern_and_label(
|
|
2695
|
-
self,
|
|
2720
|
+
self,
|
|
2721
|
+
namespace_pattern: str,
|
|
2722
|
+
label_selector: str,
|
|
2723
|
+
field_selector: str = None,
|
|
2696
2724
|
) -> list[(str, str)]:
|
|
2697
2725
|
"""
|
|
2698
2726
|
Selects the pods identified by a label_selector
|
|
@@ -2701,29 +2729,24 @@ class KrknKubernetes:
|
|
|
2701
2729
|
:param namespace_pattern: a namespace pattern to match
|
|
2702
2730
|
:param label_selector: a label selector string
|
|
2703
2731
|
in the format "key=value"
|
|
2704
|
-
:param
|
|
2705
|
-
|
|
2732
|
+
:param field_selector: filter results by config details
|
|
2733
|
+
select only running pods by setting "status.phase=Running"
|
|
2706
2734
|
:return: a list of pod_name and namespace tuples
|
|
2707
2735
|
"""
|
|
2708
2736
|
namespace_re = re.compile(namespace_pattern)
|
|
2709
|
-
pods_and_namespaces = self.get_all_pods(label_selector)
|
|
2710
|
-
pods_and_namespaces = [
|
|
2711
|
-
pod for pod in pods_and_namespaces if namespace_re.match(pod[1])
|
|
2712
|
-
]
|
|
2713
|
-
|
|
2714
|
-
# select only running pods
|
|
2737
|
+
pods_and_namespaces = self.get_all_pods(label_selector, field_selector)
|
|
2715
2738
|
pods_and_namespaces = [
|
|
2716
2739
|
(pod[0], pod[1])
|
|
2717
2740
|
for pod in pods_and_namespaces
|
|
2718
|
-
if
|
|
2741
|
+
if namespace_re.match(pod[1])
|
|
2719
2742
|
]
|
|
2720
|
-
|
|
2721
2743
|
return pods_and_namespaces
|
|
2722
2744
|
|
|
2723
2745
|
def monitor_pods_by_label(
|
|
2724
2746
|
self,
|
|
2725
2747
|
label_selector: str,
|
|
2726
2748
|
pods_and_namespaces: list[(str, str)],
|
|
2749
|
+
field_selector: str = None,
|
|
2727
2750
|
max_timeout: int = 30,
|
|
2728
2751
|
event: threading.Event = None,
|
|
2729
2752
|
) -> PodsMonitorThread:
|
|
@@ -2741,6 +2764,8 @@ class KrknKubernetes:
|
|
|
2741
2764
|
:param pods_and_namespaces: the list of pods collected
|
|
2742
2765
|
by `select_pods_by_label` against which the changes
|
|
2743
2766
|
in the pods state is monitored
|
|
2767
|
+
:param field_selector: filter results by config details
|
|
2768
|
+
select only running pods by setting "status.phase=Running"
|
|
2744
2769
|
:param max_timeout: the expected time the pods should take
|
|
2745
2770
|
to recover. If the killed pods are replaced in this time frame,
|
|
2746
2771
|
but they didn't reach the Ready State, they will be marked as
|
|
@@ -2762,6 +2787,7 @@ class KrknKubernetes:
|
|
|
2762
2787
|
max_timeout=max_timeout,
|
|
2763
2788
|
pods_status=pods_status,
|
|
2764
2789
|
label_selector=label_selector,
|
|
2790
|
+
field_selector=field_selector,
|
|
2765
2791
|
event=event,
|
|
2766
2792
|
)
|
|
2767
2793
|
|
|
@@ -2770,6 +2796,7 @@ class KrknKubernetes:
|
|
|
2770
2796
|
pod_name_pattern: str,
|
|
2771
2797
|
namespace_pattern: str,
|
|
2772
2798
|
pods_and_namespaces: list[(str, str)],
|
|
2799
|
+
field_selector: str = None,
|
|
2773
2800
|
max_timeout=30,
|
|
2774
2801
|
event: threading.Event = None,
|
|
2775
2802
|
) -> PodsMonitorThread:
|
|
@@ -2793,6 +2820,8 @@ class KrknKubernetes:
|
|
|
2793
2820
|
:param pods_and_namespaces: the list of pods collected by
|
|
2794
2821
|
`select_pods_by_name_pattern_and_namespace_pattern` against
|
|
2795
2822
|
which the changes in the pods state is monitored
|
|
2823
|
+
:param field_selector: filter results by config details
|
|
2824
|
+
select only running pods by setting "status.phase=Running"
|
|
2796
2825
|
:param max_timeout: the expected time the pods should take to
|
|
2797
2826
|
recover. If the killed pods are replaced in this time frame,
|
|
2798
2827
|
but they didn't reach the Ready State, they will be marked as
|
|
@@ -2813,6 +2842,7 @@ class KrknKubernetes:
|
|
|
2813
2842
|
pods_and_namespaces=pods_and_namespaces,
|
|
2814
2843
|
max_timeout=max_timeout,
|
|
2815
2844
|
pods_status=pods_status,
|
|
2845
|
+
field_selector=field_selector,
|
|
2816
2846
|
name_pattern=pod_name_pattern,
|
|
2817
2847
|
namespace_pattern=namespace_pattern,
|
|
2818
2848
|
event=event,
|
|
@@ -2823,6 +2853,7 @@ class KrknKubernetes:
|
|
|
2823
2853
|
namespace_pattern: str,
|
|
2824
2854
|
label_selector: str,
|
|
2825
2855
|
pods_and_namespaces: list[(str, str)],
|
|
2856
|
+
field_selector: str = None,
|
|
2826
2857
|
max_timeout=30,
|
|
2827
2858
|
event: threading.Event = None,
|
|
2828
2859
|
) -> PodsMonitorThread:
|
|
@@ -2845,6 +2876,8 @@ class KrknKubernetes:
|
|
|
2845
2876
|
:param pods_and_namespaces: the list of pods collected by
|
|
2846
2877
|
`select_pods_by_name_pattern_and_namespace_pattern` against
|
|
2847
2878
|
which the changes in the pods state is monitored
|
|
2879
|
+
:param field_selector: filter results by config details
|
|
2880
|
+
select only running pods by setting "status.phase=Running"
|
|
2848
2881
|
:param max_timeout: the expected time the pods should take to recover.
|
|
2849
2882
|
If the killed pods are replaced in this time frame, but they
|
|
2850
2883
|
didn't reach the Ready State, they will be marked as unrecovered.
|
|
@@ -2866,6 +2899,7 @@ class KrknKubernetes:
|
|
|
2866
2899
|
max_timeout=max_timeout,
|
|
2867
2900
|
pods_status=pods_status,
|
|
2868
2901
|
label_selector=label_selector,
|
|
2902
|
+
field_selector=field_selector,
|
|
2869
2903
|
namespace_pattern=namespace_pattern,
|
|
2870
2904
|
event=event,
|
|
2871
2905
|
)
|
|
@@ -2876,6 +2910,7 @@ class KrknKubernetes:
|
|
|
2876
2910
|
pods_status: PodsStatus,
|
|
2877
2911
|
max_timeout: int,
|
|
2878
2912
|
label_selector: str = None,
|
|
2913
|
+
field_selector: str = None,
|
|
2879
2914
|
pod_name: str = None,
|
|
2880
2915
|
namespace_pattern: str = None,
|
|
2881
2916
|
name_pattern: str = None,
|
|
@@ -2888,6 +2923,7 @@ class KrknKubernetes:
|
|
|
2888
2923
|
pods_status=pods_status,
|
|
2889
2924
|
max_timeout=max_timeout,
|
|
2890
2925
|
label_selector=label_selector,
|
|
2926
|
+
field_selector=field_selector,
|
|
2891
2927
|
pod_name=pod_name,
|
|
2892
2928
|
namespace_pattern=namespace_pattern,
|
|
2893
2929
|
name_pattern=name_pattern,
|
|
@@ -2902,6 +2938,7 @@ class KrknKubernetes:
|
|
|
2902
2938
|
pods_status: PodsStatus,
|
|
2903
2939
|
max_timeout: int,
|
|
2904
2940
|
label_selector: str = None,
|
|
2941
|
+
field_selector: str = None,
|
|
2905
2942
|
pod_name: str = None,
|
|
2906
2943
|
namespace_pattern: str = None,
|
|
2907
2944
|
name_pattern: str = None,
|
|
@@ -2921,6 +2958,7 @@ class KrknKubernetes:
|
|
|
2921
2958
|
select_method = partial(
|
|
2922
2959
|
self.select_pods_by_label,
|
|
2923
2960
|
label_selector=label_selector,
|
|
2961
|
+
field_selector=field_selector,
|
|
2924
2962
|
)
|
|
2925
2963
|
elif (
|
|
2926
2964
|
name_pattern
|
|
@@ -2932,6 +2970,7 @@ class KrknKubernetes:
|
|
|
2932
2970
|
self.select_pods_by_name_pattern_and_namespace_pattern,
|
|
2933
2971
|
pod_name_pattern=name_pattern,
|
|
2934
2972
|
namespace_pattern=namespace_pattern,
|
|
2973
|
+
field_selector=field_selector,
|
|
2935
2974
|
)
|
|
2936
2975
|
elif (
|
|
2937
2976
|
namespace_pattern
|
|
@@ -2943,6 +2982,7 @@ class KrknKubernetes:
|
|
|
2943
2982
|
self.select_pods_by_namespace_pattern_and_label,
|
|
2944
2983
|
namespace_pattern=namespace_pattern,
|
|
2945
2984
|
label_selector=label_selector,
|
|
2985
|
+
field_selector=field_selector,
|
|
2946
2986
|
)
|
|
2947
2987
|
else:
|
|
2948
2988
|
pods_status.error = (
|
|
@@ -2959,22 +2999,19 @@ class KrknKubernetes:
|
|
|
2959
2999
|
time_offset = time.time() - start_time
|
|
2960
3000
|
remaining_time = max_timeout - time_offset
|
|
2961
3001
|
current_pods_and_namespaces = select_method()
|
|
2962
|
-
|
|
2963
3002
|
# no pods have been killed or pods have been killed and
|
|
2964
3003
|
# respawned with the same names
|
|
2965
3004
|
if set(pods_and_namespaces) == set(current_pods_and_namespaces):
|
|
2966
3005
|
for pod in current_pods_and_namespaces:
|
|
3006
|
+
|
|
2967
3007
|
pod_info = self.get_pod_info(pod[0], pod[1])
|
|
2968
|
-
|
|
3008
|
+
# for pod_info in pod_list_info:
|
|
3009
|
+
if pod_info:
|
|
2969
3010
|
pod_creation_timestamp = (
|
|
2970
3011
|
pod_info.creation_timestamp.timestamp()
|
|
2971
3012
|
)
|
|
2972
|
-
|
|
2973
|
-
|
|
2974
|
-
if pod_info.status and start_time < pod_creation_timestamp:
|
|
2975
|
-
# in this case the pods to wait have been respawn
|
|
2976
|
-
# with the same name
|
|
2977
|
-
missing_pods.add(pod)
|
|
3013
|
+
if start_time < pod_creation_timestamp:
|
|
3014
|
+
missing_pods.add(pod)
|
|
2978
3015
|
pods_to_wait.update(missing_pods)
|
|
2979
3016
|
|
|
2980
3017
|
# pods have been killed but respawned with different names
|
|
@@ -3004,9 +3041,7 @@ class KrknKubernetes:
|
|
|
3004
3041
|
# inject the chaos, let's see the next iteration.
|
|
3005
3042
|
if len(pods_to_wait) == 0:
|
|
3006
3043
|
continue
|
|
3007
|
-
|
|
3008
3044
|
futures = []
|
|
3009
|
-
|
|
3010
3045
|
with ThreadPoolExecutor() as executor:
|
|
3011
3046
|
for pod_and_namespace in pods_to_wait:
|
|
3012
3047
|
if pod_and_namespace not in pods_already_watching:
|
|
@@ -3030,20 +3065,24 @@ class KrknKubernetes:
|
|
|
3030
3065
|
# sum the time elapsed waiting before the pod
|
|
3031
3066
|
# has been rescheduled (rescheduling time)
|
|
3032
3067
|
# to the effective recovery time of the pod
|
|
3033
|
-
result.
|
|
3034
|
-
|
|
3035
|
-
|
|
3036
|
-
|
|
3037
|
-
|
|
3038
|
-
|
|
3039
|
-
|
|
3068
|
+
if result.pod_readiness_time:
|
|
3069
|
+
result.pod_rescheduling_time = (
|
|
3070
|
+
time.time()
|
|
3071
|
+
- start_time
|
|
3072
|
+
- result.pod_readiness_time
|
|
3073
|
+
)
|
|
3074
|
+
result.total_recovery_time = (
|
|
3075
|
+
result.pod_readiness_time
|
|
3076
|
+
+ result.pod_rescheduling_time
|
|
3077
|
+
)
|
|
3040
3078
|
|
|
3041
|
-
|
|
3079
|
+
pods_status.recovered.append(result)
|
|
3042
3080
|
for future in undone:
|
|
3043
3081
|
result = future.result()
|
|
3044
3082
|
pods_status.unrecovered.append(result)
|
|
3045
3083
|
|
|
3046
3084
|
missing_pods.clear()
|
|
3085
|
+
|
|
3047
3086
|
# if there are missing pods, pods affected
|
|
3048
3087
|
# by the chaos did not restart after the chaos
|
|
3049
3088
|
# an exception will be set in the PodsStatus
|
|
@@ -3383,3 +3422,75 @@ class KrknKubernetes:
|
|
|
3383
3422
|
resources.memory = json_obj["node"]["memory"]["availableBytes"]
|
|
3384
3423
|
resources.disk_space = json_obj["node"]["fs"]["availableBytes"]
|
|
3385
3424
|
return resources
|
|
3425
|
+
|
|
3426
|
+
def get_container_ids(self, pod_name: str, namespace: str) -> list[str]:
|
|
3427
|
+
"""
|
|
3428
|
+
Gets the container ids of the selected pod
|
|
3429
|
+
:param pod_name: name of the pod
|
|
3430
|
+
:param namespace: namespace of the pod
|
|
3431
|
+
|
|
3432
|
+
:return: a list of container id
|
|
3433
|
+
"""
|
|
3434
|
+
|
|
3435
|
+
container_ids: list[str] = []
|
|
3436
|
+
|
|
3437
|
+
pod = self.get_pod_info(pod_name, namespace)
|
|
3438
|
+
if pod:
|
|
3439
|
+
for container in pod.containers:
|
|
3440
|
+
container_ids.append(
|
|
3441
|
+
re.sub(r".*://", "", container.containerId)
|
|
3442
|
+
)
|
|
3443
|
+
return container_ids
|
|
3444
|
+
|
|
3445
|
+
def get_pod_pids(
|
|
3446
|
+
self,
|
|
3447
|
+
base_pod_name: str,
|
|
3448
|
+
base_pod_namespace: str,
|
|
3449
|
+
base_pod_container_name: str,
|
|
3450
|
+
pod_name: str,
|
|
3451
|
+
pod_namespace: str,
|
|
3452
|
+
pod_container_id: str,
|
|
3453
|
+
) -> Optional[list[str]]:
|
|
3454
|
+
"""
|
|
3455
|
+
Retrieves the PIDs assigned to the pod in the node. The command
|
|
3456
|
+
must be executed inside a privileged Pod with `hostPID` set to true
|
|
3457
|
+
|
|
3458
|
+
:param base_pod_name: name of the pod where the command is run
|
|
3459
|
+
:param base_pod_namespace: namespace of the pod
|
|
3460
|
+
where the command is run
|
|
3461
|
+
:param base_pod_container_name: container name of the pod
|
|
3462
|
+
where the command is run
|
|
3463
|
+
:param pod_name: Pod name associated with the PID
|
|
3464
|
+
:param pod_namespace: namespace of the Pod associated with the PID
|
|
3465
|
+
:param pod_container_id: container id of Pod associated with the PID
|
|
3466
|
+
|
|
3467
|
+
:return: list of pids None.
|
|
3468
|
+
"""
|
|
3469
|
+
|
|
3470
|
+
if not self.check_if_pod_exists(base_pod_name, base_pod_namespace):
|
|
3471
|
+
raise Exception(
|
|
3472
|
+
f"base pod {base_pod_name} does not exist in "
|
|
3473
|
+
f"namespace {base_pod_namespace}"
|
|
3474
|
+
)
|
|
3475
|
+
if not self.check_if_pod_exists(pod_name, pod_namespace):
|
|
3476
|
+
raise Exception(
|
|
3477
|
+
f"target pod {pod_name} does not exist in "
|
|
3478
|
+
f"namespace {pod_namespace}"
|
|
3479
|
+
)
|
|
3480
|
+
|
|
3481
|
+
cmd = (
|
|
3482
|
+
"for dir in /proc/[0-9]*; do [ $(cat $dir/cgroup | grep %s) ] && "
|
|
3483
|
+
"echo ${dir/\/proc\//}; done" % pod_container_id # noqa
|
|
3484
|
+
)
|
|
3485
|
+
|
|
3486
|
+
pids = self.exec_cmd_in_pod(
|
|
3487
|
+
[cmd],
|
|
3488
|
+
base_pod_name,
|
|
3489
|
+
base_pod_namespace,
|
|
3490
|
+
base_pod_container_name,
|
|
3491
|
+
)
|
|
3492
|
+
if pids:
|
|
3493
|
+
pids_list = pids.split("\n")
|
|
3494
|
+
pids_list = list(filter(None, pids_list))
|
|
3495
|
+
return pids_list
|
|
3496
|
+
return None
|
|
@@ -26,7 +26,7 @@ class PodsMonitorPool:
|
|
|
26
26
|
self.events: list[Event] = []
|
|
27
27
|
|
|
28
28
|
def select_and_monitor_by_label(
|
|
29
|
-
self, label_selector: str, max_timeout: int
|
|
29
|
+
self, label_selector: str, field_selector: str, max_timeout: int
|
|
30
30
|
):
|
|
31
31
|
"""
|
|
32
32
|
Pushes into the pool a monitoring thread for all the pods identified
|
|
@@ -47,18 +47,23 @@ class PodsMonitorPool:
|
|
|
47
47
|
event = Event()
|
|
48
48
|
self.events.append(event)
|
|
49
49
|
pods_and_namespaces = self.krkn_lib.select_pods_by_label(
|
|
50
|
-
label_selector=label_selector
|
|
50
|
+
label_selector=label_selector, field_selector=field_selector
|
|
51
51
|
)
|
|
52
52
|
pod_monitor_thread = self.krkn_lib.monitor_pods_by_label(
|
|
53
53
|
label_selector=label_selector,
|
|
54
54
|
pods_and_namespaces=pods_and_namespaces,
|
|
55
|
+
field_selector=field_selector,
|
|
55
56
|
max_timeout=max_timeout,
|
|
56
57
|
event=event,
|
|
57
58
|
)
|
|
58
59
|
self.pods_monitor_threads.append(pod_monitor_thread)
|
|
59
60
|
|
|
60
61
|
def select_and_monitor_by_name_pattern_and_namespace_pattern(
|
|
61
|
-
self,
|
|
62
|
+
self,
|
|
63
|
+
pod_name_pattern: str,
|
|
64
|
+
namespace_pattern: str,
|
|
65
|
+
field_selector: str,
|
|
66
|
+
max_timeout: int,
|
|
62
67
|
):
|
|
63
68
|
"""
|
|
64
69
|
Pushes into the pool a monitoring thread for all the pods identified
|
|
@@ -74,6 +79,7 @@ class PodsMonitorPool:
|
|
|
74
79
|
pattern used to filter the pods to be monitored
|
|
75
80
|
(must be the same used in
|
|
76
81
|
`select_pods_by_name_pattern_and_namespace_pattern`)
|
|
82
|
+
:param field_selector: Pod field selector
|
|
77
83
|
:param max_timeout: the expected time the pods should take to
|
|
78
84
|
recover. If the killed pods are replaced in this time frame,
|
|
79
85
|
but they didn't reach the Ready State, they will be marked as
|
|
@@ -90,6 +96,7 @@ class PodsMonitorPool:
|
|
|
90
96
|
self.krkn_lib.select_pods_by_name_pattern_and_namespace_pattern(
|
|
91
97
|
pod_name_pattern=pod_name_pattern,
|
|
92
98
|
namespace_pattern=namespace_pattern,
|
|
99
|
+
field_selector=field_selector,
|
|
93
100
|
)
|
|
94
101
|
)
|
|
95
102
|
|
|
@@ -98,6 +105,7 @@ class PodsMonitorPool:
|
|
|
98
105
|
pod_name_pattern=pod_name_pattern,
|
|
99
106
|
namespace_pattern=namespace_pattern,
|
|
100
107
|
pods_and_namespaces=pods_and_namespaces,
|
|
108
|
+
field_selector=field_selector,
|
|
101
109
|
max_timeout=max_timeout,
|
|
102
110
|
event=event,
|
|
103
111
|
)
|
|
@@ -109,6 +117,7 @@ class PodsMonitorPool:
|
|
|
109
117
|
self,
|
|
110
118
|
namespace_pattern: str,
|
|
111
119
|
label_selector: str,
|
|
120
|
+
field_selector: str = None,
|
|
112
121
|
max_timeout=30,
|
|
113
122
|
):
|
|
114
123
|
"""
|
|
@@ -138,6 +147,7 @@ class PodsMonitorPool:
|
|
|
138
147
|
self.krkn_lib.select_pods_by_namespace_pattern_and_label(
|
|
139
148
|
namespace_pattern=namespace_pattern,
|
|
140
149
|
label_selector=label_selector,
|
|
150
|
+
field_selector=field_selector,
|
|
141
151
|
)
|
|
142
152
|
)
|
|
143
153
|
|
|
@@ -146,6 +156,7 @@ class PodsMonitorPool:
|
|
|
146
156
|
namespace_pattern=namespace_pattern,
|
|
147
157
|
label_selector=label_selector,
|
|
148
158
|
pods_and_namespaces=pods_and_namespaces,
|
|
159
|
+
field_selector=field_selector,
|
|
149
160
|
max_timeout=max_timeout,
|
|
150
161
|
event=event,
|
|
151
162
|
)
|