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.
Files changed (59) hide show
  1. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/PKG-INFO +1 -1
  2. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/pyproject.toml +1 -1
  3. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/k8s/krkn_kubernetes.py +207 -96
  4. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/k8s/pods_monitor_pool.py +14 -3
  5. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/k8s/templates/node_exec_pod.j2 +6 -1
  6. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/models/k8s/models.py +4 -0
  7. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/prometheus/krkn_prometheus.py +1 -1
  8. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/telemetry/k8s/krkn_telemetry_kubernetes.py +0 -2
  9. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/base_test.py +7 -0
  10. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_check.py +2 -3
  11. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_create.py +3 -5
  12. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_delete.py +2 -3
  13. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_get.py +104 -5
  14. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_list.py +13 -0
  15. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_monitor.py +168 -137
  16. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_pods_monitor_pool.py +7 -3
  17. krkn_lib-5.1.0/src/krkn_lib/tests/test_krkn_prometheus.py +234 -0
  18. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_telemetry_kubernetes.py +57 -51
  19. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_version.py +1 -1
  20. krkn_lib-5.0.2/src/krkn_lib/tests/test_krkn_prometheus.py +0 -229
  21. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/LICENSE +0 -0
  22. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/README.md +0 -0
  23. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/elastic/__init__.py +0 -0
  24. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/elastic/krkn_elastic.py +0 -0
  25. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/k8s/__init__.py +0 -0
  26. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/k8s/templates/hog_pod.j2 +0 -0
  27. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/k8s/templates/service_hijacking_config_map.j2 +0 -0
  28. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/k8s/templates/service_hijacking_pod.j2 +0 -0
  29. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/k8s/templates/syn_flood_pod.j2 +0 -0
  30. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/models/__init__.py +0 -0
  31. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/models/elastic/__init__.py +0 -0
  32. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/models/elastic/models.py +1 -1
  33. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/models/k8s/__init__.py +0 -0
  34. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/models/krkn/__init__.py +0 -0
  35. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/models/krkn/models.py +0 -0
  36. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/models/telemetry/__init__.py +0 -0
  37. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/models/telemetry/models.py +0 -0
  38. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/ocp/__init__.py +0 -0
  39. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/ocp/krkn_openshift.py +0 -0
  40. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/prometheus/__init__.py +0 -0
  41. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/telemetry/__init__.py +0 -0
  42. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/telemetry/k8s/__init__.py +0 -0
  43. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/telemetry/ocp/__init__.py +0 -0
  44. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/telemetry/ocp/krkn_telemetry_openshift.py +0 -0
  45. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/__init__.py +0 -0
  46. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_elastic.py +0 -0
  47. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_elastic_models.py +1 -1
  48. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_exec.py +0 -0
  49. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_misc.py +2 -2
  50. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_models.py +1 -1
  51. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_openshift.py +0 -0
  52. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_telemetry_models.py +0 -0
  53. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_telemetry_openshift.py +0 -0
  54. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_utils.py +0 -0
  55. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/utils/__init__.py +0 -0
  56. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/utils/functions.py +0 -0
  57. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/utils/safe_logger.py +0 -0
  58. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/version/__init__.py +0 -0
  59. {krkn_lib-5.0.2 → krkn_lib-5.1.0}/src/krkn_lib/version/version.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: krkn-lib
3
- Version: 5.0.2
3
+ Version: 5.1.0
4
4
  Summary: Foundation library for Kraken
5
5
  License: Apache-2.0
6
6
  Author: Red Hat Chaos Team
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "krkn-lib"
3
- version = "5.0.2"
3
+ version = "5.1.0"
4
4
  description = "Foundation library for Kraken"
5
5
  authors = ["Red Hat Chaos Team"]
6
6
  license = "Apache-2.0"
@@ -529,7 +529,10 @@ class KrknKubernetes:
529
529
  return managedclusters
530
530
 
531
531
  def list_pods(
532
- self, namespace: str, label_selector: str = None
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(namespace, label_selector)
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(self, label_selector: str = None) -> list[[str, str]]:
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(self, name: str, namespace: str = "default") -> Pod:
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
- pod_exists = self.check_if_pod_exists(name=name, namespace=namespace)
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
- container_list = []
1513
-
1514
- # Create a list of containers present in the pod
1515
- for container in response.spec.containers:
1516
- volume_mount_list = []
1517
- for volume_mount in container.volume_mounts:
1518
- volume_mount_list.append(
1519
- VolumeMount(
1520
- name=volume_mount.name,
1521
- mountPath=volume_mount.mount_path,
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
- container_list.append(
1525
- Container(
1526
- name=container.name,
1527
- image=container.image,
1528
- volumeMounts=volume_mount_list,
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
- for i, container in enumerate(response.status.container_statuses):
1533
- container_list[i].ready = container.ready
1534
-
1535
- # Create a list of volumes associated with the pod
1536
- volume_list = []
1537
- for volume in response.spec.volumes:
1538
- volume_name = volume.name
1539
- pvc_name = (
1540
- volume.persistent_volume_claim.claim_name
1541
- if volume.persistent_volume_claim is not None
1542
- else None
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
- volume_list.append(Volume(name=volume_name, pvcName=pvc_name))
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(self, label_selector: str) -> list[(str, str)]:
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 max_timeout: the maximum time in seconds
2622
- to wait before considering the pod "not recovered" after the Chaos
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
- # select only running pods
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, pod_name_pattern: str, namespace_pattern: str
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
- # select only running pods
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, namespace_pattern: str, label_selector: str
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 max_timeout: the maximum time in seconds
2705
- to wait before considering the pod "not recovered" after the Chaos
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 not self.is_pod_terminating(pod[0], pod[1])
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
- if pod_info is not None:
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
- else:
2973
- continue
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.pod_rescheduling_time = (
3034
- time.time() - start_time - result.pod_readiness_time
3035
- )
3036
- result.total_recovery_time = (
3037
- result.pod_readiness_time
3038
- + result.pod_rescheduling_time
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
- pods_status.recovered.append(result)
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, pod_name_pattern: str, namespace_pattern: str, max_timeout: int
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
  )