krkn-lib 5.0.1__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.1 → krkn_lib-5.1.0}/PKG-INFO +1 -1
  2. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/pyproject.toml +1 -1
  3. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/k8s/krkn_kubernetes.py +226 -93
  4. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/k8s/pods_monitor_pool.py +14 -3
  5. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/k8s/templates/node_exec_pod.j2 +6 -1
  6. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/models/k8s/models.py +9 -1
  7. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/prometheus/krkn_prometheus.py +1 -1
  8. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/telemetry/k8s/krkn_telemetry_kubernetes.py +0 -2
  9. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/tests/base_test.py +7 -0
  10. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_check.py +2 -3
  11. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_create.py +3 -5
  12. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_delete.py +2 -3
  13. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_get.py +104 -5
  14. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_list.py +13 -0
  15. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_monitor.py +168 -137
  16. {krkn_lib-5.0.1 → 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.1 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_telemetry_kubernetes.py +57 -51
  19. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_version.py +1 -1
  20. krkn_lib-5.0.1/src/krkn_lib/tests/test_krkn_prometheus.py +0 -229
  21. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/LICENSE +0 -0
  22. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/README.md +0 -0
  23. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/elastic/__init__.py +0 -0
  24. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/elastic/krkn_elastic.py +0 -0
  25. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/k8s/__init__.py +0 -0
  26. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/k8s/templates/hog_pod.j2 +0 -0
  27. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/k8s/templates/service_hijacking_config_map.j2 +0 -0
  28. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/k8s/templates/service_hijacking_pod.j2 +0 -0
  29. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/k8s/templates/syn_flood_pod.j2 +0 -0
  30. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/models/__init__.py +0 -0
  31. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/models/elastic/__init__.py +0 -0
  32. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/models/elastic/models.py +1 -1
  33. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/models/k8s/__init__.py +0 -0
  34. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/models/krkn/__init__.py +0 -0
  35. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/models/krkn/models.py +0 -0
  36. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/models/telemetry/__init__.py +0 -0
  37. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/models/telemetry/models.py +0 -0
  38. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/ocp/__init__.py +0 -0
  39. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/ocp/krkn_openshift.py +0 -0
  40. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/prometheus/__init__.py +0 -0
  41. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/telemetry/__init__.py +0 -0
  42. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/telemetry/k8s/__init__.py +0 -0
  43. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/telemetry/ocp/__init__.py +0 -0
  44. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/telemetry/ocp/krkn_telemetry_openshift.py +0 -0
  45. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/tests/__init__.py +0 -0
  46. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_elastic.py +0 -0
  47. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_elastic_models.py +1 -1
  48. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_exec.py +0 -0
  49. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_misc.py +2 -2
  50. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_kubernetes_models.py +1 -1
  51. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_openshift.py +0 -0
  52. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_telemetry_models.py +0 -0
  53. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_krkn_telemetry_openshift.py +0 -0
  54. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/tests/test_utils.py +0 -0
  55. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/utils/__init__.py +0 -0
  56. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/utils/functions.py +0 -0
  57. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/utils/safe_logger.py +0 -0
  58. {krkn_lib-5.0.1 → krkn_lib-5.1.0}/src/krkn_lib/version/__init__.py +0 -0
  59. {krkn_lib-5.0.1 → 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.1
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.1"
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:
@@ -851,12 +864,18 @@ class KrknKubernetes:
851
864
 
852
865
  # Outputs a json blob with informataion about all pods in a given namespace
853
866
  def get_all_pod_info(
854
- self, namespace: str = "default", label_selector: str = None
867
+ self,
868
+ namespace: str = "default",
869
+ label_selector: str = None,
870
+ field_selector: str = None,
855
871
  ) -> list[str]:
856
872
  """
857
873
  Get details of all pods in a namespace
858
874
 
859
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
+
860
879
  :return list of pod details
861
880
  """
862
881
  try:
@@ -867,12 +886,14 @@ class KrknKubernetes:
867
886
  pretty=True,
868
887
  label_selector=label_selector,
869
888
  limit=self.request_chunk_size,
889
+ field_selector=field_selector,
870
890
  )
871
891
  else:
872
892
  ret = self.list_continue_helper(
873
893
  self.cli.list_namespaced_pod,
874
894
  namespace,
875
895
  limit=self.request_chunk_size,
896
+ field_selector=field_selector,
876
897
  )
877
898
  except ApiException as e:
878
899
  logging.error(
@@ -1137,8 +1158,18 @@ class KrknKubernetes:
1137
1158
  :param namespace: namespace (optional default `default`)
1138
1159
  """
1139
1160
  try:
1161
+ starting_creation_timestamp = self.cli.read_namespaced_pod(
1162
+ name=name, namespace=namespace
1163
+ ).metadata.creation_timestamp
1140
1164
  self.cli.delete_namespaced_pod(name=name, namespace=namespace)
1165
+
1141
1166
  while self.cli.read_namespaced_pod(name=name, namespace=namespace):
1167
+
1168
+ ending_creation_timestamp = self.cli.read_namespaced_pod(
1169
+ name=name, namespace=namespace
1170
+ ).metadata.creation_timestamp
1171
+ if starting_creation_timestamp != ending_creation_timestamp:
1172
+ break
1142
1173
  time.sleep(1)
1143
1174
  except ApiException as e:
1144
1175
  if e.status == 404:
@@ -1481,7 +1512,9 @@ class KrknKubernetes:
1481
1512
  except Exception as e:
1482
1513
  logging.error("Error trying to apply_yaml" + str(e))
1483
1514
 
1484
- 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]:
1485
1518
  """
1486
1519
  Retrieve information about a specific pod
1487
1520
 
@@ -1491,62 +1524,70 @@ class KrknKubernetes:
1491
1524
  kubectl command in the given format if the pod exists.
1492
1525
  Returns None if the pod doesn't exist
1493
1526
  """
1494
-
1495
- pod_exists = self.check_if_pod_exists(name=name, namespace=namespace)
1496
- if pod_exists:
1527
+ try:
1528
+ pod_info = None
1497
1529
  response = self.cli.read_namespaced_pod(
1498
1530
  name=name, namespace=namespace, pretty="true"
1499
1531
  )
1500
- container_list = []
1501
-
1502
- # Create a list of containers present in the pod
1503
- for container in response.spec.containers:
1504
- volume_mount_list = []
1505
- for volume_mount in container.volume_mounts:
1506
- volume_mount_list.append(
1507
- VolumeMount(
1508
- name=volume_mount.name,
1509
- 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,
1510
1550
  )
1511
1551
  )
1512
- container_list.append(
1513
- Container(
1514
- name=container.name,
1515
- image=container.image,
1516
- 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
1517
1559
  )
1518
- )
1519
1560
 
1520
- for i, container in enumerate(response.status.container_statuses):
1521
- container_list[i].ready = container.ready
1522
-
1523
- # Create a list of volumes associated with the pod
1524
- volume_list = []
1525
- for volume in response.spec.volumes:
1526
- volume_name = volume.name
1527
- pvc_name = (
1528
- volume.persistent_volume_claim.claim_name
1529
- if volume.persistent_volume_claim is not None
1530
- 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,
1531
1584
  )
1532
- volume_list.append(Volume(name=volume_name, pvcName=pvc_name))
1533
-
1534
- # Create the Pod data class object
1535
- pod_info = Pod(
1536
- name=response.metadata.name,
1537
- podIP=response.status.pod_ip,
1538
- namespace=response.metadata.namespace,
1539
- containers=container_list,
1540
- nodeName=response.spec.node_name,
1541
- volumes=volume_list,
1542
- status=response.status.phase,
1543
- )
1544
- return pod_info
1545
- else:
1585
+ except Exception:
1546
1586
  logging.error(
1547
1587
  "Pod '%s' doesn't exist in namespace '%s'", name, namespace
1548
1588
  )
1549
1589
  return None
1590
+ return pod_info
1550
1591
 
1551
1592
  def check_if_namespace_exists(self, name: str) -> bool:
1552
1593
  """
@@ -2599,24 +2640,21 @@ class KrknKubernetes:
2599
2640
  )
2600
2641
  return None
2601
2642
 
2602
- 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)]:
2603
2646
  """
2604
2647
  Selects the pods identified by a label_selector
2605
2648
 
2606
2649
  :param label_selector: a label selector string
2607
2650
  in the format "key=value"
2608
- :param max_timeout: the maximum time in seconds
2609
- 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"
2610
2653
  :return: a list of pod_name and namespace tuples
2611
2654
  """
2612
- pods_and_namespaces = self.get_all_pods(label_selector)
2655
+ pods_and_namespaces = self.get_all_pods(label_selector, field_selector)
2613
2656
  pods_and_namespaces = [(pod[0], pod[1]) for pod in pods_and_namespaces]
2614
- # select only running pods
2615
- pods_and_namespaces = [
2616
- pod
2617
- for pod in pods_and_namespaces
2618
- if not self.is_pod_terminating(pod[0], pod[1])
2619
- ]
2657
+
2620
2658
  return pods_and_namespaces
2621
2659
 
2622
2660
  def select_service_by_label(
@@ -2648,7 +2686,10 @@ class KrknKubernetes:
2648
2686
  return selected_services
2649
2687
 
2650
2688
  def select_pods_by_name_pattern_and_namespace_pattern(
2651
- self, pod_name_pattern: str, namespace_pattern: str
2689
+ self,
2690
+ pod_name_pattern: str,
2691
+ namespace_pattern: str,
2692
+ field_selector: str = None,
2652
2693
  ) -> list[(str, str)]:
2653
2694
  """
2654
2695
  Selects the pods identified by a namespace_pattern
@@ -2658,6 +2699,8 @@ class KrknKubernetes:
2658
2699
  :param namespace_pattern: a namespace pattern to match
2659
2700
  :param max_timeout: the maximum time in seconds to wait
2660
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"
2661
2704
  :return: a list of pod_name and namespace tuples
2662
2705
  """
2663
2706
  namespace_re = re.compile(namespace_pattern)
@@ -2666,20 +2709,18 @@ class KrknKubernetes:
2666
2709
  pods_and_namespaces = []
2667
2710
  for namespace in namespaces:
2668
2711
  if namespace_re.match(namespace):
2669
- pods = self.list_pods(namespace)
2712
+ pods = self.list_pods(namespace, field_selector=field_selector)
2670
2713
  for pod in pods:
2671
2714
  if podname_re.match(pod):
2672
2715
  pods_and_namespaces.append((pod, namespace))
2673
- # select only running pods
2674
- pods_and_namespaces = [
2675
- (pod[0], pod[1])
2676
- for pod in pods_and_namespaces
2677
- if not self.is_pod_terminating(pod[0], pod[1])
2678
- ]
2716
+
2679
2717
  return pods_and_namespaces
2680
2718
 
2681
2719
  def select_pods_by_namespace_pattern_and_label(
2682
- self, namespace_pattern: str, label_selector: str
2720
+ self,
2721
+ namespace_pattern: str,
2722
+ label_selector: str,
2723
+ field_selector: str = None,
2683
2724
  ) -> list[(str, str)]:
2684
2725
  """
2685
2726
  Selects the pods identified by a label_selector
@@ -2688,20 +2729,16 @@ class KrknKubernetes:
2688
2729
  :param namespace_pattern: a namespace pattern to match
2689
2730
  :param label_selector: a label selector string
2690
2731
  in the format "key=value"
2691
- :param max_timeout: the maximum time in seconds
2692
- 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"
2693
2734
  :return: a list of pod_name and namespace tuples
2694
2735
  """
2695
2736
  namespace_re = re.compile(namespace_pattern)
2696
- pods_and_namespaces = self.get_all_pods(label_selector)
2697
- pods_and_namespaces = [
2698
- pod for pod in pods_and_namespaces if namespace_re.match(pod[1])
2699
- ]
2700
- # select only running pods
2737
+ pods_and_namespaces = self.get_all_pods(label_selector, field_selector)
2701
2738
  pods_and_namespaces = [
2702
2739
  (pod[0], pod[1])
2703
2740
  for pod in pods_and_namespaces
2704
- if not self.is_pod_terminating(pod[0], pod[1])
2741
+ if namespace_re.match(pod[1])
2705
2742
  ]
2706
2743
  return pods_and_namespaces
2707
2744
 
@@ -2709,6 +2746,7 @@ class KrknKubernetes:
2709
2746
  self,
2710
2747
  label_selector: str,
2711
2748
  pods_and_namespaces: list[(str, str)],
2749
+ field_selector: str = None,
2712
2750
  max_timeout: int = 30,
2713
2751
  event: threading.Event = None,
2714
2752
  ) -> PodsMonitorThread:
@@ -2726,6 +2764,8 @@ class KrknKubernetes:
2726
2764
  :param pods_and_namespaces: the list of pods collected
2727
2765
  by `select_pods_by_label` against which the changes
2728
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"
2729
2769
  :param max_timeout: the expected time the pods should take
2730
2770
  to recover. If the killed pods are replaced in this time frame,
2731
2771
  but they didn't reach the Ready State, they will be marked as
@@ -2747,6 +2787,7 @@ class KrknKubernetes:
2747
2787
  max_timeout=max_timeout,
2748
2788
  pods_status=pods_status,
2749
2789
  label_selector=label_selector,
2790
+ field_selector=field_selector,
2750
2791
  event=event,
2751
2792
  )
2752
2793
 
@@ -2755,6 +2796,7 @@ class KrknKubernetes:
2755
2796
  pod_name_pattern: str,
2756
2797
  namespace_pattern: str,
2757
2798
  pods_and_namespaces: list[(str, str)],
2799
+ field_selector: str = None,
2758
2800
  max_timeout=30,
2759
2801
  event: threading.Event = None,
2760
2802
  ) -> PodsMonitorThread:
@@ -2778,6 +2820,8 @@ class KrknKubernetes:
2778
2820
  :param pods_and_namespaces: the list of pods collected by
2779
2821
  `select_pods_by_name_pattern_and_namespace_pattern` against
2780
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"
2781
2825
  :param max_timeout: the expected time the pods should take to
2782
2826
  recover. If the killed pods are replaced in this time frame,
2783
2827
  but they didn't reach the Ready State, they will be marked as
@@ -2798,6 +2842,7 @@ class KrknKubernetes:
2798
2842
  pods_and_namespaces=pods_and_namespaces,
2799
2843
  max_timeout=max_timeout,
2800
2844
  pods_status=pods_status,
2845
+ field_selector=field_selector,
2801
2846
  name_pattern=pod_name_pattern,
2802
2847
  namespace_pattern=namespace_pattern,
2803
2848
  event=event,
@@ -2808,6 +2853,7 @@ class KrknKubernetes:
2808
2853
  namespace_pattern: str,
2809
2854
  label_selector: str,
2810
2855
  pods_and_namespaces: list[(str, str)],
2856
+ field_selector: str = None,
2811
2857
  max_timeout=30,
2812
2858
  event: threading.Event = None,
2813
2859
  ) -> PodsMonitorThread:
@@ -2830,6 +2876,8 @@ class KrknKubernetes:
2830
2876
  :param pods_and_namespaces: the list of pods collected by
2831
2877
  `select_pods_by_name_pattern_and_namespace_pattern` against
2832
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"
2833
2881
  :param max_timeout: the expected time the pods should take to recover.
2834
2882
  If the killed pods are replaced in this time frame, but they
2835
2883
  didn't reach the Ready State, they will be marked as unrecovered.
@@ -2851,6 +2899,7 @@ class KrknKubernetes:
2851
2899
  max_timeout=max_timeout,
2852
2900
  pods_status=pods_status,
2853
2901
  label_selector=label_selector,
2902
+ field_selector=field_selector,
2854
2903
  namespace_pattern=namespace_pattern,
2855
2904
  event=event,
2856
2905
  )
@@ -2861,6 +2910,7 @@ class KrknKubernetes:
2861
2910
  pods_status: PodsStatus,
2862
2911
  max_timeout: int,
2863
2912
  label_selector: str = None,
2913
+ field_selector: str = None,
2864
2914
  pod_name: str = None,
2865
2915
  namespace_pattern: str = None,
2866
2916
  name_pattern: str = None,
@@ -2873,6 +2923,7 @@ class KrknKubernetes:
2873
2923
  pods_status=pods_status,
2874
2924
  max_timeout=max_timeout,
2875
2925
  label_selector=label_selector,
2926
+ field_selector=field_selector,
2876
2927
  pod_name=pod_name,
2877
2928
  namespace_pattern=namespace_pattern,
2878
2929
  name_pattern=name_pattern,
@@ -2887,6 +2938,7 @@ class KrknKubernetes:
2887
2938
  pods_status: PodsStatus,
2888
2939
  max_timeout: int,
2889
2940
  label_selector: str = None,
2941
+ field_selector: str = None,
2890
2942
  pod_name: str = None,
2891
2943
  namespace_pattern: str = None,
2892
2944
  name_pattern: str = None,
@@ -2906,6 +2958,7 @@ class KrknKubernetes:
2906
2958
  select_method = partial(
2907
2959
  self.select_pods_by_label,
2908
2960
  label_selector=label_selector,
2961
+ field_selector=field_selector,
2909
2962
  )
2910
2963
  elif (
2911
2964
  name_pattern
@@ -2917,6 +2970,7 @@ class KrknKubernetes:
2917
2970
  self.select_pods_by_name_pattern_and_namespace_pattern,
2918
2971
  pod_name_pattern=name_pattern,
2919
2972
  namespace_pattern=namespace_pattern,
2973
+ field_selector=field_selector,
2920
2974
  )
2921
2975
  elif (
2922
2976
  namespace_pattern
@@ -2928,6 +2982,7 @@ class KrknKubernetes:
2928
2982
  self.select_pods_by_namespace_pattern_and_label,
2929
2983
  namespace_pattern=namespace_pattern,
2930
2984
  label_selector=label_selector,
2985
+ field_selector=field_selector,
2931
2986
  )
2932
2987
  else:
2933
2988
  pods_status.error = (
@@ -2944,17 +2999,19 @@ class KrknKubernetes:
2944
2999
  time_offset = time.time() - start_time
2945
3000
  remaining_time = max_timeout - time_offset
2946
3001
  current_pods_and_namespaces = select_method()
2947
-
2948
3002
  # no pods have been killed or pods have been killed and
2949
3003
  # respawned with the same names
2950
3004
  if set(pods_and_namespaces) == set(current_pods_and_namespaces):
2951
3005
  for pod in current_pods_and_namespaces:
2952
- if not self.is_pod_running(pod[0], pod[1]):
2953
- missing_pods.add(pod)
2954
- if len(missing_pods) == 0:
2955
- continue
2956
- # in this case the pods to wait have been respawn
2957
- # with the same name
3006
+
3007
+ pod_info = self.get_pod_info(pod[0], pod[1])
3008
+ # for pod_info in pod_list_info:
3009
+ if pod_info:
3010
+ pod_creation_timestamp = (
3011
+ pod_info.creation_timestamp.timestamp()
3012
+ )
3013
+ if start_time < pod_creation_timestamp:
3014
+ missing_pods.add(pod)
2958
3015
  pods_to_wait.update(missing_pods)
2959
3016
 
2960
3017
  # pods have been killed but respawned with different names
@@ -2984,12 +3041,12 @@ class KrknKubernetes:
2984
3041
  # inject the chaos, let's see the next iteration.
2985
3042
  if len(pods_to_wait) == 0:
2986
3043
  continue
2987
-
2988
3044
  futures = []
2989
-
2990
3045
  with ThreadPoolExecutor() as executor:
2991
3046
  for pod_and_namespace in pods_to_wait:
2992
3047
  if pod_and_namespace not in pods_already_watching:
3048
+
3049
+ # need name of new pod
2993
3050
  future = executor.submit(
2994
3051
  self.__wait_until_pod_is_ready_worker,
2995
3052
  pod_name=pod_and_namespace[0],
@@ -3008,20 +3065,24 @@ class KrknKubernetes:
3008
3065
  # sum the time elapsed waiting before the pod
3009
3066
  # has been rescheduled (rescheduling time)
3010
3067
  # to the effective recovery time of the pod
3011
- result.pod_rescheduling_time = (
3012
- time.time() - start_time - result.pod_readiness_time
3013
- )
3014
- result.total_recovery_time = (
3015
- result.pod_readiness_time
3016
- + result.pod_rescheduling_time
3017
- )
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
+ )
3018
3078
 
3019
- pods_status.recovered.append(result)
3079
+ pods_status.recovered.append(result)
3020
3080
  for future in undone:
3021
3081
  result = future.result()
3022
3082
  pods_status.unrecovered.append(result)
3023
3083
 
3024
3084
  missing_pods.clear()
3085
+
3025
3086
  # if there are missing pods, pods affected
3026
3087
  # by the chaos did not restart after the chaos
3027
3088
  # an exception will be set in the PodsStatus
@@ -3361,3 +3422,75 @@ class KrknKubernetes:
3361
3422
  resources.memory = json_obj["node"]["memory"]["availableBytes"]
3362
3423
  resources.disk_space = json_obj["node"]["fs"]["availableBytes"]
3363
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